tue*_*ist 102 python logging python-logging
我想为我的应用程序提供loglevel TRACE(5),因为我认为这debug()
还不够.另外log(5, msg)
不是我想要的.如何将自定义日志级别添加到Python记录器?
我有mylogger.py
以下内容:
import logging
@property
def log(obj):
myLogger = logging.getLogger(obj.__class__.__name__)
return myLogger
Run Code Online (Sandbox Code Playgroud)
在我的代码中,我以下列方式使用它:
class ExampleClass(object):
from mylogger import log
def __init__(self):
'''The constructor with the logger'''
self.log.debug("Init runs")
Run Code Online (Sandbox Code Playgroud)
现在我想打个电话 self.log.trace("foo bar")
在此先感谢您的帮助.
编辑(2016年12月8日):我改变了接受pfa的答案,即恕我直言,这是一个很好的解决方案,基于Eric S.的非常好的建议.
pfa*_*pfa 150
@Eric S.
Eric S.的答案非常好,但我通过实验了解到,这将始终导致在新调试级别记录的消息被打印 - 无论日志级别设置为什么.因此,如果您将新的级别数设置为9,如果调用setLevel(50),将错误地打印较低级别的消息.为防止这种情况发生,您需要在"debugv"函数中使用另一行来检查是否实际启用了相关的日志记录级别.
修复了检查日志记录级别是否已启用的示例:
import logging
DEBUG_LEVELV_NUM = 9
logging.addLevelName(DEBUG_LEVELV_NUM, "DEBUGV")
def debugv(self, message, *args, **kws):
if self.isEnabledFor(DEBUG_LEVELV_NUM):
# Yes, logger takes its '*args' as 'args'.
self._log(DEBUG_LEVELV_NUM, message, args, **kws)
logging.Logger.debugv = debugv
Run Code Online (Sandbox Code Playgroud)
如果你看一下代码9
中setLevel(50)
的Python 2.7,这是所有标准的日志功能做(.critical,的.debug等).
我显然无法回复别人的答案因为缺乏声誉......希望Eric如果看到这个就会更新他的帖子.=)
小智 59
我接受了"避免看到lambda"的答案,并且必须修改log_at_my_log_level的添加位置.我也看到了保罗所做的问题"我觉得这不行.你不需要logger作为log_at_my_log_level中的第一个arg吗?" 这对我有用
import logging
DEBUG_LEVELV_NUM = 9
logging.addLevelName(DEBUG_LEVELV_NUM, "DEBUGV")
def debugv(self, message, *args, **kws):
# Yes, logger takes its '*args' as 'args'.
self._log(DEBUG_LEVELV_NUM, message, args, **kws)
logging.Logger.debugv = debugv
Run Code Online (Sandbox Code Playgroud)
Mad*_*ist 45
将所有现有答案与大量使用经验相结合,我认为我已经提出了所有需要完成的事项列表,以确保完全无缝地使用新级别.以下步骤假定您要添加TRACE
具有值的新级别logging.DEBUG - 5 == 5
:
logging.addLevelName(logging.DEBUG - 5, 'TRACE')
需要调用以获取内部注册的新级别,以便可以按名称引用它.logging
为了保持一致性,需要将新级别作为属性添加到自身中:logging.TRACE = logging.DEBUG - 5
.trace
需要将一个调用的方法添加到logging
模块中.它应该表现得就像debug
,info
等等.trace
需要将一个调用的方法添加到当前配置的记录器类中.由于这不是100%保证logging.Logger
,logging.getLoggerClass()
而是使用.所有步骤均在以下方法中说明:
def addLoggingLevel(levelName, levelNum, methodName=None):
"""
Comprehensively adds a new logging level to the `logging` module and the
currently configured logging class.
`levelName` becomes an attribute of the `logging` module with the value
`levelNum`. `methodName` becomes a convenience method for both `logging`
itself and the class returned by `logging.getLoggerClass()` (usually just
`logging.Logger`). If `methodName` is not specified, `levelName.lower()` is
used.
To avoid accidental clobberings of existing attributes, this method will
raise an `AttributeError` if the level name is already an attribute of the
`logging` module or if the method name is already present
Example
-------
>>> addLoggingLevel('TRACE', logging.DEBUG - 5)
>>> logging.getLogger(__name__).setLevel("TRACE")
>>> logging.getLogger(__name__).trace('that worked')
>>> logging.trace('so did this')
>>> logging.TRACE
5
"""
if not methodName:
methodName = levelName.lower()
if hasattr(logging, levelName):
raise AttributeError('{} already defined in logging module'.format(levelName))
if hasattr(logging, methodName):
raise AttributeError('{} already defined in logging module'.format(methodName))
if hasattr(logging.getLoggerClass(), methodName):
raise AttributeError('{} already defined in logger class'.format(methodName))
# This method was inspired by the answers to Stack Overflow post
# http://stackoverflow.com/q/2183233/2988730, especially
# http://stackoverflow.com/a/13638084/2988730
def logForLevel(self, message, *args, **kwargs):
if self.isEnabledFor(levelNum):
self._log(levelNum, message, *args, **kwargs)
def logToRoot(message, *args, **kwargs):
logging.log(levelNum, message, *args, **kwargs)
logging.addLevelName(levelNum, levelName)
setattr(logging, levelName, levelNum)
setattr(logging.getLoggerClass(), methodName, logForLevel)
setattr(logging, methodName, logToRoot)
Run Code Online (Sandbox Code Playgroud)
Wis*_*ind 36
这个问题相当陈旧,但我刚刚处理了相同的主题,并找到了一种类似于已经提到过的方法,这对我来说似乎有点清洁.这是在3.4上测试的,所以我不确定使用的方法是否存在于旧版本中:
from logging import getLoggerClass, addLevelName, setLoggerClass, NOTSET
VERBOSE = 5
class MyLogger(getLoggerClass()):
def __init__(self, name, level=NOTSET):
super().__init__(name, level)
addLevelName(VERBOSE, "VERBOSE")
def verbose(self, msg, *args, **kwargs):
if self.isEnabledFor(VERBOSE):
self._log(VERBOSE, msg, args, **kwargs)
setLoggerClass(MyLogger)
Run Code Online (Sandbox Code Playgroud)
Der*_*Weh 20
虽然我们已经有很多正确的答案,但在我看来,以下更像是 Pythonic:
import logging
from functools import partial, partialmethod
logging.TRACE = 5
logging.addLevelName(logging.TRACE, 'TRACE')
logging.Logger.trace = partialmethod(logging.Logger.log, logging.TRACE)
logging.trace = partial(logging.log, logging.TRACE)
Run Code Online (Sandbox Code Playgroud)
如果你想mypy
在你的代码上使用,建议添加# type: ignore
禁止添加属性的警告。
sch*_*mar 19
谁开始使用内部方法(self._log
)的不良做法,为什么每个答案都基于此?!pythonic解决方案将使用,self.log
所以你不必乱用任何内部的东西:
import logging
SUBDEBUG = 5
logging.addLevelName(SUBDEBUG, 'SUBDEBUG')
def subdebug(self, message, *args, **kws):
self.log(SUBDEBUG, message, *args, **kws)
logging.Logger.subdebug = subdebug
logging.basicConfig()
l = logging.getLogger()
l.setLevel(SUBDEBUG)
l.subdebug('test')
l.setLevel(logging.DEBUG)
l.subdebug('test')
Run Code Online (Sandbox Code Playgroud)
我发现为传递log()函数的logger对象创建一个新属性更容易.我认为logger模块提供addLevelName()和log()就是出于这个原因.因此,不需要子类或新方法.
import logging
@property
def log(obj):
logging.addLevelName(5, 'TRACE')
myLogger = logging.getLogger(obj.__class__.__name__)
setattr(myLogger, 'trace', lambda *args: myLogger.log(5, *args))
return myLogger
Run Code Online (Sandbox Code Playgroud)
现在
mylogger.trace('This is a trace message')
Run Code Online (Sandbox Code Playgroud)
应该按预期工作.
我认为你必须对类进行子Logger
类化并添加一个方法trace
,该方法基本上调用Logger.log
低于的级别DEBUG
.我没试过这个,但这就是文档所指出的.
这对我有用:
import logging
logging.basicConfig(
format=' %(levelname)-8.8s %(funcName)s: %(message)s',
)
logging.NOTE = 32 # positive yet important
logging.addLevelName(logging.NOTE, 'NOTE') # new level
logging.addLevelName(logging.CRITICAL, 'FATAL') # rename existing
log = logging.getLogger(__name__)
log.note = lambda msg, *args: log._log(logging.NOTE, msg, args)
log.note('school\'s out for summer! %s', 'dude')
log.fatal('file not found.')
Run Code Online (Sandbox Code Playgroud)
正如 @marqueed 指出的那样,lambda/funcName 问题已使用 logger._log 修复。我认为使用 lambda 看起来更干净一些,但缺点是它不能接受关键字参数。我自己从来没有用过,所以没什么大不了的。
注意设置:学校放暑假了!老兄 致命设置:找不到文件。
创建自定义记录器的提示:
_log
,使用log
(您不必检查isEnabledFor
)getLogger
起到了一些神奇作用,因此您需要通过以下方式设置类setLoggerClass
__init__
如果您不存储任何内容,则无需为记录器定义类# Lower than debug which is 10
TRACE = 5
class MyLogger(logging.Logger):
def trace(self, msg, *args, **kwargs):
self.log(TRACE, msg, *args, **kwargs)
Run Code Online (Sandbox Code Playgroud)
调用此记录器时,请使用setLoggerClass(MyLogger)
它作为默认记录器getLogger
logging.setLoggerClass(MyLogger)
log = logging.getLogger(__name__)
# ...
log.trace("something specific")
Run Code Online (Sandbox Code Playgroud)
您需要setFormatter
,setHandler
以及setLevel(TRACE)
对handler
与对log
自身实际SE这低水平跟踪
归档时间: |
|
查看次数: |
40928 次 |
最近记录: |