Skip to content

add_logging

adds some logging messages to a function

>>> @add_logging()
... def foo():
...     pass

Note

add_logging supports async functions

Parameters:

Name Type Description Default
fn Callable

function to be decorated

None
logger Logger

specific logger to use (otherwise root-logger)

root
call bool

whether to log when the function is called

True
call_args bool

whether to log the functions call arguments (only with call=True)

True
timeit bool

whether to log the functions execution time

True
timeit_precision int

precision of the logged execution time (only with timeit=True)

2
result bool

whether to log the returned value of the function

True
Source code in src/loggext/decorators/add_logging.py
def add_logging(
        fn: t.Callable = None,
        *, logger: logging.Logger = logging.root,
        call: bool = True,
        call_args: bool = True,
        timeit: bool = True,
        timeit_precision: int = 2,
        result: bool = True,
        ):
    r"""
    adds some logging messages to a function

    ```pycon

    >>> @add_logging()
    ... def foo():
    ...     pass

    ```

    !!! note
        `add_logging` supports async functions

    :param fn: function to be decorated
    :param logger: specific logger to use (otherwise root-logger)
    :param call: whether to log when the function is called
    :param call_args: whether to log the functions call arguments (only with `call=True`)
    :param timeit: whether to log the functions execution time
    :param timeit_precision: precision of the logged execution time (only with `timeit=True`)
    :param result: whether to log the returned value of the function
    """
    def decorator(func: t.Callable) -> t.Callable:
        if iscoroutinefunction(func):
            @functools.wraps(func)
            async def wrapper(*args, **kwargs):
                timing = timer(precision=timeit_precision)
                try:
                    if logger.isEnabledFor(logging.DEBUG) and call:
                        message = f"{func} was called"
                        if call_args:
                            message += f" with ({_format_args(*args, **kwargs)})"
                        logger.debug(message)
                    res = await func(*args, **kwargs)
                    if logger.isEnabledFor(logging.DEBUG) and (result or timeit):
                        resfmt = f" {res!r}" if result else ""
                        timefmt = f" after {next(timing)}" if timeit else ""
                        logger.debug(f"{func} returned{resfmt}{timefmt}")
                    return res
                except BaseException as exc:
                    message = f"{func} raised {type(exc).__qualname__}"
                    if timeit:
                        message += f" after {next(timing)}"
                    logger.exception(message, exc_info=exc)
                    raise exc
        else:
            @functools.wraps(func)
            def wrapper(*args, **kwargs):
                timing = timer(precision=timeit_precision)
                try:
                    if logger.isEnabledFor(logging.DEBUG) and call:
                        message = f"{func} was called"
                        if call_args:
                            message += f" with ({_format_args(*args, **kwargs)})"
                        logger.debug(message)
                    res = func(*args, **kwargs)
                    if logger.isEnabledFor(logging.DEBUG) and (result or timeit):
                        resfmt = f" {res!r}" if result else ""
                        timefmt = f" after {next(timing)}" if timeit else ""
                        logger.debug(f"{func} returned{resfmt}{timefmt}")
                    return res
                except BaseException as exc:
                    message = f"{func} raised {type(exc).__qualname__}"
                    if timeit:
                        message += f" after {next(timing)}"
                    logger.exception(message, exc_info=exc)
                    raise exc

        return wrapper

    return decorator if fn is None else decorator(func=fn)