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.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
17 from logging.handlers import SysLogHandler
19 from cmframework.apis import cmerror
22 class CMMaskFormatter(object):
23 def __init__(self, orig_formatter, patterns):
24 self.orig_formatter = orig_formatter
25 self.patterns = patterns
27 def format(self, record):
28 msg = self.orig_formatter.format(record)
29 regex = r'([\\]*\"{}[\\]*\":\s[\\]*\")[^\"\\\s]+([\\]*\")'
30 for pattern in self.patterns:
32 msg = re.sub(regex.format(pattern),
33 r'\1*** password ***\2', msg)
37 def __getattr__(self, attr):
38 return getattr(self.orig_formatter, attr)
41 class CMLogger(object):
42 levels = {'debug': logging.DEBUG,
44 'warning': logging.WARNING,
45 'error': logging.error}
49 dests = {'console': DEST_CONSOLE,
50 'syslog': DEST_SYSLOG}
52 def __init__(self, dest, verbose, level, mask_names=None):
53 self.verbose = verbose
58 self.mask_formatter = None
59 if mask_names is None:
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' %
68 if self.dest not in CMLogger.dests.values():
69 raise cmerror.CMError('Invalid destination value, possible values are %s' %
73 if self.dest is CMLogger.DEST_CONSOLE:
74 format_str = '[%(asctime)s %(levelname)7s %(module)s(%(lineno)3s)] %(message)s'
76 format_str = '[%(module)s(%(lineno)3s)] %(message)s'
78 format_str = '%(message)s'
80 self.formatter = logging.Formatter(format_str)
81 self.mask_formatter = CMMaskFormatter(self.formatter, mask_names)
82 self.set_dest(self.dest)
84 logging.getLogger().setLevel(self.level)
86 def set_level(self, level):
88 logging.getLogger().setLevel(self.level)
90 def set_dest(self, dest):
91 if self.dest != dest or self.handler is None:
93 logging.getLogger().removeHandler(self.handler)
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)
105 def str_to_level(level):
108 ret = CMLogger.levels[level]
110 raise cmerror.CMError('Invalid log level, possible values %s' %
111 str(CMLogger.levels.keys()))
115 def str_to_dest(dest):
118 ret = CMLogger.dests[dest]
120 raise cmerror.CMError('Invalid destination, possible values %s' %
121 str(CMLogger.dests.keys()))
125 def level_to_str(level):
126 for key, value in CMLogger.levels.iteritems():
132 def dest_to_str(dest):
133 for key, value in CMLogger.dests.iteritems():
140 log_dest = CMLogger.str_to_dest('console')
141 log_level = CMLogger.str_to_level('debug')
142 _ = CMLogger(log_dest, True, log_level)
144 logging.error('hello %s!', world)
145 logging.warn('hello %s!', world)
146 logging.info('hello %s!', world)
147 logging.debug('hello %s!', world)
150 if __name__ == '__main__':