Submit python logging library seed code
[logging-analytics.git] / pylog / onaplogging / mdcformatter.py
1 # Copyright (c) 2018 VMware, Inc.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at:
6 #
7 #       http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
13 import logging
14
15
16 class MDCFormatter(logging.Formatter):
17     """
18     A custom MDC formatter to prepare Mapped Diagnostic Context
19     to enrich log message.
20     """
21
22     def __init__(self, fmt=None, mdcfmt=None, datefmt=None):
23         """
24         :param fmt: build-in format string contains standard
25                Python %-style mapping keys
26         :param mdcFmt: mdc format with '{}'-style mapping keys
27         :param datefmt: Date format to use
28         """
29
30         super(MDCFormatter, self).__init__(fmt=fmt, datefmt=datefmt)
31         self._tmpfmt = self._fmt
32         if mdcfmt:
33             self._mdcFmt = mdcfmt
34         else:
35             self._mdcFmt = '{reqeustID}'
36
37     def _mdcfmtKey(self):
38         """
39          maximum barce match algorithm to find the mdc key
40         :return: key in brace  and key not in brace,such as ({key}, key)
41         """
42
43         left = '{'
44         right = '}'
45         target = self._mdcFmt
46         st = []
47         keys = []
48         for index, v in enumerate(target):
49             if v == left:
50                 st.append(index)
51             elif v == right:
52
53                 if len(st) == 0:
54                     continue
55
56                 elif len(st) == 1:
57                     start = st.pop()
58                     end = index
59                     keys.append(target[start:end + 1])
60                 elif len(st) > 0:
61                     st.pop()
62
63         keys = filter(lambda x: x[1:-1].strip('\n \t  ') != "", keys)
64         words = None
65         if keys:
66             words = map(lambda x: x[1:-1], keys)
67
68         return keys, words
69
70     def _replaceStr(self, keys):
71
72         fmt = self._mdcFmt
73         for i in keys:
74             fmt = fmt.replace(i, i[1:-1] + "=" + i)
75
76         return fmt
77
78     def format(self, record):
79         """
80         Find mdcs in log record extra field, if key form mdcFmt dosen't
81         contains mdcs, the values will be empty.
82         :param record: the logging record instance
83         :return:  string
84         for example:
85             the mdcs dict in logging record is
86             {'key1':'value1','key2':'value2'}
87             the mdcFmt is" '{key1} {key3}'
88             the output of mdc message: 'key1=value1 key3='
89
90         """
91         mdcIndex = self._fmt.find('%(mdc)s')
92         if mdcIndex == -1:
93             return super(MDCFormatter, self).format(record)
94
95         mdcFmtkeys, mdcFmtWords = self._mdcfmtKey()
96         if mdcFmtWords is None:
97
98             self._fmt = self._fmt.replace("%(mdc)s", "")
99             return super(MDCFormatter, self).format(record)
100
101         mdc = record.__dict__.get('mdc', None)
102         res = {}
103         for i in mdcFmtWords:
104             if mdc and i in mdc:
105                 res[i] = mdc[i]
106             else:
107                 res[i] = ""
108
109         del mdc
110         try:
111             mdcstr = self._replaceStr(keys=mdcFmtkeys).format(**res)
112             self._fmt = self._fmt.replace("%(mdc)s", mdcstr)
113             s = super(MDCFormatter, self).format(record)
114             return s
115
116         except KeyError as e:
117             print ("The mdc key %s format is wrong" % e.message)
118         except Exception:
119             raise
120
121         finally:
122             # reset fmt format
123             self._fmt = self._tmpfmt