Automatic debug logs when control goes inside/outside of a function

Question:

I am trying one project, that has many functions. I am using standard logging module The requirement is to log DEBUG logs which says:

<timestamp> DEBUG entered foo() 
<timestamp> DEBUG exited foo()
<timestamp> DEBUG entered bar()
<timestamp> DEBUG exited bar()

But I don’t want to write the DEBUG logs inside every function. Is there a way in Python which takes care of automatic log containing entry and exit of functions?

I don’t want to use any decorator to all functions, unless it is the only solution in Python.

Asked By: Sumanth Lingappa

||

Answers:

Any reason you don’t want to use a decorator? It’s pretty simple:

from functools import wraps
import logging

logging.basicConfig(filename='some_logfile.log', level=logging.DEBUG)

def tracelog(func):

    @wraps(func) # to preserve docstring
    def inner(*args, **kwargs):
        logging.debug('entered {0}, called with args={1}, kwargs={2}'.format(func.func_name, *args, **kwargs))
        func(*args, **kwargs)
        logging.debug('exited {0}'.format(func.func_name))

    return inner

If you get that, then passing in an independent logger is just another layer deep:

def tracelog(log):

    def real_decorator(func):
        @wraps(func)
        def inner(*args, **kwargs):
            log.debug('entered {0} called with args={1}, kwargs={2}'.format(func.func_name, *args, **kwargs))
            func(*args, **kwargs)
            log.debug('exited {0}'.format(func.func_name))
        return inner
    return real_decorator

Cool thing, is that this works for functions and methods

Usage example:

@tracelog(logger)
def somefunc():
    print('running somefunc')
Answered By: willnx

You want to have a look at sys.settrace.

There is a nice explanation with code examples for call tracing here: https://pymotw.com/2/sys/tracing.html

A very primitive way to do it, look at the link for more worked examples:

import sys
def trace_calls(frame, event, arg):
    if event not in ('call', 'return'):
       return
    co = frame.f_code
    func_name = co.co_name
    if func_name == 'write':
       # Ignore write() calls from print statements
       return
    if event == 'call':
       print "ENTER: %s" % func_name
    else:
       print "EXIT: %s" % func_name

 sys.settrace(trace_calls)
Answered By: schlenk
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.