Python标准模块logging

在python的logging模块中主要有四个组件:
logger: 日志类,应用程序往往通过调用它提供的api来记录日志。
handler: 对日志信息处理,可以将日志发送(保存)到不同的目标域中。
filter: 对日志信息进行过滤。
formatter:日志的格式化。

下面写了一个简单的脚本试一下各个组件的功能        
import logging
#创建两个日志类
LOG1=logging.getLogger('a.b.c')
LOG2=logging.getLogger('d.e')
#创建handler对象
console = logging.FileHandler('/home/dwapp/joe.wangh/test/logging/test.log','a')
#设置日志输出信息的格式
formatter = logging.Formatter('%(name)s %(asctime)s %(levelname)s %(message)s')
console.setFormatter(formatter)
#设置过滤器 可以设置多个过滤器 只要日志信息不满足其中任何一个 就不会被输出
filter=logging.Filter('a.b')
#console.addFilter(filter)
#给两个日志类绑定handler对象
LOG1.addHandler(console)
LOG2.addHandler(console)
#设置输出日志信息的等级 这里设为logging.INFO 意味着只输出高于logging.INFO等级的日志信息
LOG1.setLevel(logging.INFO)
LOG2.setLevel(logging.DEBUG)
#输出一些日志信息
LOG1.debug('debug')
LOG1.info('info')
LOG1.warning('warning')
LOG1.error('error')
LOG1.critical('critical')

LOG2.debug('debug')
LOG2.info('info')
LOG2.warning('warning')
LOG2.error('error')
LOG2.critical('critical')
   
运行一下看看结果
dwapp@pttest1:/home/dwapp/joe.wangh/test/logging>python t1.py 
dwapp@pttest1:/home/dwapp/joe.wangh/test/logging>cat test.log 
a.b.c 2010-11-24 18:53:20,160 INFO info
a.b.c 2010-11-24 18:53:20,183 WARNING warning
a.b.c 2010-11-24 18:53:20,183 ERROR error
a.b.c 2010-11-24 18:53:20,183 CRITICAL critical
d.e 2010-11-24 18:53:20,183 DEBUG debug
d.e 2010-11-24 18:53:20,183 INFO info
d.e 2010-11-24 18:53:20,184 WARNING warning
d.e 2010-11-24 18:53:20,184 ERROR error
d.e 2010-11-24 18:53:20,184 CRITICAL critical
   
把#console.addFilter(filter)的注释取消掉 再执行一遍    
dwapp@pttest1:/home/dwapp/joe.wangh/test/logging>python t1.py 
dwapp@pttest1:/home/dwapp/joe.wangh/test/logging>
dwapp@pttest1:/home/dwapp/joe.wangh/test/logging>cat test.log 
a.b.c 2010-11-24 18:54:33,264 INFO info
a.b.c 2010-11-24 18:54:33,287 WARNING warning
a.b.c 2010-11-24 18:54:33,287 ERROR error
a.b.c 2010-11-24 18:54:33,287 CRITICAL critical    

我们看到 这次以d.e开头的日志信息都被过滤掉了

例子:

import glob
import logging
import logging.handlers
LOG_FILENAME='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
循环打日志 ,第一个文件达到maxBytes大小后,就写入第二个文件  。。。。


import logging
import os


log = logging.getLogger()
formatter = logging.Formatter('[%(asctime)s] [%(name)s] %(levelname)s: %(message)s')


stream_handler = logging.StreamHandler()
file_handler = logging.FileHandler(os.path.join("c:\\", "analysis.log"))


file_handler.setFormatter(formatter)
stream_handler.setFormatter(formatter)


log.addHandler(file_handler)
log.addHandler(stream_handler)
log.setLevel(logging.DEBUG)


log.warn("a warning %s " % "c:\\")
打印结果:

[2012-04-10 10:49:35,859] [root] WARNING: a warning c:\ 

##############################################################

下面附上formatter的一些信息

%(name)s

Logger的名字

%(levelno)s

