Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic logging function wrapper

So what I'm trying to do is essentially take a bunch of pre-existing functions from commonly used libraries (such as subprocess,shutil,etc...) and wrap them in a function that will ouput what the function is doing as well as errors if any occur. My current code looks something like this.

def copytree(self,*args, **kwargs):
    self.debug(f":- Copying tree from \"{args[0]}\" to \"{args[1]}\"")
    try:
        shutil.copytree(*args,**kwargs)
    except Exception as e:
        self.error(f":- Failed to copy tree from \"{args[0]}\" to \"{args[1]}\" ; \"{e}\"")
        return False        
    self.debug(f":- Done")
    return True

I feel like there is probably a better way to do this in which there is a generic wrapper that can be used on any function but I am having trouble conceptualizing it. I'm also not sure if there is a way to account for functions that don't raise exceptions within said generic wrapper.

Also: self.debug and self.error are both just from the logging module

like image 633
als9xd Avatar asked Sep 06 '25 02:09

als9xd


2 Answers

I would use function decorator and logging module.

Here is a simple and dirty example :

import logging
logging.basicConfig(level=logging.INFO)


# decorator
def logged(func):
    def wrapper(*args, **kwargs):
        try:
            logging.info("started '{0}', parameters : {1} and {2}".
                         format(func.__name__, args, kwargs))
            return func(*args, **kwargs)
        except Exception as e:
            logging.exception(e)
    return wrapper


@logged
def foo(val):
    print(val/2)


if __name__ == "__main__":
    foo("a")

Output :

INFO:root:started 'foo', parameters : ('a',) and {}

ERROR:root:unsupported operand type(s) for /: 'str' and 'int'

Traceback (most recent call last): File "C:/Users/xxxx.py", line 9, in wrapper return func(*args, **kwargs) File "C:/Users/xxxx.py", line 17, in foo print(val/2)

TypeError: unsupported operand type(s) for /: 'str' and 'int'

like image 146
C.LECLERC Avatar answered Sep 07 '25 14:09

C.LECLERC


I would recommend this method:

def log_function(logger: Logger):
    def logger_wrapper(func):
        @wraps(func)
        def inner(*args, **kwargs):
            logger.info(f"Called {func.__name__}({args}, {kwargs})")
            func(*args, **kwargs)

        return inner

    return logger_wrapper

You can use it like

@log_function(logger=getLogger())
def foo(val):
    print(val/2)

This allows you to configure your logger if you need to.

like image 23
Agustin Barrachina Avatar answered Sep 07 '25 16:09

Agustin Barrachina