可以Python的日志记录格式取决于消息的日志级别进行修改?(Can Python's lo

2019-07-03 21:57发布

我使用Python的logging机制进行打印输出到屏幕上。 我可以用print语句做到这一点,但我想,让用户更精细调谐的粒度禁用某些类型的输出。 我喜欢印刷错误的格式,而是希望有一个简单的格式时,输出电平为“信息”。

例如:

  logger.error("Running cmd failed")
  logger.info("Running cmd passed")

在这个例子中,我想错误的格式进行不同的印刷:

 # error Aug 27, 2009 - ERROR: Running cmd failed # info Running cmd passed 

是否有可能有不同的日志级别不同的格式,而无需多个记录的对象? 我宁愿一旦创建它要做到这一点,而无需修改记录,因为有大量的if / else语句来确定输出应该如何记录。

Answer 1:

是的,你可以有一个自定义为此Formatter类:

class MyFormatter(logging.Formatter):
    def format(self, record):
        #compute s according to record.levelno
        #for example, by setting self._fmt
        #according to the levelno, then calling
        #the superclass to do the actual formatting
        return s

然后,附加MyFormatter实例您的处理程序。



Answer 2:

我只是碰到了这个问题,并遇到了麻烦,在留在上面的例子中“洞”填充。 下面是我用了一个更完整,工作版本。 希望这可以帮助别人:

# Custom formatter
class MyFormatter(logging.Formatter):

    err_fmt  = "ERROR: %(msg)s"
    dbg_fmt  = "DBG: %(module)s: %(lineno)d: %(msg)s"
    info_fmt = "%(msg)s"


    def __init__(self, fmt="%(levelno)s: %(msg)s"):
        logging.Formatter.__init__(self, fmt)


    def format(self, record):

        # Save the original format configured by the user
        # when the logger formatter was instantiated
        format_orig = self._fmt

        # Replace the original format with one customized by logging level
        if record.levelno == logging.DEBUG:
            self._fmt = MyFormatter.dbg_fmt

        elif record.levelno == logging.INFO:
            self._fmt = MyFormatter.info_fmt

        elif record.levelno == logging.ERROR:
            self._fmt = MyFormatter.err_fmt

        # Call the original formatter class to do the grunt work
        result = logging.Formatter.format(self, record)

        # Restore the original format configured by the user
        self._fmt = format_orig

        return result

编辑:

Halloleo致意,下面是如何使用上述脚本的例子:

fmt = MyFormatter()
hdlr = logging.StreamHandler(sys.stdout)

hdlr.setFormatter(fmt)
logging.root.addHandler(hdlr)
logging.root.setLevel(DEBUG)

编辑2:

Python3记录已经改变了一点。 见这里的Python3方法。



Answer 3:

并再次像JS的答案,但更紧凑。

class SpecialFormatter(logging.Formatter):
    FORMATS = {logging.DEBUG :"DBG: %(module)s: %(lineno)d: %(message)s",
               logging.ERROR : "ERROR: %(message)s",
               logging.INFO : "%(message)s",
               'DEFAULT' : "%(levelname)s: %(message)s"}

    def format(self, record):
        self._fmt = self.FORMATS.get(record.levelno, self.FORMATS['DEFAULT'])
        return logging.Formatter.format(self, record)

hdlr = logging.StreamHandler(sys.stderr)
hdlr.setFormatter(SpecialFormatter())
logging.root.addHandler(hdlr)
logging.root.setLevel(logging.INFO)


Answer 4:

这是一个适应estani的回答到新的执行logging.Formatter现在依靠格式样式。 矿依赖于'{'样式的格式,但它可以适应。 可以细化到更一般的,并允许格式化的风格和自定义消息作为参数的选择__init__了。

class SpecialFormatter(logging.Formatter):
    FORMATS = {logging.DEBUG : logging._STYLES['{']("{module} DEBUG: {lineno}: {message}"),
           logging.ERROR : logging._STYLES['{']("{module} ERROR: {message}"),
           logging.INFO : logging._STYLES['{']("{module}: {message}"),
           'DEFAULT' : logging._STYLES['{']("{module}: {message}")}

    def format(self, record):
        # Ugly. Should be better
        self._style = self.FORMATS.get(record.levelno, self.FORMATS['DEFAULT'])
        return logging.Formatter.format(self, record)

hdlr = logging.StreamHandler(sys.stderr)
hdlr.setFormatter(SpecialFormatter())
logging.root.addHandler(hdlr)
logging.root.setLevel(logging.INFO)


Answer 5:

而不是依靠样式或内部字段,你还可以创建取决于record.levelno(或其他标准)委托给其他格式化格式化。 这是我的愚见稍微清晰的解决方案。 下面的代码应该对任何Python版本工作> = 2.7:

最简单的方法将是这个样子:

class MyFormatter(logging.Formatter):

    default_fmt = logging.Formatter('%(levelname)s in %(name)s: %(message)s')
    info_fmt = logging.Formatter('%(message)s')

    def format(self, record):
        if record.levelno == logging.INFO:
            return self.info_fmt.format(record)
        else:
            return self.default_fmt.format(record)

但你可以使它更通用的:

class VarFormatter(logging.Formatter):

    default_formatter = logging.Formatter('%(levelname)s in %(name)s: %(message)s')

    def __init__(self, formats):
        """ formats is a dict { loglevel : logformat } """
        self.formatters = {}
        for loglevel in formats:
            self.formatters[loglevel] = logging.Formatter(formats[loglevel])

    def format(self, record):
        formatter = self.formatters.get(record.levelno, self.default_formatter)
        return formatter.format(record)

我用的字典为输入这里,但很明显,你也可以使用元组,** kwargs,不管你的船浮筒。 这将被使用,如:

formatter = VarFormatter({logging.INFO: '[%(message)s]', 
                          logging.WARNING: 'warning: %(message)s'})
<... attach formatter to logger ...>


Answer 6:

上述解决方案可与3.3.3版本。 然而,随着3.3.4您会收到以下错误。

FORMATS = { logging.DEBUG : logging._STYLES['{']("{module} DEBUG: {lineno}: {message}"),

类型错误:“元组”对象不是可调用

在日志类LIB \ logging__init一些摸索__后,PY我发现一个数据结构已经从3.3.3改为3.3.4导致问题

3.3.3

_STYLES = {
    '%': PercentStyle,
    '{': StrFormatStyle,
    '$': StringTemplateStyle
}

3.3.4

_STYLES = {
   '%': (PercentStyle, BASIC_FORMAT),
   '{': (StrFormatStyle, '{levelname}:{name}:{message} AA'),
    '$': (StringTemplateStyle, '${levelname}:${name}:${message} BB'),
}

因此,更新的解决方案是

class SpecialFormatter(logging.Formatter):
     FORMATS = {logging.DEBUG : logging._STYLES['{'][0]("{module} DEBUG: {lineno}: {message}"),
       logging.ERROR : logging._STYLES['{'][0]("{module} ERROR: {message}"),
       logging.INFO : logging._STYLES['{'][0]("{module}: {message}"),
       'DEFAULT' : logging._STYLES['{'][0]("{module}: {message}")}

 def format(self, record):
    # Ugly. Should be better
    self._style = self.FORMATS.get(record.levelno, self.FORMATS['DEFAULT'])
    return logging.Formatter.format(self, record)


Answer 7:

如果你只是希望跳过格式化一定的水平,你可以做的东西比其他的答案,如以下简单:

class FormatterNotFormattingInfo(logging.Formatter):
    def __init__(self, fmt = '%(levelname)s:%(message)s'):
        logging.Formatter.__init__(self, fmt)

    def format(self, record):
        if record.levelno == logging.INFO:
            return record.getMessage()
        return logging.Formatter.format(self, record)

这也有之前和3.2版本不使用像self._fmt也不self._style内部变量后工作的优势。



文章来源: Can Python's logging format be modified depending on the message log level?