参考:
Advanced logging tutorial:https://docs.python.org/2.7/howto/logging.html#advanced-logging-tutorial
15.7. logging - Logging facility for Python:https://docs.python.org/2.7/library/logging.html?highlight=logging#module-logging
15.8. logging.config - Logging configuration:https://docs.python.org/2.7/library/logging.config.html
15.9. logging.handlers - Logging handlers:https://docs.python.org/2.7/library/logging.handlers.html
####################################################################
对于python的logging模块不了解的可以先查看文章:
python logging - 初级:http://blog.csdn.net/u012005313/article/details/51581442
logging模块有4个最关键的组件:Logging,Handler,Filter和Formatter
官方给出解释如下:
- 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.
使用logging模块时,首先需要得到一个Logger类的实例,称为记录器(logger)。每个记录器都有一个名字,并且logging模块是通过名字来管理这些记录器的,两个记录器之间可以通过命名空间的层次结构来确定关系(Each instance has a name, and they are conceptually arranged in a namespace hierarchy using dots (periods) as separators)。比如,名字为‘one‘的记录器就是名字为‘one.two‘,‘one.three‘,‘one.four‘的记录器的父辈,也就是说,使用点号(‘.’)来确定父子的关系。记录器的名字命名没有任何要求,你可以选择你喜欢的,但最好名字能够表明该记录器在程序中的作用。
可以使用getLogger函数来获取记录器,常用的是命名为模块名或文件名:
logger = logging.getLogger(__name__)
所有记录器(logger)的父辈是root记录器,它的名字就是“root”。
默认情况下,信息会被输出到控制台,默认的输出格式是logging.BASIC_FORMAT:
severity:logger name:message
这些可以通过函数basicConfig进行修改:
basicConfig(**kwargs)
函数功能:为整个日志系统进行基础配置(Do basic configuration for the logging system)
如果root记录器已经有处理器(handler)配置(关于处理器将在下文讲解),那么函数basicConfig将不会起作用。
可以使用以下的关键字参数:
如果在多线程中使用baskcConfig函数,那么该函数必须在主线程中使用。
####################################################
其流程图如下:
###################################################################33
下面讲解Logger,Handler以及Formatter的使用
Logger
记录器有三部分的功能:
1.它提供了一些方法(debug(),info(),warning(),error(),critical()等),供开发者使用
2.记录器依据自身等级或过滤器(filter)来判断是否生成信息(message)
3.记录器将信息发送到所有绑定到自身的处理器(handler)
记录器上最常用的方法可以分为两个部分:配置和信息发送
以下是最常用的配置方法:
1.Logger.setLevel():指定记录器能够处理信息的最低等级(he lowest-severity)。logging模块中,debug是最低的等级,critical是最高的等级。比如,设置记录器等级为INFO,那么该记录器能够处理INFO,WARNING,ERROR,CRITICAL的信息,而会忽略DEBUG等级的信息。
2.Logger.addHandler()和Logger.removeHandler():绑定处理器(handler)到指定的记录器上,以及解除绑定
3.Logger.addFilter()和Logger.removeFilter():绑定过滤器(filter)到指定的过滤器上,以及解除绑定
当记录器配置解除后,以下方法可以处理日志信息:
Logger.debug(),Logger.info(),Logger.warning(),Logger.error()和Logger.critical()函数:用于处理信息,同时设定了该信息的等级(level or severity),以便于记录器判断是否处理该信息
getLogger函数返回一个记录器实例的引用,多次使用该函数去引用相同名字的记录器实例将返回同一个记录器。
每个记录器都必须设定一个等级(level or severity)。但如果没有显式设定,那么会根据它的父辈的等级来进行设定;如果父辈也没有显式设定,那么继续查找父辈的父辈,依次类推-查找所有的父辈直到找到一个显式设置的等级。root记录器是所有记录器的父辈,它的等级默认为WARNING。
logging模块使用层次命名空间来管理所有记录器,从而设置了一个很好的方法。子记录器将会把信息传送给绑定在父记录器上的处理器(handler),因此,不需要为所有记录器配置处理器,只需要在父记录器上绑定处理器,那么子记录器的消息就能够通过该处理器进行处理(可以通过设置记录器的propagate属性为False来关闭向上传播,默认为True)。
################################################
Handler
处理器负责将信息发送到指定的地点。记录器可以绑定0个或者多个处理器(通过addHandler方法)。比如,我们需要将程序中的所有日志信息都保存在文件中,将等级在error及以上的信息发送到控制台,将所有的critical等级的信息都发送到email,那么,我们仅需定义3个不同的处理器,在处理器上指定这3个目的地即可。
通常我们并不直接使用Handler实例,而是引用它的子类。Handler作为一个基类定义了一些基本的函数,子类扩展另外的功能。常用的Handler子类有StreamHandler和FileHandler,另外,我们还会提到RotatingFileHandler(详细的Handler子类)。
我们对Handler的使用的方法不多。常用在配置阶段:
1.setLevel:指定处理器能够处理的最低等级
2.setFormatter:绑定一个Formatter到处理器
3.addFilter和removeFilter
下面介绍常用的Handler子类:
class logging.StreamHandler(stream=None)
输出日志信息到控制台
class logging.FileHandler(filename, mode='a', encoding=None, delay=False)
输出日志信息到文件。常用的文件打开方式为添加信息。
class logging.handlers.RotatingFileHandler(filename, mode='a', maxBytes=0, backupCount=0, encoding=None, delay=0)
输出日志信息到文件。需要设置文件所占的最大字节数(maxBytes)以及文件备份数(backupCount)。当前输入文件总是filename文件,比如,filename是‘he.log‘,那么当该文件所占字节达到最大时,将he.log文件保存为he.log.1文件,如果已存在he.log.1文件,那么将其保存为he.log.2文件,依次类推,直到达到文件备份数为止,比如,backupCount=5,那么如果已存在he.log.5文件,则将其删除。
如果所有记录器(logger)均没有绑定处理器(handler),那么root记录器会默认生成一个输出到控制台的handler。
#################################3
Formatter
Formatter对象配置最终的日志的结构,顺序以及内容。它有两个可选参数:
logging.Formatter.__init__(fmt=None, datefmt=None)
默认的fmt格式是使用原始信息。默认的时间格式为:
%Y-%m-%d %H:%M:%S
#################################3
在设置等级(level or severity)时可以使用数字。logging模块内置了一些常数,如下表所示:
#################################
下面介绍logging的一些用法:
1.在多个线程中使用logging模块
logging模块是线程安全的,所以可以在多个线程中共同使用同一个logging实例。但是logging模块并不是进程安全的,在多个进程中使用可能会出现问题。
2.在多个模块中使用logging
module_a.py:
#!/usr/bin/env python #-*- coding: utf-8 -*- import logging import module_b # 创建logger实例 logger = logging.getLogger('module_a') logger.setLevel(logging.DEBUG) # 创建流处理器 sh = logging.StreamHandler() sh.setLevel(logging.DEBUG) # 创建Formatter formatter = logging.Formatter('%(asctime)s-%(name)s-%(levelname)s-%(message)s') # Formatter绑定在Handler上 sh.setFormatter(formatter) # Handler绑定在logger上 logger.addHandler(sh) logger.debug("this is debug") logger.info("this is info") module_b.hello() logger.warn("this is warn") logger.error("this is error") modu = module_b.Clas() modu.hi() logger.critical("this is critical")
module_b.py:
#!/usr/bin/env python #-*- coding: utf-8 -*- import logging # create logger logg = logging.getLogger('module_a.module_b') logg.setLevel(logging.DEBUG) class Clas: def __init__(self): logg.info("class: Clas") def hi(self): logg.debug("Clas -> hi") def hello(): logg.error("hello world")
结果:
如上图所示,子记录器(‘module_a.module_b‘)可以不用自己设置处理器,而调用父记录器绑定的处理器即可
修改如下可以使得结果更加直观易懂:
# 创建Formatter formatter = logging.Formatter('%(asctime)s-%(name)20s-%(levelname)8s-%(message)s')
或者:
# 创建Formatter formatter = logging.Formatter('%(asctime)s-%(name)-20s-%(levelname)-8s-%(message)s')
3.使用多个处理器和formatter
multiple_handlers_and_formatters.py:
绑定两个处理器,一个处理器将所有信息输出到控制台窗口,其信息格式为:
'%(asctime)s %(name)-6s: %(levelname)-8s: %(message)s'
另一个处理器将error等级及以上的信息输出到文件logging2.log,其信息格式为:
'%(levelname)-8s-%(message)s'
#!/usr/bin/env python #-*- coding: utf-8 -*- import logging # create logger logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) # set StreamHandler sh = logging.StreamHandler() sh.setLevel(logging.DEBUG) # set Formatter formatter1 = logging.Formatter('%(asctime)s %(name)-6s: %(levelname)-8s: %(message)s') sh.setFormatter(formatter1) # set FileHandler fh = logging.FileHandler("multi.log") fh.setLevel(logging.ERROR) # set Formatter formatter2 = logging.Formatter('%(levelname)-8s-%(message)s') fh.setFormatter(formatter2) # add handlers to logger logger.addHandler(sh) logger.addHandler(fh) # logging logger.debug('debug message') logger.info('info message') logger.warn('warnning message') logger.error('error message') logger.critical('critical message')
结果:
控制台窗口:
multi.log:
ERROR -error message CRITICAL-critical message
还有一种更简便的方法,就是使用basicConfig函数:
#!/usr/bin/env python #-*- coding: utf-8 -*- import logging logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(name)-6s: %(levelname)-8s: %(message)s') # create logger logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) # set FileHandler fh = logging.FileHandler("multi.log") fh.setLevel(logging.ERROR) # set Formatter formatter = logging.Formatter('%(levelname)-8s-%(message)s') fh.setFormatter(formatter) # add handlers to logger logger.addHandler(fh) # logging logger.debug('debug message') logger.info('info message') logger.warn('warnning message') logger.error('error message') logger.critical('critical message')
能够达到同样的效果
4.使用FileRotationHandler处理器
代码如下:
#!/usr/bin/env python #-*- coding: utf-8 -*- import glob import logging import logging.handlers LOG_FILENAME = 'rotation/logging_rotatingfile_example.out' # set up a specific logger with our desired output level my_logger = logging.getLogger('MyLogger') my_logger.setLevel(logging.DEBUG) # add the log message handler to the logger handler = logging.handlers.RotatingFileHandler(LOG_FILENAME, maxBytes=20, backupCount=5) my_logger.addHandler(handler) # log some messages for i in range(20): my_logger.debug('i = %d'%i) # see what files are created logfiles = glob.glob('%s*'%LOG_FILENAME) for filename in logfiles: print filename
在这里设置单个文件的最大容量为20字节,设置5个备份文件(所以共有6个文件)
rotation文件夹内: