日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

python logging

 londonKu 2012-11-23

開(kāi)發(fā)Python, 一直以來(lái)都是使用自己編寫(xiě)的logging模塊. 比較土......

今天發(fā)現(xiàn)python的標(biāo)準(zhǔn)模塊的這個(gè)功能做的挺好, 記錄一下, 以后使用模塊來(lái)進(jìn)行l(wèi)ogging.

對(duì)于這個(gè)模塊的介紹網(wǎng)上也很多, 我也不用自己寫(xiě)了, 比較好的如下,

http://crazier9527./blog/290018    Python的標(biāo)準(zhǔn)logging模塊

http://blog./2010/06/03/python-logging-module/   Python的logging模塊

http://docs./library/logging.html  官方文檔

下面就對(duì)于在項(xiàng)目中比較需要用到的部分摘錄一些,

簡(jiǎn)單的例子

[python] view plaincopy
  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.
后面會(huì)看到這種以'.'分隔的hierarchical structures有什么用.

Formatter

Formatter對(duì)象定義了最終log信息的順序,結(jié)構(gòu)和內(nèi)容, 后面會(huì)詳細(xì)解釋.

Handler

這兒用到了StreamHandler和FileHandler, 用于向不同的輸出端打log.

SetLevel

Logging有如下級(jí)別: DEBUG,INFO,WARNING,ERROR,CRITICAL

默認(rèn)級(jí)別是WARNING, logging模塊只會(huì)輸出指定level以上的log

這樣的好處, 就是在項(xiàng)目開(kāi)發(fā)時(shí)debug用的log, 在產(chǎn)品release階段不用一一注釋, 只需要調(diào)整logger的級(jí)別就可以了, 很方便的.

 

Formatter

Formatter對(duì)象定義了最終log信息的順序,結(jié)構(gòu)和內(nèi)容.于基本的logging.Handler類不同,應(yīng)用可以直接實(shí)例化formatter類,當(dāng)然,如果需要你也可以子例化formatter以便定制它的一些行為.構(gòu)造函數(shù)接受兩個(gè)可選參數(shù):一個(gè)信息格式字符串和一個(gè)日期格式字符串.如果沒(méi)有信息格式字符串,直接輸出log信息.如果沒(méi)有日期格式字符串,默認(rèn)的格式是:%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里面已經(jīng)有了

第二種配置方法, 我覺(jué)得在項(xiàng)目里面是比較實(shí)用的, 通過(guò)編寫(xiě)配置文件, 在code里面只需要用fileConfig配置一下logging, 顯得比較簡(jiǎn)潔.

這個(gè)可以參照http://crazier9527./blog/290026 或 官方文檔.

 

Multiple handlers and formatters

Loggers是一個(gè)簡(jiǎn)單的Python對(duì)象.addHandler()方法沒(méi)有最多或者最少配額,當(dāng)你的應(yīng)用需要在把所有的log信息打到一個(gè)txt文件中去,同時(shí)又需要把errors級(jí)別一上的錯(cuò)誤信息打到console時(shí),你就會(huì)體會(huì)到這個(gè)特性的好處.只要簡(jiǎn)單的配置一下合適的handlers就可以實(shí)現(xiàn)這個(gè)功能.應(yīng)用對(duì)logging的調(diào)用用不著修改.以下是對(duì)前一個(gè)基于module的配置例子的改進(jìn):

[python] view plaincopy
  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(只要在同一個(gè)Python interpreter process)

上面我曾提到過(guò),所有的對(duì)logging.getLogger(‘someLogger’)的調(diào)用都會(huì)返回同一個(gè)對(duì)象.這個(gè)規(guī)則不僅僅在同一個(gè)module有效,而且對(duì)在同一個(gè)Python的解釋器進(jìn)程里面的多個(gè)module也有效.而且,應(yīng)用代碼可以在一個(gè)module里面定義一個(gè)父logger,而在另一個(gè)module里面繼承這個(gè)logger,所有對(duì)這個(gè)子logger的調(diào)用都會(huì)轉(zhuǎn)到父logger里面去,如下所示:

