Imported Upstream version 4.0.5

This commit is contained in:
Mario Fetka
2021-07-25 07:50:50 +02:00
parent 8ff3be4216
commit 3bfaa6e020
2049 changed files with 317193 additions and 1632423 deletions

View File

@@ -16,20 +16,26 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
import os
import re
import time
import warnings
import sys
import six
#-------------------------------------------------------------------------------
# Module exports
__all__ = ['log_mgr', 'root_logger', 'standard_logging_setup',
'ISO8601_UTC_DATETIME_FMT',
'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'
@@ -56,151 +62,163 @@ 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 _DeprecatedLogger(object):
def __init__(self, logger, name):
self._logger = logger
self._name = name
class IPALogManager(LogManager):
'''
Subclass the LogManager to enforce some IPA specfic logging
conventions.
def _warn(self):
warnings.warn(
"{} is deprecated, use a module-level logger".format(self._name),
DeprecationWarning)
* Default to timestamps in UTC.
* Default to ISO 8601 timestamp format.
* Default the message format.
'''
def debug(self, *args, **kwargs):
self._warn()
self._logger.debug(*args, **kwargs)
log_logger_level_config_re = re.compile(r'^log_logger_level_(debug|info|warn|warning|error|critical|\d+)$')
def info(self, *args, **kwargs):
self._warn()
self._logger.info(*args, **kwargs)
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.
'''
def warning(self, *args, **kwargs):
self._warn()
self._logger.warning(*args, **kwargs)
super(IPALogManager, self).__init__(IPA_ROOT_LOGGER_NAME, configure_state)
def error(self, *args, **kwargs):
self._warn()
self._logger.error(*args, **kwargs)
def configure_from_env(self, env, configure_state=None):
'''
Read the loggger configuration from the Env config. The
following items may be configured:
def critical(self, *args, **kwargs):
self._warn()
self._logger.critical(*args, **kwargs)
Logger Levels
*log_logger_XXX = comma separated list of regexps*
def exception(self, *args, **kwargs):
self._warn()
self._logger.exception(*args, **kwargs)
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 = ipapython\.dn\..*
log_logger_level_35 = ipalib\.plugins\.dogtag
def get_logger(who, bind_logger_names=False):
if isinstance(who, six.string_types):
warnings.warn(
"{}.log_mgr.get_logger is deprecated, use "
"logging.getLogger".format(__name__),
DeprecationWarning)
The first line says any logger belonging to the ipapython.dn module
will have it's level configured to debug.
logger_name = who
else:
caller_globals = sys._getframe(1).f_globals
logger_name = caller_globals.get('__name__', '__main__')
if logger_name == '__main__':
logger_name = caller_globals.get('__file__', logger_name)
logger_name = os.path.basename(logger_name)
The second line say the ipa.plugins.dogtag logger will be
configured to level 35.
logger = logging.getLogger(logger_name)
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.
if not isinstance(who, six.string_types):
obj_name = '%s.%s' % (who.__module__, who.__class__.__name__)
logger = _DeprecatedLogger(logger, obj_name)
The return value of this function is a dict with the following
format:
if bind_logger_names:
method = 'log'
if hasattr(who, method):
raise ValueError('%s is already bound to %s' % (method, repr(who)))
setattr(who, method, logger)
logger_regexps
List of (regexp, level) tuples
for method in ('debug',
'info',
'warning',
'error',
'exception',
'critical'):
if hasattr(who, method):
raise ValueError(
'%s is already bound to %s' % (method, repr(who)))
setattr(who, method, getattr(logger, method))
: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 = []
config = {'logger_regexps' : logger_regexps,
}
return logger
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:
logger_regexps.append((regexp, level))
continue
class Filter(object):
def __init__(self, regexp, level):
self.regexp = re.compile(regexp)
self.level = level
self.configure(config, configure_state)
return config
def filter(self, record):
return (not self.regexp.match(record.name) or
record.levelno >= self.level)
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
class Formatter(logging.Formatter):
def __init__(
self, fmt=LOGGING_FORMAT_STDOUT, datefmt=ISO8601_UTC_DATETIME_FMT):
super(Formatter, self).__init__(fmt, datefmt)
self.converter = time.gmtime
return super(IPALogManager, self).create_log_handlers(configs, logger, configure_state)
#-------------------------------------------------------------------------------
def standard_logging_setup(filename=None, verbose=False, debug=False,
filemode='w', console_format=None):
if console_format is None:
console_format = LOGGING_FORMAT_STANDARD_CONSOLE
root_logger = logging.getLogger()
root_logger.setLevel(logging.DEBUG)
filemode='w', console_format=LOGGING_FORMAT_STANDARD_CONSOLE):
handlers = []
# File output is always logged at debug level
if filename is not None:
umask = os.umask(0o177)
try:
file_handler = logging.FileHandler(filename, mode=filemode)
finally:
os.umask(umask)
file_handler.setLevel(logging.DEBUG)
file_handler.setFormatter(Formatter(LOGGING_FORMAT_STANDARD_FILE))
root_logger.addHandler(file_handler)
file_handler = dict(name='file',
filename=filename,
filemode=filemode,
permission=0600,
level='debug',
format=LOGGING_FORMAT_STANDARD_FILE)
handlers.append(file_handler)
level = logging.ERROR
if log_mgr.handlers.has_key('console'):
log_mgr.remove_handler('console')
level = 'error'
if verbose:
level = logging.INFO
level = 'info'
if debug:
level = logging.DEBUG
level = 'debug'
console_handler = logging.StreamHandler()
console_handler.setLevel(level)
console_handler.setFormatter(Formatter(console_format))
root_logger.addHandler(console_handler)
console_handler = dict(name='console',
stream=sys.stderr,
level=level,
format=console_format)
handlers.append(console_handler)
def convert_log_level(value):
try:
level = int(value)
except ValueError:
try:
level = {
'debug': logging.DEBUG,
'info': logging.INFO,
'warn': logging.WARNING,
'warning': logging.WARNING,
'error': logging.ERROR,
'critical': logging.CRITICAL
}[value.lower()]
except KeyError:
raise ValueError('unknown log level (%s)' % value)
return level
# 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
log_mgr = sys.modules[__name__]
#
# 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.
root_logger = _DeprecatedLogger(logging.getLogger(),
'{}.log_mgr.root_logger'.format(__name__))
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