diff options
author | John Dennis <jdennis@redhat.com> | 2011-11-15 14:39:31 -0500 |
---|---|---|
committer | Martin Kosek <mkosek@redhat.com> | 2011-11-23 09:36:18 +0100 |
commit | 56401c1abe7d4c78650acfcd9bbe8c8edc1dac57 (patch) | |
tree | a759f9fb51d4e2e110c55dbecc45f436386ee30f /ipapython/ipa_log_manager.py | |
parent | 730f1228a91ec9c6e575181807da2ab994a38071 (diff) | |
download | freeipa.git-56401c1abe7d4c78650acfcd9bbe8c8edc1dac57.tar.gz freeipa.git-56401c1abe7d4c78650acfcd9bbe8c8edc1dac57.tar.xz freeipa.git-56401c1abe7d4c78650acfcd9bbe8c8edc1dac57.zip |
ticket 2022 - modify codebase to utilize IPALogManager, obsoletes logging
change default_logger_level to debug in configure_standard_logging
add new ipa_log_manager module, move log_mgr there, also export
root_logger from log_mgr.
change all log_manager imports to ipa_log_manager and change
log_manager.root_logger to root_logger.
add missing import for parse_log_level()
Diffstat (limited to 'ipapython/ipa_log_manager.py')
-rw-r--r-- | ipapython/ipa_log_manager.py | 270 |
1 files changed, 270 insertions, 0 deletions
diff --git a/ipapython/ipa_log_manager.py b/ipapython/ipa_log_manager.py new file mode 100644 index 00000000..11e30d11 --- /dev/null +++ b/ipapython/ipa_log_manager.py @@ -0,0 +1,270 @@ +# Authors: John Dennis <jdennis@redhat.com> +# +# Copyright (C) 2011 Red Hat +# see file 'COPYING' for use and warranty information +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +#------------------------------------------------------------------------------- + +# Module exports +__all__ = ['log_mgr', 'root_logger', 'standard_logging_setup', + 'IPA_ROOT_LOGGER_NAME', 'ISO8601_UTC_DATETIME_FMT', + 'LOGGING_FORMAT_STDERR', 'LOGGING_FORMAT_STDOUT', 'LOGGING_FORMAT_FILE'] + +#------------------------------------------------------------------------------- + +import sys +import re +import copy + +from log_manager import LogManager, parse_log_level + +#------------------------------------------------------------------------------- + +# Our root logger, all loggers will be descendents of this. +IPA_ROOT_LOGGER_NAME = 'ipa' + +# Format string for time.strftime() to produce a ISO 8601 date time +# formatted string in the UTC time zone. +ISO8601_UTC_DATETIME_FMT = '%Y-%m-%dT%H:%M:%SZ' + +# Logging format string for use with logging stderr handlers +LOGGING_FORMAT_STDERR = 'ipa: %(levelname)s: %(message)s' + +# Logging format string for use with logging stdout handlers +LOGGING_FORMAT_STDOUT = '[%(asctime)s %(name)s] <%(levelname)s>: %(message)s' + +# Logging format string for use with logging file handlers +LOGGING_FORMAT_FILE = '\t'.join([ + '%(asctime)s', + '%(process)d', + '%(threadName)s', + '%(name)s', + '%(levelname)s', + '%(message)s', +]) + +# Used by standard_logging_setup() for console message +LOGGING_FORMAT_STANDARD_CONSOLE = '%(name)-12s: %(levelname)-8s %(message)s' + +# Used by standard_logging_setup() for file message +LOGGING_FORMAT_STANDARD_FILE = '%(asctime)s %(levelname)s %(message)s' + +#------------------------------------------------------------------------------- + +class IPALogManager(LogManager): + ''' + Subclass the LogManager to enforce some IPA specfic logging + conventions. + + * Default to timestamps in UTC. + * Default to ISO 8601 timestamp format. + * Default the message format. + ''' + + log_logger_level_config_re = re.compile(r'^log_logger_level_(debug|info|warn|warning|error|critical|\d+)$') + log_handler_level_config_re = re.compile(r'^log_handler_(\S+)_level$') + + def __init__(self, configure_state=None): + ''' + :parameters: + configure_state + Used by clients of the log manager to track the + configuration state, may be any object. + ''' + + super(IPALogManager, self).__init__(IPA_ROOT_LOGGER_NAME, configure_state) + + def configure_from_env(self, env, configure_state=None): + ''' + Read the loggger configuration from the Env config. The + following items may be configured: + + Logger Levels + *log_logger_XXX = comma separated list of regexps* + + Logger levels can be explicitly specified for specific loggers as + opposed to a global logging level. Specific loggers are indiciated + by a list of regular expressions bound to a level. If a logger's + name matches the regexp then it is assigned that level. The keys + in the Env config must begin with "log_logger_level\_" and then be + followed by a symbolic or numeric log level, for example:: + + log_logger_level_debug = ipalib\.dn\..* + log_logger_level_35 = ipalib\.plugins\.dogtag + + The first line says any logger belonging to the ipalib.dn module + will have it's level configured to debug. + + The second line say the ipa.plugins.dogtag logger will be + configured to level 35. + + Note: logger names are a dot ('.') separated list forming a path + in the logger tree. The dot character is also a regular + expression metacharacter (matches any character) therefore you + will usually need to escape the dot in the logger names by + preceeding it with a backslash. + + Handler Levels + *log_handler_XXX_level = level* + + Handler levels may be specified with a key containing the + name of the handler (XXX) and whose value is the level. For + example:: + + log_handler_console_level = debug + + Would set the console handler level to debug. + + These are the predefined log handlers: + + console + Writes to stderr. + file + Writes to the default log file. + + + The return value of this function is a dict with the following + format: + + logger_regexps + List of (regexp, level) tuples + handlers + Dict, key is handler name, value is dict of handler config. + + Handler config dict: + + level + handler log level + + :parameters: + env + Env object configuration values are read from. + configure_state + If other than None update the log manger's configure_state + variable to this object. Clients of the log manager can + use configure_state to track the state of the log manager. + ''' + logger_regexps = [] + handlers = {} + config = {'logger_regexps' : logger_regexps, + 'handlers' : handlers, + } + + for attr in ('debug', 'verbose'): + value = getattr(env, attr, None) + if value is not None: + config[attr] = value + + for attr in list(env): + # Get logger level configuration + match = IPALogManager.log_logger_level_config_re.search(attr) + if match: + value = match.group(1) + level = parse_log_level(value) + value = getattr(env, attr) + regexps = re.split('\s*,\s*', value) + # Add the regexp, it maps to the configured level + for regexp in regexps: + print "%s %s" % (regexp, level) + logger_regexps.append((regexp, level)) + continue + + # Get handler configuration + match = IPALogManager.log_handler_level_config_re.search(attr) + if match: + value = getattr(env, attr) + try: + level = parse_log_level(value) + except Exception, e: + print >>sys.stderr, 'ERROR could not parse log handler level: %s=%s' % (attr, value) + continue + name = match.group(1) + print "%s %s" % (name, level) + handler_config = handlers.get(name) + if handler_config is None: + handler_config = {'name' : name} + handler_config['level'] = level + continue + + self.configure(config, configure_state) + return config + + def create_log_handlers(self, configs, logger=None, configure_state=None): + 'Enforce some IPA specific configurations' + configs = copy.copy(configs) + + for cfg in configs: + if not 'time_zone_converter' in cfg: + cfg['time_zone_converter'] = 'utc' + if not 'datefmt' in cfg: + cfg['datefmt'] = ISO8601_UTC_DATETIME_FMT + if not 'format' in cfg: + cfg['format'] = LOGGING_FORMAT_STDOUT + + return super(IPALogManager, self).create_log_handlers(configs, logger, configure_state) + +#------------------------------------------------------------------------------- + +def standard_logging_setup(filename=None, verbose=False, debug=False, filemode='w'): + handlers = [] + + # File output is always logged at debug level + if filename is not None: + file_handler = dict(name='file', + filename=filename, + filemode=filemode, + permission=0600, + level='debug', + format=LOGGING_FORMAT_STANDARD_FILE) + handlers.append(file_handler) + + if log_mgr.handlers.has_key('console'): + log_mgr.remove_handler('console') + level = 'error' + if verbose: + level = 'info' + if debug: + level = 'debug' + + console_handler = dict(name='console', + stream=sys.stderr, + level=level, + format=LOGGING_FORMAT_STANDARD_CONSOLE) + handlers.append(console_handler) + + + # default_level must be debug becuase we want the file handler to + # always log at the debug level. + log_mgr.configure(dict(default_level='debug', + handlers=handlers), + configure_state='standard') + + return log_mgr.root_logger + +#------------------------------------------------------------------------------- + +# Single shared instance of log manager +# +# By default always starts with stderr console handler at error level +# so messages generated before logging is fully configured have some +# place to got and won't get lost. + +log_mgr = IPALogManager() +log_mgr.configure(dict(default_level='error', + handlers=[dict(name='console', + stream=sys.stderr)]), + configure_state='default') +root_logger = log_mgr.root_logger |