diff options
Diffstat (limited to 'pylog/onaplogging/mdcformatter.py')
-rw-r--r-- | pylog/onaplogging/mdcformatter.py | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/pylog/onaplogging/mdcformatter.py b/pylog/onaplogging/mdcformatter.py new file mode 100644 index 0000000..f63ec94 --- /dev/null +++ b/pylog/onaplogging/mdcformatter.py @@ -0,0 +1,123 @@ +# 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 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): + """ + :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 + """ + + super(MDCFormatter, self).__init__(fmt=fmt, datefmt=datefmt) + 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 = 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('%(mdc)s') + if mdcIndex == -1: + return super(MDCFormatter, self).format(record) + + mdcFmtkeys, mdcFmtWords = self._mdcfmtKey() + if mdcFmtWords is None: + + self._fmt = self._fmt.replace("%(mdc)s", "") + return super(MDCFormatter, self).format(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) + self._fmt = self._fmt.replace("%(mdc)s", mdcstr) + s = super(MDCFormatter, self).format(record) + return s + + except KeyError as e: + print ("The mdc key %s format is wrong" % e.message) + except Exception: + raise + + finally: + # reset fmt format + self._fmt = self._tmpfmt |