1 # Copyright (c) 2018 VMware, Inc.
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:
7 # http://www.apache.org/licenses/LICENSE-2.0
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.
21 __all__ = ['patch_loggingMDC', 'MDC']
23 _replace_func_name = ['info', 'critical', 'fatal', 'debug',
24 'error', 'warn', 'warning', 'findCaller']
27 class MDCContext(threading.local):
29 A Thread local instance to storage mdc values
33 super(MDCContext, self).__init__()
38 return self._localDict.get(key, None)
40 def put(self, key, value):
42 self._localDict[key] = value
44 def remove(self, key):
46 if key in self.localDict:
47 del self._localDict[key]
51 self._localDict.clear()
55 return self._localDict
59 return self._localDict == {} or self._localDict is None
67 @functools.wraps(func)
68 def replace(*args, **kwargs):
69 kwargs['extra'] = _getmdcs(extra=kwargs.get('extra', None))
74 def _getmdcs(extra=None):
76 Put mdc dict in logging record extra filed with key 'mdc'
87 # make sure extra key dosen't override mdckey
88 if key in mdc or key == 'mdc':
89 raise KeyError("Attempt to overwrite %r in MDC" % key)
99 def info(self, msg, *args, **kwargs):
101 if self.isEnabledFor(logging.INFO):
102 self._log(logging.INFO, msg, args, **kwargs)
106 def debug(self, msg, *args, **kwargs):
108 if self.isEnabledFor(logging.DEBUG):
109 self._log(logging.DEBUG, msg, args, **kwargs)
113 def warning(self, msg, *args, **kwargs):
114 if self.isEnabledFor(logging.WARNING):
115 self._log(logging.WARNING, msg, args, **kwargs)
119 def exception(self, msg, *args, **kwargs):
121 kwargs['exc_info'] = 1
122 self.error(msg, *args, **kwargs)
126 def critical(self, msg, *args, **kwargs):
128 if self.isEnabledFor(logging.CRITICAL):
129 self._log(logging.CRITICAL, msg, args, **kwargs)
133 def error(self, msg, *args, **kwargs):
134 if self.isEnabledFor(logging.ERROR):
135 self._log(logging.ERROR, msg, args, **kwargs)
138 def findCaller(self):
140 f = logging.currentframe()
143 rv = "(unkown file)", 0, "(unknow function)"
144 while hasattr(f, "f_code"):
146 filename = os.path.normcase(co.co_filename)
147 # jump through local 'replace' func frame
148 if filename == logging._srcfile or co.co_name == "replace":
151 rv = (co.co_filename, f.f_lineno, co.co_name)
157 def patch_loggingMDC():
159 The patch to add MDC ability in logging Record instance at runtime
161 localModule = sys.modules[__name__]
162 for attr in dir(logging.Logger):
163 if attr in _replace_func_name:
164 newfunc = getattr(localModule, attr, None)
166 setattr(logging.Logger, attr, newfunc)