logging(日志)
日志记录是程序员工具箱中非常有用的工具。它可以帮助您更好地理解程序的流程,并发现您在开发过程中可能没有想到的场景。
日志为开发人员提供了额外的一组眼睛,这些眼睛不断关注应用程序正在经历的流程。它们可以存储信息,例如访问应用程序的用户或IP。如果发生错误,那么通过告诉您程序在到达发生错误的代码行之前的状态,它们可以提供比堆栈跟踪更多的见解。
通过从正确的位置记录有用的数据,您不仅可以轻松地调试错误,还可以使用数据分析应用程序的性能以规划扩展或查看使用模式以规划营销。
Python提供了一个日志系统作为其标准库的一部分,因此您可以快速将日志记录添加到您的应用程序中。在本文中,您将了解为什么使用此模块是向应用程序添加日志记录以及如何快速入门的最佳方式,您将了解一些可用的高级功能。
Logging模块
Python中的日志记录模块是一个随时可用且功能强大的模块,旨在满足初学者和企业团队的需求。它被大多数第三方Python库使用,因此您可以将日志消息与这些库中的日志消息集成,以为您的应用程序生成同类日志。
将记录添加到Python程序就像这样简单:
import logging
导入日志记录模块后,您可以使用称为“logger”的内容来记录您要查看的消息。默认情况下,有5个标准级别指示事件的严重性。每个都有一个相应的方法,可用于记录该严重级别的事件。按严重程度增加的顺序定义的级别如下:
- DEBUG
- 信息 info
- 警告 warning
- 错误 error
- 危急 critical
日志记录模块为您提供了一个默认记录器,使您无需进行太多配置即可开始使用。可以调用每个级别的相应方法,如以下示例所示:
import logging
logging.debug('这里是调试信息')
logging.info('这里是详情信息')
logging.warning('这里是警告信息')
logging.error('这里是错误信息')
logging.critical('这里是危机信息')
上述程序的输出如下所示:
WARNING:root:这里是警告信息
ERROR:root:这里是错误信息
CRITICAL:root:这里是危机信息
输出显示每条消息之前的严重性级别root
,即日志记录模块为其默认记录器提供的名称。(记录器将在后面的章节中详细讨论。)此格式显示由冒号(:
)分隔的级别,名称和消息,是默认的输出格式,可以配置为包括时间戳,行号和其他内容细节。
请注意,并没有记录debug()
和info()
消息。这是因为,默认情况下,日志记录模块会记录严重性级别为WARNING
或更高的邮件。您可以通过将日志记录模块配置为根据需要记录所有级别的事件来更改它。您还可以通过更改配置来定义自己的严重性级别,但通常不建议这样做,因为它可能会导致您可能正在使用的某些第三方库的日志混淆。
基本配置
您可以使用该方法配置日志记录:basicConfig(**kwargs)
一些常用的参数basicConfig()
如下:
-
level
:根记录器将设置为指定的严重性级别。 -
filename
:这指定文件。 -
filemode
:如果filename
给定,则以此模式打开文件。默认值为a
,表示追加。 -
format
:这是日志消息的格式。
通过使用该level
参数,您可以设置要记录的日志消息级别。这可以通过传递类中可用的一个常量来完成,这将允许记录该级别或更高级别的所有日志记录调用。这是一个例子:
import logging
logging.basicConfig(level=logging.DEBUG)
logging.debug('This will get logged')
DEBUG:root:This will get logged
DEBUG
现在将记录DEBUG
级别或更高级别的事件。
同样,对于记录到文件而不是控制台,filename
并且filemode
可以使用,您可以使用确定消息的格式format
。以下示例显示了所有三个的用法:
import logging
logging.basicConfig(filename='app.log', filemode='w', format='%(name)s - %(levelname)s - %(message)s')
logging.warning('This will get logged to a file')
root - ERROR - This will get logged to a file
该消息将如下所示,但将写入名为app.log
而不是控制台的文件。filemode设置为w
,这意味着每次basicConfig()
调用日志文件都以“写入模式”打开,程序的每次运行都将重写该文件。filemode的默认配置a
是append。
您可以使用更多参数进一步自定义根记录器basicConfig()
,可在此处找到。
应该注意,basicConfig()
只有在之前没有配置根记录器的情况下,调用配置根记录器才有效。基本上,这个函数只能调用一次。
debug()
,info()
,warning()
,error()
,和critical()
也称basicConfig()
自动无参数,如果它以前没有叫。这意味着在第一次调用上述函数之一后,您无法再配置根记录器,因为它们会在basicConfig()
内部调用该函数。
默认设置basicConfig()
是将记录器设置为以下列格式写入控制台:
ERROR:root:This is an error message
格式化输出
虽然您可以将任何可以表示为字符串的变量作为消息传递给您的日志,但是有一些基本元素已经成为其中的一部分,LogRecord
并且可以轻松添加到输出格式中。如果要将进程ID与级别和消息一起记录,可以执行以下操作:
import logging
logging.basicConfig(format='%(process)d-%(levelname)s-%(message)s')
logging.warning('This is a Warning')
18472-WARNING-This is a Warning
format
可以使用LogRecord
您喜欢的任何排列中的属性字符串。可以在此处找到可用属性的完整列表。
这是另一个可以添加日期和时间信息的示例:
import logging
logging.basicConfig(format='%(asctime)s - %(message)s', level=logging.INFO)
logging.info('Admin logged in')
2018-07-11 20:12:06,288 - Admin logged in
%(asctime)s
增加了创造时间LogRecord
。可以使用datefmt
属性更改格式,该属性使用与datetime模块中的格式化函数相同的格式化语言,例如time.strftime()
:
import logging
logging.basicConfig(format='%(asctime)s - %(message)s', datefmt='%d-%b-%y %H:%M:%S')
logging.warning('Admin logged out')
12-Jul-18 20:53:19 - Admin logged out
记录变量数据
在大多数情况下,您可能希望在日志中包含应用程序中的动态信息。您已经看到日志记录方法将字符串作为参数,并且在单独的行中使用可变数据格式化字符串并将其传递给log方法似乎很自然。但实际上,这可以通过使用消息的格式字符串并将变量数据作为参数附加来直接完成。这是一个例子:
import logging
name = 'John'
logging.error('%s raised an error', name)
类和函数
到目前为止,我们已经看到了一个名为默认记录器root
,用于通过日志模块,只要其功能被直接称为是这样的:logging.debug()
。您可以(并且应该)通过创建Logger
类的对象来定义自己的记录器,尤其是在应用程序具有多个模块的情况下。我们来看看模块中的一些类和函数。
日志记录模块中定义的最常用类如下:
- **Logger:**这是一个类,其对象将直接在应用程序代码中用于调用函数。
- **LogRecord:**记录器自动创建
LogRecord
具有与记录事件相关的所有信息的对象,例如记录器的名称,功能,行号,消息等。 - **Handler:**处理程序将
LogRecord
控制器或文件发送到所需的输出目标。Handler
对于像的子类的碱StreamHandler
,FileHandler
,SMTPHandler
,HTTPHandler
,等等。这些子类将日志记录输出发送到相应的目标,如sys.stdout
磁盘文件。 - **Formatter:**您可以通过指定列出输出应包含的属性的字符串格式来指定输出的格式。
其中,我们主要处理Logger
类的对象,这些对象使用模块级函数进行实例化logging.getLogger(name)
。getLogger()
使用相同的多次调用name
将返回对同一Logger
对象的引用,这使我们无法将记录器对象传递到需要它的每个部分。这是一个例子:
import logging
logger = logging.getLogger('example_logger')
logger.warning('This is a warning')
This is a warning
同样,与根记录器不同,无法使用自定义记录器进行配置basicConfig()
。您必须使用处理程序和格式化程序对其进行配置:
使用Handler
当您想要配置自己的记录器并在生成日志时将日志发送到多个位置时,处理程序就会出现。处理程序将日志消息发送到已配置的目标(如标准输出流或文件或HTTP)或通过SMTP发送到您的电子邮件。
您创建的记录器可以有多个处理程序,这意味着您可以将其设置为保存到日志文件并通过电子邮件发送。
与记录器一样,您也可以在处理程序中设置严重性级别。如果要为同一记录器设置多个处理程序但希望每个处理程序具有不同的严重性级别,这将非常有用。例如,您可能希望将具有级别WARNING
及更高级别的日志记录到控制台,但是具有级别ERROR
及更高级别的所有内容也应保存到文件中。这是一个执行该操作的程序:
# logging_example.py
import logging
# Create a custom logger
logger = logging.getLogger(__name__)
# Create handlers
c_handler = logging.StreamHandler()
f_handler = logging.FileHandler('file.log')
c_handler.setLevel(logging.WARNING)
f_handler.setLevel(logging.ERROR)
# Create formatters and add it to handlers
c_format = logging.Formatter('%(name)s - %(levelname)s - %(message)s')
f_format = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
c_handler.setFormatter(c_format)
f_handler.setFormatter(f_format)
# Add handlers to the logger
logger.addHandler(c_handler)
logger.addHandler(f_handler)
logger.warning('This is a warning')
logger.error('This is an error')
__main__ - WARNING - This is a warning
__main__ - ERROR - This is an error
在这里,logger.warning()
创建一个LogRecord
包含事件的所有信息并将其传递给它拥有的所有处理程序:c_handler
和f_handler
。
c_handler
是一个StreamHandler
带有级别WARNING
并从中获取信息LogRecord
以生成指定格式的输出并将其打印到控制台。f_handler
是一个FileHandler
有级别的 ERROR
,它忽略LogRecord
了它的级别WARNING
。
当logger.error()
调用时,c_handler
行为与以前完全相同,并f_handler
获得a LogRecord
级别ERROR
,因此它继续生成输出c_handler
,但不是将其打印到控制台,而是以这种格式将其写入指定的文件:
2018-08-03 16:12:21,723 - __main__ - ERROR - This is an error
将与__name__
变量对应的记录器的名称记录为__main__
,这是Python分配给执行开始的模块的名称。如果此文件由某个其他模块导入,则该__name__
变量将对应于其名称*logging_example*。这是它的样子:
# run.py
import logging_example
logging_example - WARNING - This is a warning
logging_example - ERROR - This is an error
保持冷静并阅读日志
记录模块被认为非常灵活。它的设计非常实用,应该适合您的开箱即用。您可以将基本日志记录添加到一个小项目中,或者如果您正在处理一个大项目,则可以创建自己的自定义日志级别,处理程序类等。
如果您还没有在应用程序中使用日志记录,那么现在是开始的好时机。完成后,日志记录肯定会消除开发过程中的大量摩擦,并帮助您找到将应用程序提升到新的水平的机会。
Python 日志模块详解及应用
日志概述
百度百科的日志概述:
Windows网络操作系统都设计有各种各样的日志文件,如应用程序日志,安全日志、系统日志、Scheduler服务日志、FTP日志、WWW日志、DNS服务器日志等等,这些根据你的系统开启的服务的不同而有所不同。我们在系统上进行一些操作时,这些日志文件通常会记录下我们操作的一些相关内容,这些内容对系统安全工作人员相当有用。比如说有人对系统进行了IPC探测,系统就会在安全日志里迅速地记下探测者探测时所用的IP、时间、用户名等,用FTP探测后,就会在FTP日志中记下IP、时间、探测所用的用户名等。
我映像中的日志:
查看日志是开发人员日常获取信息、排查异常、发现问题的最好途径,日志记录中通常会标记有异常产生的原因、发生时间、具体错误行数等信息,这极大的节省了我们的排查时间,无形中提高了编码效率。
日志分类
我们可以按照输出终端进行分类,也可以按照日志级别进行分类。输出终端指的是将日志在控制台输出显示和将日志存入文件;日志级别指的是 Debug、Info、WARNING、ERROR以及CRITICAL等严重等级进行划分。
Python 的 logging
logging提供了一组便利的日志函数,它们分别是:debug()、 info()、 warning()、 error() 和 critical()。logging函数根据它们用来跟踪的事件的级别或严重程度来命名。标准级别及其适用性描述如下(以严重程度递增排序):
每个级别对应的数字值为 CRITICAL:50,ERROR:40,WARNING:30,INFO:20,DEBUG:10,NOTSET:0。 Python 中日志的默认等级是 WARNING,DEBUG 和 INFO 级别的日志将不会得到显示,在 logging 中更改设置。
日志输出
输出到控制台
使用 logging 在控制台打印日志,这里我们用 Pycharm 编辑器来观察:
import logging
logging.debug('调试信息')
logging.warning('警告信息')
logging.info('详情信息')
从上图运行的结果来看,的确只显示了 WARNING 级别的信息,验证了上面的观点。同时也在控制台输出了日志内容,默认情况下 Python 中使用 logging 模块中的函数打印日志,日志只会在控制台输出,而不会保存到日文件。
有什么办法可以改变默认的日志级别呢?
当然是有的,logging 中提供了 basicConfig 让使用者可以适时调节默认日志级别,我们可以将上面的代码改为:
import logging
logging.basicConfig(level=logging.INFO)
logging.debug('调试信息')
logging.info('详情信息')
logging.warning('警告信息')
在 basicConfig 中设定 level 参数的级别即可。
保存到文件
刚才演示了如何在控制台输出日志内容,并且*设定日志的级别,那现在就来看看如何将日志保存到文件。依旧是强大的 basicConfig,我们再将上面的代码改为:
import logging
logging.basicConfig(level=logging.DEBUG, filename='coder.log', filemode='a')
logging.debug('调试信息')
logging.info('详情信息')
logging.warning('警告信息')
在配置中填写 filename (指定文件名) 和 filemode (文件写入方式),控制台的日志输出就不见了,那么 coder.log 会生成么?
在 .py 文件的同级目录生成了名为 coder.log 的日志。
通过简单的代码设置,我们就完成了日志文件在控制台和文件中的输出。