How can I log a functions arguments in a reusable way in Python?

arguments, function, logging, python

Solution

Decorators are what you are looking for. Here's an example:

import logging
from functools import wraps


def arg_logger(func):

    @wraps(func)
    def new_func(*args, **kwargs):
        saved_args = locals()
        try:
            return func(*args, **kwargs)
        except:
            logging.exception("Oh no! My args were: " + str(saved_args))
            raise

    return new_func


@arg_logger
def func(arg1, arg2):
    return 1 / 0

if __name__ == '__main__':
    func(1, 2)

Here, I'm using arg_logger() as a decorator. Apply the decorator to any function you want to have this new behavior.

There's a good discussion about decorators here.

Problem

I've found myself writing code like this several times: ``` def my_func(a, b, *args, **kwargs): saved_args = locals() # Learned about this from http://stackoverflow.com/a/3137022/2829764 local_var = "This is some other local var that I don't want to log" try: a/b except Exception as e: logging.exception("Oh no! My args were: " + str(saved_args)) raise ``` Running `my_func(1, 0, "spam", "ham", my_kwarg="eggs")` gives this output on stderr: ``` ERROR:root:Oh no! My args were: {'a': 1, 'args': (u'spam', u'ham'), 'b': 0, 'kwargs': {'my_kwarg': u'eggs'}} Traceback (most recent call last): File "/Users/kuzzooroo/Desktop/question.py", line 17, in my_func a/b ZeroDivisionError: division by zero ``` My question is, can I write something reusable so that I don't have to save locals() at the top of the function? And can it be done in a nice Pythonic way? EDIT: one more request in response to @mtik00: ideally I'd like some way to access saved_args or the like from within my_func so that I can do something other than log uncaught exceptions (maybe I want to catch the exception in my_func, log an error, and keep going).

Original source

Related problems