下面這個(gè)是主模塊的代碼,

[python] view plaincopy
  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()")  

這個(gè)是子模塊的代碼,

[python] view plaincopy
  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/"")  

可以看到, 我們?cè)谥髂K里面定義了一個(gè)logger 'spam_application', 并對(duì)他進(jìn)行了配置.

那么在這個(gè)解釋器進(jìn)程里面的任何地方去通過(guò)getLogger('spam_application')得到的對(duì)象都是一樣的, 不需要從新定義配置, 可以直接使用.

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

所謂的父子logger只是簡(jiǎn)單的通過(guò)命名來(lái)識(shí)別, 任意以'spam_application.'開(kāi)頭的logger都是他的子logger, 例如'spam_application.auxiliary'

這個(gè)在實(shí)際的開(kāi)發(fā)中, 還是很方便的, 對(duì)于一個(gè)application,

首先通過(guò)logging配置文件編寫(xiě)好這個(gè)application所對(duì)應(yīng)的log策略, 可以只生成一個(gè)根logger, 比如叫'Project'

然后在Main函數(shù)里面, 通過(guò)fileConfig加載logging的配置

接著在appliction的任意地方, 不同的模塊中, 可以使用Project的子logger, 如Project.UI, Project.Core, 來(lái)進(jìn)行l(wèi)og, 并且不需要反復(fù)的定義和配置各個(gè)logger.





如果使用Python寫(xiě)一個(gè)比較大型的程序,你一定會(huì)用上日志系統(tǒng)。特別是Python這樣的動(dòng)態(tài)語(yǔ)言,很多錯(cuò)誤都只能在運(yùn)行的時(shí)候才能發(fā)現(xiàn),一個(gè) 好的日志系統(tǒng)對(duì)于Python程序相當(dāng)重要。最簡(jiǎn)單的解決方案當(dāng)然是直接使用print輸出運(yùn)行信息。但是這樣太簡(jiǎn)單了,沒(méi)有分級(jí)功能,如果在發(fā)布的時(shí)候 想去掉調(diào)試用的運(yùn)行信息還得找出所有的print語(yǔ)句進(jìn)行修改。再者,print只能輸出到控制臺(tái),想要輸出到文件或者通過(guò)電子郵件發(fā)送到其他地方,一個(gè) print語(yǔ)句就沒(méi)辦法解決了。


通過(guò)使用Python的日志系統(tǒng),就可以解決以上問(wèn)題。

首先看一下這個(gè)示例:
import logging
LOG=logging.getLogger(’應(yīng)用程序名’)
console = logging.StreamHandler()
console.setLevel(logging.INFO)
LOG.addHandler(console)
LOG.debug(’調(diào)試信息’)
LOG.info(’有用的信息’)
LOG.warning(’警告信息’)
LOG.error(’錯(cuò)誤信息’)
LOG.critical(’嚴(yán)重錯(cuò)誤信息’)
上面的代碼想控制臺(tái)輸出了五種錯(cuò)誤信息。分為五個(gè)從低到高的級(jí)別,從DEBUG到CRITICAL。此外,我們還指定了程序輸出的級(jí)別,只有INFO級(jí)別以上的信息才會(huì)被輸出。


這就是日志系統(tǒng)最常用的使用方法。這段代碼中有兩個(gè)概念可以幫助我們更進(jìn)一步使用Python的日志系統(tǒng):


1.        “Logger”。每個(gè)程序在輸出信息之前都要獲得一個(gè)Logger。Logger通常對(duì)應(yīng)了程序的模塊名,比如聊天工具的圖形界面模塊可以這樣獲得它的Logger:
LOG=logging.getLogger(”chat.gui”)
而核心模塊可以這樣:
LOG=logging.getLogger(”chat.kernel”)

我們接下來(lái)可以看到使用這種命名方法的用途。

