代码之家  ›  专栏  ›  技术社区  ›  Brad Solomon

通过模块名称和严重性记录到不同位置

  •  2
  • Brad Solomon  · 技术社区  · 7 年前

    我有一个存储库,它最好的特点是作为一个专门的应用程序,而不是一个库。

    下面是一个示例结构:

    logtest/
        logtest/
            __init__.py
            a.py
            b.py
            ...
            e.py
            f.py
        LICENSE
        README
        .gitignore, etc
    

    我想使用一个 logging.handlers.RotatingFileHandler severity level

    每个 .py 文件当前仅包含 logger = logging.getLogger(__name__) ; 对于 a.py logger.name == 'logtest.a' . 我想要实现的是为每个记录器设置多个处理程序:

    • 仅与相应模块相关的模块,即。 /tmp/mod-a.log . 不应设置此处理程序的级别。
    • 与五个日志记录级别相关的五个 NOTSET ,即10至50级。每一个都有适当的 .level

    一张照片可能会说明更多:

    logtest/a.py  -->  /tmp/a.log  # Any severity level
    logtest/b.py  -->  /tmp/b.log
    ... 
    logtest/e.py  -->  /tmp/e.log
    
    logtest/a.py  __
    logtest/b.py  __\___ `/tmp/level-critical.log` (if level is logging.CRITICAL)
    logtest/e.py  __/
    
    logtest/a.py  __
    logtest/b.py  __\___ `/tmp/level-error.log` (if level is logging.ERROR)
    logtest/e.py  __/
    

    (是的,我知道这将冗余地记录消息。)

    什么是推荐和有效的设计方法,如设置?好像 logging.config.dictConfig 会很有用的,除了能远离 logging.getLogger(__name__)


    如果上面有点不清楚:我有一个 logger 每个模块的实例 __init__.py ,每个都是通过 logging.getLogger(_名称__)

    _levels = ("debug", "info", "warning", "error", "critical")
    _level_handlers = {
        level: {
            "class": "logging.handlers.RotatingFileHandler",
            "filename": "/tmp/level-{}.log".format(level),
            "maxBytes": 750000,
            "backupCount": 5,
            "level": level.upper()
        } for level in _levels
    }
    
    LOGGING = {
        "version": 1,
        "loggers": {
            # Root - all other logger.getLogger(__name__) instances are children
            "": {
                "handlers": _levels,
            }
        }
    }
    
    LOGGING['handlers'] = _level_handlers
    logging.config.dictConfig(LOGGING)
    

    但我不确定如何治疗第二部分。

    1 回复  |  直到 7 年前
        1
  •  0
  •   Brad Solomon    7 年前

    我目前的解决方案分为两部分(当然,我还是很欣赏其他方法):

    • 在中设置基于级别的处理程序 __init__ __name__
    • 添加一个助手函数 getModuleLogger() 模仿 getLogger() 在内部 __初始化__ ,但也添加了一个特定于该模块的文件处理程序。

    getModuleLogger(__name__) 就像它通常所说的那样 logging.getLogger(__name__)

    从…起 __init__.py

    __all__ = ()
    
    import logging
    import logging.config
    import logging.handlers
    import os
    
    _levels = ("debug", "info", "warning", "error", "critical")
    _level_handlers = {
        level: {
            "class": "logging.handlers.RotatingFileHandler",
            "filename": "/tmp/level-{}.log".format(level),
            "maxBytes": 750_000,
            "backupCount": 5,
            "level": level.upper()
        } for level in _levels
    }
    
    LOGGING = {
        "version": 1,
        "loggers": {
            # Using the package name means modules in the package are nested
            # as children of this parent logger and will inherit its handlers
            __name__: {
                "handlers": _levels,
            }
        }
    }
    
    LOGGING['handlers'] = _level_handlers
    logging.config.dictConfig(LOGGING)
    
    
    def getModuleLogger(name):
        """Call this from modules instead of standard logging.getLogger()."""
        logger = logging.getLogger(name)
        logger.setLevel(logging.DEBUG)
        handler = logging.handlers.RotatingFileHandler(
            filename="/tmp/module-{}.log".format(name),
            maxBytes=750_000, backupCount=5
        )
        handler.setLevel(logging.DEBUG)
        logger.addHandler(handler)
        return logger
    

    从…起 a.py

    from logtest import getModuleLogger
    
    logger = getModuleLogger(__name__)
    
    def test_a():
        logger.info("info from a.py")
        logger.critical("critical from a.py")
    

    >>> from logtest import a, b
    >>> a.test_a()
    >>> b.test_b()
    >>> from logtest.a import logger
    >>> logger.handlers
    [<RotatingFileHandler /tmp/module-logtest.a.log (DEBUG)>]
    >>> from pprint import pprint
    >>> pprint(logger.parent.handlers)
    [<RotatingFileHandler /tmp/level-debug.log (DEBUG)>,
     <RotatingFileHandler /tmp/level-info.log (INFO)>,
     <RotatingFileHandler /tmp/level-warning.log (WARNING)>,
     <RotatingFileHandler /tmp/level-error.log (ERROR)>,
     <RotatingFileHandler /tmp/level-critical.log (CRITICAL)>]
    >>> exit()
    
    [logtest/] $ cat /tmp/module-logtest.a.log 
    info from a.py
    critical from a.py
    [logtest/] $ cat /tmp/module-logtest.b.log 
    info from b.py
    critical from b.py
    [logtest/] $ cat /tmp/level-critical.log 
    critical from a.py
    critical from b.py