【问题标题】:Filtering log levels过滤日志级别
【发布时间】:2021-09-28 20:35:56
【问题描述】:

我正在尝试将日志级别分成单独的文件(每个级别一个)。目前我已经为每个级别定义了一个文件,但是在我当前的配置下,上层会传播到下层。

我的日志配置是:

version: 1

formatters:
  standard:
    format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
  error:
    format: "%(levelname)s <PID %(process)d:%(processName)s> %(name)s.%(funcName)s(): %(message)s"

handlers:
  console:
    class: logging.StreamHandler
    formatter: standard
    level: DEBUG

  debug_file_handler:
    class: logging.handlers.RotatingFileHandler
    formatter: standard
    level: DEBUG
    filename: logs/debug.log
    encoding: utf8
    mode: "w"
    maxBytes: 10485760 # 10MB
    backupCount: 1

  info_file_handler:
    class: logging.handlers.RotatingFileHandler
    formatter: standard
    level: INFO
    filename: logs/info.log
    encoding: utf8
    mode: "w"
    maxBytes: 10485760 # 10MB
    backupCount: 1

  warning_file_handler:
    class: logging.handlers.RotatingFileHandler
    formatter: standard
    level: WARNING
    filename: logs/warning.log
    encoding: utf8
    mode: "w"
    maxBytes: 10485760 # 10MB
    backupCount: 1

  error_file_handler:
    class: logging.handlers.RotatingFileHandler
    formatter: error
    level: ERROR
    filename: logs/error.log
    encoding: utf8
    mode: "w"
    maxBytes: 10485760 # 10MB
    backupCount: 1

  critical_file_handler:
    class: logging.handlers.RotatingFileHandler
    formatter: error
    level: CRITICAL
    filename: logs/critical.log
    encoding: utf8
    mode: "w"
    maxBytes: 10485760 # 10MB
    backupCount: 1

loggers:
  development:
    handlers: [ console, debug_file_handler ]
    propagate: false
  production:
    handlers: [ info_file_handler, warning_file_handler, error_file_handler, critical_file_handler ]
    propagate: false
root:
  handlers: [ debug_file_handler, info_file_handler, warning_file_handler, error_file_handler, critical_file_handler ]

然后我加载配置并像这样设置记录器:

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

logger = logging.getLogger(LOGS_MODE)
logger.setLevel(LOGS_LEVEL)

LOGS_MODELOGS_LEVEL 在我项目的配置文件中定义:

# Available loggers: development, production
LOGS_MODE = 'production'
# Available levels: CRITICAL = 50, ERROR = 40, WARNING = 30, INFO = 20, DEBUG = 10
LOGS_LEVEL = 20

当我想使用记录器时:

from src.logger import logger

我在他们提到使用过滤器的地方找到了这些答案:#1#2,但他们都说要使用不同的处理程序并为每个处理程序指定级别,但是使用这种方法,我将不得不导入不同的记录器一些案例,而不仅仅是一个。这是实现它的唯一方法吗?

问候。

更新 1:

当我使用 YAML 文件加载记录器配置时,我找到了这个答案 #3

所以我在我的文件logger.py中定义了过滤器:

with open(path_log_config_file, 'rt') as config_file:
    config = yaml.safe_load(config_file.read())
    logging.config.dictConfig(config)
    

class InfoFilter(logging.Filter):
    def __init__(self):
        super().__init__()

    def filter(self, record):
        return record.levelno == logging.INFO


class WarningFilter(logging.Filter):
    def __init__(self):
        super().__init__()

    def filter(self, record):
        return record.levelno == logging.WARNING


class ErrorFilter(logging.Filter):
    def __init__(self):
        super().__init__()

    def filter(self, record):
        return record.levelno == logging.ERROR


class CriticalFilter(logging.Filter):
    def __init__(self):
        super().__init__()

    def filter(self, record):
        return record.levelno == logging.CRITICAL


logger = logging.getLogger(LOGS_MODE)
logger.setLevel(LOGS_LEVEL)

在 YAML 文件中:

filters:
  info_filter:
    (): src.logger.InfoFilter
  warning_filter:
    (): src.logger.WarningFilter
  error_filter:
    (): src.logger.ErrorFilter
  critical_filter:
    (): src.logger.CriticalFilter

handlers:
  console:
    class: logging.StreamHandler
    formatter: standard
    level: DEBUG

  debug_file_handler:
    class: logging.handlers.RotatingFileHandler
    formatter: standard
    level: DEBUG
    filename: logs/debug.log
    encoding: utf8
    mode: "w"
    maxBytes: 10485760 # 10MB
    backupCount: 1

  info_file_handler:
    class: logging.handlers.RotatingFileHandler
    formatter: standard
    level: INFO
    filename: logs/info.log
    encoding: utf8
    mode: "w"
    maxBytes: 10485760 # 10MB
    backupCount: 1
    filters: [ info_filter ]

  warning_file_handler:
    class: logging.handlers.RotatingFileHandler
    formatter: standard
    level: WARNING
    filename: logs/warning.log
    encoding: utf8
    mode: "w"
    maxBytes: 10485760 # 10MB
    backupCount: 1
    filters: [ warning_filter ]

  error_file_handler:
    class: logging.handlers.RotatingFileHandler
    formatter: error
    level: ERROR
    filename: logs/error.log
    encoding: utf8
    mode: "w"
    maxBytes: 10485760 # 10MB
    backupCount: 1
    filters: [ error_filter ]

  critical_file_handler:
    class: logging.handlers.RotatingFileHandler
    formatter: error
    level: CRITICAL
    filename: logs/critical.log
    encoding: utf8
    mode: "w"
    maxBytes: 10485760 # 10MB
    backupCount: 1
    filters: [ critical_filter ]

