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.