Logging日誌模塊

典型的日誌記錄的步驟是這樣的:java

  1. 建立logger
  2. 建立handler
  3. 定義formatter
  4. 給handler添加formatter
  5. 給logger添加handler

寫成代碼差很少就是醬嬸的(這個是照別的網頁抄的,參考附註):python

複製代碼
1 import logging 
 2 
 3 # 一、建立一個logger 
 4 logger = logging.getLogger('mylogger') 
 5 logger.setLevel(logging.DEBUG) 
 6 
 7 # 二、建立一個handler,用於寫入日誌文件 
 8 fh = logging.FileHandler('test.log') 
 9 fh.setLevel(logging.DEBUG) 
10 
11 # 再建立一個handler,用於輸出到控制檯 
12 ch = logging.StreamHandler() 
13 ch.setLevel(logging.DEBUG) 
14 
15 # 三、定義handler的輸出格式(formatter)
16 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') 
17 
18 # 四、給handler添加formatter
19 fh.setFormatter(formatter) 
20 ch.setFormatter(formatter) 
21 
22 # 五、給logger添加handler 
23 logger.addHandler(fh) 
24 logger.addHandler(ch)
複製代碼

以後才能夠正式的開始記錄日誌。Java裏面的java.util.Logging類差很少也是這樣,代碼還要更復雜一點。Golang的日誌相對寫法簡單一些,不過沒有什麼格式,系統記錄一條時間,內容格式徹底本身手畫。第三方的日誌庫卻是沒有接觸過,像Java的Log4j,Golang的log4go和seelog等等,不知道用起來會不會簡單一點。我一直都記不住這些,由於不太理解logger和handler爲何要這樣寫。一直到此次任務中出現的在我看來至關「詭異」的bug,才深刻理解了一下。json

個人任務是這樣的,要作一個日誌切割的工具,按天將日誌分割開,即天天0點產生一個新日誌,將舊日誌更名。而且,將超過3個月的日誌刪除掉,以保證磁盤空間不會被log佔滿。程序要求能夠切割多個目錄中的不一樣日誌,具體路徑由json中配置。框架

這裏用到了logging.handlers類中的TimedRotatingFileHandler方法,用以得到一個handler。大概的寫法爲:函數

1 logger = logging.getLogger() #得到logger
2 handler = logging.handlers.TimedRotatingFileHandler(logfile, 'S', 1, 0) #切割日誌
3 handler.suffix = '%Y%m%d' #切割後的日誌設置後綴
4 logger.addHandler(handler) #把logger添加上handler
5 logger.fatal(datetime.datetime.now().strftime('%Y-%m-%d')) #在新日誌中寫上當天的日期

這裏我沒有設置level和formatter。由於只是分割,對新日誌沒有什麼影響。TimedRotatingFileHandler函數的方法見附註,或查看python的源碼,這個函數是python寫的,能夠找到定義。這裏我使用的是每秒生成一個新的日誌文件,以後用Crontab在天天0點調度,而後用for循環處理json中的每個日誌文件。工具

可是奇怪的是,每次運行程序,第一個切割的日誌生成一個分割後的文件,然後面的都生成兩個新日誌。百思不得其解。後檢查代碼以爲,多是程序中設置的時間過短了,每秒生成一個文件,有可能一秒鐘處理不完,就生成了兩個。雖然這個說法沒有什麼科學根據,可是仍是把TimedRotatingFileHandler中的第三個參數改爲了60,即每60秒生成一個文件。完成,靜靜的等待crontab到時間。spa

 

叮!時間到。趕忙檢查一下結果。一個好消息和一個壞消息。好消息是此次每一個日誌都只切割生成了一個新文件,沒有生成兩個。壞消息是每一個文件裏面添加的當天的日期的數量見鬼了。我切割了4條日誌,生成的新日誌裏面就分別寫上了1、2、3、四行當天日期。日誌

 

此刻個人心裏幾乎是崩潰的。我開始思考爲何會這樣。很明顯四行日期是調用了4次logger.fatal('datetime.datetime.now().strftime('%Y-%m-%d')) 這個函數。換句話說,我每一次for循環都在這個log裏面寫了一句話。但是明明每一個for是處理一個日誌,下一次for應該是處理下一個日誌的,爲何會再處理這個日誌一次?我忽然想到,logger.addHandler(handler)是每次循環都會運行的,也就是說,logger是同一個logger,添加了4次handler。到第4次循環的時候,這個logger中有4個handler,也就會往4個不一樣的日誌中添加內容了。呃。code

 

若是是這樣的話,那麼把上面的程序改改,第一句和最後一句放在循環外,循環內只用中間的三句。此次OK了。回頭再看log記錄的步驟,也就明白了logger和handler究竟是個什麼鬼:logger能夠看作是一個記錄日誌的人,對於記錄的每一個日誌,他須要有一套規則,好比記錄的格式(formatter),等級(level)等等,這個規則就是handler。使用logger.addHandler(handler)添加多個規則,就可讓一個logger記錄多個日誌。至於logging.getLogger()方法得到的root logger和繼承關係,能夠詳見附註的網頁,這裏我也只是大概明白了什麼意思,尚未具體用過。也許未來在框架中使用,要記錄較爲複雜的日誌時候會用到吧。orm

相關文章
相關標籤/搜索