数字形式的日志级别

%(levelname)s

文本形式的日志级别

%(pathname)s

调用日志输出函数的模块的完整路径名,可能没有

%(filename)s

调用日志输出函数的模块的文件名

%(module)s

调用日志输出函数的模块名

%(funcName)s

调用日志输出函数的函数名

%(lineno)d

调用日志输出函数的语句所在的代码行

%(created)f

当前时间,用UNIX标准的表示时间的浮 点数表示

%(relativeCreated)d

输出日志信息时的,自Logger创建以 来的毫秒数

%(asctime)s

字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒

%(thread)d

线程ID。可能没有

%(threadName)s

线程名。可能没有

%(process)d

进程ID。可能没有

%(message)s

用户输出的消息

============================

开发Python, 一直以来都是使用自己编写的logging模块. 比较土......

今天发现python的标准模块的这个功能做的挺好, 记录一下, 以后使用模块来进行logging.

对于这个模块的介绍网上也很多, 我也不用自己写了, 比较好的如下,

http://crazier9527.iteye.com/blog/290018    Python的标准logging模块

http://blog.endlesscode.com/2010/06/03/python-logging-module/   Python的logging模块

http://docs.python.org/library/logging.html  官方文档

下面就对于在项目中比较需要用到的部分摘录一些,

简单的例子

[python]  view plain copy
  1. import logging  
  2. import sys  
  3. logger = logging.getLogger("endlesscode")  
  4. formatter = logging.Formatter('%(name)-12s %(asctime)s %(levelname)-8s %(message)s''%a, %d %b %Y %H:%M:%S',)  
  5. file_handler = logging.FileHandler("test.log")  
  6. file_handler.setFormatter(formatter)  
  7. stream_handler = logging.StreamHandler(sys.stderr)  
  8. logger.addHandler(file_handler)  
  9. logger.addHandler(stream_handler)  
  10. #logger.setLevel(logging.ERROR)  
  11. logger.error("fuckgfw")  
  12. logger.removeHandler(stream_handler)  
  13. logger.error("fuckgov")  

上面这段代码基本包含logging模块的基本feature

GetLogger

GetLogger() returns a reference to a logger instance with the specified name if it is provided, or root if not. The names are period-separated hierarchical structures. Multiple calls to getLogger() with the same name will return a reference to the same logger object.
后面会看到这种以'.'分隔的hierarchical structures有什么用.

Formatter

Formatter对象定义了最终log信息的顺序,结构和内容, 后面会详细解释.

Handler

这儿用到了StreamHandler和FileHandler, 用于向不同的输出端打log.

SetLevel

Logging有如下级别: DEBUG,INFO,WARNING,ERROR,CRITICAL

默认级别是WARNING, logging模块只会输出指定level以上的log

这样的好处, 就是在项目开发时debug用的log, 在产品release阶段不用一一注释, 只需要调整logger的级别就可以了, 很方便的.

 

Formatter

Formatter对象定义了最终log信息的顺序,结构和内容.于基本的logging.Handler类不同,应用可以直接实例化formatter类,当然,如果需要你也可以子例化formatter以便定制它的一些行为.构造函数接受两个可选参数:一个信息格式字符串和一个日期格式字符串.如果没有信息格式字符串,直接输出log信息.如果没有日期格式字符串,默认的格式是:%Y-%m-%d %H:%M:%S

上面的代码给出了Formatter的例子, 下面表格给出所有可以使用的format,

Handler

Logging包含很多handler, 可能用到的有下面几种

  1. StreamHandler instances send error messages to streams (file-like objects).
  2. FileHandler instances send error messages to disk files.
  3. RotatingFileHandler instances send error messages to disk files, with support for maximum log file sizes and log file rotation.
  4. TimedRotatingFileHandler instances send error messages to disk files, rotating the log file at certain timed intervals.
  5. SocketHandler instances send error messages to TCP/IP sockets.
  6. DatagramHandler instances send error messages to UDP sockets.
  7. SMTPHandler instances send error messages to a designated email address.

最常用的也就是StreamHandler和FileHandler

 

Configuration

  1. Creating loggers, handlers, and formatters explicitly using Python code that calls the configuration methods listed above.
  2. Creating a logging config file and reading it using the fileConfig() function.
  3. Creating a dictionary of configuration information and passing it to the dictConfig() function.

第一种配置方法前面的code里面已经有了

第二种配置方法, 我觉得在项目里面是比较实用的, 通过编写配置文件, 在code里面只需要用fileConfig配置一下logging, 显得比较简洁.

这个可以参照http://crazier9527.iteye.com/blog/290026 或 官方文档.

 

Multiple handlers and formatters

Loggers是一个简单的Python对象.addHandler()方法没有最多或者最少配额,当你的应用需要在把所有的log信息打到一个txt文件中去,同时又需要把errors级别一上的错误信息打到console时,你就会体会到这个特性的好处.只要简单的配置一下合适的handlers就可以实现这个功能.应用对logging的调用用不着修改.以下是对前一个基于module的配置例子的改进:

[python]  view plain copy
  1. import logging  
  2. logger = logging.getLogger("simple_example")  
  3. logger.setLevel(logging.DEBUG)  
  4. # create file handler which logs even debug messages  
  5. fh = logging.FileHandler("spam.log")  
  6. fh.setLevel(logging.DEBUG)  
  7. # create console handler with a higher log level  
  8. ch = logging.StreamHandler()  
  9. ch.setLevel(logging.ERROR)  
  10. # create formatter and add it to the handlers  
  11. formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")  
  12. ch.setFormatter(formatter)  
  13. fh.setFormatter(formatter)  
  14. # add the handlers to logger  
  15. logger.addHandler(ch)  
  16. logger.addHandler(fh)  
  17. # "application" code  
  18. logger.debug("debug message")  
  19. logger.info("info message")  
  20. logger.warn("warn message")  
  21. logger.error("error message")  
  22. logger.critical("critical message")  

 

多module使用Logging(只要在同一个Python interpreter process)

上面我曾提到过,所有的对logging.getLogger(‘someLogger’)的调用都会返回同一个对象.这个规则不仅仅在同一个module有效,而且对在同一个Python的解释器进程里面的多个module也有效.而且,应用代码可以在一个module里面定义一个父logger,而在另一个module里面继承这个logger,所有对这个子logger的调用都会转到父logger里面去,如下所示:

下面这个是主模块的代码,

[python]  view plain copy
  1. import logging  
  2. import auxiliary_module  
  3. # create logger with "spam_application"  
  4. logger = logging.getLogger("spam_application")  
  5. logger.setLevel(logging.DEBUG)  
  6. # create file handler which logs even debug messages  
  7. fh = logging.FileHandler("spam.log")  
  8. fh.setLevel(logging.DEBUG)  
  9. # create console handler with a higher log level  
  10. ch = logging.StreamHandler()  
  11. ch.setLevel(logging.ERROR)  
  12. # create formatter and add it to the handlers  
  13. formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")  
  14. fh.setFormatter(formatter)  
  15. ch.setFormatter(formatter)  
  16. # add the handlers to the logger  
  17. logger.addHandler(fh)  
  18. logger.addHandler(ch)  
  19. logger.info("creating an instance of auxiliary_module.Auxiliary")  
  20. a = auxiliary_module.Auxiliary()  
  21. logger.info("created an instance of auxiliary_module.Auxiliary")  
  22. logger.info("calling auxiliary_module.Auxiliary.do_something")  
  23. a.do_something()  
  24. logger.info("finished auxiliary_module.Auxiliary.do_something")  
  25. logger.info("calling auxiliary_module.some_function()")  
  26. auxiliary_module.some_function()  
  27. logger.info("done with auxiliary_module.some_function()")  

这个是子模块的代码,

