Last active
June 22, 2020 09:38
-
-
Save a-recknagel/03221b29514dc38d84712510d4f87d38 to your computer and use it in GitHub Desktop.
log arg decorator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
>>> from logging.config import dictConfig | |
>>> dictConfig( | |
... { | |
... "version": 1, | |
... "disable_existing_loggers": False, | |
... "formatters": { | |
... "standard": { | |
... "format": "%(asctime)s [%(levelname)s] %(name)s: %(message)s" | |
... } | |
... }, | |
... "handlers": { | |
... "default": { | |
... "level": 10, | |
... "formatter": "standard", | |
... "class": "logging.StreamHandler", | |
... "stream": "ext://sys.stdout", | |
... } | |
... }, | |
... "loggers": {"": {"handlers": ["default"], "level": 10}} | |
... } | |
... ) | |
>>> @log_args() | |
... def foo(a, b=1, *args, **kwargs): | |
... return "FOO" | |
... | |
>>> foo(0) | |
2020-06-22 11:01:19,157 [INFO] __main__: foo(a=0) | |
'FOO' |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from logging import getLogger, _nameToLevel | |
from inspect import signature | |
from functools import wraps | |
def log_args(loglevel_name="INFO", max_chars=20): | |
"""This decorator logs the arguments passed to a function before calling it. | |
Default loglevel is INFO and default argument truncation threshold is 20 character. If | |
you want to disable truncation, pass -1 instead. | |
""" | |
if loglevel_name not in _nameToLevel: | |
raise ValueError(f"'{loglevel_name}' is not a valid log level name. Please pick one of {[*_nameToLevel]} instead.") | |
loglevel = _nameToLevel[loglevel_name] | |
def outer(func): | |
logger = getLogger(func.__module__) | |
parameters = signature(func).parameters | |
@wraps(func) | |
def inner(*args, **kwargs): | |
# map arg- and kwarg-strings to their parameter names | |
parameter_map = ( | |
[[param[0], str(arg)] for arg, param in zip(args, parameters)] + | |
[[name, str(value)] for name, value in kwargs.items()] | |
) | |
# truncate values, if necessary. this can probably be handled somewhat nicer. | |
for mapping in parameter_map: | |
if max_chars < 0: | |
continue | |
if len(mapping[1]) > max_chars: | |
mapping[1] = f"{mapping[1][:max_chars]} ..." | |
# build a string representing the call ... | |
parameter_string = ", ".join(f"{name}={value}" for name, value in parameter_map) | |
# ... and log it | |
logger.log(loglevel, f"{func.__name__}({parameter_string})") | |
return func(*args, **kwargs) | |
return inner | |
return outer |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment