django logging 模块

环境信息

  • python 3.10
  • django 4.0

Python logging 模块说明

Django 使用 Python 内置的 logging 模块处理系统日志,一份 Python logging 配置由下面四个部分组成:

  • Loggers
  • Handlers
  • Filters
  • Formatters

Loggers

logger 是日志系统的入口。每个 logger 都是命名了的 bucket , 消息写入 bucket 以便进一步处理
logger 可以配置 日志级别 。日志级别描述了由该 logger 处理的消息的严重性。 Python 定义了下面几种日志级别:

  • DEBUG :排查故障时使用的低级别系统信息
  • INFO :一般的系统信息
  • WARNING :描述系统发生了一些小问题的信息
  • ERROR :描述系统发生了大问题的信息
  • CRITICAL :描述系统发生严重问题的信息

每一条写入 logger 的消息都是一条 日志记录 。每一条日志记录也包含 日志级别 ,代表对应消息的严重程度。日志记录还包含有用的元数据,来描述被记录了日志的事件细节,例如堆栈跟踪或者错误码。

当 logger 处理一条消息时,会将自己的 日志级别 和这条消息的 日志级别 做对比。如果消息的日志级别匹配或者高于 logger 的日志级别,它就会被进一步处理。否则这条消息就会被忽略掉。

当 logger 确定了一条消息需要处理之后,会把它传给 Handler 。

Handlers

Handler 是决定如何处理 logger 中每一条消息的引擎。它描述特定的日志行为,比如把消息输出到 屏幕(stdout) 、 文件 或 网络 socket 。
和 logger 一样, handler 也有 日志级别 的概念。如果一条日志记录的级别不匹配或者低于 handler 的日志级别,对应的消息会被 handler 忽略。

一个 logger 可以有多个 handler ,每一个 handler 可以有不同的日志级别。这样就可以根据消息的重要性不同,来提供不同格式的输出。例如,你可以添加一个 handler 把 ERROR 和 CRITICAL 消息发送短消息,再添加另一个 handler 把所有的消息(包括 ERROR 和 CRITICAL 消息)保存到文件里以便日后分析。

Filters

在日志记录从 logger 传到 handler 的过程中,使用 Filter 来做额外的控制。
默认情况下,只要级别匹配,任何日志消息都会被处理。不过,也可以通过添加 filter 来给日志处理的过程增加额外条件。例如,可以添加一个 filter 只允许某个特定来源的 ERROR 消息输出。

Filter 还被用来在日志输出之前对日志记录做修改。例如,可以写一个 filter ,当满足一定条件时,把日志记录从 ERROR 降到 WARNING 级别。

Filter 在 logger 和 handler 中都可以添加;多个 filter 可以链接起来使用,来做多重过滤操作。

Formatters

日志记录最终是需要以文本来呈现的。 Formatter 描述了文本的格式。一个 formatter 通常由包含 LogRecord attributes 的 Python 格式化字符串 组成,不过你也可以为特定的格式来配置自定义的 formatter。

Python logging 模块使用方式介绍

logging 模块提供了两种记录日志的方式:

  • 第一种方式是使用 logging 提供的模块级别的方法
  • 第二种方式是使用 Logging 日志系统的四大组件

logging 模块级别方法使用说明

logging 提供的模块级别常用方法有:

方法名 说明 示例
logging.basicConfig(**kwargs) 对 root logger 进行一次性配置
logging.debug(msg, args, *kwargs) 记录级别为 DEBUG 的日志 logging.debug('debug msg')
logging.info(msg, args, *kwargs) 记录级别为 INFO 的日志
logging.warning(msg, args, *kwargs) 记录级别为 WARNING 的日志
logging.error(msg, args, *kwargs) 记录级别为 ERROR 的日志
logging.critical(msg, args, *kwargs) 记录级别为 CRITICAL 的日志
logging.log(level, args, *kwargs) 记录级别为 level 的日志 logging.log(logging.DEBUG, 'debug msg')

logging.basicConfig() 方法说明

该方法用于为 logging 日志系统做一些基本配置, logging.basicConfig() 函数是一个一次性的简单配置工具使,也就是说只有在第一次调用该函数时会起作用,后续再次调用该函数时完全不会产生任何操作的,多次调用的设置并不是累加操作。方法定义如下:

logging.basicConfig(**kwargs)

该方法可接收的关键字参数如下:

参数 说明
filename 写入日志的文件名
filemode 打开日志文件的模式,默认为 a ,该选项在 filename 指定时才生效
format 日志格式字符串, 指定日志输出时所包含的字段信息以及它们的顺序
datefmt 指定日期/时间格式。该选项要在 format 中包含时间字段 %(asctime)s 时才有效
level 指定日志级别
stream 指定日志输出目标 stream,如 sys.stdout 、 sys.stderr 以及 网络stream 。需要说明的是, stream 和 filename 不能同时提供,否则会引发 ValueError 异常
style Python 3.2 中新添加的配置项。指定 format 格式字符串的风格,可取值为 % 、 { 和 $ ,默认为 %
handlers Python 3.3 中新添加的配置项。该选项如果被指定,它应该是一个创建了多个 Handler 的可迭代对象,这些 handler 将会被添加到 root logger 。需要说明的是: filename 、s tream 和 handlers 这三个配置项只能有一个存在,不能同时出现 2 个或 3 个,否则会引发 ValueError 异常。

logging 模块中定义好的可以用于 format 日志格式字符串的字段主要有

字段名称 使用格式 说明
asctime %(asctime)s 日志事件发生的时间(可读时间),如:2003-07-08 16:49:45,896
created %(created)f 日志事件发生的时间(时间戳)
levelname %(levelname)s 日志级别
levelno %(levelno)s 日志记录的数字形式的日志级别(10, 20, 30, 40, 50)
name %(name)s 所使用的日志器名称,默认是 root ,因为默认使用的是 rootLogger
message %(message)s 日志记录的文本内容
pathname %(pathname)s 调用日志记录方法的源码文件的全路径
filename %(filename)s pathname 的文件名部分,包含文件后缀
module %(module)s filename 的名称部分,不包含后缀
lineno %(lineno)d 调用日志记录方法的源代码所在的行号
funcName %(funcName)s 调用日志记录方法的函数名
process %(process)d 进程 ID
processName %(processName)s 进程名称,Python 3.1 新增
thread %(thread)d 线程 ID
threadName %(thread)s 线程名称

logging 模块级别方法中的 kwargs 参数说明

logging.debug() , logging.info() 等方法的定义中,除了 msg 和 args 参数外,还有一个 **kwargs 参数。它们支持 3 个关键字参数: exc_info , stack_info , extra

  • exc_info : 布尔值,如果该参数的值设置为 True ,则会将异常异常信息添加到日志消息中。如果没有异常信息则添加 None 到日志信息中。
  • stack_info : 布尔值,默认值为 False 。如果该参数的值设置为 True ,栈信息将会被添加到日志信息中。
  • extra : 这是一个字典( dict )参数,它可以用来自定义消息格式中所包含的字段,但是它的 key 不能与 logging 模块定义的字段冲突

exc_info 使用示例:

>>> try:
... 1 / 0
... except:
... logging.error('except occor', exc_info=True)
...
ERROR:root:except occor
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
ZeroDivisionError: division by zero

stack_info 使用示例:

>>> try:
... 1 / 0
... except:
... logging.error('except', stack_info=True)
...
ERROR:root:except
Stack (most recent call last):
File "<stdin>", line 4, in <module>

Django 配置 logging

在 Django 配置文件( settings.py ) 中添加以下配置

settings.py
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format': '[%(asctime)s][%(levelname)s][%(pathname)s %(module)s %(lineno)s %(process)d %(thread)d] %(message)s'
}
},
'handlers': {
'file': {
'level': 'INFO',
'class': 'logging.handlers.RotatingFileHandler',
'filename': 'default.log',
'maxBytes': 1024 * 1024 * 5,
'backupCount': 5,
'formatter': 'verbose',
},
'console': {
'class': 'logging.StreamHandler',
'formatter': 'verbose',
},
'django.server': {
'level': 'INFO',
'class': 'logging.StreamHandler',
'formatter': 'verbose',
},
},
'loggers': {
'django': {
'handlers': ['console', 'file'],
'level': 'INFO',
},
'django.server': {
'handlers': ['django.server'],
'level': 'INFO',
'propagate': False,
},
}
}

代码中可以通过以下方式写入日志到对应 logger :

views.py
import logging
logger = logging.getLogger(`django.server`)
logger.info('aaa')

loggers 类型 为 django 将处理所有类型的日志

Django 简单使用示例

以下配置为 Django 中使用 logging 模块的简单示例,配置后在 Django 项目代码中直接使用 logging 方法即可写入日志

settings.py
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format': '[%(asctime)s][%(levelname)s][%(pathname)s %(module)s %(lineno)s %(process)d %(thread)d] %(message)s'
}
},
'handlers': {
'file': {
'level': 'INFO',
'class': 'logging.handlers.RotatingFileHandler',
'filename': 'default.log',
'maxBytes': 1024 * 1024 * 5,
'backupCount': 5,
'formatter': 'verbose',
},
'console': {
'class': 'logging.StreamHandler',
'formatter': 'verbose',
},
},
'root': {
'handlers': ['file', 'console'],
'level': 'DEBUG',
},
}

参考链接

django logging 模块官网说明