Python教程-Python中的日志记录
在本教程中,我们将学习Python标准日志记录模块的基础知识。
什么是日志记录?
日志记录是Python标准库中的一个模块,它提供了从Python程序中发布日志消息的框架工作的功能。日志记录用于跟踪软件运行时发生的事件。
当开发人员进行日志记录工作时,他们广泛使用此模块。这是在软件开发、运行和调试中非常重要的工具。
日志记录有助于存储日志记录。假设没有日志记录,程序在执行过程中被中断,我们将无法找到问题的真正原因。
尽管我们可能会找到崩溃的原因,但解决问题将耗费大量时间。使用日志记录,我们可以留下一串面包屑,以便如果程序中发生问题,我们可以轻松找到问题的原因。
在运行应用程序时,我们可能会面临许多问题,例如我们假设一个整数,但给了我们一个浮点数,服务正在维护中等等。这些问题很难确定,也很耗时。
日志记录的工作原理
日志记录是一种由初学者和企业广泛使用的强大模块。该模块提供了一种方法,可以组织不同的控制处理程序,并将日志消息传递给这些处理程序。
要发布日志消息,我们需要导入日志记录模块,如下所示。
import logging
现在,我们将调用日志记录器以记录我们想要查看的消息。日志记录模块提供了五个级别,指定事件的严重性。每个事件都包含可以用于记录特定严重级别事件的并行方法。让我们了解以下事件及其工作方式。
- DEBUG - 用于提供详细信息,仅在诊断问题时使用。
- INFO - 提供有关事物按照我们的预期工作的信息。
- WARNING - 用于警告发生了意外事件,或者我们将在未来的时间面临问题。
- ERROR - 用于在我们遇到严重问题时通知,软件未执行某些程序。
- CRITICAL - 指定严重错误,程序本身可能无法继续执行。
上述级别足以处理任何类型的问题。这些级别的相应数值如下所示。
级别 | 数值 |
---|---|
NOTSET | 0 |
DEBUG | 10 |
INFO | 20 |
WARNING | 30 |
ERROR | 40 |
CRITICAL | 50 |
日志记录模块提供了许多功能。它包括几个常量、类和方法。常量由全大写字母表示,类由大写字母表示。小写字母表示方法。
让我们看看模块本身提供的几个记录器对象。
- Logger.info(msg): 用于记录具有INFO级别的消息。
- Logger.warning(msg): 用于记录具有WARNING级别的消息。
- Logger.error(msg): 用于记录具有ERROR级别的消息。
- Logger.critical(msg): 用于记录具有CRITICAL级别的消息。
- Logger.log(lvl, msg): 用于记录具有整数级别lvl的消息。
- Logger.exception(msg): 用于记录具有ERROR级别的消息。
- Logger.setLevel(lvl): 用于将此记录器的开始级别设置为lvl。它将忽略所有低于此级别的消息。
- Logger.addFilter(filt): 用于将特定过滤器filt添加到此记录器。
- Logger.removeFilter(filt): 用于从此记录器中删除特定过滤器filt。
- Logger.filter(record): 将记录器的过滤器应用于记录。如果记录可用且要处理,则返回True。否则,它将返回False。
- Logger.addHandler(hdlr): 用于将特定处理程序hdlr添加到此记录器。
- Logger.removeHandler(hdlr): 用于从此记录器中删除特定处理程序hdlr。
- Logger.hasHandlers(): 用于验证记录器是否包含任何已配置的处理程序。
让我们了解以下示例。
示例 -
import logging
logging.debug('The debug message is displaying')
logging.info('The info message is displaying')
logging.warning('The warning message is displaying')
logging.error('The error message is displaying')
logging.critical('The critical message is displaying')
输出:
WARNING:root:The warning message is displaying
ERROR:root:The error message is displaying
CRITICAL:root:The critical message is displaying
说明:
如上所示,每条消息都显示了根记录器,这是分配给其默认记录器的日志模块名称。消息和级别名称由冒号(:)分隔,并以默认输出格式打印消息。
我们可以注意到debug()和info()消息没有显示消息,因为默认情况下,日志模块以WARNING、ERROR和CRITICAL的严重级别记录消息。
基本配置
日志记录的主要任务是将事件记录存储在文件中。日志记录模块提供了basicConfig(kwargs),用于配置日志记录。
它接受一些常用参数,如下所示。
- level - 设置根级别的指定严重级别。
- filename - 指定一个文件。
- filemode - 以特定模式打开文件。默认情况下,打开文件的模式是'a',表示我们可以追加内容。
- format - 格式定义了日志消息的格式。
我们可以使用level参数设置日志消息的级别,根据我们要记录的级别进行设置。我们需要将一个常量传递给类中,以允许所有日志调用。
让我们了解以下示例。
示例 -
import logging
logging.basicConfig(level=logging.DEBUG)
logging.debug('The dubug message is logged')
输出:
DEBUG:root: The debug will be get logged
类似地,我们可以将消息记录到文件而不是显示在控制台上,可以在basicConfig()函数中使用filename和filemode,并使用format属性决定消息的格式。让我们了解以下示例。
示例 -
import logging
logging.basicConfig(filename='msg.log', filemode='w', format='%(name)s - %(levelname)s - %(message)s')
logging.warning('This will get logged to a file')
输出:
root - WARNING - This will get logged to a file
说明:
上述输出将显示在msg.log文件中,而不是控制台上。我们以'w'方式打开文件,这意味着文件以“写入模式”打开。如果多次调用basicConfig(),则每次运行程序都将重新编写日志文件的输出。basicConfig()函数可以通过传递其他参数进行修改。
让我们了解以下示例。
示例 -
import logging
#Create and configure logger using the basicConfig() function
logging.basicConfig(filename="newfile.log",
format='%(asctime)s %(message)s',
filemode='w')
#Creating an object of the logging
logger=logging.getLogger()
#Setting the threshold of logger to DEBUG
logger.setLevel(logging.DEBUG)
#Test messages
logger.debug("This is a harmless debug Message")
logger.info("This is just an information")
logger.warning("It is a Warning. Please make changes")
logger.error("You are trying to divide by zero")
logger.critical("Internet is down")
输出:
2020-09-05 13:17:39,204 This is a harmless debug Message
2020-09-05 13:17:39,205 This is just an information
2020-09-05 13:17:39,205 It is a Warning. Please make changes
2020-09-05 13:17:39,205 You are trying to divide by zero
2020-09-05 13:17:39,205 Internet is down
说明:
上述代码将生成一个文件,并在打开文件时查看输出。
格式化输出
传递给程序作为要记录的消息的字符串可以根据我们的要求进行修改。给定字符串中有一些基本元素,是LogRecord的一部分。让我们了解以下示例。
示例 -
import logging
logging.basicConfig(format='%(process)d-%(levelname)s-%(message)s')
logging.warning('This is a Warning Message')
输出:
18472-WARNING-This is a Warning Message
format参数可以接受任何形式的包含LogRecord属性的字符串,根据我们的要求进行设置。
让我们了解以下示例 -
示例 -
import logging
logging.basicConfig(format='%(asctime)s - %(message)s', level=logging.INFO)
logging.info('Admin logged in')
输出:
2020-09-02 20:12:06,288 - Admin logged in
asctime属性添加了LogRecord的创建时间。我们还可以使用datefmt属性自定义格式,该属性提供与datetime模块相同功能的函数。
示例 -
import logging
logging.basicConfig(format='%(asctime)s - %(message)s', datefmt='%d-%b-%y %H:%M:%S')
logging.warning('Admin logged out')
输出:
02-Sep-20 13:29:05 - Admin logged out
记录变量数据
有时,我们希望在日志中包含应用程序中的动态信息。日志方法接受字符串作为参数,并且将字符串格式化为包含变量数据的字符串,并传递给日志方法是一种良好的做法。
但是,除此之外,我们还可以使用消息的格式字符串,并将变量数据附加为参数,而不是使用上述方法。
让我们了解以下示例 -
import logging
name = 'Peter Decosta'
logging.error('%s raised an error', name)
输出:
ERROR:root: Peter Decosta raised an error
说明:
传递给方法的参数将作为消息中的变量数据。我们可以使用f{string}来格式化给定的字符串。它提供了一种处理字符串的简短且易于使用的方法。
示例 -
import logging
name = 'Antonio Mino'
logging.error(f'{name} raised an error')
输出:
ERROR:root: Antonio Mino raised an error
捕获堆栈跟踪
我们可以使用日志记录模块捕获应用程序中的完整堆栈跟踪。在日志记录函数中有一个exc_info参数;如果将其设置为True,它可以捕获异常信息。
让我们了解以下示例 -
示例 -
import logging
a = 10
b = 0
try:
c = a / b
except Exception as e:
logging.error("Exception occurred", exc_info=True)
输出:
ERROR:root:Exception occurred
Traceback (most recent call last):
File "C:/Users/DEVANSH SHARMA/PycharmProjects/Hello/loggingFile.py", line 224, in <module>
c = a / b
ZeroDivisionError: division by zero
说明:
如果我们不将exc_info设置为true,则输出不会提供关于异常的信息。如果仅显示以下输出,则在数千行代码中调试错误将会很困难。
ERROR:root:Exception occurred
获取有关异常的完整信息还有其他选项。日志记录模块提供了exception()方法,它记录具有ERROR并附加异常信息的消息。要使用它,与调用logging.error(exc_info=True)相同,调用logging.exception()方法。
让我们了解以下示例。
示例 -
import logging
a = 10
b = 0
try:
c = a / b
except Exception as e:
logging.exception("Exception occurred", exc_info=True)
输出:
ERROR:root:Exception occurred
Traceback (most recent call last):
File "C:/Users/DEVANSH SHARMA/PycharmProjects/Hello/loggingFile.py", line 224, in <module>
c = a / b
ZeroDivisionError: division by zero
我们可以在error()、debug()或critical()方法中使用任何一个选项来获取有关异常的信息。
类和函数
到目前为止,我们已经看到了称为root的默认记录器。每当调用其函数,如logging.debug()、logging.error()等,日志记录模块都会使用它。我们还可以通过创建Logger类的对象来定义自己的记录器。在此,我们定义了常用的类和函数。
以下是日志记录模块中定义的类和函数。
- Logger - 记录器对象用于直接调用函数。
- LogRecord - 它自动生成包含有关所有已记录事件的信息的LogRecord文件,如记录器的名称、函数、行号、消息等。
- Handler - 处理程序用于将LogRecord分派到输出端点。FileHandler、StreamHandler、HTTPHandler、SMTTPHandler是Handler的子类。
- Formatters - 格式化程序用于定义输出的结构。它使用字符串格式化方法指定日志消息的格式。
通常,我们使用Logger类的对象来处理,这些对象是使用logging.getLogger(name)函数创建的。如果多次使用相同名称调用getLogger()方法,则它将返回同一记录器对象的引用。
让我们了解以下示例:
示例 -
import logging
logger = logging.getLogger('first_logger')
logger.warning('This is a warning message')
输出:
This is a warning message
说明:
我们创建了自己的记录器名称first_logger,但与根记录器不同,first_logger不是输出格式的一部分。要显示它,将其传递给配置函数。然后输出将如下所示。
WARNING:first_logger:This is a warning message
使用处理程序
处理程序通常用于配置记录器并将日志同时发送到多个位置。它将日志消息发送到标准输出流、HTTP或电子邮件上的文件。
让我们了解以下示例,创建处理程序。
示例:
import logging
# Create a custom logger_obj
logger_obj = logging.getLogger(__name__)
# Create handlers
w_handler = logging.StreamHandler()
e_handler = logging.FileHandler('file.log')
w_handler.setLevel(logging.WARNING)
e_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')
w_handler.setFormatter(c_format)
e_handler.setFormatter(f_format)
# Add handlers to the logger_obj
logger_obj.addHandler(w_handler)
logger_obj.addHandler(e_handler)
logger_obj.warning('This is a warning message')
logger_obj.error('This is an error message')
输出:
__main__ - WARNING - This is a warning message
__main__ - ERROR - This is an error message
说明:
在以下程序中,我们创建了一个名为logger_obj的自定义记录器,并创建一个存储所有记录的LogRecord,并将其传递给它的所有处理程序:w_handlers和e_handlers。
w_handlers是带有级别WARNING的流处理程序。它接受来自LogRecord的日志并将其格式化为字符串。e_handlers是带有级别ERROR的文件处理程序,它以相同的方式执行操作。两个处理程序都具有自己的格式化程序。
在记录器对象上调用warning()和error()方法将消息添加到队列。有一个很小的差异,warning()方法不会将消息传递给e_handlers,因为它的级别小于error()的级别。
通过这种方式,您可以将消息同时记录到不同的地方,并使用不同的格式对其进行格式化。
更多配置选项
日志记录模块有更多的配置选项,可以根据需要进行设置。以下是一些示例:
- handlers属性 - 指定与记录器关联的处理程序列表。
- level属性 - 设置与记录器关联的级别。级别对象决定是否处理消息。
- parent属性 - 指定父记录器。
- filters属性 - 指定与记录器关联的过滤器列表。
- manager属性 - 指定与记录器关联的记录器管理器对象。
- name属性 - 指定记录器的名称。
- disabled属性 - 如果设置为True,则记录器将禁用。
- propagate属性 - 如果设置为False,则消息不会传播到父记录器。
- root属性 - 获取根记录器。
- setLevel(level) - 设置记录器的级别。
- addHandler(handler) - 将处理程序添加到记录器。
- removeHandler(handler) - 从记录器中删除处理程序。
- addFilter(filter) - 添加过滤器以限制哪些记录被处理。
- removeFilter(filter) - 从记录器中删除过滤器。
总结
在Python中,日志记录是一种强大的工具,用于在开发和维护应用程序时跟踪事件和错误。通过使用日志记录,我们可以轻松诊断和解决问题,同时保持应用程序的可维护性。在开发过程中,了解如何配置和使用日志记录模块是一个重要的技能。
希望这个教程对你有所帮助,让你更好地理解如何在Python中使用日志记录。如果你有任何问题或需要进一步的帮助,请随时提出。