日志基础教程
日志是对软件执行时所发生事件的一种追踪方式。软件开发人员对他们的代码添加日志调用,借此来指示某事件的发生。一个事件通过一些包含变量数据的描述信息来描述(比如:每个事件发生时的数据都是不同的)。开发者还会区分事件的重要性,重要性也被称为 等级 或 严重性
什么时候使用 Logging
对于简单的日志使用来说日志功能提供了一系列便利的函数。它们是 debug()
,info()
,warning()
,error()
和 critical()
。想要决定何时使用日志,请看下表,其中显示了对于每个通用任务集合来说最好的工具。
你想要执行的任务 |
此任务最好的工具 |
---|---|
对于命令行或程序的应用,结果显示在控制台。 |
|
在对程序的普通操作发生时提交事件报告(比如:状态监控和错误调查) |
|
提出一个警告信息基于一个特殊的运行时事件 |
|
对一个特殊的运行时事件报告错误 |
引发异常 |
报告错误而不引发异常(如在长时间运行中的服务端进程的错误处理) |
|
日志功能应以所追踪事件级别或严重性而定。各级别适用性如下(以严重性递增):
级别 |
何时使用 |
---|---|
|
细节信息,仅当诊断问题时适用。 |
|
确认程序按预期运行 |
|
表明有已经或即将发生的意外(例如:磁盘空间不足)。程序仍按预期进行 |
|
由于严重的问题,程序的某些功能已经不能正常执行 |
|
严重的错误,表明程序已不能继续执行 |
默认的级别是``WARNING``,意味着只会追踪该级别及以上的事件,除非更改日志配置。
所追踪事件可以以不同形式处理。最简单的方式是输出到控制台。另一种常用的方式是写入磁盘文件。
一个简单的例子
一个非常简单的例子:
import logging
logging.warning('Watch out!') # will print a message to the console
logging.info('I told you so') # will not print anything
如果你在命令行中输入这些代码并运行,你将会看到:
WARNING:root:Watch out!
输出到命令行。INFO
消息并没有出现,因为默认级别是 WARNING
。打印的信息包含事件的级别以及在日志调用中的对于事件的描述,例如“Watch out!”。暂时不用担心“root”部分:之后会作出解释。输出格式可按需要进行调整,格式化选项同样会在之后作出解释。
记录日志到文件
一种非常常见的情况是将日志事件记录到文件,让我们继续往下看。请确认启动新的Python 解释器,不要在上一个环境中继续操作:
import logging
logging.basicConfig(filename='example.log',level=logging.DEBUG)
logging.debug('This message should go to the log file')
logging.info('So should this')
logging.warning('And this, too')
现在,如果我们打开日志文件,我们应当能看到日志信息:
DEBUG:root:This message should go to the log file
INFO:root:So should this
WARNING:root:And this, too
该示例同样展示了如何设置日志追踪级别的阈值。该示例中,由于我们设置的阈值是 DEBUG
,所有信息全部打印
如果你想从命令行设置日志级别,例如:
--log=INFO
并且在一些 loglevel 变量中你可以获得 --log
命令的参数,你可以使用:
getattr(logging, loglevel.upper())
通过 level 参数获得你将传递给 basicConfig()
的值。你需要对用户输入数据进行错误排查,可如下例:
# assuming loglevel is bound to the string value obtained from the
# command line argument. Convert to upper case to allow the user to
# specify --log=DEBUG or --log=debug
numeric_level = getattr(logging, loglevel.upper(), None)
if not isinstance(numeric_level, int):
raise ValueError('Invalid log level: %s' % loglevel)
logging.basicConfig(level=numeric_level, ...)
对 basicConfig()
的调用应该在 debug()
, info()
等的前面。因为它被设计为一次性的配置,只有第一次调用会进行操作,随后的调用不会产生有效操作。
如果多次运行上述脚本,则连续运行的消息将追加到文件 example.log 。 如果你希望每次运行重新开始,而不是记住先前运行的消息,则可以通过将上例中的调用更改为来指定 filemode 参数:
logging.basicConfig(filename='example.log', filemode='w', level=logging.DEBUG)
输出将与之前相同,但不再追加进日志文件,因此早期运行的消息将丢失。
从多个模块记录日志
如果你的程序包含多个模块,这里有一个如何组织日志记录的示例:
# myapp.py
import logging
import mylib
def main():
logging.basicConfig(filename='myapp.log', level=logging.INFO)
logging.info('Started')
mylib.do_something()
logging.info('Finished')
if __name__ == '__main__':
main()
# mylib.py
import logging
def do_something():
logging.info('Doing something')
如果你运行 myapp.py ,你应该在 myapp.log 中看到:
INFO:root:Started
INFO:root:Doing something
INFO:root:Finished
这是你期待看到的。 你可以使用 mylib.py 中的模式将此概括为多个模块。 请注意,对于这种简单的使用模式,除了查看事件描述之外,你不能通过查看日志文件来了解应用程序中消息的 来源 。 如果要跟踪消息的位置,则需要参考教程级别以外的文档 - 请参阅 进阶日志教程 。
记录变量数据
要记录变量数据,请使用格式字符串作为事件描述消息,并将变量数据作为参数附加。 例如:
import logging
logging.warning('%s before you %s', 'Look', 'leap!')
将显示:
WARNING:root:Look before you leap!
如你所见,将可变数据合并到事件描述消息中使用旧的 %-s形式的字符串格式化。 这是为了向后兼容:logging 包的出现时间早于较新的格式化选项例如 str.format()
和 string.Template
。 这些较新格式化选项 是 受支持的,但探索它们超出了本教程的范围:有关详细信息,请参阅 Using particular formatting styles throughout your application。
更改显示消息的格式
要更改用于显示消息的格式,你需要指定要使用的格式:
import logging
logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.DEBUG)
logging.debug('This message should appear on the console')
logging.info('So should this')
logging.warning('And this, too')
这将输出:
DEBUG:This message should appear on the console
INFO:So should this
WARNING:And this, too
请注意,前面示例中出现的“root”已消失。 对于可以出现在格式字符串中的全部内容,你可以参考以下文档 LogRecord 属性 ,但为了简单使用,你只需要 levelname (严重性), message (事件描述,包括可变数据),也许在事件发生时显示。 这将在下一节中介绍。
在消息中显示日期/时间
要显示事件的日期和时间,你可以在格式字符串中放置 '%(asctime)s'
import logging
logging.basicConfig(format='%(asctime)s %(message)s')
logging.warning('is when this event was logged.')
应该打印这样的东西:
2010-12-12 11:41:42,612 is when this event was logged.
日期/时间显示的默认格式(如上所示)类似于 ISO8601 或 RFC 3339 。 如果你需要更多地控制日期/时间的格式,请为 basicConfig
提供 datefmt 参数,如下例所示:
import logging
logging.basicConfig(format='%(asctime)s %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')
logging.warning('is when this event was logged.')
这会显示如下内容:
12/12/2010 11:46:36 AM is when this event was logged.
datefmt 参数的格式与 time.strftime()
支持的格式相同。