对网站、微服务来说,log(日志)是比较重要的运维工具。 Django的log,主要是复用Python标准库中的logging模块,在settings.py
中进行配置。 此外,也提供了一些独特的扩展。
LOGGING = {
'version': 1,
'disable_existing_loggers': False, # 是否禁用已经存在的日志器
'formatters': {
'verbose': {
'format': '{levelname} {asctime} {module} {process:d} {thread:d} {message}',
'style': '{',
},
'simple': {
'format': '{levelname} {message}',
'style': '{',
}
},
'filters': { # 对日志进行过滤
'require_debug_true': { # django在debug模式下才输出日志
'()': 'django.utils.log.RequireDebugTrue',
},
},
'handlers': { # 日志处理方法
'console': { # 向终端中输出日志
'level': 'INFO',
'filters': ['require_debug_true'],
'class': 'logging.StreamHandler',
'formatter': 'simple'
},
'file': { # 向文件中输出日志
'level': 'INFO',
'class': 'logging.handlers.RotatingFileHandler',
'filename': os.path.join(os.path.dirname(BASE_DIR), "logs/meiduo.log"), # 日志文件的位置
# 'filename': BASE_DIR / "logs/meeting.log", # 日志文件的位置
'maxBytes': 300 * 1024 * 1024,
'backupCount': 10,
'formatter': 'verbose'
},
},
'loggers': { # 日志器
'django': { # 定义了一个名为django的日志器
'handlers': ['console', 'file'], # 可以同时向终端与文件中输出日志
'propagate': True, # 是否继续传递日志信息
'level': 'INFO', # 日志器接收的最低日志级别
},
}
}
一份 Python logging 配置有下面四个部分组成:
日志记录最终是需要以文本来呈现的。Formatter 描述了文本的格式。一个 formatter 通常由包含 LogRecord attributes 的 Python 格式化字符串组成,不过你也可以为特定的格式来配置自定义的 formatter。
'formatters': {
'verbose': {
'format': '{asctime} {module}.{funcName} {lineno:3} {levelname:7} => {message}',
'style': '{',
},
'simple': {
'format': "{levelname} -- {message}",
'style': '{',
}
},
Formatter就是log格式化的样式。 这里定义了两种formatter,那就是verbose
和simple
。
比较常用的:
{asctime}
: 默认的日期与时间,默认形式大概是2021-03-11 17:17:25,223
。这个形式可以通过datefmt
修改。{module}
:模块名。{funcName}
: 函数名。{lineno:3}
: 行号,至少显示3个字符,少则补空格。{levelname:7}
: log级别。{message}
: log内容。其他的:
{created}
: 创建日志记录的时间。{filename}
: 文件名。{msecs}
: 创建日志记录时的毫秒部分。{name}
: formatter的名称。{pathname}
: 源文件的完整路径名。{process}
: process ID。{processName}
: process 名称。{thread}
: 线程ID。{threadName}
: 线程名称。{relativeCreated}
: 与加载记录模块的时间相比,创建日志记录的时间在毫秒内。style
的选择有{
, %
, $
{
: 是指{asctime}
这种形式%
: 是指%(asctime)s
这种形式$
: 是指$asctime或$(asctime)
这种形式Django自带模块默认的格式化形式,打印出来,日期时间的形式大致是这样:16/Nov/2018 09:03:22
。 相当于设置了下面的datefmt
。
'formatters': {
'default': {
...
'style': '{',
'datefmt': '%d/%b/%Y %H:%M:%S',
},
},
Handler 是决定如何处理 logger 中每一条消息的引擎。它描述特定的日志行为,比如把消息输出到屏幕、文件或网络 socket。
和 logger 一样,handler 也有日志级别的概念。如果一条日志记录的级别不匹配或者低于 handler 的日志级别,对应的消息会被 handler 忽略。
一个 logger 可以有多个 handler,每一个 handler 可以有不同的日志级别。这样就可以根据消息的重要性不同,来提供不同格式的输出。例如,你可以添加一个 handler 把 ERROR
和 CRITICAL
消息发到寻呼机,再添加另一个 handler 把所有的消息(包括 ERROR
和 CRITICAL
消息)保存到文件里以便日后分析。
'handlers': {
'console': {
'class': 'logging.StreamHandler',
'formatter': 'verbose',
},
'file': {
'class': 'logging.handlers.RotatingFileHandler',
'formatter': 'verbose',
'filename': '/tmp/django.log',
'maxBytes': 4194304, # 4 MB
'backupCount': 10,
'level': 'DEBUG',
},
},
console
、file
是处理器的名称
class
是指定处理log的类,在Python里logging.handlers中。
可选class
列出如下,详见Useful Handlers。
class | 功能 |
---|---|
StreamHandler | 输出到Stream。通常用来打印到标准输出。 |
FileHandler | 打印到文件。 |
NullHandler | 不格式化也不打印。主要是为了避免No handlers could be found for logger XXX 的设计。 |
WatchedFileHandler | 自动重开log文件,配合别的会自动切分的log文件使用。 |
RotatingFileHandler | 自动按大小切分的log文件。 |
TimedRotatingFileHandler | 按时间自动切分的log文件。 |
SocketHandler | 向Socket打log,基于TCP协议。 |
DatagramHandler | 向Socket打log,基于UDP协议。 |
SysLogHandler | 在Unix-like系统打印到remote或local的Unix syslog。 |
NTEventLogHandler | 在Windows系统打印到微软的event log。 |
SMTPHandler | 通过email发送log。 |
MemoryHandler | 打印到内存buffer。 |
HTTPHandler | 通过HTTP协议向服务器发送log。 |
QueueHandler | 打log到Queue中,适合多进程(multiprocessing)场景。 |
这里主要选择了StreamHandler和RotatingFileHandler。 既能在./manage.py runserver
时打印在前台,又能在部署后打印到文件,方便前期开发和后期运维。
此外,Django额外定义了一个handler——AdminEmailHandler,向管理员发送邮件。
'handlers': {
'mail_admins': {
'level': 'ERROR',
'class': 'django.utils.log.AdminEmailHandler',
'email_backend': 'django.core.mail.backends.filebased.EmailBackend',
'include_html': True,
}
},
有需要可以添加,但要确保邮件SMTP服务器的通畅。
formatter
是指定一个格式化方式,也就是前面formatters
定义的那些。 这里选择了前面定义的verboase
。
level
是选择log的最低等级。 由低到高,列出如下,需要按需选择。
- DEBUG: Low level system information for debugging purposes.
- INFO: General system information.
- WARNING: Information describing a minor problem that has occurred.
- ERROR: Information describing a major problem that has occurred.
- CRITICAL: Information describing a critical problem that has occurred.
logger 是日志系统的入口。每个 logger 都是命名了的 bucket, 消息写入 bucket 以便进一步处理。
每一条写入 logger 的消息都是一条 日志记录。每一条日志记录也包含 日志级别,代表对应消息的严重程度。日志记录还包含有用的元数据,来描述被记录了日志的事件细节,例如堆栈跟踪或者错误码。
当 logger 处理一条消息时,会将自己的日志级别和这条消息的日志级别做对比。如果消息的日志级别匹配或者高于 logger 的日志级别,它就会被进一步处理。否则这条消息就会被忽略掉。
当 logger 确定了一条消息需要处理之后,会把它传给 Handler。
'loggers': {
'': {
'handlers': ['console', 'file'],
'level': os.getenv('DJANGO_LOG_LEVEL', 'INFO'),
},
'django': {
'handlers': ['console', 'file'],
'level': os.getenv('DJANGO_LOG_LEVEL', 'INFO'),
'propagate': False,
},
},
loggers
模块,最重要的是选择设置哪些logger。 这里设置了''
(root)和'django'
。 前者是为了方便地使用logging
,所以设了root的logger,这也是默认的logger。 后者是打印所有Django自身的logger。
propagate
是设定是否向父logger传播信息。 对root来说,这一条可有可无。 但在本例中,root被使用了,所以'django'
logger必须设置为'propagate': False,
,否则会打印两次。
level
有如下几个级别:
DEBUG
:排查故障时使用的低级别系统信息INFO
:一般的系统信息WARNING
:描述系统发生了一些小问题的信息ERROR
:描述系统发生了大问题的信息CRITICAL
:描述系统发生严重问题的信息Django额外提供的loggers扩展如下:
在日志记录从 logger 传到 handler 的过程中,使用 Filter 来做额外的控制。
默认情况下,只要级别匹配,任何日志消息都会被处理。不过,也可以通过添加 filter 来给日志处理的过程增加额外条件。例如,可以添加一个 filter 只允许某个特定来源的 ERROR
消息输出。
Filter 还被用来在日志输出之前对日志记录做修改。例如,可以写一个 filter,当满足一定条件时,把日志记录从 ERROR
降到 WARNING
级别。
Filter 在 logger 和 handler 中都可以添加;多个 filter 可以链接起来使用,来做多重过滤操作。
'filters': { # 对日志进行过滤
'require_debug_true': { # django在debug模式下才输出日志
'()': 'django.utils.log.RequireDebugTrue',
},
},
这个过滤器接受一个回调函数(它应该接受一个单一的参数,即要记录的记录),并对每个通过过滤器的记录进行调用。如果回调函数返回 False,则不会对该记录进行处理。
例如,要从管理员邮件中过滤掉 UnreadablePostError
(当用户取消上传时引发),你可以创建一个过滤函数:
from django.http import UnreadablePostError
def skip_unreadable_post(record):
if record.exc_info:
exc_type, exc_value = record.exc_info[:2]
if isinstance(exc_value, UnreadablePostError):
return False
return True
然后将其添加到你的日志记录配置中:
'filters': {
'skip_unreadable_posts': {
'()': 'django.utils.log.CallbackFilter',
'callback': skip_unreadable_post,
}
},
'handlers': {
'mail_admins': {
'level': 'ERROR',
'filters': ['skip_unreadable_posts'],
'class': 'django.utils.log.AdminEmailHandler'
}
},
只有当 settings.DEBUG 为 False 时,该过滤器才会传递记录。
该过滤器在默认的 logging
配置中使用如下,以确保 AdminEmailHandler
只在 DEBUG
为 False
时向管理员发送错误邮件:
'filters': {
'require_debug_false': {
'()': 'django.utils.log.RequireDebugFalse',
}
},
'handlers': {
'mail_admins': {
'level': 'ERROR',
'filters': ['require_debug_false'],
'class': 'django.utils.log.AdminEmailHandler'
}
},
该过滤器类似于 RequireDebugFalse
,但只有当 DEBUG
为 True
时才会传递记录。
基于Nginx+Supervisord+uWSGI+Django1.11.1+Python3.6.5构建