使用 YAML 和过滤器登录 python

res*_*est 7 python logging

想要使用 YAML 设置带有过滤器的记录器。

YAML配置文件config.yaml如下:

version: 1

formatters:
  simple:
    format: "%(asctime)s %(name)s: %(message)s"
  extended:
    format: "%(asctime)s %(name)s %(levelname)s: %(message)s"

filters:
  noConsoleFilter:
    class: noConsoleFilter

handlers:
  console:
    class: logging.StreamHandler
    level: INFO
    formatter: simple
    filters: [noConsoleFilter]

  file_handler:
    class: logging.FileHandler
    level: INFO
    filename: test.log
    formatter: extended

root:
  handlers: [console, file_handler]
  propagate: true
Run Code Online (Sandbox Code Playgroud)

...主程序如下main.py

import logging.config
import yaml

class noConsoleFilter(logging.Filter):
    def filter(self, record):
        print("filtering!")
        return not (record.levelname == 'INFO') & ('no-console' in record.msg)

with open('config.yaml', 'r') as f:
    log_cfg = yaml.safe_load(f.read())
    logging.config.dictConfig(log_cfg)  

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

logger.info("no-console. Should not be in console, but be in test.log!")
logger.info('This is an info message')
logger.error('This is an error message')
Run Code Online (Sandbox Code Playgroud)

控制台中的预期输出没有“no-console”消息:

   2020-04-27 18:05:26,936 __main__: This is an info message 
   2020-04-27 18:05:26,936 __main__: This is an error message
Run Code Online (Sandbox Code Playgroud)

但看起来 class:noConsoleFilter甚至没有被考虑,因为 print 语句也不起作用。

我哪里错了?我该如何修复它?

dan*_*elo 8

语法有点奇怪,但它在日志记录文档中的“用户定义对象”下进行了描述,您必须使用 key (),而不是class。就像这样:

filters:
  noConsoleFilter:
    (): noConsoleFilter
Run Code Online (Sandbox Code Playgroud)

接下来,您需要为类指定一个限定名称。如果您直接运行脚本,而不是作为模块运行,则可以在以下位置引用它__main__

filters:
  noConsoleFilter:
    (): __main__.noConsoleFilter
Run Code Online (Sandbox Code Playgroud)

我还建议对类名使用 PEP 8 CapWords 约定。这是一个稍微整理过的、完全独立的示例:

# logging.yml
version: 1

formatters:
  simple_formatter:
    format: "%(asctime)s %(name)s: %(message)s"
  extended_formatter:
    format: "%(asctime)s %(name)s %(levelname)s: %(message)s"

filters:
  no_console_filter:
    (): __main__.NoConsoleFilter

handlers:
  console_handler:
    class: logging.StreamHandler
    level: INFO
    formatter: simple_formatter
    filters: [no_console_filter]

  file_handler:
    class: logging.FileHandler
    level: INFO
    filename: test.log
    formatter: extended_formatter

root:
  handlers: [console_handler, file_handler]
  propagate: true
Run Code Online (Sandbox Code Playgroud)
# script.py
import logging.config
import yaml

class NoConsoleFilter(logging.Filter):
    def filter(self, record):
        print('filtering!')
        return not (record.levelname == 'INFO') & ('no-console' in record.msg)

with open('logging.yml', 'r') as f:
    log_cfg = yaml.safe_load(f.read())
    logging.config.dictConfig(log_cfg)

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

logger.info('no-console. Should not be in console, but be in test.log!')
logger.info('This is an info message')
logger.error('This is an error message')
Run Code Online (Sandbox Code Playgroud)