Python 记录日志
在本教程中,我们将学习标准日志模块的基本知识。
什么是日志记录
日志记录是Python的一个模块,位于标准库中,提供从Python程序中发布日志消息的框架工作。日志记录用于跟踪软件运行时发生的事件。
开发人员在进行日志记录工作时广泛使用此模块。这是一种非常重要的工具,用于软件开发、运行和调试。
日志记录有助于存储日志记录。假设没有日志记录,并且程序在执行过程中被中断,我们将无法找到问题的实际原因。
不过,我们可以通过检测崩溃的原因来解决问题,但这将耗费大量时间。使用日志记录,我们可以留下踪迹,从而在程序出现问题时可以轻松找到问题的原因。
在运行应用程序时,我们可能会遇到许多问题,例如我们假设是整数,但给定的是浮点数,服务正在维护等。这些问题很难确定并且耗时。
日志记录的工作原理
日志记录是一个功能强大的模块,被初学者和企业广泛使用。该模块提供了组织不同控制处理程序并将日志消息传输到这些处理程序的能力。
要发布日志消息,我们需要导入以下日志记录模块。
import logging
现在,我们将调用日志记录器来记录我们想要看到的消息。日志记录模块提供了五个级别来指定事件的严重程度。每个事件都包含可以用来记录严重级别事件的并行方法。让我们理解以下事件及其工作原理。
- DEBUG – 用于提供详细信息,仅在诊断问题时使用。
- INFO – 提供有关事物按我们所希望的工作的信息。
- WARNING – 用于警告突发事件发生,或者我们将在未来面临问题。
- ERROR – 当我们遇到严重问题时通知,软件未执行某些程序。
- CRITICAL – 指定严重错误,程序本身可能无法继续执行。
以上级别足以处理任何类型的问题。这些级别的相应数值如下所示。
Level | Numeric Values |
---|---|
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(kwarg)** 用于配置日志。
它接受一些常用参数,如下所示。
- 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
同样地,我们可以将消息记录到文件中而不是显示在控制台上,可以在 filename 和 filemode 中使用 basicConfig() 函数,并且我们可以使用格式属性来决定消息的格式。让我们看下面的示例。
示例
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.exception() 方法,就像调用 logging.error(exc_info = True) 一样。
让我们来看下面的示例。
示例
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()等方法时,logging模块会使用它。我们还可以通过创建 Logger 类的对象来定义自己的日志记录器。这里,我们定义了常用的类和函数。
以下是logging模块中定义的类和函数。
- Logger – 日志记录器对象用于直接调用函数。
- LogRecord – 它会自动创建包含与所有被记录事件相关信息的日志记录文件,例如日志记录器的名称、函数、行号、消息等。
- Handler – 处理程序用于将LogRecord分派到输出端点。FileHandler、StreamHandler、HTTPHandler、SMTTPHandler是Handler的子类。
- Formatters – 格式化程序用于定义输出的结构。它使用字符串格式化方法来指定日志消息的格式。
如果没有要格式化的消息,默认值是使用原始消息。默认的日期格式为。
%Y-%m-%d %H:%M:%S
以下格式用于将日志消息转换为易读的格式。
'%(asctime)s - %(levelname)s - %(message)s'
我们通常使用Logger类的对象进行工作,这些对象是使用 logging.getLogger(name) 函数创建的。如果多次使用 getLogger() 方法并且name相同,它将返回相同logger对象的引用。
让我们来看一个示例:
示例
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_handler是一个 级别为ERROR的文件处理程序。它忽略级别为WARNING的LogRecord。
结论
日志记录模块灵活易用。它非常有用,可以跟踪日志记录并向用户显示适当的消息。它提供了创建自定义日志级别、处理程序类和许多其他有用方法的灵活性。
它还为小型项目提供基本的日志记录。
在本教程中,我们讨论了日志记录模块的所有基本概念,并涵盖了使用不同级别生成消息的方法。