Python之日志处理(logging模块) 作者: jlb 2020年05月26日 [TOC] ## 一、日志相关概念 日志是一种可以追踪某些软件运行时发生时间的方法。软件开发人员可以向他们的代码中调用日志记录相关的方法表明发生了某些事情。一个事件可以用一个包含可选变量数据的消息来描述。此外,事件也有重要性的概念,这个重要性也可以被称为严重级别(level)。 ### 1、 日志的作用 * 程序调试 * 了解软件运行情况 * 程序运行故障分析及问题定位 如果应用的日志信息足够详细和丰富,还可以用来做用户行为分析,如:分析用户的操作行为、类型洗好、地域分布以及其它更多的信息,由此可以实现改进业务、提高商业利益 ### 2、日志等级 * DEBUG * INFO * NOTICE * WARNING * ERROR * CRITICAL * ALERT * EMERGENCY ### 3、日志字段信息与格式 一条日志信息对应的是一个事件的发生,而一个事件通常需要包括以下几个内容: * 事件发生时间 * 事件发生位置 * 事件的严重程度–日志级别 * 事件内容 上面这些都是一条日志记录中可能包含的字段信息,当然还可以包括一些其他信息,如进程ID、进程名称、线程ID、线程名称等。日志格式就是用来定义一条日志记录中包含那些字段的,且日志格式通常都是可以自定义的。 说明: 输出一条日志时,日志内容和日志级别是需要开发人员明确指定的。对于而其它字段信息,只需要是否显示在日志中就可以了 ## 二、logging模块简介 ### 1、logging模块的日志级别 logging模块默认定义几个日志等级,它允许开发人员定义其他日志级别,但是这是不推荐的,尤其是开发供别人使用的库时,这回导致日志级别的混乱。 | 日志等级(level) | 描述 | | :---: | --- | |DEUBG|最详细的日志信息,典型应用场景:问题诊断 | | INFO |信息详细程度仅次于DEBUG,通常只记录关键节点信息,用于确认一切都按照我们预期的那样进行工作 | | WARNING| 当某些不期望的事情发生时记录的信息,如(磁盘可用空间较低),但是此时应用还能正常运行 | |ERROR| 由于一个严重的问题导致某些功能不能正确运行是记录的信息| |CRITICAL | 当发生严重错误,导致应用程序不能继续运行时记录的信息| ### 2、logging模块的使用方式介绍 logging模块提供了两种记录日志的方式: * 使用logging提供的模块级别的函数 * 使用logging日志系统的四大组件 logging所提供的模块级别的日志记录函数也是对logging日志系统相关类的封装。 logging模块的级别常用函数 | 函数 | 说明 | |:---:|:---:| |logging.debug(msg, \*args, \**kwargs) |记录一条严重级别为DEBUG的日志记录 | |logging.info(msg, \*args, \**kwargs) |记录一条严重级别为INFO的日志记录 | |logging.warning(msg, \*args, \**kwargs) |记录一条严重级别为WARNING的日志记录 | |logging.error(msg, \*args, \**kwargs) |记录一条严重级别为ERROR的日志记录 | |logging.critical(msg, \*args, \**kwargs) |记录一条严重级别为CRITICAL的日志记录 | |logging.log(msg, \*args, \**kwargs) |记录一条严重级别为level的日志记录 | |logging.basicConfig(\**kwargs) |对logger进行配置| 其中logging.basicConfig(**kwargs)函数用于指定“要记录的日志级别”、“日志格式”、“日志输出位置”、“日志文件的打开模式”等信息,其他几个都是用于记录各个级别日志的函数。 logging模块的四大组件 | 组件 | 说明 | | ---| ---| | loggers| 提供应用程序直接使用的接口 | handlers| 用于将日志记录发送到指定的目的位置 | filters| 提供更细粒度的日志过滤功能,用于决定那些日志将会被输出(其他日志就会被忽略) | formatters| 用于控制日志信息的最终输出格式 说明: logging模块提供的模块级别的那些函数实际上也是通过这几个组件的相关实现类来记录日志的,只是在创建这些类的实例时设置了一些默认值。 ## 三、使用logging提供的模块级别的函数记录日志 ### 1、最简单的日志输出 简单的不同日志级别的日志记录: ```python import logging logging.debug("This is a debug log.") logging.info("This is a info log.") logging.warning("This is a warning log.") logging.error("This is a error log.") logging.critical("This is a critical log.") ``` 也可以这么写: ```python logging.log(logging.DEBUG, "This is a debug log.") logging.log(logging.INFO, "This is a info log.") logging.log(logging.WARNING, "This is a warning log.") logging.log(logging.ERROR, "This is a error log.") logging.log(logging.CRITICAL, "This is a critical log.") ``` 输出结果: ``` WARNING:root:This is a warning log. ERROR:root:This is a error log. CRITICAL:root:This is a critical log. ``` 前两条因为默认日志级别是WAARNING所以没有输出 ### 2. logging.basicConfig()函数说明 该方法用于为logging日志系统做一些基本配置,方法定义如下: ``` logging.basicConfig(**kwargs) ``` 该函数可接受的关键字参数如下: | 参数名称| 描述| | :---: | --- | | filename| 指定日志输出目标文件名,指定该设置后日志信息不会输出到控制台 |filemod| 指日志文件的打开模式,默认为`a`。需要注意的是:该选项只有在filename指定是才有效 | format| 指定日志格式字符串,即指定日志输出时所包含的字段信息以及它们的顺序 | detafmt| 指定日期/时间格式,需要注意的是,该选项要在format中包含`%(asctime)s`时才有效 |level| 指定日志输出级别 | stream| 指定日志输出目标stream,如sys.stdout、sys.stderr以及网络stream。stream和filename不能同时使用,否则会引发`ValueError`异常 | style| python3.2中新添加,指点format格式风格课取值`%`、`{`和`$`默认`%` | handlers| python3.3 新添加。它应该是一个创建多个Handler的可迭代对象,这些handler将会被添加到root logger。handler、stream和filename只能存在一个,否则会引发`ValueError`异常 ### 4. logging模块定义的格式字符串字段 我们来列举一下logging模块中定义好的可以用于format格式字符串中字段有哪些: | 字段/属性名称| 使用格式 | 描述 | | :---: | :---: | ---| | name |(name)s | Logger的名字,默认是`root`,因为默认使用`rootLogger` | levelno |%(levelno)s | 数字形式的日志级别(10、20、30、40、50) | levelname |%(levelname)s | 文本形式的日志级别(DEBUG、INFO、WARNING、ERROR、CRITICAL) | pathname | %(pathname)s | 调用日志输出函数的模块的完整路径名,可能没有 | filename | %(filename)s | 调用日志输出函数的模块的文件名 | module | %(module)s | 调用日志输出函数的模块名 | funcName | %(funcName)s | 调用日志输出函数的函数名 | lineno |%(lineno)d | 调用日志输出函数的语句所在的代码行 | created |%(created)f | 当前时间,用UNIX标准的表示时间的浮点数表示 | relativeCreated |%(relativeCreated)d | 输出日志信息时的,自Logger创建以来的毫秒数 | msecs | %(mescs)d | 日志打算事件的毫秒部分 | asctime |%(asctime)s | 字符串形式的当前时间。默认格式是“2003-07-08 16:49:45,896”。逗号后面的是毫秒 | thread |%(thread)d | 线程ID。可能没有 | threadName |%(threadName)s | 线程名。可能没有 | process |%(process)d | 进程ID。可能没有 | processName | %(processName)s |进程名 python3.1新增 | message | %(message)s | 用户输出的消息,通过`msg % args`计算得到 ### 经过简单配置的日志输出 ``` # 创建一个日志器logger并设置其日志级别为DEBUG logger = logging.getLogger('simple_logger') logger.setLevel(logging.DEBUG) # 创建一个流处理器handler并设置其日志级别为DEBUG handler = logging.StreamHandler(sys.stdout) handler.setLevel(logging.DEBUG) # 创建一个格式器formatter并将其添加到处理器handler formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") handler.setFormatter(formatter) # 为日志器logger添加上面创建的处理器handler logger.addHandler(handler) # 日志输出 logger.debug('debug message') logger.info('info message') logger.warn('warn message') logger.error('error message') logger.critical('critical message') ``` 运行输出: ``` 2017-05-15 11:30:50,955 - simple_logger - DEBUG - debug message 2017-05-15 11:30:50,955 - simple_logger - INFO - info message 2017-05-15 11:30:50,955 - simple_logger - WARNING - warn message 2017-05-15 11:30:50,955 - simple_logger - ERROR - error message 2017-05-15 11:30:50,955 - simple_logger - CRITICAL - critical message ```