學習 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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章