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 可以有不同的日志级别。这样就可以根据消息的重要性不同,来提供不同格式的输出。例如,你可以添加一个 handlerERRORCRITICAL 消息发送短消息,再添加另一个 handler 把所有的消息(包括 ERRORCRITICAL 消息)保存到文件里以便日后分析。

Filters

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

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

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

Formatters

日志记录最终是需要以文本来呈现的。Formatter 描述了文本的格式。一个 formatter 通常由包含 LogRecord attributesPython 格式化字符串 组成,不过你也可以为特定的格式来配置自定义的 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.stdoutsys.stderr以及 网络stream。需要说明的是,streamfilename 不能同时提供,否则会引发 ValueError 异常
style Python 3.2 中新添加的配置项。指定 format 格式字符串的风格,可取值为 %{$,默认为 %
handlers Python 3.3 中新添加的配置项。该选项如果被指定,它应该是一个创建了多个 Handler 的可迭代对象,这些 handler 将会被添加到 root logger 。需要说明的是:filename、streamhandlers 这三个配置项只能有一个存在,不能同时出现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() 等方法的定义中,除了 msgargs 参数外,还有一个 **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 模块官网说明