前言
Django对于日志输出的信息是很完善的,request的信息,setting配置,trackback的信息,一应俱全,足够我们调试了。但是在线上环境,如果让用户看到这些信息,是很不安全的(暴露代码)。所以在线上我们要关闭Debug,但是又不能扔掉这些调试信息,这就要用到logging模块。
logging模块其实是Python的模块,在Django中有很多本地化的支持。
Python日志记录配置由四部分组成:
- Logger(记录仪)
- Handler处理程序
- Filters过滤器
- Formaters格式化程序
Logger
记录器是记录系统的入口点。每个记录器都是一个命名存储桶,可以将消息写入进行处理。
记录器配置为具有日志级别。此日志级别描述了记录器将处理的消息的严重性。Python定义了以下日志级别:
-
DEBUG
:用于调试目的的低级系统信息 -
INFO
:一般系统信息 -
WARNING
:描述已发生的小问题的信息。 -
ERROR
:描述已发生的主要问题的信息。 -
CRITICAL
:描述已发生的严重问题的信息。
一旦记录器确定需要处理消息,它就会传递给处理程序。
处理程序
处理程序是确定记录器中每条消息发生情况的引擎。它描述了特定的日志记录行为,例如将消息写入屏幕,文件或网络套接字。
与记录器一样,处理程序也具有日志级别。如果日志记录的日志级别未达到或超过处理程序的级别,则处理程序将忽略该消息。
记录器可以有多个处理程序,每个处理程序可以具有不同的日志级别。以这种方式,可以根据消息的重要性提供不同形式的通知。
过滤器
- 过滤器用于提供对从记录器到处理程序的日志记录传递的额外控制。
- 默认情况下,将处理满足日志级别要求的任何日志消息。但是,通过安装筛选器,您可以在日志记录过程中添加其他条件
- 例如,您可以安装仅允许
ERROR
发出来自特定源的消息的过滤器。
- 过滤器还可用于在发出之前修改日志记录。
- 例如,如果满足一组特定条件,您可以编写一个过滤器,将
ERROR
日志记录降级 为WARNING
记录。
- 过滤器可以安装在记录器或处理器上; 可以在链中使用多个过滤器来执行多个过滤操作。
格式化程序
最终,日志记录需要呈现为文本。格式化程序描述该文本的确切格式。格式化程序通常由包含LogRecord属性的Python格式化字符串组成 ; 但是,您也可以编写自定义格式化程序来实现特定的格式化行为。
使用日志记录
配置记录器,处理程序,过滤器和格式化程序后,需要将日志记录调用放入代码中。使用日志框架非常简单。这是一个例子:
# import the logging library
import logging
# Get an instance of a logger
logger = logging.getLogger(__name__)
def my_view(request, arg1, arg):
...
if bad_mojo:
# Log an error message
logger.error('Something went wrong!')
配置日志记录
常用配置
BASE_LOG_DIR = os.path.join(BASE_DIR, "log")
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'standard': {
'format': '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]'
'[%(levelname)s][%(message)s]'
},
'simple': {
'format': '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'
},
'collect': {
'format': '%(message)s'
}
},
'filters': {
'require_debug_true': {
'()': 'django.utils.log.RequireDebugTrue',
},
},
'handlers': {
'console': {
'level': 'DEBUG',
'filters': ['require_debug_true'], # 只有在Django debug为True时才在屏幕打印日志
'class': 'logging.StreamHandler',
'formatter': 'simple'
},
'SF': {
'level': 'INFO',
'class': 'logging.handlers.RotatingFileHandler', # 保存到文件,根据文件大小自动切
'filename': os.path.join(BASE_LOG_DIR, "xxx_info.log"), # 日志文件
'maxBytes': 1024 * 1024 * 50, # 日志大小 50M
'backupCount': 3, # 备份数为3 xx.log --> xx.log.1 --> xx.log.2 --> xx.log.3
'formatter': 'standard',
'encoding': 'utf-8',
},
'TF': {
'level': 'INFO',
'class': 'logging.handlers.TimedRotatingFileHandler', # 保存到文件,根据时间自动切
'filename': os.path.join(BASE_LOG_DIR, "xxx_info.log"), # 日志文件
'backupCount': 3, # 备份数为3 xx.log --> xx.log.2018-08-23_00-00-00 --> xx.log.2018-08-24_00-00-00 --> ...
'when': 'D', # 每天一切, 可选值有S/秒 M/分 H/小时 D/天 W0-W6/周(0=周一) midnight/如果没指定时间就默认在午夜
'formatter': 'standard',
'encoding': 'utf-8',
},
'error': {
'level': 'ERROR',
'class': 'logging.handlers.RotatingFileHandler', # 保存到文件,自动切
'filename': os.path.join(BASE_LOG_DIR, "xxx_err.log"), # 日志文件
'maxBytes': 1024 * 1024 * 5, # 日志大小 50M
'backupCount': 5,
'formatter': 'standard',
'encoding': 'utf-8',
},
'collect': {
'level': 'INFO',
'class': 'logging.handlers.RotatingFileHandler', # 保存到文件,自动切
'filename': os.path.join(BASE_LOG_DIR, "xxx_collect.log"),
'maxBytes': 1024 * 1024 * 50, # 日志大小 50M
'backupCount': 5,
'formatter': 'collect',
'encoding': "utf-8"
}
},
'loggers': {
'': { # 默认的logger应用如下配置
'handlers': ['SF', 'console', 'error'], # 上线之后可以把'console'移除
'level': 'DEBUG',
'propagate': True,
},
'collect': { # 名为 'collect'的logger还单独处理
'handlers': ['console', 'collect'],
'level': 'INFO',
}
},
}
可以添加发送邮件
#管理员邮箱
ADMINS = (
('laixintao','*******@163.com'),
)
#非空链接,却发生404错误,发送通知MANAGERS
SEND_BROKEN_LINK_EMAILS = True
MANAGERS = ADMINS
#Email设置
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST= 'smtp.163.com'#QQ邮箱SMTP服务器(邮箱需要开通SMTP服务)
EMAIL_PORT= 25 #QQ邮箱SMTP服务端口
EMAIL_HOST_USER = '**********@163.com' #我的邮箱帐号
EMAIL_HOST_PASSWORD = '**************' #授权码
EMAIL_SUBJECT_PREFIX = 'website' #为邮件标题的前缀,默认是'[django]'
EMAIL_USE_TLS = True #开启安全链接
DEFAULT_FROM_EMAIL = SERVER_EMAIL = EMAIL_HOST_USER #设置发件人
#logging日志配置
LOGGING = {
'version': 1,
'disable_existing_loggers': True,
'formatters': {#日志格式
'standard': {
'format': '%(asctime)s [%(threadName)s:%(thread)d] [%(name)s:%(lineno)d] [%(module)s:%(funcName)s] [%(levelname)s]- %(message)s'}
},
'filters': {#过滤器
'require_debug_false': {
'()': 'django.utils.log.RequireDebugFalse',
}
},
'handlers': {#处理器
'null': {
'level': 'DEBUG',
'class': 'logging.NullHandler',
},
'mail_admins': {#发送邮件通知管理员
'level': 'ERROR',
'class': 'django.utils.log.AdminEmailHandler',
'filters': ['require_debug_false'],# 仅当 DEBUG = False 时才发送邮件
'include_html': True,
},
'debug': {#记录到日志文件(需要创建对应的目录,否则会出错)
'level':'DEBUG',
'class':'logging.handlers.RotatingFileHandler',
'filename': os.path.join(BASE_DIR, "log",'debug.log'),#日志输出文件
'maxBytes':1024*1024*5,#文件大小
'backupCount': 5,#备份份数
'formatter':'standard',#使用哪种formatters日志格式
},
'console':{#输出到控制台
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'standard',
},
},
'loggers': {#logging管理器
'django': {
'handlers': ['console'],
'level': 'DEBUG',
'propagate': False
},
'django.request': {
'handlers': ['debug','mail_admins'],
'level': 'ERROR',
'propagate': True,
},
# 对于不在 ALLOWED_HOSTS 中的请求不发送报错邮件
'django.security.DisallowedHost': {
'handlers': ['null'],
'propagate': False,
},
}
}
以上的配置文件中,有三个日志处理器。分别是:
- ‘django.request':django的request发生error会自动记录,然后使用debug将信息记录到文件,还有mail_admins将信息通过邮件发送给管理员。这里邮件的功能非常棒!并不是一个纯文本信息,而是一个html文件,和我们在浏览器看到的错误页面一模一样!要正常使用邮件功能需要像我一样配置一下上面的邮件发件人信息。我是直接去网易申请了一个邮箱。要格外注意三点:
- 一定要去邮件服务商开启SMTP服务;
- 不同的邮件服务商可能有一些特殊的设置,比如网易,会给你一个客户端授权码,这个才是密码,而不是网页的登录密码。
- 注意服务商有没有对发信频率的限制。
- ‘django':使用console处理器,将信息输出。在开发的时候就可以使用这个处理器(什么?print? 太low了!)
- 最后一个处理器见注释
日志模块流程图