我现在的问题出在过滤器部分。我不知道如何指定每个类的名称。在回复#3 中,他使用了__main__.,因为他直接运行脚本,而不是作为模块运行,并且没有说明如果您使用模块该怎么做。

阅读User-defined objects 文档参考我尝试使用ext://,正如Access to external objects 部分所述,但我得到的错误与尝试使用src.logger.InfoFilter 指定层次结构时相同。

    logging.config.dictConfig(config)
  File "/usr/lib/python3.8/logging/config.py", line 808, in dictConfig
    dictConfigClass(config).configure()
  File "/usr/lib/python3.8/logging/config.py", line 553, in configure
    raise ValueError('Unable to configure '
ValueError: Unable to configure filter 'info_filter'
python-BaseException

我的项目树是(只显示了重要的部分):

.
├── resources
│   ├── log.yaml
│   └── properties.py
├── src
│   ├── main.py
│   └── logger.py
└── ...

【问题讨论】:

    标签: python logging


    【解决方案1】:

    我提交了另一个答案,因为您的问题随着您的更新 1 发生了很大变化。

    复制注意事项:

    • 我重新创造了你的树枝
    • 我的 PYTHONPATH 仅指向根(src/ressources/ 的父级)
    • 我从根目录(当前目录)运行脚本
    • 我在顶层创建了一个logs/ 目录(否则我得到ValueError: Unable to configure handler 'critical_file_handler': [Errno 2] No such file or directory: 'C:\\PycharmProjects\\so69336121\\logs\\critical.log'

    您遇到的问题是周期性导入引起的。当 logger 模块被导入时,它首先加载和 YAML 文件,该文件要求实例化一些 src.logger.*Filter 对象,由于文件尚未完全初始化,它无法找到这些对象。我建议将有效的代码放入主函数在启动时可以调用的函数中。

    这是我所拥有的:

    # file: src/logger.py
    
    import logging.config
    
    import yaml  # by `pip install pyyaml`
    
    
    path_log_config_file = "ressources/log.yml"
    LOGS_LEVEL = logging.ERROR
    LOGS_MODE = "production"
    
    
    def setup_logging():
        with open(path_log_config_file, 'rt') as config_file:
            config = yaml.safe_load(config_file.read())
            logging.config.dictConfig(config)
    
    # ... the rest of the file you provided
    
    # file: src/main.py
    
    from src.logger import setup_logging, logger
    
    
    setup_logging()
    
    logger.debug("DEBUG")
    logger.info("INFO")
    logger.warning("WARNING")
    logger.error("ERROR")
    logger.critical("CRITICAL")
    

    然后我得到一个错误:

    ValueError: dictionary doesn't specify a version
    

    通过将此行添加到 YAML 文件的顶部来解决:

    version: 1
    

    cfdocumentation

    然后我得到了这个错误:

    ValueError: Unable to configure handler 'console': Unable to set formatter 'standard': 'standard'
    

    因为您的格式化程序未定义(您可能误复制粘贴)。在这里,将其添加到您的 YAML 文件中:

    formatters:
      standard:
        format: '%(asctime)s [%(levelname)s] %(name)s: %(message)s'
      error:
        format: 'ERROR %(asctime)s [%(levelname)s] %(name)s: %(message)s'
    

    它运行没有错误,但没有写入日志。快速调试器断点显示从未调用过 *Filter.filter 方法。我检查了logger 对象,确实它没有附加处理程序。它也可以添加到 YAML 中:

    loggers:
      production:
        handlers: [ debug_file_handler, info_file_handler, warning_file_handler, error_file_handler, critical_file_handler ]
        propagate: False
    

    现在它可以工作了。

    【讨论】:

    • 该死的法瑞克!我(再次)忘记了循环导入,感谢您的注意。关于 YAML 文件,您是对的,我没有复制整个配置,以免问题太长,这就是您遇到其他错误的原因。对于那些与问题本身无关的错误花费了您的时间,我深表歉意,我应该复制整个文件以使您更轻松。否则,它现在可以工作了,非常感谢!
    • @Aker666 当你有一个复杂的问题时,最好放一个完整的可重复的例子;-) 理想情况下是Minimal Reproducible Example。此外,您经常会在尝试构建 MRE 时找到解决方案 :)
    【解决方案2】:

    我想你误会了。

    他们都说要使用不同的处理程序并为每个处理程序指定级别

    正确。

    但使用这种方法,在某些情况下我将不得不导入不同的记录器,而不仅仅是一个

    不,您可以向一个记录器添加任意数量的处理程序。这就是为什么该方法被称为Logger.addHandler 并且每个记录器对象都有一个处理程序列表(它的.handlers 成员)。

    您只需为您的 5 个处理程序设置一个记录器。

    【讨论】:

    • 啊,好的。非常感谢您的澄清。下班回家我试试看。
    • 您好,我已经更新了我的问题,详细介绍了我在尝试添加过滤器时遇到的问题。如果不是太麻烦的话,如果你能看一下,我将不胜感激。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-19
    • 2020-10-04
    • 2012-09-11
    • 2019-09-20
    • 1970-01-01
    • 2015-06-23
    相关资源
    最近更新 更多