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