【博文推荐 】 python Howto之logging模块(1)


 本博文出自Bkjia博客无名博主,有任何问题请进入博主页面互动讨论!
博文地址:http://xdzw608.blog.51cto.com/4812210/1608718

本文来源于对py2.7.9 docs中howto-logging部分加之源代码的理解。官方文档链接如下,我用的是下载的pdf版本,应该是一致的:https://docs.python.org/2/howto/logging.html

我们不按照文档上由浅入深的讲解顺序,因为就这么点东西不至于有“入”这个动作。

使用logging模块记录日志涉及四个主要类,使用官方文档中的概括最为合适:

logger提供了应用程序可以直接使用的接口;

handler将(logger创建的)日志记录发送到合适的目的输出;

filter提供了细度设备来决定输出哪条日志记录;

formatter决定日志记录的最终输出格式。

写log的一般顺序为:

一、创建logger:

我们不要通过logging.Logger来直接实例化得到logger,而是需要通过logging.getLogger("name")来生成logger对象。

不 是说我们不能实现Logger的实例化,而是我们期待的是同一个name得到的是同一个logger,这样多模块之间可以共同使用同一个 logger,getLogger正是这样的解决方案,它内部使用loggerDict字典来维护,可以保证相同的名字作为key会得到同一个 logger对象。我们可以通过实例来验证一下:

  1. #test_logger1.py 
  2.  
  3. #coding:utf-8 
  4.  
  5. import logging 
  6.  
  7. print logging.getLogger("mydear"
  8.  
  9. import test_logger2 
  10.  
  11. test_logger2.run()   #调用文件2中的函数,保证两个模块共同处于生存期 
  12.  
  13. #test_logger2.py 
  14.  
  15. #coding:utf-8 
  16.   
  17. import logging 
  18.  
  19. def run(): 
  20.  
  21. print logging.getLogger("mydear"

输出:

<logging.Logger object at 0x00000000020ECF28>
<logging.Logger object at 0x00000000020ECF28>

结果表明两个文件中通过"mydear"调用getLogger可以保证得到的logger对象是同一个。而分别进行Logger类的实例化则不能保证。

有了logger之后就可以配置这个logger,例如设置日志级别setLevel,绑定控制器addHandler,添加过滤器addFilter等。

配置完成后,就可以调用logger的方法写日志了,根据5个日志级别对应有5个日志记录方法,分别为logger.debug,logger.info,logger.warning,logger.error,logger.critical。 

二、配置Logger对象的日志级别:

logger.setLevel(logging.DEBUG)  #DEBUG以上的日志级别会被此logger处理 

三、创建handler对象

handler 负责将log分发到某个目的输出,存在多种内置的Handler将log分发到不同的目的地,或是控制台,或是文件,或是某种形式的stream,或是 socket等。一个logger可以绑定多个handler,例如,一条日志可以同时输出到控制台和文件中。

以FileHandler和StreamHandler为例:

logfile= logging.FileHandler("./log.txt")  #创建一个handler,用于将日志输出到文件中   

console = logging.StreamHandler() #创建另一个handler,将日志导向流

handler对象也需要设置日志级别,由于一个logger可以包含多个handler,所以每个handler设置日志级别是有必要的。用通俗的话 讲,比如,我们需要处理debug以上级别的消息,所以我们将logger的日志级别定为DEBUG;然后我们想把error以上的日志输出到控制台,而 DEBUG以上的消息输出到文件中,这种分流就需要两个Handler来控制。

logfile.setLevel(logging.DEBUG)

console.setLevel(logging.ERROR)

除了对handler对象设置日志级别外,还可以指定formatter,即日志的输出格式。对handler对象设置日志格式,说明了可以将一条记录以不同的格式输出到控制台,文件或其他目的地。

formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

logfile.setFormatter(formatter) #设置handler的日志输出格式

formatter创建时使用的关键字,最后会以列表的形式展现,这不是重点。

四、绑定handler到logger中

至此handlers和logger已经准备好了,下面我们就将handlers绑定到logger上,一个logger对象可以绑定多个handler。

logger.addHandler(logfile)  #logger是通过getLogger得到的Logger对象

logger.addHandler(console) 

五、使用logger真正写日志

logger.debug("some debug message.")

logger.info("some info message.")

看上去,中间步骤(创建handler,设置日志级别,设置输出格式等)更像是配置Logger,一旦配置完成则直接调用写日志的接口即可,稍后这些日志将按照先前的配置输出。

呜呼,好多内容啊,来点简单的吧.

下面的代码,是最简单的。导入logging之后就进行了写日志操作:

  1. #coding:utf-8 
  2. import logging 
  3.  
  4. logging.debug("debug mes"
  5.  
  6. logging.info("info mes"
  7.  
  8. logging.warning("warn mes"

控制台输出如下:

WARNING:root:warn mes

咦?发生了什么情况,为什么只输出了warning?handler、logger、formatter去哪儿了?

-_-!说好的最简单的呢?为了让自己讲信用,我尽可能把它解释成“最简单的”。




评论关闭