satori/satori/common/logging.py

141 lines
4.5 KiB
Python

# 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.
#
"""Logging Module.
This module handles logging to the standard python logging subsystem and to the
console.
"""
from __future__ import absolute_import
import logging
import os
import sys
LOG = logging.getLogger(__name__)
class DebugFormatter(logging.Formatter):
"""Log formatter.
Outputs any 'data' values passed in the 'extra' parameter if provided.
**Example**:
.. code-block:: python
LOG.debug("My message", extra={'data': locals()})
"""
def format(self, record):
"""Print out any 'extra' data provided in logs."""
if hasattr(record, 'data'):
return "%s. DEBUG DATA=%s" % (logging.Formatter.format(self,
record), record.__dict__['data'])
return logging.Formatter.format(self, record)
def init_logging(config, default_config=None):
"""Configure logging based on log config file.
Turn on console logging if no logging files found
:param config: object with configuration namespace (ex. argparse parser)
:keyword default_config: path to a python logging configuration file
"""
if config.get('logconfig') and os.path.isfile(config.get('logconfig')):
logging.config.fileConfig(config['logconfig'],
disable_existing_loggers=False)
elif default_config and os.path.isfile(default_config):
logging.config.fileConfig(default_config,
disable_existing_loggers=False)
else:
init_console_logging(config)
def find_console_handler(logger):
"""Return a stream handler, if it exists."""
for handler in logger.handlers:
if (isinstance(handler, logging.StreamHandler) and
handler.stream == sys.stderr):
return handler
def log_level(config):
"""Get debug settings from configuration.
--debug: turn on additional debug code/inspection (implies
logging.DEBUG)
--verbose: turn up logging output (logging.DEBUG)
--quiet: turn down logging output (logging.WARNING)
default is logging.INFO
:param config: object with configuration namespace (ex. argparse parser)
"""
if config.get('debug') is True:
return logging.DEBUG
elif config.get('verbose') is True:
return logging.DEBUG
elif config.get('quiet') is True:
return logging.WARNING
else:
return logging.INFO
def get_debug_formatter(config):
"""Get debug formatter based on configuration.
:param config: configuration namespace (ex. argparser)
--debug: log line numbers and file data also
--verbose: standard debug
--quiet: turn down logging output (logging.WARNING)
default is logging.INFO
:param config: object with configuration namespace (ex. argparse parser)
"""
if config.get('debug') is True:
return DebugFormatter('%(pathname)s:%(lineno)d: %(levelname)-8s '
'%(message)s')
elif config.get('verbose') is True:
return logging.Formatter(
'%(name)-30s: %(levelname)-8s %(message)s')
elif config.get('quiet') is True:
return logging.Formatter('%(message)s')
else:
return logging.Formatter('%(message)s')
def init_console_logging(config):
"""Enable logging to the console.
:param config: object with configuration namespace (ex. argparse parser)
"""
# define a Handler which writes messages to the sys.stderr
console = find_console_handler(logging.getLogger())
if not console:
console = logging.StreamHandler()
logging_level = log_level(config)
console.setLevel(logging_level)
# set a format which is simpler for console use
formatter = get_debug_formatter(config)
# tell the handler to use this format
console.setFormatter(formatter)
# add the handler to the root logger
logging.getLogger().addHandler(console)
logging.getLogger().setLevel(logging_level)
global LOG # pylint: disable=W0603
LOG = logging.getLogger(__name__) # reset