2.        “Handler”。用于處理程序的輸出。 Python的日志系統(tǒng)有多種Handler可以使用。有些Handler可以把信息輸出到控制臺(tái),有些Logger可以把信息輸出到文件,還有些 Handler可以把信息發(fā)送到網(wǎng)絡(luò)上。如果覺(jué)得不夠用,還可以編寫(xiě)自己的Handler。
所有的Handler可以支持三個(gè)操作:

1.      設(shè)置輸出格式。比如設(shè)置輸出的信息中包含時(shí)間和級(jí)別信息:
LOG=logging.getLogger(”chat.gui”)
console = logging.StreamHandler()
console.setLevel(logging.INFO)
formatter = logging.Formatter(’%(asctime)s %(levelname)s %(message)s’)
console.setFormatter(formatter)
LOG.addHandler(console)
熟悉Python的朋友應(yīng)該會(huì)發(fā)現(xiàn),logging.Formatter的參數(shù)實(shí)際上只是Python常用的“%”字符串格式化。它使用“%(name)s”表示占位符。下面是一個(gè)完整的表格,展示了日志系統(tǒng)可以輸出的各種信息:


%(name)s                           Logger的名字

%(levelno)s                        數(shù)字形式的日志級(jí)別

%(levelname)s                  文本形式的日志級(jí)別

%(pathname)s                  調(diào)用日志輸出函數(shù)的模塊的完整路徑名,可能沒(méi)有

%(filename)s                     調(diào)用日志輸出函數(shù)的模塊的文件名

%(module)s                       調(diào)用日志輸出函數(shù)的模塊名

%(funcName)s                  調(diào)用日志輸出函數(shù)的函數(shù)名

%(lineno)d                          調(diào)用日志輸出函數(shù)的語(yǔ)句所在的代碼行

%(created)f                         當(dāng)前時(shí)間,用UNIX標(biāo)準(zhǔn)的表示時(shí)間的浮點(diǎn)數(shù)表示

%(relativeCreated)d          輸出日志信息時(shí)的,自Logger創(chuàng)建以來(lái)的毫秒數(shù)

%(asctime)s                       字符串形式的當(dāng)前時(shí)間。默認(rèn)格式是“2003-07-08 16:49:45,896”。逗號(hào)后面的是毫秒

%(thread)d                          線程ID。可能沒(méi)有

%(threadName)s               線程名。可能沒(méi)有

%(process)d                       進(jìn)程ID??赡軟](méi)有

%(message)s                    用戶輸出的消息


2.      設(shè)置輸出級(jí)別
在上面我們已經(jīng)演示了如何設(shè)置輸出級(jí)別了。除了Python內(nèi)置的五種級(jí)別,我們還可以自定義輸出級(jí)別。
TODO 子定義輸出級(jí)別

3.      設(shè)置過(guò)濾器
細(xì)心的朋友一定會(huì)發(fā)現(xiàn)前文調(diào)用logging.getLogger()時(shí)參數(shù)的格式類似于“A.B.C”。采取這樣的格式其實(shí)就是為了可以配置過(guò)濾器??匆幌逻@段代碼:
LOG=logging.getLogger(”chat.gui.statistic”)
console = logging.StreamHandler()
console.setLevel(logging.INFO)
formatter = logging.Formatter(’%(asctime)s %(levelname)s %(message)s’)
console.setFormatter(formatter)
filter=logging.Filter(”chat.gui”)
console.addFilter(filter)
LOG.addHandler(console)

和前面不同的是我們?cè)贖andler上添加了一個(gè)過(guò)濾器?,F(xiàn)在我們輸出日志信息的時(shí)候就會(huì)經(jīng)過(guò)過(guò)濾器的處理。名為“A.B”的過(guò)濾器只讓名字帶有 “A.B”前綴的Logger輸出信息??梢蕴砑佣鄠€(gè)過(guò)濾器,只要有一個(gè)過(guò)濾器拒絕,日志信息就不會(huì)被輸出。另外,在Logger中也可以添加過(guò)濾器。

