Python中的日志记录模块是功能强大的内置模块,因此你可以快速将日志记录添加到应用程序中。
日志级别
有5种不同的日志级别指示事件的严重程度。 默认情况下,系统仅记录 警告(WARNING) 级别及更高级别的事件。
import logginglogging.debug('This is a debug message' ) logging.info('This is an info message' ) logging.warning('This is a warning message' ) logging.error('This is an error message' ) logging.critical('This is a critical message' )
WARNING:root:This is a warning message ERROR:root:This is an error message CRITICAL:root:This is a critical message
配置
使用 basicConfig(**kwargs)
,你可以自定义根记录器。 最常见的参数是 level
, format
和 filename
。查看全部可能的参数:https://docs.python.org/3/library/logging.html#logging.basicConfig 。查看可能的 format :https://docs.python.org/3/library/logging.html#logrecord-attributes 。查看如何设置时间字符串:https://docs.python.org/3/library/time.html#time.strftime 。请注意,此函数仅应调用一次,通常在导入模块后首先调用。 如果根记录器已经配置了处理程序,则该设置无效。 例如,在 basicConfig
之前调用 logging.info(...)
将提前设置处理程序。
import logginglogging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' , datefmt='%m/%d/%Y %H:%M:%S' ) logging.debug('Debug message' )
模块内记录和记录器层次结构
在具有多个模块的应用程序中,最佳实践是使用 __name__
全局变量创建内部记录器。 这将使用你的模块名称创建一个记录器,并确保没有名称冲突。 日志记录模块创建记录器的层次结构,从根记录器开始,然后将新的记录器添加到该层次结构中。 如果随后将模块导入另一个模块,则可以通过记录器名称将日志消息与正确的模块关联。 请注意,更改根记录器的 basicConfig
还将影响层次结构中其他(下部)记录器的日志事件。
import logginglogger = logging.getLogger(__name__) logger.info('HELLO' ) import logginglogging.basicConfig(level=logging.INFO, format='%(name)s - %(levelname)s - %(message)s' ) import helper
传播
默认情况下,除了附加到创建的记录器的任何处理程序外,所有创建的记录器还将日志事件传递给高级记录器的处理程序。 你可以通过设置 propagate = False
来禁用此功能。 有时,当你想知道为什么看不到来自另一个模块的日志消息时,则可能是此属性。
import logginglogger = logging.getLogger(__name__) logger.propagate = False logger.info('HELLO' ) import logginglogging.basicConfig(level=logging.INFO, format='%(name)s - %(levelname)s - %(message)s' ) import helper
日志处理程序
处理程序对象负责将适当的日志消息调度到处理程序的特定目标。 例如,你可以使用不同的处理程序通过HTTP或通过电子邮件将消息发送到标准输出流,文件。 通常,你为每个处理程序配置一个级别( setLevel()
),一个格式化程序( setFormatter()
)和一个可选的过滤器( addFilter()
)。 有关可能的内置处理程序,请参见 https://docs.python.org/3/howto/logging.html#useful-handlers 。 当然,你也可以通过派生这些类来实现自己的处理程序。
import logginglogger = logging.getLogger(__name__) stream_handler = logging.StreamHandler() file_handler = logging.FileHandler('file.log' ) stream_handler.setLevel(logging.WARNING) file_handler.setLevel(logging.ERROR) stream_format = logging.Formatter('%(name)s - %(levelname)s - %(message)s' ) file_format = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s' ) stream_handler.setFormatter(stream_format) file_handler.setFormatter(file_format) logger.addHandler(stream_handler) logger.addHandler(file_handler) logger.warning('This is a warning' ) logger.error('This is an error' )
过滤器例子
class InfoFilter (logging.Filter) : def filter (self, record) : return record.levelno == logging.INFO stream_handler.addFilter(InfoFilter()) logger.addHandler(stream_handler)
其他配置方法
我们已经看到了如何配置日志,从而在代码中显式地创建日志记录器,处理程序和格式化程序。 还有其他两种配置方法:
.conf文件
创建一个 .conf (或有时存储为 .ini )文件,定义记录器,处理程序和格式化程序,并提供名称作为键。 定义其名称后,可以通过在其名称之间用下划线分隔之前添加单词 logger , handler 和 formatter 进行配置。 然后,你可以为每个记录器,处理程序和格式化程序设置属性。 在下面的示例中,将使用 StreamHandler 配置根记录器和名为 simpleExample 的记录器。
[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
import loggingimport logging.configlogging.config.fileConfig('logging.conf' ) logger = logging.getLogger('simpleExample' ) logger.debug('debug message' ) logger.info('info message' )
捕获堆栈跟踪
将跟踪记录记录在异常日志中对于解决问题非常有用。 你可以通过将 excinfo 参数设置为True来捕获 logging.error()
中的回溯。
import loggingtry : a = [1 , 2 , 3 ] value = a[3 ] except IndexError as e: logging.error(e) logging.error(e, exc_info=True )
ERROR:root:list index out of range ERROR:root:list index out of range Traceback (most recent call last): File "<ipython-input-6-df97a133cbe6>" , line 5 , in <module> value = a[3 ] IndexError: list index out of range
如果未捕获正确的 Exception,则还可以使用 traceback.formatexc() 方法记录该异常。
滚动 FileHandler
当你有一个大型应用程序将许多事件记录到一个文件中,而你只需要跟踪最近的事件时,请使用RotatingFileHandler来使文件保持较小。 当日志达到一定数量的字节时,它将被“滚动”。 你还可以保留多个备份日志文件,然后再覆盖它们。
import loggingfrom logging.handlers import RotatingFileHandlerlogger = logging.getLogger(__name__) logger.setLevel(logging.INFO) handler = RotatingFileHandler('app.log' , maxBytes=2000 , backupCount=5 ) logger.addHandler(handler) for _ in range(10000 ): logger.info('Hello, world!' )
TimedRotatingFileHandler
如果你的应用程序将长时间运行,则可以使用 TimedRotatingFileHandler。 这将根据经过的时间创建一个轮换日志。 when 参数的可能时间条件是:
second (s)
minute (m)
hour (h)
day (d)
w0-w6 (工作日, 0=星期一)
midnight
import loggingimport timefrom logging.handlers import TimedRotatingFileHandler logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) handler = TimedRotatingFileHandler('timed_test.log' , when='m' , interval=1 , backupCount=5 ) logger.addHandler(handler) for i in range(6 ): logger.info('Hello, world!' ) time.sleep(50 )
以JSON格式登录
如果你的应用程序从不同的模块(特别是在微服务体系结构中)生成许多日志,那么定位重要的日志以进行分析可能会很困难。 因此,最佳实践是以JSON格式记录你的消息,并将其发送到集中式日志管理系统。 然后,你可以轻松地搜索,可视化和分析日志记录。
我建议使用此开源JSON记录器:https://github.com/madzak/python-json-logger
pip install python-json-logger
import loggingfrom pythonjsonlogger import jsonloggerlogger = logging.getLogger() logHandler = logging.StreamHandler() formatter = jsonlogger.JsonFormatter() logHandler.setFormatter(formatter) logger.addHandler(logHandler)
GitHub repo: qiwihui/blog
Follow me: @qiwihui
Site: QIWIHUI