使用Python的日志库: logging

Python里常用的日志工具包是logging,很多第三方库也使用了它作日志记录。本文介绍logging的一些使用方法。

import logging

引入logging库后即使用,有下面几个日志记录函数,分别对应不同的日志级别:

  • debug
  • info
  • warning
  • error
  • critical

配置日志级别

logging的默认日志等级是WARNING,所以不作其它配置时,下面这条语句不会记录任何信息:

logging.info('This is an info message')
# 打印错误信息时,需使用exc_info才会显示traceback
logging.error("Expected error occurred", exc_info=True)

解决办法是使用basicConfig方法修改日志级别:

logging.basicConfig(level=logging.INFO, force=True)

由于logging只能初始化一次,而在先前调用logging.info时默认已初始化过了,这里若不使用force=True,上面这配置将无用。

其它配置

将日志写入文件

使用basicConfig还可以配置日志以文件形式记录:

logging.basicConfig(filename='my.log', filemode='a', format='%(name)s - %(levelname)s - %(message)s', level=logging.INFO)
  • filemode分为a追加, w替换。
  • format参数里用到的name, levelname, message等是日志记录属性,这里分别表示当前的日志名、日志等级与消息。还有很多其它属性可用,请参考LogRecord

将日志写书标准输出

若只需要把日志输出到标准输出:

import sys
logging.basicConfig(stream=sys.stdout, level=logging.INFO)

使用多个日志记录

logging支持多个日志实例,即支持多个Logger。

上文以logging.info('msg')的方式记录日志,其实使用的是根日志实例,即

logging.info('msg')

等效于

root_logger = logging.getLogger()
root_logger.info('msg')

通常我们希望为不同的模块配置不同的日志记录方式。这时可先通过logging.basicConfig函数为所有日志实例配置默认的参数,然后生成实例时再传入各自的配置:

# 这两行可获取其它库的日志,并将其等级为WARNING
console_logger = logging.getLogger('other_module') # 这里使用的名称与目标库使用的相同
console_logger.setLevel(logging.WARNING)

console_logger.info('不显示')

try:
    fail_fn()
except Exception as e:
    # 打印错误信息时,需使用exc_info才会显示traceback
    console_logger.error("Expected error occurred", exc_info=True)

# 创建新日志实例,使用文件记录日志
logfile = 'my.log'
file_logger = logging.getLogger('my_module')
file_logger.setLevel(logging.INFO)
file_log_handler = logging.FileHandler(logfile, mode='w', encoding='utf8')
f_format = logging.Formatter('%(asctime)s %(name)s %(levelname)s %(message)s')
file_log_handler.setFormatter(f_format)
file_logger.addHandler(file_log_handler)

file_logger.info('这条日志将出现在标准输出,并记录于{}'.format(logfile))

logging通过不同的Handler处理日志,而日志格式又是与日志的Handler关联的,所以上面必须调用file_log_handler.setFormatter配置格式。

格式化输出

可使用f'{varname}'的形式简化字符串拼接:

url = 'https://www.baidu.com'
path = '/tmp/baidu.txt'
logging.info(f'checking {url} {path}')

完整示例

# coding: utf-8

import logging

def cal():
    print('calculating ...')
    return 3

def fail_fn():
    raise Exception('funny error')

logging.info('这行不会显示:a是{}'.format(cal()))

logging.basicConfig(level=logging.DEBUG, force=True)

logging.info('这行会显示:a是{}'.format(cal()))

root_logger = logging.getLogger()

root_logger.info('root logger实例')

# 这两行可获取其它库的日志,并将其等级为WARNING
console_logger = logging.getLogger('other_module') # 这里使用的名称与目标库使用的相同
console_logger.setLevel(logging.WARNING)

console_logger.info('不显示')

try:
    fail_fn()
except Exception as e:
    # 打印错误信息时,需使用exc_info才会显示traceback
    console_logger.error("Expected error occurred", exc_info=True)

# 创建新日志实例,使用文件记录日志
logfile = 'my.log'
file_logger = logging.getLogger('my_module')
file_logger.setLevel(logging.INFO)
file_log_handler = logging.FileHandler(logfile, mode='w', encoding='utf8')
f_format = logging.Formatter('%(asctime)s %(name)s %(levelname)s %(message)s')
file_log_handler.setFormatter(f_format)
file_logger.addHandler(file_log_handler)

file_logger.info('这条日志将出现在标准输出,并记录于{}'.format(logfile))

参考

  • https://realpython.com/python-logging
  • https://docs.python.org/3/library/logging.html
Comment