每個(gè)Logger可以附加多個(gè)Handler。接下來(lái)我們就來(lái)介紹一些常用的Handler:
1)        logging.StreamHandler
使用這個(gè)Handler可以向類似與sys.stdout或者sys.stderr的任何文件對(duì)象(file object)輸出信息。它的構(gòu)造函數(shù)是:
StreamHandler([strm])
其中strm參數(shù)是一個(gè)文件對(duì)象。默認(rèn)是sys.stderr

2)    2.logging.FileHandler
和StreamHandler類似,用于向一個(gè)文件輸出日志信息。不過(guò)FileHandler會(huì)幫你打開(kāi)這個(gè)文件。它的構(gòu)造函數(shù)是:
FileHandler(filename[,mode])
filename是文件名,必須指定一個(gè)文件名
mode是文件的打開(kāi)方式。參見(jiàn)Python內(nèi)置函數(shù)open()的用法。默認(rèn)是’a',即添加到文件末尾。

3)    3.logging.handlers.RotatingFileHandler
這個(gè)Handler類似于上面的FileHandler,但是它可以管理文件大小。當(dāng)文件達(dá)到一定大小之后,它會(huì)自動(dòng)將當(dāng)前日志文件改名,然后創(chuàng)建 一個(gè)新的同名日志文件繼續(xù)輸出。比如日志文件是chat.log。當(dāng)chat.log達(dá)到指定的大小之后,RotatingFileHandler自動(dòng)把 文件改名為chat.log.1。不過(guò),如果chat.log.1已經(jīng)存在,會(huì)先把chat.log.1重命名為chat.log.2。。。最后重新創(chuàng)建 chat.log,繼續(xù)輸出日志信息。它的構(gòu)造函數(shù)是:
RotatingFileHandler( filename[, mode[, maxBytes[, backupCount]]])
其中filename和mode兩個(gè)參數(shù)和FileHandler一樣。
maxBytes用于指定日志文件的最大文件大小。如果maxBytes為0,意味著日志文件可以無(wú)限大,這時(shí)上面描述的重命名過(guò)程就不會(huì)發(fā)生。
backupCount用于指定保留的備份文件的個(gè)數(shù)。比如,如果指定為2,當(dāng)上面描述的重命名過(guò)程發(fā)生時(shí),原有的chat.log.2并不會(huì)被更名,而是被刪除。

4)    4.logging.handlers.TimedRotatingFileHandler
這個(gè)Handler和RotatingFileHandler類似,不過(guò),它沒(méi)有通過(guò)判斷文件大小來(lái)決定何時(shí)重新創(chuàng)建日志文件,而是間隔一定時(shí)間就 自動(dòng)創(chuàng)建新的日志文件。重命名的過(guò)程與RotatingFileHandler類似,不過(guò)新的文件不是附加數(shù)字,而是當(dāng)前時(shí)間。它的構(gòu)造函數(shù)是:
TimedRotatingFileHandler( filename [,when [,interval [,backupCount]]])
其中filename參數(shù)和backupCount參數(shù)和RotatingFileHandler具有相同的意義。
interval是時(shí)間間隔。
when參數(shù)是一個(gè)字符串。表示時(shí)間間隔的單位,不區(qū)分大小寫(xiě)。它有以下取值:
S 秒M 分H 小時(shí)D 天W 每星期(interval==0時(shí)代表星期一)midnight 每天凌晨

5)    5.logging.handlers.SocketHandler
6)    6.logging.handlers.DatagramHandler
以上兩個(gè)Handler類似,都是將日志信息發(fā)送到網(wǎng)絡(luò)。不同的是前者使用TCP協(xié)議,后者使用UDP協(xié)議。它們的構(gòu)造函數(shù)是:
Handler(host, port)
其中host是主機(jī)名,port是端口名

7)    7.logging.handlers.SysLogHandler
8)    8.logging.handlers.NTEventLogHandler
9)    9.logging.handlers.SMTPHandler
10)    10.logging.handlers.MemoryHandler
11)    11.logging.handlers.HTTPHandler

這些我自己沒(méi)用過(guò),期待大家補(bǔ)充?;蛘邊⒖糚ython的使用手冊(cè)

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多