这是我用于记录的格式化字符串:
'%(asctime)s - %(levelname)-10s - %(funcName)s - %(message)s'
Run Code Online (Sandbox Code Playgroud)
但为了显示日志消息,我有一个包装器做了更多(我设置不同的日志级别,配置不同的日志后端,提供访问自定义级别的便利功能,等):
class MyLogger(logging.Logger):
def split_line(self, level, message):
....
self.log.(level, line)
def progress(self, message):
self.split_line(PROGRESS, message)
Run Code Online (Sandbox Code Playgroud)
使用此设置,每当我记录一些东西:
def myfunc():
log.progress('Hello')
Run Code Online (Sandbox Code Playgroud)
我明白了:
013-10-27 08:47:30,130 - PROGRESS - split_line - Hello
Run Code Online (Sandbox Code Playgroud)
这不是我想要的,即:
013-10-27 08:47:30,130 - PROGRESS - myfunc - Hello
Run Code Online (Sandbox Code Playgroud)
如何告诉记录器使用正确的上下文作为函数名?我认为这在堆栈框架上实际上会高出两个级别.
这是一个显示问题的测试程序:
import sys
import logging
PROGRESS = 1000
class MyLogger(logging.Logger):
PROGRESS = PROGRESS
LOG_FORMATTER = '%(asctime)s - %(levelname)-10s - %(funcName)s - %(message)s'
DEF_LOGGING_LEVEL = logging.WARNING
def __init__(self, log_name, level=None):
logging.Logger.__init__(self, log_name)
self.formatter = logging.Formatter(self.LOG_FORMATTER)
self.initLogger(level)
def initLogger(self, level=None):
self.setLevel(level or self.DEF_LOGGING_LEVEL)
self.propagate = False
def add_handler(self, log_file, use_syslog):
if use_syslog : hdlr = logging.handlers.SysLogHandler(address='/dev/log')
elif log_file : hdlr = logging.FileHandler(log_file)
else : hdlr = logging.StreamHandler(sys.stderr)
hdlr.setFormatter(self.formatter)
self.addHandler(hdlr)
return hdlr
def addHandlers(self, log_file=None, progress_file=None, use_syslog=False):
self.logger_hdlr = self.add_handler(log_file, use_syslog)
if progress_file:
self.progress_hdlr = self.add_handler(progress_file, use_syslog)
self.progress_hdlr.setLevel(self.PROGRESS)
else:
self.progress_hdlr = None
def split_line(self, level, txt, *args):
txt = txt % (args)
for line in txt.split('\n'):
self.log(level, line)
def progress(self, txt, *args):
self.split_line(self.PROGRESS, txt, *args)
logging.setLoggerClass(MyLogger)
logging.addLevelName(PROGRESS, 'PROGRESS')
logger = logging.getLogger(__name__)
logger.addHandlers()
name = 'John'
logger.progress('Hello %s\nHow are you doing?', name)
Run Code Online (Sandbox Code Playgroud)
生产:
2013-10-27 09:47:39,577 - PROGRESS - split_line - Hello John
2013-10-27 09:47:39,577 - PROGRESS - split_line - How are you doing?
Run Code Online (Sandbox Code Playgroud)
本质上,问题的代码在于类中Logger:
这个方法
def findCaller(self):
"""
Find the stack frame of the caller so that we can note the source
file name, line number and function name.
"""
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
rv = "(unknown file)", 0, "(unknown function)"
while hasattr(f, "f_code"):
co = f.f_code
filename = os.path.normcase(co.co_filename)
if filename == _srcfile:
f = f.f_back
continue
rv = (co.co_filename, f.f_lineno, co.co_name)
break
return rv
Run Code Online (Sandbox Code Playgroud)
返回调用者链中不属于当前模块的第一个函数。
您可以Logger通过添加稍微复杂的逻辑来子类化并重写此方法。跳过另一个调用深度级别或添加另一个条件。
在您非常特殊的情况下,避免自动线路分割并执行以下操作可能会更简单
logger.progress('Hello %s', name)
logger.progress('How are you doing?')
Run Code Online (Sandbox Code Playgroud)
或做
def splitter(txt, *args)
txt = txt % (args)
for line in txt.split('\n'):
yield line
for line in splitter('Hello %s\nHow are you doing?', name):
logger.progress(line)
Run Code Online (Sandbox Code Playgroud)
并有一个
def progress(self, txt, *args):
self.log(self.PROGRESS, txt, *args)
Run Code Online (Sandbox Code Playgroud)
也许它会帮你省去很多麻烦。
编辑2:不,那没有帮助。现在它会显示您progress的调用者函数名称......