JensBlawatt

Python Logging Decorator

Hin und wieder ist es notwendig, die Parameter und die Rückgabewerte einer Funktion zu überprüfen. In Python kann man hierfür das logging Paket und den später folgenden Decorator für die Funktionen verwenden.

Zuvor müssen wir aber erstmal dafür sorgen, dass die Informationen irgendwo ausgegeben werden. In diesem Fall auf der Konsole.

import logging

# Einen Logger mit dem Namen foo.bar erstellen.
logger = logging.getLogger('foo.bar')
# Den Log-Level DEBUG setzten.
logger.setLevel(logging.DEBUG)
# Festlegen, dass die Meldungen auf der Konsole ausgegeben werden sollen.
logger.addHandler(logging.StreamHandler())

Jetzt ertsellen wir den Decorator, z.B. in der Datei decorators.py.

import logging

# Einen default Logger festlegen, der verwendet wird, wenn
# wenn beim Decorator kein Logger übergeben wurde.
_logger = logging.getLogger(__name__)


def log(level=logging.DEBUG, logger=None):
    logger = logger or _logger

    def inner(fnc):
        def wrapper(*args, **kwargs):
            logger.log(
                level,
                'calling method. name=%s; args=%s; kwargs=%s;',
                fnc, args, kwargs
            )
            return_value = fnc(*args, **kwargs)
            logger.log(
                level,
                'method called. name=%s; args=%s; kwargs=%s; return_value=%s',
                fnc, args, kwargs, return_value
            )
            return return_value
        return wrapper
    return inner

Jetzt verwenden wir den Decorator. Hierfür erstellen wir zwei Methoden, denen wir die Parameter foo und bar übergeben. Zurückgegeben, wird ein Tuple dieser beiden Werte. Über die Methoden setzten wir unseren Decorator. Die Parameter des Decorators legen fest, in welchen Logger und mit welchem Level die Meldungen ausgegeben werden sollen.

import decorators

@decorators.log(logger=logger, level=logging.WARN)
def log_warning(foo, bar):
    return foo, bar


@decorators.log(logger=logger, level=logging.DEBUG)
def log_debug(foo, bar):
    return foo, bar

Jetzt rufen wir die Funktion auf:

>>> log_warning('foo', bar='bar')
[WARNING] calling method. name=<function log_warning at 0x2bf9320>; args=('foo',); kwargs={'bar': 'bar'};
[WARNING] method called. name=<function log_warning at 0x2bf9320>; args=('foo',); kwargs={'bar': 'bar'}; return_value=('foo', 'bar')

>>> log_debug('foo', bar='bar')
[DEBUG] calling method. name=<function log_warning at 0x2bf9320>; args=('foo',); kwargs={'bar': 'bar'};
[DEBUG] method called. name=<function log_warning at 0x2bf9320>; args=('foo',); kwargs={'bar': 'bar'}; return_value=('foo', 'bar')