一 簡單應用ide
import logging logging.debug('debug message') logging.info('info message') logging.warning('warning message') logging.error('error message') logging.critical('critical message')
輸出:函數
WARNING:root:warning message
ERROR:root:error message
CRITICAL:root:critical messagespa
可見,默認狀況下Python的logging模塊將日誌打印到了標準輸出中,且只顯示了大於等於WARNING級別的日誌,這說明默認的日誌級別設置爲WARNING(日誌級別等級CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET),默認的日誌格式爲日誌級別:Logger名稱:用戶輸出消息。.net
二 靈活配置日誌級別,日誌格式,輸出位置線程
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='/tmp/test.log', filemode='w') logging.debug('debug message') logging.info('info message') logging.warning('warning message') logging.error('error message') logging.critical('critical message')
查看輸出:
cat /tmp/test.log
Mon, 05 May 2014 16:29:53 test_logging.py[line:9] DEBUG debug message
Mon, 05 May 2014 16:29:53 test_logging.py[line:10] INFO info message
Mon, 05 May 2014 16:29:53 test_logging.py[line:11] WARNING warning message
Mon, 05 May 2014 16:29:53 test_logging.py[line:12] ERROR error message
Mon, 05 May 2014 16:29:53 test_logging.py[line:13] CRITICAL critical message
可見在logging.basicConfig()函數中可經過具體參數來更改logging模塊默認行爲,可用參數有
filename:用指定的文件名建立FiledHandler(後邊會具體講解handler的概念),這樣日誌會被存儲在指定的文件中。
filemode:文件打開方式,在指定了filename時使用這個參數,默認值爲「a」還可指定爲「w」。
format:指定handler使用的日誌顯示格式。
datefmt:指定日期時間格式。
level:設置rootlogger(後邊會講解具體概念)的日誌級別
stream:用指定的stream建立StreamHandler。能夠指定輸出到sys.stderr,sys.stdout或者文件(f=open('test.log','w')),默認爲sys.stderr。若同時列出了filename和stream兩個參數,則stream參數會被忽略。
format參數中可能用到的格式化串:
%(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用戶輸出的消息debug
三 logger對象日誌
上述幾個例子中咱們瞭解到了logging.debug()、logging.info()、logging.warning()、logging.error()、logging.critical()(分別用以記錄不一樣級別的日誌信息),logging.basicConfig()(用默認日誌格式(Formatter)爲日誌系統創建一個默認的流處理器(StreamHandler),設置基礎配置(如日誌級別等)並加到root logger(根Logger)中)這幾個logging模塊級別的函數,另外還有一個模塊級別的函數是logging.getLogger([name])(返回一個logger對象,若是沒有指定名字將返回root logger)code
先看一個最簡單的過程:orm
import logging logger = logging.getLogger() # 建立一個handler,用於寫入日誌文件 fh = logging.FileHandler('test.log') # 再建立一個handler,用於輸出到控制檯 ch = logging.StreamHandler() formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') fh.setFormatter(formatter) ch.setFormatter(formatter) logger.addHandler(fh) #logger對象能夠添加多個fh和ch對象 logger.addHandler(ch) logger.debug('logger debug message') logger.info('logger info message') logger.warning('logger warning message') logger.error('logger error message') logger.critical('logger critical message')
先簡單介紹一下,logging庫提供了多個組件:Logger、Handler、Filter、Formatter。Logger對象提供應用程序可直接使用的接口,Handler發送日誌到適當的目的地,Filter提供了過濾日誌信息的方法,Formatter指定日誌顯示格式。對象
(1)
Logger是一個樹形層級結構,輸出信息以前都要得到一個Logger(若是沒有顯示的獲取則自動建立並使用root Logger,如第一個例子所示)。
logger = logging.getLogger()返回一個默認的Logger也即root Logger,並應用默認的日誌級別、Handler和Formatter設置。
固然也能夠經過Logger.setLevel(lel)指定最低的日誌級別,可用的日誌級別有logging.DEBUG、logging.INFO、logging.WARNING、logging.ERROR、logging.CRITICAL。
Logger.debug()、Logger.info()、Logger.warning()、Logger.error()、Logger.critical()輸出不一樣級別的日誌,只有日誌等級大於或等於設置的日誌級別的日誌纔會被輸出。
logger.debug('logger debug message') logger.info('logger info message') logger.warning('logger warning message') logger.error('logger error message') logger.critical('logger critical message')
只輸出了
2014-05-06 12:54:43,222 - root - WARNING - logger warning message
2014-05-06 12:54:43,223 - root - ERROR - logger error message
2014-05-06 12:54:43,224 - root - CRITICAL - logger critical message
從這個輸出能夠看出logger = logging.getLogger()返回的Logger名爲root。這裏沒有用logger.setLevel(logging.Debug)顯示的爲logger設置日誌級別,因此使用默認的日誌級別WARNIING,故結果只輸出了大於等於WARNIING級別的信息。
(2) 若是咱們再建立兩個logger對象:
################################################## logger1 = logging.getLogger('mylogger') logger1.setLevel(logging.DEBUG) logger2 = logging.getLogger('mylogger') logger2.setLevel(logging.INFO) logger1.addHandler(fh) logger1.addHandler(ch) logger2.addHandler(fh) logger2.addHandler(ch) logger1.debug('logger1 debug message') logger1.info('logger1 info message') logger1.warning('logger1 warning message') logger1.error('logger1 error message') logger1.critical('logger1 critical message') logger2.debug('logger2 debug message') logger2.info('logger2 info message') logger2.warning('logger2 warning message') logger2.error('logger2 error message') logger2.critical('logger2 critical message')
結果:
這裏有兩個個問題:
<1>咱們明明經過logger1.setLevel(logging.DEBUG)將logger1的日誌級別設置爲了DEBUG,爲什麼顯示的時候沒有顯示出DEBUG級別的日誌信息,而是從INFO級別的日誌開始顯示呢?
原來logger1和logger2對應的是同一個Logger實例,只要logging.getLogger(name)中名稱參數name相同則返回的Logger實例就是同一個,且僅有一個,也即name與Logger實例一一對應。在logger2實例中經過logger2.setLevel(logging.INFO)設置mylogger的日誌級別爲logging.INFO,因此最後logger1的輸出聽從了後來設置的日誌級別。
<2>爲何logger一、logger2對應的每一個輸出分別顯示兩次?
這是由於咱們經過logger = logging.getLogger()顯示的建立了root Logger,而logger1 = logging.getLogger('mylogger')建立了root Logger的孩子(root.)mylogger,logger2一樣。而孩子,孫子,重孫……既會將消息分發給他的handler進行處理也會傳遞給全部的祖先Logger處理。
ok,那麼如今咱們把
# logger.addHandler(fh)
# logger.addHandler(ch) 註釋掉,咱們再來看效果:
由於咱們註釋了logger對象顯示的位置,因此才用了默認方式,即標準輸出方式。由於它的父級沒有設置文件顯示方式,因此在這裏只打印了一次。
孩子,孫子,重孫……可逐層繼承來自祖先的日誌級別、Handler、Filter設置,也能夠經過Logger.setLevel(lel)、Logger.addHandler(hdlr)、Logger.removeHandler(hdlr)、Logger.addFilter(filt)、Logger.removeFilter(filt)。設置本身特別的日誌級別、Handler、Filter。若不設置則使用繼承來的值。
<3>Filter
限制只有知足過濾規則的日誌纔會輸出。
好比咱們定義了filter = logging.Filter('a.b.c'),並將這個Filter添加到了一個Handler上,則使用該Handler的Logger中只有名字帶 a.b.c前綴的Logger才能輸出其日誌。
filter = logging.Filter('mylogger')
logger.addFilter(filter)
這是隻對logger這個對象進行篩選
若是想對全部的對象進行篩選,則:
filter = logging.Filter('mylogger')
fh.addFilter(filter)
ch.addFilter(filter)
這樣,全部添加fh或者ch的logger對象都會進行篩選。
完整代碼:
import logging logger = logging.getLogger() # 建立一個handler,用於寫入日誌文件 fh = logging.FileHandler('test.log') # 再建立一個handler,用於輸出到控制檯 ch = logging.StreamHandler() formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') fh.setFormatter(formatter) ch.setFormatter(formatter) # 定義一個filter filter = logging.Filter('mylogger') fh.addFilter(filter) ch.addFilter(filter) # logger.addFilter(filter) logger.addHandler(fh) logger.addHandler(ch) logger.setLevel(logging.DEBUG) logger.debug('logger debug message') logger.info('logger info message') logger.warning('logger warning message') logger.error('logger error message') logger.critical('logger critical message') ################################################## logger1 = logging.getLogger('mylogger') logger1.setLevel(logging.DEBUG) logger2 = logging.getLogger('mylogger') logger2.setLevel(logging.INFO) logger1.addHandler(fh) logger1.addHandler(ch) logger2.addHandler(fh) logger2.addHandler(ch) logger1.debug('logger1 debug message') logger1.info('logger1 info message') logger1.warning('logger1 warning message') logger1.error('logger1 error message') logger1.critical('logger1 critical message') logger2.debug('logger2 debug message') logger2.info('logger2 info message') logger2.warning('logger2 warning message') logger2.error('logger2 error message') logger2.critical('logger2 critical message')
#coding:utf-8 import logging # 建立一個logger logger = logging.getLogger() logger1 = logging.getLogger('mylogger') logger1.setLevel(logging.DEBUG) logger2 = logging.getLogger('mylogger') logger2.setLevel(logging.INFO) logger3 = logging.getLogger('mylogger.child1') logger3.setLevel(logging.WARNING) logger4 = logging.getLogger('mylogger.child1.child2') logger4.setLevel(logging.DEBUG) logger5 = logging.getLogger('mylogger.child1.child2.child3') logger5.setLevel(logging.DEBUG) # 建立一個handler,用於寫入日誌文件 fh = logging.FileHandler('/tmp/test.log') # 再建立一個handler,用於輸出到控制檯 ch = logging.StreamHandler() # 定義handler的輸出格式formatter formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') fh.setFormatter(formatter) ch.setFormatter(formatter) #定義一個filter #filter = logging.Filter('mylogger.child1.child2') #fh.addFilter(filter) # 給logger添加handler #logger.addFilter(filter) logger.addHandler(fh) logger.addHandler(ch) #logger1.addFilter(filter) logger1.addHandler(fh) logger1.addHandler(ch) logger2.addHandler(fh) logger2.addHandler(ch) #logger3.addFilter(filter) logger3.addHandler(fh) logger3.addHandler(ch) #logger4.addFilter(filter) logger4.addHandler(fh) logger4.addHandler(ch) logger5.addHandler(fh) logger5.addHandler(ch) # 記錄一條日誌 logger.debug('logger debug message') logger.info('logger info message') logger.warning('logger warning message') logger.error('logger error message') logger.critical('logger critical message') logger1.debug('logger1 debug message') logger1.info('logger1 info message') logger1.warning('logger1 warning message') logger1.error('logger1 error message') logger1.critical('logger1 critical message') logger2.debug('logger2 debug message') logger2.info('logger2 info message') logger2.warning('logger2 warning message') logger2.error('logger2 error message') logger2.critical('logger2 critical message') logger3.debug('logger3 debug message') logger3.info('logger3 info message') logger3.warning('logger3 warning message') logger3.error('logger3 error message') logger3.critical('logger3 critical message') logger4.debug('logger4 debug message') logger4.info('logger4 info message') logger4.warning('logger4 warning message') logger4.error('logger4 error message') logger4.critical('logger4 critical message') logger5.debug('logger5 debug message') logger5.info('logger5 info message') logger5.warning('logger5 warning message') logger5.error('logger5 error message') logger5.critical('logger5 critical message')
import os import time import logging from config import settings def get_logger(card_num, struct_time): if struct_time.tm_mday < 23: file_name = "%s_%s_%d" %(struct_time.tm_year, struct_time.tm_mon, 22) else: file_name = "%s_%s_%d" %(struct_time.tm_year, struct_time.tm_mon+1, 22) file_handler = logging.FileHandler( os.path.join(settings.USER_DIR_FOLDER, card_num, 'record', file_name), encoding='utf-8' ) fmt = logging.Formatter(fmt="%(asctime)s : %(message)s") file_handler.setFormatter(fmt) logger1 = logging.Logger('user_logger', level=logging.INFO) logger1.addHandler(file_handler) return logger1