Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Log stack trace for python warning

A package that I'm using in my python program is throwing a warning that I'd like to understand the exact cause of. I've set logging.captureWarning(True) and am capturing the warning in my logging, but still have no idea where it is coming from. How do I also log the stack trace so I can see where in my code the warning is coming from? Do I use traceback?

like image 544
user1507844 Avatar asked Jan 29 '15 07:01

user1507844


People also ask

How do I check Python error logs?

To log an exception in Python we can use logging module and through that we can log the error. Logging an exception in python with an error can be done in the logging. exception() method. This function logs a message with level ERROR on this logger.

What is logging DEBUG in Python?

Debugging is an important step of any software development project. The logging module is part of the standard Python library, provides tracking for events that occur while software runs, and can output these events to a separate log file to allow you to keep track of what occurs while your code runs.

What is Exc_info true?

Setting exc_info to True will cause the logging to include the full stack trace…. exactly like logger. exception() does. The only difference is that you can easily change the log level to something other than error: Just replace logger.


2 Answers

I've ended up going with the below:

import warnings
import traceback

_formatwarning = warnings.formatwarning

def formatwarning_tb(*args, **kwargs):
    s = _formatwarning(*args, **kwargs)
    tb = traceback.format_stack()
    s += ''.join(tb[:-1])
    return s

warnings.formatwarning = formatwarning_tb
logging.captureWarnings(True)
like image 160
user1507844 Avatar answered Nov 14 '22 21:11

user1507844


It's a little hackish, but you can monkeypatch the warnings.warn method to this:

import traceback
import warnings

def g():
    warnings.warn("foo", Warning)

def f():
    g()
    warnings.warn("bar", Warning)

_old_warn = warnings.warn
def warn(*args, **kwargs):
    tb = traceback.extract_stack()
    _old_warn(*args, **kwargs)
    print("".join(traceback.format_list(tb)[:-1]))
warnings.warn = warn

f()
print("DONE")

This is the output:

/tmp/test.py:14: Warning: foo
  _old_warn(*args, **kwargs)
  File "/tmp/test.py", line 17, in <module>
    f()
  File "/tmp/test.py", line 8, in f
    g()
  File "/tmp/test.py", line 5, in g
    warnings.warn("foo", Warning)

/tmp/test.py:14: Warning: bar
  _old_warn(*args, **kwargs)
  File "/tmp/test.py", line 17, in <module>
    f()
  File "/tmp/test.py", line 9, in f
    warnings.warn("bar", Warning)

DONE

See that calling the original warnings.warn function does not report the line you'd want, bu the stack trace is indeed correct (you could print the warning message yourself).

like image 38
Lluís Vilanova Avatar answered Nov 14 '22 22:11

Lluís Vilanova