目录
对一名开发者来说最糟糕的情况,莫过于要弄清楚一个不熟悉的应用为何不工作。有时候,你甚至不知道系统运行,是否跟原始设计一致。
在线运行的应用就是黑盒子,需要被跟踪监控。最简单也最重要的方式就是记录日志。记录日志允许我们在开发软件的同时,让程序在系统运行时发出信息,这些信息对于我们和系统管理员来说都是有用的。
就像为将来的程序员写代码文档一样,我们应该让新软件产生足够的日志供系统的开发者和管理员使用。日志是关于应用运行状态的系统文件的关键部分。给软件加日志产生句时,要向给未来维护系统的开发者和管理员写文档一样。
一些纯粹主义者认为一个受过训练的开发者使用日志和测试的时候几乎不需要交互调试器。如果我们不能用详细的日志解释开发过程中的应用,那么当代码在线上运行的时候,解释它们会变得更困难。
这篇文章介绍了 Python 的 logging 模块,包括它的设计以及针对更多复杂案例的适用方法。这篇文章不是写给开发者的文档,它更像是一个指导手册,来说明 Python 的 logging 模板是如何搭建的,并且激发感兴趣的人深入研究。
1 为什么使用 logging 模块?
也许会有开发者会问,为什么不是简单的 print 语句呢? Logging 模块有很多优势,包括:
- 多线程支持
- 通过不同级别的日志分类
- 灵活性和可配置性
- 将如何记录日志与记录什么内容分离
最后一点,将我们记录内容从记录方式中真正分离,保证了软件不同部分的合作。举个例子,它允许一个框架或库的开发者增加日志并且让系统管理员或负责运行配置的人员决定稍后应该记录什么。
2 Logging 模块中有什么
Logging 模块完美地将它的每个部分的职责分离(遵循 Apache Log4j API 的方法)。让我们看看一个日志线是如何通过这个模块的代码,并且研究下它的不同部分。
2.1 记录器(Logger)
记录器是开发者经常交互的对象。那些主要的 API 说明了我们想要记录的内容。
举个记录器的例子,我们可以分类请求发出一条信息,而不用担心它们是如何从哪里被发出的。
比如,当我们写下 logger.info(“Stock was sold at %s”, price) 我们在头脑中就有如下模块:
我们需要一条线。假设有些代码在记录器中运行,让这条线出现在控制台或文件中。但是在内部实际发生了什么呢?
2.2 日志记录
日志记录是 logging 模块用来满足所有需求信息的包。它们包含了需要记录日志的地方、变化的字符串、参数、请求的信息队列等信息。
它们都是被记录的对象。每次我们调用记录器时,都会生成这些对象。但这些对象是如何序列化到流中的呢?通过处理器!
2.3 处理器
处理器将日志记录发送给其他输出终端,他们获取日志记录并用相关函数中处理它们。
比如,一个文件处理器将会获取一条日志记录,并且把它添加到文件中。
标准的 logging 模块已经具备了多种内置的处理器,例如:
多种文件处理器(TimeRotated, SizeRotated, Watched),可以写入文件中
- StreamHandler 输出目标流比如 stdout 或 stderr
- SMTPHandler 通过 email 发送日志记录
- SocketHandler 将日志文件发送到流套接字
- SyslogHandler、NTEventHandler、HTTPHandler及MemoryHandler等
目前我们有个类似于真实情况的模型:
大部分的处理器都在处理字符串(SMTPHandler和FileHandler等)。或许你想知道这些结构化的日志记录是如何转变为易于序列化的字节的。
2.4 格式器
格式器负责将丰富的元数据日志记录转换为字符串,如果什么都没有提供,将会有个默认的格式器。
一般的格式器类由 logging 库提供,采用模板和风格作为输入。然后占位符可以在一个 LogRecord 对象中声明所有属性。
比如:’%(asctime)s %(levelname)s %(name)s: %(message)s’ 将会生成日志类似于 2017-07-19 15:31:13,942 INFO parent.child: Hello EuroPython.
请注意:属性信息是通过提供的参数对日志的原始模板进行插值的结果。(比如,对于 logger.info(“Hello %s”, “Laszlo”) 这条信息将会是 “Hello Laszlo”)
所有默认的属性都可以在日志文档中找到。
好了,现在我们了解了格式器,我们的模型又发生了变化: