開(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)單的例子
上面這段代碼基本包含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. 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, 可能用到的有下面幾種
最常用的也就是StreamHandler和FileHandler
Configuration
第一種配置方法前面的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):
多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è)是主模塊的代碼,
這個(gè)是子模塊的代碼,
可以看到, 我們?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è) |
|