Package: verbose-log-decorator
Log DecoratorThis package provides log decorators for sync and async Python functions which logs function input arguments,
result and raised exceptions in verbose manner.REQUIREMENTSPython >= 3.6 (async/await and f-strings are used in the package).Python packages from setup.pyinstall_requires.INSTALLATIONpip install verbose-log-decoratorOVERVIEWTo integrate log decorators into your code you should just perform a few steps:Choose/implement function which you want to log.Choose right decorator to use (sync or async) and add it to your function:import logging
 import sys

 from log_decorator.log import log
 from log_decorator.log_formatter import LogFormatter

 logger = logging.getLogger('service_logger')
 handler = logging.StreamHandler(sys.stdout)

 formatter = LogFormatter(fmt='%(asctime)s %(message)s', formatter_mode='compact')
 handler.setFormatter(formatter)
 handler.setLevel(logging.INFO)
 logger.addHandler(handler)
 logger.setLevel(logging.INFO)


 @log()
 def test_log_function(x, y):
     return x / yCall you function and receive output:test_log_function(4, 2)

 # Log output:

 # 2021-08-17 12:39:59,282 call __main__.test_log_function {'input_data': {'x': 4, 'y': 2}}
 # 2021-08-17 12:39:59,283 return __main__.test_log_function {'input_data': {'x': 4, 'y': 2}, 'result': 2}To log exceptions nothing additional is required:@log()
    def test_log_function(x, y):
        return x / y

    test_log_function(4, 0)

    # Log output:

    # 2021-08-17 13:14:16,508 call __main__.test_log_function {'input_data': {'x': 4, 'y': 0}}
    # 2021-08-17 13:14:16,509 error in __main__.test_log_function Traceback (most recent call last):
    # File ".../test.py", line 69, in _log
    #   result = wrapped(*args, **kwargs)
    # File "test.py", line 19, in test_log_function
    #   return x / y
    # ZeroDivisionError: division by zero {'input_data': {'x': 4, 'y': 0}}ADVANCED USAGElog_formatter.pyThis module provides class LogFormatter which can be used with or without log decorators from the package.
This class can be used as regular log formatters from standard library, but has some additional attributes.class LogFormatter(
    formatter_mode: FormatterMode = FormatterMode.VERBOSE,
    limit_keys_to: Optional[Iterable] = ('input_data', 'result'),
    max_length: Optional[int] = DEFAULT_MAX_LOG_LENGTH,
    separator: str = DEFAULT_SEPARATOR,
    **kwargs,
)formatter_mode- eitherFormatterMode.COMPACTorFormatterMode.VERBOSE(default):inverbosemode logs will be formatted in human-readable way with new lines, separators etc., this mode is
recommended for external log storage/explorer such as Graylog.incompactmode logs will be formatted as single-line records (except exceptions), this mode is recommended for
logging to console.limit_keys_to- it allows you to restrict which info to add to log records, pass any iterable here orNoneto
disable any restrictions.max_length- restricts max single record length, passNoneto disable any restrictions.separator- used inverbosemode only to separate different additional log items to improve readability, passNoneto disable separation.kwargs- these arguments will be passed to base class (logging.Formatter).log.pyThis module provides log decorator forsyncfunctions and methods and some utility functions.def get_logger(logger_name: str = 'service_logger') -> logger isntance with specified name and disabled propagationdef log(
    logger_inst: logging.Logger = get_logger(),
    lvl: int = logging.INFO,
    *,
    hide_output: bool = False,
    hidden_params: Iterable[str] = (),
    exceptions_only: bool = False,
    track_exec_time: bool = False,
    frequency: int or None = None,
    exception_hook: Callable or None = None,
) -> log_decorator_implementationlogger_inst- logger instance to use, by passing you own instance you can configure some additional details such
as logger name etc.lvl- logging level, function calls and returns will be logged with this level, exceptions will be logger withERRORlevel.hide_output- ifTruethen result of the function call will be completely hidden in log.minify_logs- ifTruethen logs would be minified to reduce storage consumption.hide_input_from_return- ifTruethen return log will not contain input arguments.hidden_params- pass iterable of strings to hide some arguments or their parts from the log. To hide part of an
argument use__to access key or index in dict or in an iterable and then its name/index, e.g. if you will passhidden_params=['test__key__1']to log decorator and call function with argumenttest={'key': [1,2,3]}then in
logs you will seetest: {'key': [1, 'hidden', 3]}. To hide multiple parts add all desired paths tohidden_paramsexceptions_only- ifTruethen only exception will be logged.track_exec_time- ifTruean additional keyexecution_time_mswill be added to log, don't forget to add it
tolimit_keys_toin formatter to see it in final log.frequency- if passed then only eachnfunction call will be logged, use it e.g. to obtain some sort of
statistics of functions which are called too intensively to log each call.exception_hook- pass any callable to execute it when an exception occurs, e.g. it is an easy way to send some
notification on errors,logger_inst,exc(exception instance),extra(all collected additional info) will be
passed to this hook.async_log.pyThis module provides log decorator forasyncfunctions and methods.def log(...) -> async_log_decorator_implementationLook at sync log for signature description, the only difference is that exception_hook should be async if passed.This decorator doesn't provide async logging, but only async function calls.
To use with async code consider either stdout/UDP inputs or use approach like:non-blocking handlers.Additional features:It is possible to defineget_log_idmethod for your classes to represent them in logs in some special way. This
method will be called without arguments except of class instance or class itself (in case of passing class itself
to the logged function).Each log record will containcall_idparameter which will be equal for call, return and exception records of
the same call, it is to simplify logs reading and understanding their relations.If an exception will be raised during function call and its instance will havereturn_valueattribute then
exception will be logged, but not reraised, instead the value of this attribute will be returned.TESTINGThe package has built-in unittests with 100% coverage, to run them:Clone repository.Install test dependencies:pip install pytest pytest-asyncio pytest-covRun tests and generate HTML coverage report:pytest --cov-report html --cov=log_decoratorReview results inhtmlcov/index.htmlCONTRIBUTEIf You have found an error or want to offer changes - create a pull request, and I will review it as soon as possible!