Initial commit
[ta/config-manager.git] / cmframework / src / cmframework / utils / cmlogger.py
1 # Copyright 2019 Nokia
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 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 import re
15 import sys
16 import logging
17 from logging.handlers import SysLogHandler
18
19 from cmframework.apis import cmerror
20
21
22 class CMMaskFormatter(object):
23     def __init__(self, orig_formatter, patterns):
24         self.orig_formatter = orig_formatter
25         self.patterns = patterns
26
27     def format(self, record):
28         msg = self.orig_formatter.format(record)
29         regex = r'([\\]*\"{}[\\]*\":\s[\\]*\")[^\"\\\s]+([\\]*\")'
30         for pattern in self.patterns:
31
32             msg = re.sub(regex.format(pattern),
33                          r'\1*** password ***\2', msg)
34
35         return msg
36
37     def __getattr__(self, attr):
38         return getattr(self.orig_formatter, attr)
39
40
41 class CMLogger(object):
42     levels = {'debug': logging.DEBUG,
43               'info': logging.INFO,
44               'warning': logging.WARNING,
45               'error': logging.error}
46
47     DEST_CONSOLE = 1
48     DEST_SYSLOG = 2
49     dests = {'console': DEST_CONSOLE,
50              'syslog': DEST_SYSLOG}
51
52     def __init__(self, dest, verbose, level, mask_names=None):
53         self.verbose = verbose
54         self.dest = dest
55         self.level = level
56         self.formatter = None
57         self.handler = None
58         self.mask_formatter = None
59         if mask_names is None:
60             mask_names = []
61         self.init(mask_names)
62
63     def init(self, mask_names):
64         if self.level not in CMLogger.levels.values():
65             raise cmerror.CMError('Invalid level value, possible values are %s' %
66                                   str(CMLogger.levels))
67
68         if self.dest not in CMLogger.dests.values():
69             raise cmerror.CMError('Invalid destination value, possible values are %s' %
70                                   str(CMLogger.dests))
71
72         if self.verbose:
73             if self.dest is CMLogger.DEST_CONSOLE:
74                 format_str = '[%(asctime)s %(levelname)7s %(module)s(%(lineno)3s)] %(message)s'
75             else:
76                 format_str = '[%(module)s(%(lineno)3s)] %(message)s'
77         else:
78             format_str = '%(message)s'
79
80         self.formatter = logging.Formatter(format_str)
81         self.mask_formatter = CMMaskFormatter(self.formatter, mask_names)
82         self.set_dest(self.dest)
83
84         logging.getLogger().setLevel(self.level)
85
86     def set_level(self, level):
87         self.level = level
88         logging.getLogger().setLevel(self.level)
89
90     def set_dest(self, dest):
91         if self.dest != dest or self.handler is None:
92             if self.handler:
93                 logging.getLogger().removeHandler(self.handler)
94
95             if self.dest is CMLogger.DEST_CONSOLE:
96                 self.handler = logging.StreamHandler(sys.stdout)
97                 self.handler.setFormatter(self.mask_formatter)
98             elif self.dest is CMLogger.DEST_SYSLOG:
99                 print '====> setting destination to syslog'
100                 self.handler = SysLogHandler(address='/dev/log')
101                 self.handler.setFormatter(self.mask_formatter)
102             logging.getLogger().addHandler(self.handler)
103
104     @staticmethod
105     def str_to_level(level):
106         ret = None
107         try:
108             ret = CMLogger.levels[level]
109         except KeyError:
110             raise cmerror.CMError('Invalid log level, possible values %s' %
111                                   str(CMLogger.levels.keys()))
112         return ret
113
114     @staticmethod
115     def str_to_dest(dest):
116         ret = None
117         try:
118             ret = CMLogger.dests[dest]
119         except KeyError:
120             raise cmerror.CMError('Invalid destination, possible values %s' %
121                                   str(CMLogger.dests.keys()))
122         return ret
123
124     @staticmethod
125     def level_to_str(level):
126         for key, value in CMLogger.levels.iteritems():
127             if value is level:
128                 return key
129         return None
130
131     @staticmethod
132     def dest_to_str(dest):
133         for key, value in CMLogger.dests.iteritems():
134             if value is dest:
135                 return key
136         return None
137
138
139 def main():
140     log_dest = CMLogger.str_to_dest('console')
141     log_level = CMLogger.str_to_level('debug')
142     _ = CMLogger(log_dest, True, log_level)
143     world = 'world'
144     logging.error('hello %s!', world)
145     logging.warn('hello %s!', world)
146     logging.info('hello %s!', world)
147     logging.debug('hello %s!', world)
148
149
150 if __name__ == '__main__':
151     main()