Initial commit
[ta/config-manager.git] / cmframework / src / cmframework / utils / cmlogger.py
diff --git a/cmframework/src/cmframework/utils/cmlogger.py b/cmframework/src/cmframework/utils/cmlogger.py
new file mode 100644 (file)
index 0000000..eba7fd3
--- /dev/null
@@ -0,0 +1,151 @@
+# Copyright 2019 Nokia
+
+# 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.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+import re
+import sys
+import logging
+from logging.handlers import SysLogHandler
+
+from cmframework.apis import cmerror
+
+
+class CMMaskFormatter(object):
+    def __init__(self, orig_formatter, patterns):
+        self.orig_formatter = orig_formatter
+        self.patterns = patterns
+
+    def format(self, record):
+        msg = self.orig_formatter.format(record)
+        regex = r'([\\]*\"{}[\\]*\":\s[\\]*\")[^\"\\\s]+([\\]*\")'
+        for pattern in self.patterns:
+
+            msg = re.sub(regex.format(pattern),
+                         r'\1*** password ***\2', msg)
+
+        return msg
+
+    def __getattr__(self, attr):
+        return getattr(self.orig_formatter, attr)
+
+
+class CMLogger(object):
+    levels = {'debug': logging.DEBUG,
+              'info': logging.INFO,
+              'warning': logging.WARNING,
+              'error': logging.error}
+
+    DEST_CONSOLE = 1
+    DEST_SYSLOG = 2
+    dests = {'console': DEST_CONSOLE,
+             'syslog': DEST_SYSLOG}
+
+    def __init__(self, dest, verbose, level, mask_names=None):
+        self.verbose = verbose
+        self.dest = dest
+        self.level = level
+        self.formatter = None
+        self.handler = None
+        self.mask_formatter = None
+        if mask_names is None:
+            mask_names = []
+        self.init(mask_names)
+
+    def init(self, mask_names):
+        if self.level not in CMLogger.levels.values():
+            raise cmerror.CMError('Invalid level value, possible values are %s' %
+                                  str(CMLogger.levels))
+
+        if self.dest not in CMLogger.dests.values():
+            raise cmerror.CMError('Invalid destination value, possible values are %s' %
+                                  str(CMLogger.dests))
+
+        if self.verbose:
+            if self.dest is CMLogger.DEST_CONSOLE:
+                format_str = '[%(asctime)s %(levelname)7s %(module)s(%(lineno)3s)] %(message)s'
+            else:
+                format_str = '[%(module)s(%(lineno)3s)] %(message)s'
+        else:
+            format_str = '%(message)s'
+
+        self.formatter = logging.Formatter(format_str)
+        self.mask_formatter = CMMaskFormatter(self.formatter, mask_names)
+        self.set_dest(self.dest)
+
+        logging.getLogger().setLevel(self.level)
+
+    def set_level(self, level):
+        self.level = level
+        logging.getLogger().setLevel(self.level)
+
+    def set_dest(self, dest):
+        if self.dest != dest or self.handler is None:
+            if self.handler:
+                logging.getLogger().removeHandler(self.handler)
+
+            if self.dest is CMLogger.DEST_CONSOLE:
+                self.handler = logging.StreamHandler(sys.stdout)
+                self.handler.setFormatter(self.mask_formatter)
+            elif self.dest is CMLogger.DEST_SYSLOG:
+                print '====> setting destination to syslog'
+                self.handler = SysLogHandler(address='/dev/log')
+                self.handler.setFormatter(self.mask_formatter)
+            logging.getLogger().addHandler(self.handler)
+
+    @staticmethod
+    def str_to_level(level):
+        ret = None
+        try:
+            ret = CMLogger.levels[level]
+        except KeyError:
+            raise cmerror.CMError('Invalid log level, possible values %s' %
+                                  str(CMLogger.levels.keys()))
+        return ret
+
+    @staticmethod
+    def str_to_dest(dest):
+        ret = None
+        try:
+            ret = CMLogger.dests[dest]
+        except KeyError:
+            raise cmerror.CMError('Invalid destination, possible values %s' %
+                                  str(CMLogger.dests.keys()))
+        return ret
+
+    @staticmethod
+    def level_to_str(level):
+        for key, value in CMLogger.levels.iteritems():
+            if value is level:
+                return key
+        return None
+
+    @staticmethod
+    def dest_to_str(dest):
+        for key, value in CMLogger.dests.iteritems():
+            if value is dest:
+                return key
+        return None
+
+
+def main():
+    log_dest = CMLogger.str_to_dest('console')
+    log_level = CMLogger.str_to_level('debug')
+    _ = CMLogger(log_dest, True, log_level)
+    world = 'world'
+    logging.error('hello %s!', world)
+    logging.warn('hello %s!', world)
+    logging.info('hello %s!', world)
+    logging.debug('hello %s!', world)
+
+
+if __name__ == '__main__':
+    main()