Python日志模块logging的使用详解 PS: 转载自 https://github.com/HuiDBK/LogSetupDemo
日志
在开发一些大型项目的时候,都会使用日志来记录项目运行时产生的信息,以备出错时定位分析和从日志信息中提取数据统计分析等。在 Python
中使用 logging
内置模块即可对项目进行日志的配置。
logging模块的使用 简单使用
logging
模块提供了一系列便利的函数
它们分别是 debug(), info(), warning(), error(), critical()
1 2 3 4 5 6 7 import logginglogging.debug('debug log test' ) logging.info('info log test' ) logging.warning('warning log test' ) logging.error('error log test' ) logging.critical('critical log test' )
输出结果:
1 2 3 WARNING:root:warning log test ERROR:root:error log test CRITICAL:root:critical log test
为什么只输出了 warning
, error
和 critical
的结果,因为 logging
模块默认使用 warning
日志级别,就是只有 warning
及以上日志等级才会显示。
日志等级从高到低,如下所示
级别
数值
何时使用
CRITICAL
50
严重的错误,表明程序已不能继续执行
ERROR
40
由于严重的问题,程序的某些功能已经不能正常执行
WARNING
30
表明有已经或即将发生的意外,程序仍按预期进行
INFO
20
确认程序按预期运行
DEBUG
10
细节信息,仅当诊断问题时适用。
NOTSET
0
无任何等级限制
我们只要把 logging
的默认日志等级改下就好了
1 2 3 4 5 6 7 8 9 import logginglogging.basicConfig(level=logging.DEBUG) logging.debug('debug log test' ) logging.info('info log test' ) logging.warning('warning log test' ) logging.error('error log test' )
输出结果如下:
1 2 3 4 DEBUG:root:debug log test INFO:root:info log test WARNING:root:warning log test ERROR:root:error log test
指定日志输出样式 当然我们还可以指定日志输出格式
1 2 3 4 5 6 7 8 9 10 11 12 import logginglog_format = '%(levelname)s %(asctime)s %(filename)s %(lineno)d %(message)s' logging.basicConfig(format =log_format, level=logging.DEBUG) logging.debug('debug log test' ) logging.info('info log test' ) logging.warning('warning log test' ) logging.error('error log test' ) logging.critical('critical log test' )
输出结果如下:
1 2 3 4 5 DEBUG 2021 -05-27 00 :04:26 ,327 main.py 65 debug log test INFO 2021 -05-27 00 :04:26 ,327 main.py 66 info log test WARNING 2021 -05-27 00 :04:26 ,327 main.py 67 warning log test ERROR 2021 -05-27 00 :04:26 ,327 main.py 68 error log test CRITICAL 2021 -05-27 00 :04:26 ,327 main.py 69 critical log test
其中日志信息格式化输出配置样式说明
%(levelname)s ,日志等级
%(asctime)s ,时间
%(filename)s ,文件名
%(lineno)d ,行号
%(message)s,日志信息
这些配置都是固定,不可随便写,还有好多日志格式化样式,这里只介绍了一些常用的格式配置,大家可以去官网查看更多的格式化配置信息。https://docs.python.org/zh-cn/3.7/library/logging.html#formatter-objects
日志记录到文件中 在 logging.basicConfig
中设置 filename
属性即可把日志信息写入文件中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import logginglog_format = '%(levelname)s %(asctime)s %(filename)s %(lineno)d %(message)s' logging.basicConfig( filename='test.log' , format =log_format, level=logging.DEBUG ) logging.debug('debug log test' ) logging.info('info log test' ) logging.warning('warning log test' ) logging.error('error log test' ) logging.critical('critical log test' )
运行程序后 test.log
如下内容
自定义日志配置
通常我们在项目中都是自定义一些通用日志配置,然后供项目全局使用。写好这些配置下次要在别的项目使用之间复制粘贴过来修改修改一下即可。来康康是如何配置的。
准备日志配置信息 配置日志详细信息,需要导入 logging.config
来进行加载日志配置信息
首先准备日志配置信息字典
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 log_dict = { 'version': 1 , 'disable_existing_loggers': False , 'formatters': { 'simple': { 'format': '%(levelname)s %(module)s %(lineno)d %(message)s' }, 'verbose': { 'format': '%(levelname)s %(asctime)s %(filename)s %(lineno)d %(message)s' }, }, 'handlers': { 'console': { 'level': 'DEBUG' , 'class': 'logging.StreamHandler' , 'formatter': 'simple' }, 'file': { 'level': 'INFO' , 'class': 'logging.handlers.RotatingFileHandler' , 'formatter': 'verbose' , 'filename': './logs/test.log' , 'maxBytes': 1024 * 1024 , 'backupCount': 20 , 'encoding': 'utf8' , }, }, 'root': { 'level': 'DEBUG' , 'handlers': ['console' ] }, 'loggers': { 'server': { 'level': 'DEBUG' , 'handlers': ['file' ], 'propagate': True } } }
其中大字典的 key
都是固定,例如 version,formatters, handlers, root, loggers
等都是固定的配置项。而有一些子选项是可以自己自定义如
formatters
下的 simple
和 verbose
,是可以改成自己想要的名字。
handlers
下的 console
和 file
也是可以修改的。
loggers
下的 server
都是一样可以修改的
具体配置的说明,在这字典中都有一一注释我就不全介绍了,我就介绍一下 handlers
日志处理器的配置
在 logging
模块中有许多 日志处理器类 ,我们只需要在 pycharm
中输入 logging.Handler
就能弹出最基本的几个日志处理类。
而上文所用到的 StreamHandler
则是流处理器,日志将随着系统标准输入、输出流展示,而我们的 PyCharm终端、控制台等 显示的信息就属于系统标准输出流。
而 RotatingFileHandler
日志处理器则是 FileHandler
的子类。其主要作用就是把日志写入文件中,当文件内容达到最大限制时可以自动扩充日志文件,以达到日志文件的轮换。
加载日志配置信息 然后使用 logging.config.dictConfig()
方法加载日志配置,该方法接受一个 字典 参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 import loggingimport logging.configlog_dict = { 'version' : 1 , 'disable_existing_loggers' : False , ...与上文一致故省略 'root' : { 'level' : 'DEBUG' , 'handlers' : ['console' ] }, 'loggers' : { 'server' : { 'level' : 'DEBUG' , 'handlers' : ['file' ], 'propagate' : True } } } def setup_logging (): """ 配置日志信息 :return: """ logging.config.dictConfig(config=log_dict) logger = logging.getLogger() logger.debug('debug log test' ) logger.info('info log test' ) logger.warning('warning log test' ) logger.error('error log test' ) def main (): setup_logging() if __name__ == '__main__' : main()
使用 logging.getLogger()
即可获取相应配置日志器,其接受一个日志器的名字,不传则默认使用 root
根日志器,同 logging.getLogger('root')
效果一致。
如果之间运行程序会出现如下错误
1 ValueError: Unable to configure handler 'file'
那是因为你在日志配置中设置了一个文件处理器 file
,其日志文件将存储在 filename
配置项中,在这里是
1 ./logs/test.log # 代表存储在当前路径下的 logs目录下的 test.log 文件
logging
模块不会自动帮我们创建目录,因此只需在当前目录中创建一个 logs
目录即可。
最后程序运行结果如下
1 2 3 4 DEBUG main 74 debug log test INFO main 75 info log test WARNING main 76 warning log test ERROR main 77 error log test
不用跟 root
根日志器,使用 server
日志器,代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 import loggingimport logging.configlog_dict = {...同上文省略...} def setup_logging (): """ 配置日志信息 :return: """ logging.config.dictConfig(config=log_dict) logger = logging.getLogger('server' ) logger.debug('debug log test' ) logger.info('info log test' ) logger.warning('warning log test' ) logger.error('error log test' ) def main (): setup_logging() if __name__ == '__main__' : main()
运行结果如下:
控制台
1 2 3 4 DEBUG main 75 debug log test INFO main 76 info log test WARNING main 77 warning log test ERROR main 78 error log test
日志文件 logs/test.log
由于 server
日志器设置了 'propagate': True
,会 将日志消息传递给父级记录器的处理程序中,因此不仅控制台会显示日志信息,文件也会记录,但文件记录的等级被设置成 INFO
了,因此 DEBUG
调试日志信息,将不会出现在文件中。
使用日志配置文件
这里我将采用 yaml
格式的日志配置文件。具体配置内容和上文大致一样,多了一个 error_file_handler
错误日志处理器,目的就是把 错误日志单独放在一个文件中,方便以后排查错误 。
创建日志配置文件 创建 logging.yaml
文件,内容如下所示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 version: 1 disable_existing_loggers: true formatters: simple: format: '%(levelname)s %(filename)s %(lineno)d %(message)s' verbose: format: '%(levelname)s %(asctime)s -Loc %(filename)s -Row %(lineno)d -%(name)s %(message)s' handlers: console: class: logging.StreamHandler level: DEBUG formatter: simple stream: ext://sys.stdout error_file_handler: class: logging.handlers.RotatingFileHandler level: ERROR formatter: verbose filename: ./logs/errors.log maxBytes: 10485760 backupCount: 20 encoding: utf8 server_file_handler: class: logging.handlers.RotatingFileHandler level: INFO formatter: verbose filename: ./logs/server.log maxBytes: 10485760 backupCount: 30 encoding: utf8 root: level: DEBUG handlers: [console ] loggers: server: level: DEBUG handlers: [server_file_handler , error_file_handler ] propagate: True
加载日志配置函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 import osimport yamlimport loggingimport coloredlogsimport logging.configBASE_DIR = os.path.dirname(os.path.abspath(__file__)) LOG_CONF_FILE = os.path.join(BASE_DIR, 'logging.yaml' ) def setup_logging (default_path=LOG_CONF_FILE, default_level=logging.DEBUG, env_key='LOG_CFG' ): """ 配置项目日志信息 :param default_path: 日志文件默认路径 :param default_level: 日志默认等级 :param env_key: 系统环境变量名 :return: """ path = default_path value = os.getenv(env_key, None ) if value is not None : path = value if os.path.exists(path): with open (path, mode='r' , encoding='utf-8' ) as f: try : logging_yaml = yaml.safe_load(f.read()) logging.config.dictConfig(logging_yaml) coloredlogs.install(level='DEBUG' ) except Exception as e: print (e) print ('无法加载日志配置文件, 请检查日志目录是否创建, 使用默认的日志配置' ) logging.basicConfig(level=default_level) coloredlogs.install(level=default_level) else : logging.basicConfig(level=default_level) coloredlogs.install(level=default_level) print ('日志配置文件不存在, 使用默认的日志配置' )
这里使用到第三方库如下
yaml
是用于读取 yaml
格式的日志配置文件
coloredlogs
用于让日志在控制台中有颜色显示。
然后我们在项目中只要执行完 setup_logging()
日志配置函数
其他模块直接使用 logging.getLogger('server')
就可获取我们配置好的日志器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 import logginglogger = logging.getLogger('server' ) logger.debug('debug log test' ) def log_test1 (): logger.info('info log test' ) def log_test2 (): try : a = 1 / 0 except Exception as e: logger.error(e) class LogDemo (object ): @staticmethod def log_test (): logger.warning('warning log test' )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 def main (): setup_logging() logger = logging.getLogger('server' ) logger.debug('debug log test' ) logger.info('info log test' ) logger.warning('warning log test' ) logger.error('error log test' ) import log_demo log_demo.log_test1() log_demo.log_test2() log_demo.LogDemo.log_test() if __name__ == '__main__' : main()
日志效果展示 运行 log_test.py
结果如下
控制台信息
全部日志配置文件信息
错误日志文件信息