在 python 中,为什么使用日志而不是 print?

对于复杂项目中的简单调试,是否有理由使用 python 日志记录器而不是 print?其他用例呢?是否有一个公认的最佳用例(特别是当您只在寻找 stdout 时) ?

我一直听说这是一种“最佳实践”,但我还不知道为什么。

61694 次浏览

正确的日志记录的最大优点之一是,您可以根据需要对消息进行分类并打开或关闭它们。例如,为项目的某一部分打开调试级别的消息可能是有用的,但是为了不被信息超载接管,并且可以很容易地集中精力在需要记录的任务上,可以为其他部分调低调试级别的消息。

而且,日志是可配置的。您可以轻松地对它们进行过滤,将它们发送到文件中,对它们进行格式化,添加时间戳,以及在全局基础上可能需要的任何其他事情。打印语句不容易管理。

如果使用日志记录,那么负责部署的人员可以配置日志记录器,将其发送到具有自定义信息的自定义位置。如果你只发表文章,他们就只能得到这些。

日志包有很多有用的特性:

  • 很容易看到日志调用是从何时何地发出的(甚至是哪行号)。
  • 您可以同时记录到文件、套接字等任何内容。
  • 您可以根据严重程度区分日志记录。

印刷品上没有这些。

另外,如果您的项目是由其他 python 工具导入的,那么对于您的包来说,将内容打印到 stdout 是不好的做法,因为用户可能不知道打印消息来自哪里。使用日志记录,包的用户可以选择是否要从您的工具传播日志记录消息。

Print 语句类似于 两个世界中最糟糕的,它结合了在线调试器的消极方面和诊断工具。你必须得到 修改程序,但是你不能从中得到 更多有用的代码

一个在线调试器允许你检查一个正在运行的程序的状态; 但是一个真正的调试器的好处是你不需要修改源代码; 不管是在调试会话之前还是之后; 你只需要把程序加载到调试器中,告诉调试器你想要查看的地方,然后就可以了。

检测应用程序可能需要预先做一些工作,以某种方式修改源代码,但是最终的诊断输出可能有大量的细节,并且可以在非常特定的程度上打开或关闭。Python 日志记录模块不仅可以显示记录的消息,还可以显示调用它的文件和函数、回溯(如果有的话)、发出消息的实际时间等等。不仅如此,诊断工具需要删除 永远不会; 当程序完成并投入生产时,它和它被添加的那天一样有效和有用; 但是它可以将它的输出保存在日志文件中,这样就不会惹恼任何人,或者可以关闭日志级别以阻止除最紧急的消息之外的所有消息。

预测对调试器的需求或使用,实际上并不比在测试时使用 ipython 更困难,并且熟悉它用来控制内置 pdb 调试器的命令。

当您发现自己认为 print 语句可能比使用 pdb (通常是这样的)更容易时,您会发现使用日志记录器会使您的程序比使用 print 语句并随后删除它更容易处理状态。

我将我的编辑器配置为将 print 语句突出显示为 语法错误,并将语句记录为注释,因为这关系到我如何看待它们。

日志记录实际上创建了一个可搜索的打印输出纯文本数据库和其他元数据(时间戳、日志级别、行号、进程等)。

这是纯金,我可以运行 egrep 超过日志文件 之后的 python 脚本已经运行。 我可以调整我的 egrep 模式搜索来精确地选择我感兴趣的内容,而忽略其他内容。这种认知负荷的减少和以后通过尝试和错误来选择我的 egrep 模式的自由对我来说是关键的好处。

tail -f mylogfile.log | egrep "key_word1|key_word2"

现在再加上一些 print 不能做的很酷的事情(发送到套接字、设置调试级别、 logrotle、添加元数据等等) ,你完全有理由选择日志而不是普通的 print 语句。

我倾向于使用 print 语句,因为它既懒惰又容易,添加日志记录需要一些常规代码,嘿,我们有 yasnipppet (emacs)和 ultisnips (vim)和其他模板工具,那么为什么要放弃使用普通 print 语句的日志记录呢?

简而言之,使用日志库的好处确实大于 print,原因如下:

  • 控制释放的物质
  • 定义要包含在日志中的信息类型
  • 配置它发出时的外观
  • 最重要的是,为您的日志设置目的地

具体而言,按严重级别分段日志事件是筛选在给定时间内哪些日志消息可能最相关的一种好方法。日志事件的严重性级别还可以指示您在看到特定消息时应该有多担心。例如,将日志类型划分为 调试信息警告至关重要错误。当您试图了解应用程序出了什么问题时,时机可以决定一切。你想知道这些问题的答案,比如:

  • “这是在我的数据库连接断开之前还是之后发生的?”
  • “具体是什么时候提出这个要求的?”

此外,很容易通过行号和文件名或方法名查看日志发生的位置,即使在哪个线程中也是如此。


下面是一个名为 罗古鲁的 Python 函数式日志库。

我想补充所有其他提到的优点,打印功能在标准配置是缓冲。刷新可能只发生在当前块的末尾(打印的地方)。 对于在非交互式 shell (例如 codebuild,gitlab-ci)中启动的任何程序或者其输出被重定向的程序来说都是如此。

如果由于任何原因程序被关闭(kill -9,硬重置计算机,...) ,如果使用 print 进行同样的操作,可能会丢失一些日志行。

但是,日志库将确保在任何调用时立即刷新打印到 stderr 和 stdout 的日志。