Django中的logging
source link: https://note.qidong.name/2018/11/django-logging/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Django中的logging
2018-11-17 09:30:39 +08 字数:2656 标签: Django Python
对网站、微服务来说,log(日志)是比较重要的运维工具。
Django的log,主要是复用Python标准库中的logging模块,在settings.py
中进行配置。
此外,也提供了一些独特的扩展。
完整示例 ¶
以下为settings.py
的片段:
TIME_ZONE = 'Asia/Shanghai'
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format': '{asctime} {module}.{funcName} {lineno:3} {levelname:7} => {message}',
'style': '{',
},
},
'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',
},
},
'loggers': {
'': {
'handlers': ['console', 'file'],
'level': os.getenv('DJANGO_LOG_LEVEL', 'INFO'),
},
'django': {
'handlers': ['console', 'file'],
'level': os.getenv('DJANGO_LOG_LEVEL', 'INFO'),
'propagate': False,
},
},
}
设置时间与时区 ¶
在log中,通过在format
设置{asctime}
,可以看到时间。
时间很可能是log最重要的一个属性。
而对中国用户来说,默认时区是个必须关注的问题,否则时间和当地时间差距较大。
需要在settings.py
中,做TIME_ZONE
配置。
TIME_ZONE = 'Asia/Shanghai'
有这个配置在,可以不用修改系统的配置。
formatters ¶
'formatters': {
'verbose': {
'format': '{asctime} {module}.{funcName} {lineno:3} {levelname:7} => {message}',
'style': '{',
},
},
format ¶
Formatter就是log格式化的样式。
这里只定义了一种formatter,那就是verbose
。
{asctime}
:默认的日期与时间,形式大概是2018-11-15 20:41:56,868
。这个形式可以修改,通过datefmt
。{module}
是模块名。{funcName}
是函数名。{lineno:3}
是行号,至少显示3个字符,少则补空格。{levelname:7}
是log级别,INFO
、ERROR
这些。{message}
是log内容。
其它可选字段,详见logrecord。
style ¶
这里style
选择{
,是指{asctime}
这种形式。
如果选择%
,则是%(asctime)s
这种形式。
还有一种选择,是$
,是$asctime
或${asctime}
这种形式。
详见Use of alternative formatting styles。
datefmt ¶
Django自带模块默认的格式化形式,打印出来,日期时间的形式大致是这样:16/Nov/2018 09:03:22
。
相当于设置了下面的datefmt
。
'formatters': {
'default': {
...
'style': '{',
'datefmt': '%d/%b/%Y %H:%M:%S',
},
},
其中,各个组成部分的含义与其它可选内容见下表:
Directive Meaning Notes %a Locale’s abbreviated weekday name. %A Locale’s full weekday name. %b Locale’s abbreviated month name. %B Locale’s full month name. %c Locale’s appropriate date and time representation. %d Day of the month as a decimal number [01,31]. %H Hour (24-hour clock) as a decimal number [00,23]. %I Hour (12-hour clock) as a decimal number [01,12]. %j Day of the year as a decimal number [001,366]. %m Month as a decimal number [01,12]. %M Minute as a decimal number [00,59]. %p Locale’s equivalent of either AM or PM. (1) %S Second as a decimal number [00,61]. (2) %U Week number of the year (Sunday as the first day of the week) as a decimal number [00,53]. All days in a new year preceding the first Sunday are considered to be in week 0. (3) %w Weekday as a decimal number [0(Sunday),6]. %W Week number of the year (Monday as the first day of the week) as a decimal number [00,53]. All days in a new year preceding the first Monday are considered to be in week 0. (3) %x Locale’s appropriate date representation. %X Locale’s appropriate time representation. %y Year without century as a decimal number [00,99]. %Y Year with century as a decimal number. %z Time zone offset indicating a positive or negative time difference from UTC/GMT of the form +HHMM or -HHMM, where H represents decimal hour digits and M represents decimal minute digits [-23:59, +23:59]. %Z Time zone name (no characters if no time zone exists). %% A literal ‘%’ character.
logging默认格式中,asctime
的逗号,
后面是三位毫秒(milliseconds),在以上格式中并不存在。
因此,如果修改为自定义格式,毫秒信息丢失。
如果要额外添加,需要指定{msecs:03d}
。
所以,如果需要毫秒信息,一般不改默认格式。
handlers ¶
'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',
},
},
formatter ¶
formatter
是指定一个格式化方式,也就是前面formatters
定义的那些。
这里选择了前面定义的verboase
。
level ¶
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.
class ¶
class
是指定处理log的类,在Python里logging.handlers中。
可选class
列出如下,详见Useful Handlers。
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服务器的通畅。
loggers ¶
'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。
- django
- django.request
- django.server
- django.template
- django.db.backends
- django.security.*
- django.security.DisallowedHost
- django.security.SuspiciousOperation
- django.security.SuspiciousOperation
- django.security.DisallowedHost
- django.db.backends.schema
propagate
是设定是否向父logger传播信息。
对root来说,这一条可有可无。
但在本例中,root被使用了,所以'django'
logger必须设置为'propagate': False,
,否则会打印两次。
其它 ¶
现在dictConfig
只有一个version
,那就是1
。
disable_existing_loggers
默认是True
,禁用已经存在的logger。
被禁用的logger仍然存在,只是不接收任何输入,包括其父logger也得不到信息
——这种行为可能导致一些问题,因此这一条通常固定设为False
。
Django还支持一些Filters,在打log到指定目标时预先过滤一些内容。 这里不使用,也未介绍。
代码示例 ¶
import logging as log
log.debug('Hello %s', 'world')
log.info('I am here!')
配置好一切后,使用起来就是这么简单。
当然,这里是因为使用了root这个logger,才不需要使用loggging.getLogger()
。
如果是写提供给别人使用的库或Django App,需要考虑更有层次的log策略。
参考 ¶
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK