logging模块记录

python版本2.6
 
 

The logging library takes a modular approach and offers the several categories of components: loggers, handlers, filters, and formatters. Loggers expose the interface that application code directly uses. Handlers send the log records to the appropriate destination. Filters provide a finer grained facility for determining which log records to send on to a handler. Formatters specify the layout of the resultant log record.

logging库中最主要的四个组件是logger,handler,filter和formatter,从字面就不难理解这四个组件的作用,logger可以说就是直接对日志对象进行操作;handler可以理解为接入logger的管道,一个logger可以添加一个或者多个handler,当logger进行日志操作时,广播通知每个handler,然后每个handler再根据各自的规则对日志信息进行相应的操作;filter和formatter可以理解为附加在handler上的一些过滤器和格式化工具。
 
 
以下代码为一个简单的demo,直接调用logging的各方法将root logger日志直接打印在控制台。root logger默认的log级别为warning,只有等于或者高于warning级别的日志才会打印
 1 import logging
 2 
 3   
 4 def loggingtest():  
 5     logging.debug('debug')
 6     logging.info('info')
 7     logging.warning('warning')
 8     logging.error('error')
 9     logging.critical ('critical' )
10 pass
11 
12 
13 if __name__ == '__main__':
14     loggingtest()
15 运行结果:
16 WARNING:root:warning
17 ERROR:root:error
18 CRITICAL:root:critical

 

logging.basicConfig([**kwargs])
Does basic configuration for the logging system by creating a StreamHandler with a default Formatter and adding it to the root logger. The functions debug()info()warning()error() and critical() will call basicConfig() automatically if no handlers are defined for the root logger
由此可见,basicConfig()属于root logger所有,专用于对root logger进行初始化配置,当root logger尚未添加handler时,直接调用如debug()等各项日志方法会自动调用该方法进行初始化配置,handler会是一个streamHandler,也就是将信息直接输出至控制台。
各项参数如下:
filename为字符串,标示输出的文本对象名称
filemode表文本模式,a为append,在原文本后续添加;w为write,覆盖写入
format为文本格式,可有一系列选项
datefmt为日期时间格式,可对format中的日期时间格式进设置
level为日志等级
stream为一个对象,比如使用open()获取的一个文件操作对象,但与filename存在矛盾之处,当这两个参数都存在时,stream被忽略
FormatDescription
filename Specifies that a FileHandler be created, using the specified filename, rather than a StreamHandler.
filemode Specifies the mode to open the file, if filename is specified (if filemode is unspecified, it defaults to ‘a’).
format Use the specified format string for the handler.
datefmt Use the specified date/time format.
level Set the root logger level to the specified level.
stream Use the specified stream to initialize the StreamHandler. Note that this argument is incompatible with ‘filename’ - if both are present, ‘stream’ is ignored.
以下demo可说明basicConfig()的作用:
 1 def loggingtest2():
 2     logfile_name = 'loggingtest.log'
 3     logfile_name2 = 'loggingtest2.log'
 4     f = open(logfile_name2, 'w')
 5     s = '%(asctime)s - %(name)s - %(thread)d - %(threadName)s - %(levelname)s - %(message)s'
 6     logging.basicConfig(filename=logfile_name,
 7                         filemode= 'w',
 8                         format= s,
 9                         datefmt= '%a, %d %b %Y %H:%M:%S',
10                         level=logging.DEBUG,
11                         stream=f)
12     logging.info('info message')
13     logging.debug('debug message')
14     logging.warn('warnning message')
15     logging.error('error message')
16 pass
17 
18 运行后loggingtest2.log内为空,loggingtest.log内容如下:
19 Tue, 05 Nov 2013 13:55:29 - root - 13176 - MainThread - INFO - info message
20 Tue, 05 Nov 2013 13:55:29 - root - 13176 - MainThread - DEBUG - debug message
21 Tue, 05 Nov 2013 13:55:29 - root - 13176 - MainThread - WARNING - warnning message
22 Tue, 05 Nov 2013 13:55:29 - root - 13176 - MainThread - ERROR - error message

 

logging.getLogger([name])
Return a logger with the specified name or, if no name is specified, return a logger which is the root logger of the hierarchy. If specified, the name is typically a dot-separated hierarchical name like “a”“a.b” or “a.b.c.d”. Choice of these names is entirely up to the developer who is using logging.
getLogger()的方法作用在于获取一个对应名称的Logger,所有的logger都是root logger的子logger,a.b logger是a logger的子logger,子logger会继承父logger的level和handler,如此即可在多个logger时进行巧妙应用。
以下demo可说明:
 1 def loggingtest3():
 2     logging.error('1')
 3     sub_logger1 = logging.getLogger( 'sub1')
 4     sub_logger1.critical( '2')
 5     sub_logger1.setLevel(logging.DEBUG)
 6     sub_logger2 = logging.getLogger( 'sub1.sub2')
 7     sub_logger2.info('3')
 8 pass
 9 
10 运行结果如下:
11 ERROR:root:1
12 CRITICAL:sub1:2
13 INFO:sub1.sub2:3
14 
15 可见sub1继承了root,sub2继承了sub1

 

class logging.StreamHandler([strm])
Returns a new instance of the StreamHandler class. If strm is specified, the instance will use it for logging output; otherwise, sys.stderr will be used.
class logging.FileHandler(filename[, mode[, encoding[, delay]]])
Returns a new instance of the FileHandler class. The specified file is opened and used as the stream for logging. If mode is not specified, 'a' is used. If encoding is not None, it is used to open the file with that encoding. If delay is true, then file opening is deferred until the first call to emit(). By default, the file grows indefinitely.
在logging中有两个比较重要且常用的handler,分别是streamHandler和fileHandler。前者可用于输出至控制台,后者可用于输出至文件。
 
以下demo可说明一个root logger也可以由getLogger()方法来获取,一个logger可以添加多个handler:
 1 def loggingtest4():
 2     root_logger = logging.getLogger( '')
 3     handler1 = logging.FileHandler( 'a.log','w' )
 4     fmt = logging.Formatter( '%(asctime )s - %(name)s - %(thread)d - %(threadName)s - %(levelname)s - %(message)s' )
 5     handler1.setFormatter(fmt)
 6     handler2 = logging.StreamHandler()
 7     handler2.setFormatter(fmt)
 8     root_logger.addHandler(handler1)
 9     root_logger.addHandler(handler2)
10     root_logger.critical( 'critical message')
11 pass
12 运行结果a.log和控制台的内容一致如下:
13 2013-11-05 15:16:31,361 - root - 5744 - MainThread - CRITICAL - critical message

 

The RotatingFileHandler class, located in the logging.handlers module, supports rotation of disk log files.
class logging.RotatingFileHandler(filename[, mode[, maxBytes[, backupCount[, encoding[, delay]]]]])
Returns a new instance of the RotatingFileHandler class. The specified file is opened and used as the stream for logging. If mode is not specified, 'a' is used. If encoding is not None, it is used to open the file with that encoding. If delay is true, then file opening is deferred until the first call to emit(). By default, the file grows indefinitely.
You can use the maxBytes and backupCount values to allow the file to rollover at a predetermined size. When the size is about to be exceeded, the file is closed and a new file is silently opened for output. Rollover occurs whenever the current log file is nearly maxBytes in length; if maxBytes is zero, rollover never occurs. If backupCount is non-zero, the system will save old log files by appending the extensions “.1”, “.2” etc., to the filename. For example, with a backupCount of 5 and a base file name of app.log, you would get app.logapp.log.1app.log.2, up to app.log.5. The file being written to is always app.log. When this file is filled, it is closed and renamed to app.log.1, and if files app.log.1app.log.2, etc. exist, then they are renamed to app.log.2app.log.3 etc. respectively.
该方法主要根据文件大小来实现对日志文件的回滚,maxBytes的单位是字节,backupCount指的是回滚个数,保留个数比回滚个数多1个。
demo如下:
 1 import glob
 2 import logging
 3 import logging.handlers
 4 def loggingtest5():
 5     log_filename = 'backup.out'
 6    
 7     logger = logging.getLogger( 'test1')
 8     logger.setLevel(logging.DEBUG)
 9    
10     handle = logging.handlers.RotatingFileHandler(log_filename, maxBytes=20 , backupCount=5)
11    
12     logger.addHandler(handle)
13    
14     for i in range(20):
15         logger.debug( 'i = %d' % i)
16        
17     logfiles = glob.glob( '%s*' % log_filename)
18     for filename in logfiles:
19         print filename
20 pass
21 运行结果:
22 backup.out
23 backup.out.1
24 backup.out.2
25 backup.out.3
26 backup.out.4
27 backup.out.5
28 日志回滚大小设置为20字节,个数设置为5个,这样就使得每次大小一达到20字节都需要回滚一次,最新的日志总是在backup.out中。

 

class logging.TimedRotatingFileHandler(filename[, when[, interval[, backupCount[, encoding[, delay[, utc]]]]]])
Returns a new instance of the TimedRotatingFileHandler class. The specified file is opened and used as the stream for logging. On rotating it also sets the filename suffix. Rotating happens based on the product of when and interval.
You can use the when to specify the type of interval. The list of possible values is below. Note that they are not case sensitive
该方法主要根据时间间隔来实现对日志文件的回滚,when代表的是时间单位,interval表示时间单位的间隔个数,backupCount指的是回滚个数,保留个数比回滚个数多1个。
demo如下:
 1 import glob
 2 import logging
 3 import logging.handlers
 4 import time
 5 def loggingtest6():
 6     log_filename = 'time.out'
 7    
 8     logger = logging.getLogger( 'test1')
 9     logger.setLevel(logging.DEBUG)
10    
11     handle = logging.handlers.TimedRotatingFileHandler(log_filename, when='s', interval=3, backupCount= 5)
12    
13     logger.addHandler(handle)
14    
15     for i in range(20):
16         time.sleep( 1)
17         logger.debug( 'i = %d' % i)
18        
19     logfiles = glob.glob( '%s*' % log_filename)
20     for filename in logfiles:
21         print filename
22 pass
23 运行结果:
24 time.out
25 time.out.2013-11-05_16-13-40
26 time.out.2013-11-05_16-13-43
27 time.out.2013-11-05_16-13-46
28 time.out.2013-11-05_16-13-49
29 time.out.2013-11-05_16-13-52
30 日志回滚时间单位设置为秒,时间间隔个数为3个,这样就使得每3秒钟需要回滚一次,最新的日志总是在time.out中。

 

The configuration file format understood by fileConfig() is based on ConfigParser functionality. The file must contain sections called [loggers][handlers] and [formatters] which identify by name the entities of each type which are defined in the file. For each such entity, there is a separate section which identifies how that entity is configured. Thus, for a logger named log01 in the [loggers] section, the relevant configuration details are held in a section [logger_log01]. Similarly, a handler called hand01 in the [handlers] section will have its configuration held in a section called [handler_hand01], while a formatter called form01 in the [formatters] section will have its configuration specified in a section called [formatter_form01]. The root logger configuration must be specified in a section called [logger_root].
[loggers]、[handlers]、[formatters]是必须有的,root logger因为作为根节点,[logger_root]也是必须有的。只要是在[loggers]、[handlers]、[formatters]中出现过的各个,就必须在接下来的各自section中进行相应的配置。
demo如下:
 1 test.ini内容如下
 2 [loggers]
 3 keys = root,test1,test2,test3
 4 
 5 [handlers]
 6 keys = root_hand,hand1,hand2,hand3
 7 
 8 [formatters]
 9 keys = root_format,format1,format2,format3
10 
11 [logger_root]
12 level = NOTSET
13 handlers = root_hand
14 
15 [logger_test1]
16 level = DEBUG
17 handlers = hand1
18 propagate=1
19 qualname=test1
20 
21 [logger_test2]
22 level = DEBUG
23 handlers = hand2
24 propagate=1
25 qualname=test1.test2
26 
27 [logger_test3]
28 level = DEBUG
29 handlers = hand3
30 propagate=0
31 qualname=test1.test3
32 
33 [handler_root_hand]
34 class=StreamHandler
35 level=DEBUG
36 formatter=root_format
37 args=(sys.stdout,)
38 
39 [handler_hand1]
40 class=StreamHandler
41 level=DEBUG
42 formatter=format1
43 args=(sys.stdout,)
44 
45 [handler_hand2]
46 class=StreamHandler
47 level=DEBUG
48 formatter=format2
49 args=(sys.stdout,)
50 
51 [handler_hand3]
52 class=StreamHandler
53 level=DEBUG
54 formatter=format3
55 args=(sys.stdout,)
56 
57 [formatter_root_format]
58 format=root_format - %( asctime)s - %(name)s - %(thread)d - %(threadName)s - %(levelname )s - %(message)s
59 datefmt=class=logging.Formatter
61 
62 [formatter_format1]
63 format=format1 - %(asctime)s - %(name)s - %(thread)d - %(threadName)s - %(levelname )s - %(message)s
64 datefmt=class=logging.Formatter
66 
67 [formatter_format2]
68 format=format2 - %(asctime)s - %(name)s - %(thread)d - %(threadName)s - %(levelname )s - %(message)s
69 datefmt=class=logging.Formatter
71 
72 [formatter_format3]
73 format=format3 - %(asctime)s - %(name)s - %(thread)d - %(threadName)s - %(levelname )s - %(message)s
74 datefmt=class=logging.Formatter
python代码如下:
 1 def loggingtest7():
 2     logging.config.fileConfig( 'test.ini')
 3     logging.info('msg' )
 4     print '###########'
 5     logger1 = logging.getLogger( "test1")
 6     logger1.error('msg1')
 7     print '###########'
 8     logger2 = logging.getLogger( "test1.test2")
 9     logger2.error('msg2')
10     print '###########'
11     logger3 = logging.getLogger( "test1.test3")
12     logger3.error('msg3')
13     print '###########'
14     logger3 = logging.getLogger( "test3")
15     logger3.error('msg3')
16 pass
运行结果如下:
 1 root_format - 2013-11-06 10:20:47,345 - root - 3332 - MainThread - INFO - msg
 2 ###########
 3 format1 - 2013-11-06 10:20:47,345 - test1 - 3332 - MainThread - ERROR - msg1
 4 root_format - 2013-11-06 10:20:47,345 - test1 - 3332 - MainThread - ERROR - msg1
 5 ###########
 6 format2 - 2013-11-06 10:20:47,345 - test1.test2 - 3332 - MainThread - ERROR - msg2
 7 format1 - 2013-11-06 10:20:47,345 - test1.test2 - 3332 - MainThread - ERROR - msg2
 8 root_format - 2013-11-06 10:20:47,345 - test1.test2 - 3332 - MainThread - ERROR - msg2
 9 ###########
10 format3 - 2013-11-06 10:20:47,345 - test1.test3 - 3332 - MainThread - ERROR - msg3
11 ###########
12 root_format - 2013-11-06 10:20:47,345 - test3 - 3332 - MainThread - ERROR - msg3
由结果可看出,propagate=1时logger会将日志操作传送至父logger的handler,父logger再传递至其父logger,逐层传递,直至root logger;当propagate=0时,日志操作的逐层传递失效。同时还要注意的是getLogger()中的name必须使用配置文件中qualname对应的值,否则会被视为创建一个新的logger。
 
以下demo为使用一个简单过滤器:
 1 class lenthfilter(logging.Filter):
 2     def filter(self, record):
 3         #print record.getMessage()
 4         return len(record.getMessage()) > 10
 5     pass
 6 pass
 7 
 8 def loggingtest9():
 9     logger = logging.getLogger( 'test')
10     logger.setLevel(logging.DEBUG)
11    
12     handler = logging.StreamHandler()
13     logger.addHandler(handler)
14    
15     filter1 = lenthfilter()
16     logger.addFilter(filter1)
17    
18     logger.info('01234567890')
19     logger.info('0123456789')
20 pass
21 运行结果如下:
22 01234567890
lengthfilter用于判断日志内容长度是否超过10,若不超过则不处理。
 
posted @ 2013-12-06 11:26  miteng  阅读(343)  评论(0编辑  收藏  举报