標籤:
make sure your python version > Python 2.3
1 從一個小案例說起:
cat howto_logging.py
#coding=utf8# file name: howto_logging# this file shows how to use logging# made by vasks, email:[email protected]import logging# 建立一個logger,層級:DEBUGlogger = logging.getLogger(‘Err_Logger‘)logger.setLevel(logging.DEBUG)# 建立一個handler,用於寫入記錄檔fh = logging.FileHandler(‘err.log‘)fh.setLevel(logging.DEBUG)# 再建立一個handler,用於輸出到控制台ch = logging.StreamHandler()ch.setLevel(logging.DEBUG)# 定義handler的輸出格式formatter = logging.Formatter(‘%(asctime)s - %(name)s - %(levelname)s - %(message)s - %(lineno)d‘)fh.setFormatter(formatter)ch.setFormatter(formatter)# 給logger添加handlerlogger.addHandler(fh)logger.addHandler(ch)# 記錄日誌 NOTSET < DEBUG < INFO < WARNING < ERROR < CRITICALlogger.debug(‘just a debug‘)logger.info(‘just a info‘)logger.warning(‘waring,please check out‘)logger.error(‘error,oh no‘)logger.critical("critical,it doesn‘t work")
終端輸出執行結果:
2015-04-02 17:03:29,421 - Err_Logger - DEBUG - just a debug - 292015-04-02 17:03:29,423 - Err_Logger - INFO - just a info - 302015-04-02 17:03:29,423 - Err_Logger - WARNING - waring,please check out - 312015-04-02 17:03:29,423 - Err_Logger - ERROR - error,oh no - 322015-04-02 17:03:29,423 - Err_Logger - CRITICAL - critical,it doesn‘t work - 33[Finished in 0.1s]
err.log的結果:
cat err.log2015-04-02 17:03:29,421 - Err_Logger - DEBUG - just a debug - 292015-04-02 17:03:29,423 - Err_Logger - INFO - just a info - 302015-04-02 17:03:29,423 - Err_Logger - WARNING - waring,please check out - 312015-04-02 17:03:29,423 - Err_Logger - ERROR - error,oh no - 322015-04-02 17:03:29,423 - Err_Logger - CRITICAL - critical,it doesn‘t work - 33
2. logging 詳解 2.1 logger:提供日誌介面,供應用代碼使用。logger最長用的操作有兩類:配置和發送日誌訊息。
- logging.getLogger(name):
可以通過logging.getLogger(name)擷取logger對象,如果不指定name則返回root對象,多次使用相同的name調用getLogger方法返回同一個logger對象。
- Logger.setLevel(lvl):
設定logger的level, level有以下幾個層級:NOTSET < DEBUG < INFO < WARNING < ERROR < CRITICAL 如果把looger的層級設定為INFO, 那麼小於INFO層級的日誌都不輸出, 大於等於INFO層級的日誌都輸出。小於的就不會輸出。
2.2 handler:將日誌記錄發送到合適的目的地,比如檔案,socket等。一個logger對象可以通過addHandler方法添加0到多個handler,每個handler又可以定義不同記錄層級,以實現日誌分級過濾顯示。
我們這裡設定了兩個,一個輸出到終端,一個輸出到err.log檔案。
handler主要有以下幾種:
StreamHandler: 輸出到控制台
FileHandler: 輸出到檔案
handler還可以設定自己的level以及輸出格式。
2.3 filter:提供一種優雅的方式決定一個日誌記錄是否發送到handler。 2.4 formatter:指定日誌記錄輸出的具體格式。formatter的構造方法需要兩個參數:訊息的格式字串和日期文字,這兩個參數都是可選的。
更多的格式:
格式 描述(代表什麼)%(name)s Name of the logger (logging channel).%(levelno)s Numeric logging level for the message (DEBUG, INFO, WARNING, ERROR, CRITICAL).%(levelname)s Text logging level for the message (‘DEBUG‘, ‘INFO‘, ‘WARNING‘, ‘ERROR‘, ‘CRITICAL‘).%(pathname)s Full pathname of the source file where the logging call was issued (if available).%(filename)s Filename portion of pathname.%(module)s Module (name portion of filename).%(funcName)s Name of function containing the logging call.%(lineno)d Source line number where the logging call was issued (if available).%(created)f Time when the LogRecord was created (as returned by time.time()).%(relativeCreated)d Time in milliseconds when the LogRecord was created, relative to the time the logging module was loaded.%(asctime)s Human-readable time when the LogRecord was created. By default this is of the form “2003-07-08 16:49:45,896” (the numbers after the comma are millisecond portion of the time).%(msecs)d Millisecond portion of the time when the LogRecord was created.%(thread)d Thread ID (if available).%(threadName)s Thread name (if available).%(process)d Process ID (if available).%(message)s The logged message, computed as msg % args.
這裡是中文的:
%(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 使用者輸出的訊息
2.5 logging.basicConfig() 2.5.1 logging.basicConfig([**kwargs])
這個函數用來配置root logger, 為root logger建立一個Handler,
設定預設的格式。
這些函數: logging.debug()、logging.info()、logging.warning()、
logging.error()、logging.critical() 如果調用的時候發現root logger沒有任何
handler, 會自動調用basicConfig添加一個handler
如果root logger已有handler, 這個函數不做任何事情,使用basicConfig來配置root logger的輸出格式和level。
例子:
import logging logging.basicConfig(format=‘%(levelname)s:%(message)s‘, level=logging.DEBUG) logging.debug(‘This message should appear on the console‘)
關於root logger以及logger的父子關係
前面多次提到root logger, 實際上logger執行個體之間還有父子關係, root logger就是處於
最頂層的logger, 它是所有logger的祖先。如:
root logger是預設的logger
如果不建立logger執行個體, 直接調用logging.debug()、logging.info()、logging.warning()、logging.error()、logging.critical()這些函數,那麼使用的logger就是 root logger, 它可以自動建立,也是單一實例的。
如何得到root logger
通過logging.getLogger()或者logging.getLogger(““)得到root logger執行個體。
預設的level
root logger預設的level是logging.WARNING
如何表示父子關係
logger的name的命名方式可以表示logger之間的父子關係. 比如:
parent_logger = logging.getLogger(‘foo‘) child_logger = logging.getLogger(‘foo.bar‘)
什麼是effective level
logger有一個概念,叫effective level。 如果一個logger沒有顯示地設定level,那麼它就
用父親的level。如果父親也沒有顯示地設定level, 就用父親的父親的level,以此推….
最後到達root logger,一定設定過level。預設為logging.WARNING
child loggers得到訊息後,既把訊息分發給它的handler處理,也會傳遞給所有祖先logger處理,
來看一個例子
import logging# 設定root loggerr = logging.getLogger()ch = logging.StreamHandler()ch.setLevel(logging.DEBUG)formatter = logging.Formatter(‘%(asctime)s - %(levelname)s - %(message)s‘)ch.setFormatter(formatter)r.addHandler(ch)# 建立一個logger作為父親p = logging.getLogger(‘foo‘)p.setLevel(logging.DEBUG)ch = logging.StreamHandler()ch.setLevel(logging.DEBUG)formatter = logging.Formatter(‘%(asctime)s - %(message)s‘)ch.setFormatter(formatter)p.addHandler(ch)# 建立一個孩子loggerc = logging.getLogger(‘foo.bar‘)c.debug(‘foo‘)
輸出如下:
2015-04-02 18:44:38,128 - foo2015-04-02 18:44:38,128 - DEBUG - foo[Finished in 0.2s]
可見, 孩子logger沒有任何handler,所以對訊息不做處理。但是它把訊息轉寄給了它的父親以及root logger。最後輸出兩條日誌。
再看個例子:
import logging # set up logging to file - see previous section for more details logging.basicConfig(level=logging.DEBUG, format=‘%(asctime)s %(name)-12s %(levelname)-8s %(message)s‘, datefmt=‘%m-%d %H:%M‘, filename=‘mylogging.log‘, filemode=‘w‘) # define a Handler which writes INFO messages or higher to the sys.stderr console = logging.StreamHandler() console.setLevel(logging.WARNING) # set a format which is simpler for console use formatter = logging.Formatter(‘%(name)-12s: %(levelname)-8s %(message)s‘) # tell the handler to use this format console.setFormatter(formatter) # add the handler to the root logger logging.getLogger(‘‘).addHandler(console) # Now, we can log to the root logger, or any other logger. First the root... logging.info(‘Jackdaws love my big sphinx of quartz.‘) # Now, define a couple of other loggers which might represent areas in your # application: logger1 = logging.getLogger(‘myapp.area1‘) logger2 = logging.getLogger(‘myapp.area2‘) logger1.debug(‘Quick zephyrs blow, vexing daft Jim.‘) logger1.info(‘How quickly daft jumping zebras vex.‘) logger2.warning(‘Jail zesty vixen who grabbed pay from quack.‘) logger2.error(‘The five boxing wizards jump quickly.‘)
終端輸出:
myapp.area2 : WARNING Jail zesty vixen who grabbed pay from quack. myapp.area2 : ERROR The five boxing wizards jump quickly. [Finished in 0.1s]
終端下 StreamHandler():
logging.info root自己info沒有設定的層級warning大,不輸出
logger1 的info和debug沒有設定的層級:warning 大,所以不輸出
logger2符合條件,輸出
文本輸出:
04-02 19:15 root INFO Jackdaws love my big sphinx of quartz.04-02 19:15 myapp.area1 DEBUG Quick zephyrs blow, vexing daft Jim.04-02 19:15 myapp.area1 INFO How quickly daft jumping zebras vex.04-02 19:15 myapp.area2 WARNING Jail zesty vixen who grabbed pay from quack.04-02 19:15 myapp.area2 ERROR The five boxing wizards jump quickly.
basicConfig中設定的警示層級是debug,所以大家都輸出了,輸出到了文本。
2.5.1 詳細說下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被忽略
本文引用這些部落格:
- http://www.cnblogs.com/captain_jack/archive/2011/01/21/1941453.html
- http://bbs.chinaunix.net/thread-3590256-1-1.html
- http://www.cnblogs.com/bjdxy/archive/2013/04/12/3016820.html
python logging - vasks