[python]  view plain copy
  1. import logging  
  2. # create logger  
  3. module_logger = logging.getLogger("spam_application.auxiliary")  
  4. class Auxiliary:  
  5.     def __init__(self):  
  6.         self.logger = logging.getLogger("spam_application.auxiliary.Auxiliary")  
  7.         self.logger.info("creating an instance of Auxiliary")  
  8.     def do_something(self):  
  9.         self.logger.info("doing something")  
  10.         a = 1 + 1  
  11.         self.logger.info("done doing something")  
  12. def some_function():  
  13.     module_logger.info("received a call to /"some_function/"")  

可以看到, 我们在主模块里面定义了一个logger 'spam_application', 并对他进行了配置.

那么在这个解释器进程里面的任何地方去通过getLogger('spam_application')得到的对象都是一样的, 不需要从新定义配置, 可以直接使用.

更方便的是, 你定义任意该logger的子logger, 都可以共享父logger的定义和配置

所谓的父子logger只是简单的通过命名来识别, 任意以'spam_application.'开头的logger都是他的子logger, 例如'spam_application.auxiliary'

这个在实际的开发中, 还是很方便的, 对于一个application,

首先通过logging配置文件编写好这个application所对应的log策略, 可以只生成一个根logger, 比如叫'Project'

然后在Main函数里面, 通过fileConfig加载logging的配置

接着在appliction的任意地方, 不同的模块中, 可以使用Project的子logger, 如Project.UI, Project.Core, 来进行log, 并且不需要反复的定义和配置各个logger.

====================

1.简单的将日志打印到屏幕

 

import logging

logging.debug('This is debug message')
logging.info('This is info message')
logging.warning('This is warning message')

 

屏幕上打印:
WARNING:root:This is warning message

默认情况下,logging将日志打印到屏幕,日志级别为WARNING;
日志级别大小关系为:CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET,当然也可以自己定义日志级别。

2.通过logging.basicConfig函数对日志的输出格式及方式做相关配置

import logging

logging.basicConfig(level=logging.DEBUG,
                format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                datefmt='%a, %d %b %Y %H:%M:%S',
                filename='myapp.log',
                filemode='w')
    
logging.debug('This is debug message')
logging.info('This is info message')
logging.warning('This is warning message')

 

./myapp.log文件中内容为:
Sun, 24 May 2009 21:48:54 demo2.py[line:11] DEBUG This is debug message
Sun, 24 May 2009 21:48:54 demo2.py[line:12] INFO This is info message
Sun, 24 May 2009 21:48:54 demo2.py[line:13] WARNING This is warning message

logging.basicConfig函数各参数:
filename: 指定日志文件名
filemode: 和file函数意义相同,指定日志文件的打开模式,'w'或'a'
format: 指定输出的格式和内容,format可以输出很多有用信息,如上例所示:
 %(levelno)s: 打印日志级别的数值
 %(levelname)s: 打印日志级别名称
 %(pathname)s: 打印当前执行程序的路径,其实就是sys.argv[0]
 %(filename)s: 打印当前执行程序名
 %(funcName)s: 打印日志的当前函数
 %(lineno)d: 打印日志的当前行号
 %(asctime)s: 打印日志的时间
 %(thread)d: 打印线程ID
 %(threadName)s: 打印线程名称
 %(process)d: 打印进程ID
 %(message)s: 打印日志信息
datefmt: 指定时间格式,同time.strftime()
level: 设置日志级别,默认为logging.WARNING
stream: 指定将日志的输出流,可以指定输出到sys.stderr,sys.stdout或者文件,默认输出到sys.stderr,当stream和filename同时指定时,stream被忽略

3.将日志同时输出到文件和屏幕

import logging

logging.basicConfig(level=logging.DEBUG,
                format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                datefmt='%a, %d %b %Y %H:%M:%S',
                filename='myapp.log',
                filemode='w')

#################################################################################################
#定义一个StreamHandler,将INFO级别或更高的日志信息打印到标准错误,并将其添加到当前的日志处理对象#
console = logging.StreamHandler()
console.setLevel(logging.INFO)
formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')
console.setFormatter(formatter)
logging.getLogger('').addHandler(console)
#################################################################################################

logging.debug('This is debug message')
logging.info('This is info message')
logging.warning('This is warning message')

 

屏幕上打印:
root        : INFO     This is info message
root        : WARNING  This is warning message

./myapp.log文件中内容为:
Sun, 24 May 2009 21:48:54 demo2.py[line:11] DEBUG This is debug message
Sun, 24 May 2009 21:48:54 demo2.py[line:12] INFO This is info message
Sun, 24 May 2009 21:48:54 demo2.py[line:13] WARNING This is warning message

4.logging之日志回滚

import logging
from logging.handlers import RotatingFileHandler

#################################################################################################
#定义一个RotatingFileHandler,最多备份5个日志文件,每个日志文件最大10M
Rthandler = RotatingFileHandler('myapp.log', maxBytes=10*1024*1024,backupCount=5)
Rthandler.setLevel(logging.INFO)
formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')
Rthandler.setFormatter(formatter)
logging.getLogger('').addHandler(Rthandler)
################################################################################################

从上例和本例可以看出,logging有一个日志处理的主对象,其它处理方式都是通过addHandler添加进去的。
logging的几种handle方式如下:

 

logging.StreamHandler: 日志输出到流,可以是sys.stderr、sys.stdout或者文件
logging.FileHandler: 日志输出到文件

日志回滚方式,实际使用时用RotatingFileHandler和TimedRotatingFileHandler
logging.handlers.BaseRotatingHandler
logging.handlers.RotatingFileHandler
logging.handlers.TimedRotatingFileHandler

logging.handlers.SocketHandler: 远程输出日志到TCP/IP sockets
logging.handlers.DatagramHandler:  远程输出日志到UDP sockets
logging.handlers.SMTPHandler:  远程输出日志到邮件地址
logging.handlers.SysLogHandler: 日志输出到syslog
logging.handlers.NTEventLogHandler: 远程输出日志到Windows NT/2000/XP的事件日志
logging.handlers.MemoryHandler: 日志输出到内存中的制定buffer
logging.handlers.HTTPHandler: 通过"GET"或"POST"远程输出到HTTP服务器

 

由于StreamHandler和FileHandler是常用的日志处理方式,所以直接包含在logging模块中,而其他方式则包含在logging.handlers模块中,
上述其它处理方式的使用请参见python2.5手册!

5.通过logging.config模块配置日志

#logger.conf

###############################################

[loggers]
keys=root,example01,example02

[logger_root]
level=DEBUG
handlers=hand01,hand02

[logger_example01]
handlers=hand01,hand02
qualname=example01
propagate=0

[logger_example02]
handlers=hand01,hand03
qualname=example02
propagate=0

###############################################

[handlers]
keys=hand01,hand02,hand03

[handler_hand01]
class=StreamHandler
level=INFO
formatter=form02
args=(sys.stderr,)

[handler_hand02]
class=FileHandler
level=DEBUG
formatter=form01
args=('myapp.log', 'a')

[handler_hand03]
class=handlers.RotatingFileHandler
level=INFO
formatter=form02
args=('myapp.log', 'a', 10*1024*1024, 5)

###############################################

[formatters]
keys=form01,form02

[formatter_form01]
format=%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s
datefmt=%a, %d %b %Y %H:%M:%S

[formatter_form02]
format=%(name)-12s: %(levelname)-8s %(message)s
datefmt=

上例3:

import logging
import logging.config

logging.config.fileConfig("logger.conf")
logger = logging.getLogger("example01")

logger.debug('This is debug message')
logger.info('This is info message')
logger.warning('This is warning message')

上例4:

import logging
import logging.config

logging.config.fileConfig("logger.conf")
logger = logging.getLogger("example02")

logger.debug('This is debug message')
logger.info('This is info message')
logger.warning('This is warning message')

6.logging是线程安全的



以上部分内容来自互联网。。。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值