I did the same as Erik, but with some changes:
import logging
import inspect
from os import path
loggers_dict = {}
def myMakeRecord(self, name, level, fn, lno, msg, args, exc_info, func=None, extra=None):
if extra and 'pathname' in extra:
fn = extra.pop('pathname')
rv = logging.LogRecord(name, level, fn, lno, msg, args, exc_info, func)
if extra is not None:
rv.__dict__.update(extra)
return rv
logging.Logger.makeRecord = myMakeRecord
def getLogger():
fn, lno, func = base_logger.findCaller()
extras = {'pathname': fn, 'lineno': lno, 'funcName': func}
fnn = path.normcase(fn)
caller_name = inspect.modulesbyfile.get(fnn, inspect.getmodule(None, fn).__name__)
if caller_name not in loggers_dict:
loggers_dict[caller_name] = logging.getLogger(caller_name)
return loggers_dict[caller_name], extras
def myLogDebug(*msg):
log, extras = getLogger()
if len(msg) == 1:
log.debug(msg[0], extra=extras)
else:
log.debug(' '.join(map(str, msg)), extra=extras)
The main thing here is the legacy, everywhere people has put the call myLogDebug on the code, then would be a messy if I change everything. Other problem was the python 2.7 version, would be nice if I could use the param stacklevel from this thread.
Then I modified some stuff to get the right caller stack frame level, and doesn't change anything from original method.
EDIT - 1
caller_name = inspect.modulesbyfile.get(fnn, inspect.getmodule(None, fn).__name__)
This part is an little hack, just to don't run all the time getmodule
from inspect module. There is an dict (an inside cache modulesbyfile
) who gets direct access to module names after first getmodule
.
Sometimes debug an track the source helps, it's not documented.