This is the formatting string that I am using for logging:
\'%(asctime)s - %(levelname)-10s - %(funcName)s - %(message)s\'
But to show the logg
Thanks to @cygnusb and the others who already provided useful pointers. I chose to use the Python 3.4 Logger.findCaller method as my starting point. The following solution has been tested with Python 2.7.9 and 3.4.2. This code is meant to be placed in its own module. It produces the correct answer with only one iteration of the loop.
import io
import sys
def _DummyFn(*args, **kwargs):
"""Placeholder function.
Raises:
NotImplementedError
"""
_, _ = args, kwargs
raise NotImplementedError()
# _srcfile is used when walking the stack to check when we've got the first
# caller stack frame, by skipping frames whose filename is that of this
# module's source. It therefore should contain the filename of this module's
# source file.
_srcfile = os.path.normcase(_DummyFn.__code__.co_filename)
if hasattr(sys, '_getframe'):
def currentframe():
return sys._getframe(3)
else: # pragma: no cover
def currentframe():
"""Return the frame object for the caller's stack frame."""
try:
raise Exception
except Exception:
return sys.exc_info()[2].tb_frame.f_back
class WrappedLogger(logging.Logger):
"""Report context of the caller of the function that issues a logging call.
That is, if
A() -> B() -> logging.info()
Then references to "%(funcName)s", for example, will use A's context
rather than B's context.
Usage:
logging.setLoggerClass(WrappedLogger)
wrapped_logging = logging.getLogger("wrapped_logging")
"""
def findCaller(self, stack_info=False):
"""Return the context of the caller's parent.
Find the stack frame of the caller so that we can note the source
file name, line number and function name.
This is based on the standard python 3.4 Logger.findCaller method.
"""
sinfo = None
f = currentframe()
# On some versions of IronPython, currentframe() returns None if
# IronPython isn't run with -X:Frames.
if f is not None:
f = f.f_back
if sys.version_info.major == 2:
rv = "(unknown file)", 0, "(unknown function)"
else:
rv = "(unknown file)", 0, "(unknown function)", sinfo
while hasattr(f, "f_code"):
co = f.f_code
filename = os.path.normcase(co.co_filename)
if filename == _srcfile or filename == logging._srcfile:
f = f.f_back
continue
# We want the frame of the caller of the wrapped logging function.
# So jump back one more frame.
f = f.f_back
co = f.f_code
if sys.version_info.major == 2:
rv = "(unknown file)", 0, "(unknown function)"
else:
rv = "(unknown file)", 0, "(unknown function)", sinfo
while hasattr(f, "f_code"):
co = f.f_code
filename = os.path.normcase(co.co_filename)
if filename == _srcfile or filename == logging._srcfile:
f = f.f_back
continue
# We want the frame of the caller of the wrapped logging function.
# So jump back one more frame.
f = f.f_back
co = f.f_code
if sys.version_info.major == 2:
rv = co.co_filename, f.f_lineno, co.co_name
else:
if stack_info:
sio = io.StringIO()
sio.write('Stack (most recent call last):\n')
traceback.print_stack(f, file=sio)
sinfo = sio.getvalue()
if sinfo[-1] == '\n':
sinfo = sinfo[:-1]
sio.close()
rv = co.co_filename, f.f_lineno, co.co_name, sinfo
break
return rv