前言
在python程序中,出于调试监测或者追踪(track)的目的,一般会在关键的部位加print语句来输出监测的变量值,但对于复杂的程序来讲,这样的调试手段就远远不够了,这也是logging库存在的意义,也有必要进行学习一番。
Logging 提供了一套函数组来满足简单记录的需求,比如debug()
,info()
,error()
,和critical()
.
这些个函数其实是有层次的,这也是logging的重要理念之一,也就是可以设置一定的阈值,当低于该阈值时候,不管它,当等于或者高于该阈值时,才进行记录。
Level | When it’s used |
---|---|
DEBUG | Detailed information, typically of interest only when diagnosing problems. |
INFO | Confirmation that things are working as expected. |
WARNING | An indication that something unexpected happened, or indicative of some problem in the near future (e.g. ‘disk space low’). The software is still working as expected. |
ERROR | Due to a more serious problem, the software has not been able to perform some function. |
CRITICAL | A serious error, indicating that the program itself may be unable to continue running. |
注意:上表的层次就是由低到高。
默认的level是WARNING
,追踪事件的方式多种多样,最简单的就是直接输出到console,另一个常见的方式是写入文件中。
初级应用
初级应用就是简单的通过logging.basicConfig进行简单的设置(或者不设置,用默认的),然后直接用logging.debug()
,logging.info()
,logging.warning()
等输出。
小例子
import logging
logging.warning('Watch out!') # will print a message to the console
logging.info('I told you so') # will not print anything
outputs:
WARNING:root:Watch out!
因为默认层是WARINING
,所以logging.info()
不输出。
Logging 到文件
import logging
logging.basicConfig(filename='example.log',level=logging.DEBUG)
logging.debug('This message should go to the log file')
logging.info('So should this')
logging.warning('And this, too')
outputs:
DEBUG:root:This message should go to the log file
INFO:root:So should this
WARNING:root:And this, too
改变输出的格式
import logging
logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.DEBUG)
logging.debug('This message should appear on the console')
logging.info('So should this')
logging.warning('And this, too')
outputs:
DEBUG:This message should appear on the console
INFO:So should this
WARNING:And this, too
这里注意'root'不见了,因为我们重新设置了输出格式,格式中只有levelname和messages。
显示时间
import logging
logging.basicConfig(format='%(asctime)s %(message)s')
logging.warning('is when this event was logged.')
outputs:
2020-09-13 14:45:26,252 is when this event was logged
高级用法
logging实际上采用了模块化的方法,提供了几个组件:loggers
,handlers
,filters
,和formatters
.
官网是这样定义几个组件的作用的:
- Loggers expose the interface that application code directly uses.
- Handlers send the log records (created by loggers) to the appropriate destination.
- Filters provide a finer grained facility for determining which log records to output.
- Formatters specify the layout of log records in the final output.
被追踪的信息就是在Logger,Handler,Filter,Formatter之间传递:
首先Logging是通过调用Logger
类实例的方法进行的,每个实例都有个名称,用'.'来作为命名空间的继承关系。
常用的对于module-level的logger的创建方法是
logger = logging.getLogger(__name__)
然后需要为log message设定destination,比如file,http get/post,email, sockets,queue等。destination是通过handler来确定的。默认是没有任何的destination的,可通过basicConfig()
来进行简单的设置:
装配
有3种装配方法:
- 用logger,handler,filter,formatter对象的装配方法进行装配
import logging
# create logger
logger = logging.getLogger('simple_example')
logger.setLevel(logging.DEBUG)
# create console handler and set level to debug
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
# create formatter
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
# add formatter to ch
ch.setFormatter(formatter)
# add ch to logger
logger.addHandler(ch)
# 'application' code
logger.debug('debug message')
logger.info('info message')
logger.warn('warn message')
logger.error('error message')
logger.critical('critical message')
- 用fileConfig()方法
logging.conf文件
[loggers] #声明logger
keys=root,rotateFileDemo #键值对
[handlers] #声明handler
keys=consoleHandler,rotateHandler #键值对
[formatters] #声明formatter
keys=simpleFormatter#键值对
[logger_root] #对于root的配置,必须是looger_xxx的形式
level=DEBUG
handlers=consoleHandler
[logger_rotateFileDemo]#对于rotateFileDemo的配置
level=DEBUG
handlers=rotateHandler
qualname=rotateDemo #logger名称,应用程序通过 logging.getLogger获取。对于不能获取的名称,记录到root模块。
propagate=0 # 是否继承父类的log 信息,0:否 1:是.其父类这里是root
[handler_consoleHandler] #对于consoleHandler的配置,必须是handler_xxx的形式
class=StreamHandler #类
level=DEBUG
formatter=simpleFormatter
args=(sys.stdout,) #类参数
[handler_rotateHandler]
class=handlers.RotatingFileHandler #这里注意是 handlers.RotatingfileHandler
level=DEBUG
formatter=simpleFormatter
args=('app.log','a',1024,5) #该类的参数
[formatter_simpleFormatter] #simpleFormatter的定义及配置
format=%(asctime)s-%(name)s-%(levelname)s-%(message)s
loggingDemo.py
import logging
import logging.config
import time
logging.config.fileConfig('logging.conf')
logger=logging.getLogger('rotateDemo')
while True:
logger.info('info message')
time.sleep(0.1)
对于RotatingFileHandler,这里args=('app.log','a',1024,5) ,即记录到app.log中,当超过1024 bytes后,分别备份为app.log.01,app.log.02,app.log.03,app.log.04,app.log.05,然后再有的话不再增加。
- 运用dictConfig()进行配置
传入dictConfig()
的dict,必须包含以下的键:
- version,当前唯一合法值是1,主要考虑到向后兼容性。
- formatters
- filters
- handlers
- class(强制必须有)
- level(可选)
- formatter(可选)
- filter(可选)
- loggers
- level(可选)
- propagare(可选)
- filters(可选)
- handlers(可选)
- root,设定root logger。
- incremental,配置是否解释为在已经存在的配置上增加,默认为False,意思就是设定的配置将代替原来的配置。
- disable_existing_loggers:是否使得已经存在loggers失效,默认为True,如果incremental 是True,则忽略该项。
例子:
import logging
import logging.config
LOGGING={
'version':1,
'formatters':{
'simple':{
'format':'[%(asctime)s]%(levelname)s%(message)s',
'datefmt':'%Y-%m-%d %H:%M:%S'
},
'verbose':{
'format':'[%(asctime)s]%(levelname)s[%(name)s.%(funcName)s%(lineno)d%(message)s',
'datefmt':'%Y-%m-%d %H:%M:%S'
}
},
'handlers':{
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
'formatter':'simple'
},
'development_logfile':{
'level':'DEBUG',
'class':'logging.FileHandler',
'filename':'test.log',
'formatter':'verbose',
},
'production_logfile':{
'level':'ERROR',
'class':'logging.handlers.RotatingFileHandler',
'filename':'test_production.log',
'maxBytes':1024,
'backupCount':3,
'formatter':'simple'
},
'dba_logfile':{
'level':'DEBUG',
'class':'logging.handlers.WatchedFileHandler',
'filename':'test_dba.log',
'formatter':'simple'
},
},
'root':{
'level':'DEBUG',
'handlers':['console'],
},
'loggers':{
'coffee':{
'handlers':['development_logfile'],
# 'propagare':0,
# 'qualname':'coffee'
},
'dba':{
'handlers':['dba_logfile']
}
}
}
logging.config.dictConfig(LOGGING)
logger=logging.getLogger('coffee')
logger.info('dictlogger info')