学习 python logging(3):组合自己的Logger

python logging模块中各个基础组件

在项目中,我们可能需要定义不同的日志格式,有时需要定位到某一行,有的就不需要,并且根据情况要筛选不同的日志等级,例如,生产环境就不需要打印 DEBUG 级别的日志。这就涉及到需要多个日志模型。

python中定义了基本的日志组件让我们可以去组装和自定义以实现日志模型,功能包括日志信息过滤(脱敏)、筛选日志等级等等。这些组件包括:
logging.Logger, logging.Handler, logging.Formatter, logging.Filter, logging.LogRecord, LoggerAdapter

1. logging.Logger

在 python 中获取 Logger 实例,一般是通过 logging.getLogger(name) 这个方法来获得,并且针对单个 name,不管获得多少次,都是同一个实例。

1.1 Logger 的方法:

  • setLevel: 设置最低的日志输出的等级。在3.2版本之后可以接受 INFO 或是 20 这样的字符串或是整型类型信息。
  • 记录日志的方法,分别有对应的等级: debuginfowarnerrorwarningexceptioncriticalfatallog
  • Handler 添加与移除: addHandler, removeHandler
  • 生成 LogRecord : makeRecord
import logging
logger = logging.getLogger('test')
logger.setLevel('INFO')
logger.debug('test logger debug')
logger.info('test logger')

输出为: No handlers could be found for logger "test", 从结果看来,还缺少Handelr实例。

2. logging.Handler

实际来处理日志记录的类, 用以做一些特殊逻辑上的操作。如记录到文件、上传日志等等。

主要的方法有:

  • setLevel
  • setFormatter
  • format: 格式化日志。
  • 过滤器: addFilter, removeFilter
  • 处理日志信息流程: handle, handleError, emit, 最终的逻辑在 emit 中,handle 的逻辑是会加上锁,调用 emit

3. logging.Formatter

格式化日志记录的类, 主要方法有:

  • format(record)
  • 处理时间信息: formatTime
  • 格式化异常信息: formatException

4. loggingFilter

Filter 的实例,能被用在 HandlerLogger 这个两个类的实例中。

该类的方法时 filter(record): 用来决定指定的 record 是否可以被记录, 能被记录返回True, 否则为False,并且,我们可以用来过滤一些参数信息,将敏感信息脱敏。

5. logging.LogRecord

用来记录一条日志中的所有信息和需要的信息。

6. 常用生成自己所需 Logger 的组合方式:

  1. 使用代码,直接使用 LoggerHandler等实例,进行组合:

    import logging
    logger = logging.getLogger('test')
    logger.setLevel('INFO')
    
    handler = logging.StreamHandler()
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    handler.setFormatter(formatter)
    
    logger.addHandler(handler)
    
    logger.debug('debug message')
    logger.info('info message')
    logger.warn('warn message')
    logger.error('error message')
    logger.critical('critical message')
    

    输出为:

    2019-01-05 17:11:46,286 - test - INFO - info message
    2019-01-05 17:11:46,286 - test - WARNING - warn message
    2019-01-05 17:11:46,286 - test - ERROR - error message
    2019-01-05 17:11:46,286 - test - CRITICAL - critical message
    
  2. 使用配置文件,加载配置文件, fileConfig()

    配置文件信息为:

    import logging
    import logging.config
    
    logging.config.fileConfig('logging.conf')
    
    # create logger
    logger = logging.getLogger('simpleExample')
    
    # 'application' code
    logger.debug('debug message')
    logger.info('info message')
    logger.warn('warn message')
    logger.error('error message')
    logger.critical('critical message')
    
    [loggers]
    keys=root,simpleExample
    
    [handlers]
    keys=consoleHandler
    
    [formatters]
    keys=simpleFormatter
    
    [logger_root]
    level=DEBUG
    handlers=consoleHandler
    
    [logger_simpleExample]
    level=DEBUG
    handlers=consoleHandler
    qualname=simpleExample
    propagate=0
    
    [handler_consoleHandler]
    class=StreamHandler
    level=DEBUG
    formatter=simpleFormatter
    args=(sys.stdout,)
    
    [formatter_simpleFormatter]
    format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
    datefmt=
    

    输出为:

    2005-03-19 15:38:55,977 - simpleExample - DEBUG - debug message
    2005-03-19 15:38:55,979 - simpleExample - INFO - info message
    2005-03-19 15:38:56,054 - simpleExample - WARNING - warn message
    2005-03-19 15:38:56,055 - simpleExample - ERROR - error message
    2005-03-19 15:38:56,130 - simpleExample - CRITICAL - critical message
    
  3. 使用 dict 类型的变量进行配置, dictConfig().

    LOGGING = {
        'version': 1,
        'disable_existing_loggers': True,
        'formatters': {
            'verbose': {
                'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
            },
            'simple': {
                'format': '%(levelname)s %(message)s'
            },
        },
        'filters': {
            'special': {
                '()': 'project.logging.SpecialFilter',
                'foo': 'bar',
            }
        },
        'handlers': {
            'null': {
                'level':'DEBUG',
                'class':'django.utils.log.NullHandler',
            },
            'console':{
                'level':'DEBUG',
                'class':'logging.StreamHandler',
                'formatter': 'simple'
            },
            'mail_admins': {
                'level': 'ERROR',
                'class': 'django.utils.log.AdminEmailHandler',
                'filters': ['special']
            }
        },
        'loggers': {
            'django': {
                'handlers':['null'],
                'propagate': True,
                'level':'INFO',
            },
            'django.request': {
                'handlers': ['mail_admins'],
                'level': 'ERROR',
                'propagate': False,
            },
            'myproject.custom': {
                'handlers': ['console', 'mail_admins'],
                'level': 'INFO',
                'filters': ['special']
            }
        }
    }
    

以上的配置 Logger 方案中,使用配置文件或是dict实例的方式更加合理,把配置和代码分离了,更容易扩展,应该作为实际项目中推荐的使用方式。


参考:

  1. https://docs.python.org/3/howto/logging.html#logging-basic-tutorial
  2. https://docs.python.org/3/library/logging.html
  3. https://docs.python.org/3/howto/logging-cookbook.html#logging-cookbook
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章