如何为自己的日志记录级别编写自己的日志记录方法

编程入门 行业动态 更新时间:2024-10-23 19:19:40
本文介绍了如何为自己的日志记录级别编写自己的日志记录方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

嗨 我想用自己的方法扩展记录器(由logging.getLogger("rrcheck")): def warnpfx(...):

Hi I would like to extend my logger (taken by logging.getLogger("rrcheck")) with my own methods like: def warnpfx(...):

如何做到最好?

我最初的愿望是让root logger将所有内容写入文件,并另外将logger("rrcheck")写入stdout,但是后者还应该具有一些其他方法和级别.我需要它在某些消息前面加上!PFXWRN"前缀(但只有那些要发送到stdout的消息),而其他消息保持不变.我还想分别设置root和命名logger的日志记录级别.

My original wish is to have a root logger writing everything to a file and additionally named logger ("rrcheck") writing to stdout, but the latter should also have some other methods and levels. I need it to prepend some messages with "! PFXWRN" prefix (but only those going to stdout) and to leave other messages unchanged. I would like also to set logging level separately for root and for 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()

这是一个输出-函数和lilne编号错误: warnpfx 而不是 test

And this is an output - function and lilne number is wrong: warnpfx instead of test

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

也许我自己的记录器方法不是最好的方法? 您建议走哪个方向(自己的记录器,自己的处理程序,自己的格式化程序等)?

Maybe my own logger approach is not the best one? Which direction would you propose to go (own logger, own handler, own formatter, etc.)?

如果我想要另一个记录器,该如何进行? 不幸的是,日志记录无法注册自己的记录器,因此getLogger(name)将需要一个必需的记录器.

How to proceed if I would like to have yet another logger? Unfortunatelly logging has no possibility to register an own logger, so then getLogger(name) would take a required one...

关于, 兹比格涅夫

Regards, Zbigniew

推荐答案

如果您选中 Python来源,您会发现罪魁祸首是Logger.findCaller方法,该方法遍历调用堆栈并搜索第一个logging.py文件中没有的行.因此,您对CheloExtendedLogger.warnpfx中的self.log的自定义调用记录了错误的行.

If you check Python sources, you'll see that the culprit is the Logger.findCaller method that walks through the call stack and searches for a first line that is not in the logging.py file. Because of this, your custom call to self.log in CheloExtendedLogger.warnpfx registers a wrong line.

不幸的是,logging.py中的代码不是非常模块化,因此修复起来很丑陋:您必须自己在子类中重新定义findCaller方法,以便它同时考虑到logging.py文件和记录器所在的文件(请注意,文件中除记录器外不应有任何其他代码,否则结果将不准确).这需要在方法主体中进行单行更改:

Unfortunately, the code in logging.py is not very modular, so the fix is rather ugly: you have to redefine the findCaller method yourself in your subclass, so that it takes into account both the logging.py file and the file in which your logger resides (note that there shouldn't be any code other than the logger in your file, or again the results will be inaccurate). This requires a one-line change in the method body:

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

为此,您需要在文件中定义自己的_srcfile变量.同样,logging.py不使用函数,而是将所有代码置于模块级别,因此您必须再次复制粘贴:

For this to work, you need to define your own _srcfile variable in your file. Again, logging.py doesn't use a function, but rather puts all the code on the module level, so you have to copy-paste again:

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)

好吧,也许如果您不关心编译版本,那么最后两行就足够了.

Well, maybe if you don't care for compiled versions, two last lines will suffice.

现在,您的代码可以按预期工作了:

Now, your code works as expected:

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

对于多个记录器类,如果您不介意记录器名称和记录器类之间的依赖关系,则可以创建logging.Logger的子类,该子类将基于其记录的调用委派给适当的记录器类名字是.可能还有其他更优雅的可能性,但我现在想不起来.

As for multiple logger classes, if you don't mind the dependency between a logger name and a logger class, you could make a subclass of logging.Logger that would delegate its calls to an appropriate logger class, based on what its name was. There are probably other, more elegant possibilities, but I can't think of any right now.

更多推荐

如何为自己的日志记录级别编写自己的日志记录方法

本文发布于:2023-11-24 04:22:22,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1623953.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:自己的   日志   何为   级别   方法

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!