前言
https://docs.djangoproject.com/zh-hans/3.1/topics/logging/
https://docs.python.org/3/library/logging.config.html#configuration-dictionary-schema
https://docs.python.org/3/library/logging.html
django 采用 python 的 logger 模块,配置方式选择字典方式
字典方式基本介绍
有一些必选的键值对 https://docs.python.org/3/library/logging.config.html#dictionary-schema-details
例如version,formatters等,具体看上面官方文档和下面的例子
关键对象介绍
loggers 根据消息界别接收日志,但不负责输出
LogRecord logger接收一条日志,就创建一个logrecord对象
handlers 绑定在logger,用于处理日志logrecord对象,例如输出到哪里. 可以将多个handler绑定到同一个logger
formatters 绑定在handler,用来格式化日志logrecord对象
filters 通过设定过滤条件,过滤从logger到handler的日志logrecord对象。非必须
额外的
LoggerAdapter(logger, extra) 用来包装logger,它接收一个logger和一个字典extra,从而将extra添加到logrecord
之后,通过LoggerAdapter对象接收的日志,再经过formatter对extra.key的编排,就实现了添加信息到原始日志的功能.
日志级别
DEBUG:排查故障时使用的低级别系统信息INFO:一般的系统信息WARNING:描述系统发生了一些小问题的信息ERROR:描述系统发生了大问题的信息CRITICAL:描述系统发生严重问题的信息
流程
给接收的日志定级别:logger.<level>("log message")
logger判断接收的日志级别是否符合logger定义的级别
如果符合,logger无差别的推送消息到多个handler,如果不符合,则忽略;另外,如果logger.propagate为真,则消息会复制一份到更高级别的logger
handler判断接收的日志级别是否符合handler定义的级别
如果符合,handler通过formatter排列logrecord对象属性,并通过handler.class将日志输出,如果不符合,则忽略;另外,如果handler有filter,则只会输出满足filter的日志
例子
写入 settings.py 中
# Logging
LOGGING = {
'version': 1, # 指明版本,目前就只有一个版本
'disable_existing_loggers': False, # 表示是否禁用所有的已经存在的日志配置
# 声明两个格式化id
'formatters': { # 格式器
'verbose': { # 详细
'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
},
'standard': { # 标准
'format': '[%(asctime)s] [%(levelname)s] %(message)s'
},
},
# 定义过滤器 special,它有一个条件函数 project.logging.SpecialFilter(foo), 函数被实例化的时候,foo='bar'
# project.logging.SpecialFilter 需要自己实现, 判断 logrecord 对象,或者满足一些条件才输出日志
'filters': {
'special': {
'()': 'project.logging.SpecialFilter',
'foo': 'bar',
},
},
# handlers:用来定义具体处理日志的方式,可以定义多种,"console"就是打印到控制台方式。file是写入到文件的方式,"mail_admins"是邮件通知
# 这里的 console/file/mail_admins 仅仅是自定义的名称
'handlers': { # 处理器
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'stream': 'ext://sys.stdout', # 文件重定向的配置,将打印到控制台的信息都重定向出去
'formatter': 'standard' # 制定输出的格式,注意 在上面的formatters配置里面选择一个,否则会报错
},
'file_all': {
'level': 'DEBUG',
'class': 'logging.handlers.TimedRotatingFileHandler',
'filename': os.path.dirname(os.path.dirname(os.path.realpath(__file__)))+'/log/all.log',
'formatter': 'standard'
'maxBytes': 1024
'when': 'midnight'
'interval': 1
'backupCount': 3
'utc': False
'encoding': 'utf-8'
},
'file_request': {
'level': 'DEBUG',
'class': 'logging.handlers.TimedRotatingFileHandler',
'filename': os.path.dirname(os.path.dirname(os.path.realpath(__file__)))+'/log/request.log',
'formatter': 'standard'
'maxBytes': 1024
'when': 'midnight'
'interval': 1
'backupCount': 3
'utc': False
'encoding': 'utf-8'
},
'file_db': {
'level': 'DEBUG',
'class': 'logging.handlers.TimedRotatingFileHandler',
'filename': os.path.dirname(os.path.dirname(os.path.realpath(__file__)))+'/log/db.log',
'formatter': 'standard'
'maxBytes': 1024
'when': 'midnight'
'interval': 1
'backupCount': 3
'utc': False
'encoding': 'utf-8'
},
'mail_admins': {
'level': 'ERROR',
'class': 'django.utils.log.AdminEmailHandler',
'filters': ['special']
},
},
'loggers': { # log记录器,配置之后就会对应的输出日志
'django': {
'handlers': ['file_all'],
'level': 'INFO',
'propagate': False,
},
'django.request ':{
'handlers': ['file_request','mail_admins'],
'level': 'INFO',
'propagate': False,
},
'django.server ':{
'handlers': ['console'],
'level': 'INFO',
'propagate': False,
},
'django.db.backends': {
'handlers': ['file_db'],
'level':'INFO',
'propagate': False,
},
# 根记录器
'root': {
'handlers': ['console'],
'level': 'WARNING',
},
},
}
logger
https://docs.python.org/3/library/logging.html#logger-objects
从上面的例子可以看到,logger有一个属性是propagate,这个属性的作用是将收到的消息复制一份到更高级别的logger
关于logger的层级意思是:通过.分割的logger_name
上述列子中,层级高低排序是:
root>django>django.request=django.server
root>django>``django.db.backends`
handler
https://docs.python.org/3/library/logging.handlers.html#module-logging.handlers
在上述例子中,handler的class都是python的内置类型
formatter
格式化logrecord对象,排版logrecord的属性
logrecord
https://docs.python.org/zh-cn/3.9/library/logging.html#logrecord-attributes
LoggerAdapter
https://docs.python.org/zh-cn/3.9/library/logging.html#loggeradapter-objects
调用
import logging, logging.config
logging.config.dictConfig(LOGGING) # django 无需此步骤,django 会自动加载
logger = logging.getLogger(__name__) # 这里的logger名称要匹配上 dictConfig 定义的 logger, 匹配遵循名称层级规则
logger.info("message")