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