嗨,
我想用我自己的方法扩展我的记录器(由logging.getLogger("rrcheck")获取),如:
def warnpfx(...):
怎么做得最好?
我最初希望有一个根记录器将所有内容写入文件,并另外命名为logger("rrcheck")写入stdout,但后者还应该有其他一些方法和级别.我需要它用"!PFXWRN"前缀(但只有那些去stdout)前缀一些消息并保留其他消息不变.我还想为root和named logger 单独设置日志记录级别.
这是我的代码:
class CheloExtendedLogger(logging.Logger):
"""
Custom logger class with additional levels and methods
"""
WARNPFX = logging.WARNING+1
def __init__(self, name):
logging.Logger.__init__(self, name, logging.DEBUG)
logging.addLevelName(self.WARNPFX, 'WARNING')
console = logging.StreamHandler()
console.setLevel(logging.DEBUG)
# create formatter and add it to the handlers
formatter = logging.Formatter("%(asctime)s [%(funcName)s: %(filename)s,%(lineno)d] %(message)s")
console.setFormatter(formatter)
# add the handlers to logger
self.addHandler(console)
return
def warnpfx(self, msg, *args, **kw):
self.log(self.WARNPFX, "! PFXWRN %s" % msg, *args, **kw)
logging.setLoggerClass(CheloExtendedLogger)
rrclogger = logging.getLogger("rrcheck")
rrclogger.setLevel(logging.INFO)
def test():
rrclogger.debug("DEBUG message")
rrclogger.info("INFO message")
rrclogger.warnpfx("warning with prefix")
test()
Run Code Online (Sandbox Code Playgroud)
这是一个输出 - 函数和lilne数是错误的:warnpfx而不是测试
2011-02-10 14:36:51,482 [test: log4.py,35] INFO message
2011-02-10 14:36:51,497 [warnpfx: log4.py,26] ! PFXWRN warning with prefix
Run Code Online (Sandbox Code Playgroud)
也许我自己的记录器方法不是最好的?
你打算去哪个方向(自己的记录器,自己的处理程序,自己的格式化程序等)?
如果我想要另一台记录器怎么办?
不幸的记录不可能注册自己的记录器,所以getLogger(name)将需要一个...
此致,
Zbigniew
如果检查Python源代码,您将看到罪魁祸首是Logger.findCaller遍历调用堆栈并搜索不在logging.py文件中的第一行的方法.正因为如此,自定义调用self.log中CheloExtendedLogger.warnpfx注册一个错线.
遗憾的是,代码logging.py并不是非常模块化的,因此修复相当丑陋:您必须findCaller在子类中自己重新定义方法,以便它考虑logging.py文件和记录器所在的文件(请注意,不应该不是文件中记录器以外的任何代码,或者结果将不准确).这需要在方法体中进行单行更改:
class CheloExtendedLogger(logging.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 = logging.currentframe().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 in (_srcfile, logging._srcfile): # This line is modified.
f = f.f_back
continue
rv = (filename, f.f_lineno, co.co_name)
break
return rv
Run Code Online (Sandbox Code Playgroud)
为此,您需要_srcfile在文件中定义自己的变量.同样,logging.py不使用函数,而是将所有代码放在模块级别,因此您必须再次复制粘贴:
if hasattr(sys, 'frozen'): #support for py2exe
_srcfile = "logging%s__init__%s" % (os.sep, __file__[-4:])
elif string.lower(__file__[-4:]) in ['.pyc', '.pyo']:
_srcfile = __file__[:-4] + '.py'
else:
_srcfile = __file__
_srcfile = os.path.normcase(_srcfile)
Run Code Online (Sandbox Code Playgroud)
好吧,也许如果你不关心编译版本,最后两行就足够了.
现在,您的代码按预期工作:
2011-02-10 16:41:48,108 [test: lg.py,16] INFO message
2011-02-10 16:41:48,171 [test: lg.py,17] ! PFXWRN warning with prefix
Run Code Online (Sandbox Code Playgroud)
对于多个记录器类,如果您不介意记录器名称和记录器类之间的依赖关系,您可以创建一个子类logging.Logger,将其调用委托给适当的记录器类,具体取决于其名称.可能还有其他更优雅的可能性,但我现在无法想到.
| 归档时间: |
|
| 查看次数: |
5437 次 |
| 最近记录: |