Source code for qarbon.log

# ----------------------------------------------------------------------------
# This file is part of qarbon (http://qarbon.rtfd.org/)
#
# Copyright (c) 2013 European Synchrotron Radiation Facility, Grenoble, France
#
# Distributed under the terms of the GNU Lesser General Public License,
# either version 3 of the License, or (at your option) any later version.
# See LICENSE.txt for more info.
# ----------------------------------------------------------------------------

"""Helper logging functions."""

__all__ = ["log", "debug", "info", "warn", "warning", "error", "exception",
           "fatal", "critical", "initialize", "is_initialized",
           "log_it", "debug_it", "info_it", "warn_it", "error_it", "fatal_it"]

import inspect
import logging
import warnings
import functools


from qarbon import config
from qarbon.util import is_string

__logging_initialized = False


[docs]def log(level, msg, *args, **kwargs): exc_info = kwargs.get('exc_info') if exc_info is not None and is_string(exc_info): kwargs.pop('exc_info') exc_info = exc_info.upper() logging.log(level, msg, *args, **kwargs) exc_level = getattr(logging, exc_info, level) logging.log(exc_level, "Exception details:", exc_info=1) else: logging.log(level, msg, *args, **kwargs)
[docs]def debug(msg, *args, **kwargs): log(logging.DEBUG, msg, *args, **kwargs)
[docs]def info(msg, *args, **kwargs): log(logging.INFO, msg, *args, **kwargs)
[docs]def warn(msg, *args, **kwargs): log(logging.WARN, msg, *args, **kwargs)
[docs]def warning(msg, *args, **kwargs): log(logging.WARNING, msg, *args, **kwargs)
[docs]def error(msg, *args, **kwargs): log(logging.ERROR, msg, *args, **kwargs)
[docs]def exception(msg, *args, **kwargs): if 'exc_info' not in kwargs: kwargs['exc_info'] = 1 error(msg, *args, **kwargs)
[docs]def fatal(msg, *args, **kwargs): log(logging.FATAL, msg, *args, **kwargs)
[docs]def critical(msg, *args, **kwargs): log(logging.CRITICAL, msg, *args, **kwargs)
[docs]def is_initialized(): return __logging_initialized
[docs]def initialize(log_level=None, log_format=None, stream=None, file_name=None, file_size=None, file_number=None): """Initializes logging. Configures the Root logger with the given log_level. If file_name is given, a rotating log file handler is added. Otherwise, adds a default output stream handler with the given log_format.""" global __logging_initialized if __logging_initialized: return root = logging.getLogger() if log_level is None: log_level = config.LOG_LEVEL if log_format is None: log_format = config.LOG_FORMAT if file_name is None: file_name = config.LOG_FILE_NAME if file_size is None: file_size = config.LOG_FILE_SIZE if file_number is None: file_number = config.LOG_FILE_NUMBER if stream is None: stream = config.LOG_STREAM for handler in set(root.handlers): root.removeHandler(handler) __set_log_file(file_name, file_size, file_number, log_format) __set_log_stream(stream, log_format) if is_string(log_level): log_level = log_level.upper() if hasattr(logging, log_level): log_level = getattr(logging, log_level) if log_level is not None: try: root.setLevel(log_level) except: warnings.warn('Invalid log level specified in ' \ 'qarbon.util.initLogging') __logging_initialized = True
def __config_handler(handler, log_format): root = logging.getLogger() formatter = logging.Formatter(log_format) handler.setFormatter(formatter) root.addHandler(handler) def __set_log_stream(stream, log_format): if stream and log_format: out_handler = logging.StreamHandler(stream) __config_handler(out_handler, log_format) def __set_log_file(file_name, file_size, file_number, log_format): if file_name and file_size and file_number and log_format: file_handler = logging.handlers.RotatingFileHandler(file_name, 'a', file_size, file_number) __config_handler(file_handler, log_format) def __log_it(obj=None, **kwargs): """Log decorator. Use it to decorate any method, function or class. It will report to the logging system when the function is called and when the function exits. :param obj: callable / class to be decorated :param logger: [default: None, means use root logger] :param log_level: [default: logging.INFO] :param show_args: [default: False] :param show_kwargs: [default:False] :param log_in: log message when entering function [default: True] :param log_out: log message when leaving function [default: True]""" if obj is None: return functools.partial(__log_it, **kwargs) elif isinstance(obj, type): # treat class for key in dir(obj): if key.startswith('__'): continue val = getattr(obj, key) if callable(val): setattr(obj, key, __log_it(val, **kwargs)) return obj if not callable(obj): raise TypeError('{!r} is not a callable object'.format(obj)) # determine the object name name = obj.__name__ if hasattr(obj, "__qualname__"): name = obj.__qualname__ # [class.]function else: if inspect.ismethod(obj): name = obj.im_class.__name__ + "." + name # determine the log object log_obj = kwargs.get('logger', None) if log_obj is None: if inspect.ismethod(obj): log_obj = logging.getLogger(obj.im_class.__name__) else: log_obj = logging.getLogger() elif isinstance(log_obj, str): log_obj = logging.getLogger(log_obj) elif isinstance(log_obj, logging.Logger): pass else: log_obj = logging.getLogger() log_level = kwargs.get('log_level', logging.INFO) log_f = functools.partial(log_obj.log, log_level) #TODO: implement the show_args and show_kwargs #show_args = kwargs.get('show_args', False) #show_kwargs = kwargs.get('show_kwargs', False) log_in = kwargs.get('log_in', True) log_out = kwargs.get('log_out', True) @functools.wraps(obj) def wrapper(*w_args, **w_kwargs): if log_in: log_f("[ IN] %s()", name) exc_ocurred = True try: result = obj(*w_args, **w_kwargs) exc_ocurred = False finally: if log_out: exc_msg, exc_info = '[OUT]', False if exc_ocurred: exc_msg = '[EXC]' log_f("%s %s()", exc_msg, name, exc_info=exc_info) return result return wrapper log_it = __log_it(log_level=logging.INFO) debug_it = __log_it(log_level=logging.DEBUG) info_it = __log_it(log_level=logging.INFO) warn_it = __log_it(log_level=logging.WARNING) error_it = __log_it(log_level=logging.ERROR) critical_it = __log_it(log_level=logging.CRITICAL) fatal_it = __log_it(log_level=logging.fatal)