官术网_书友最值得收藏!

2.5 日志記錄

日志收集與分析是運維工作中十分重要的內容,要分析日志,最好先知道日志是如何生成的,這樣才能知己知彼,分析日志才更有成效。本節將介紹如何通過Python的標準庫logging模塊定制自己多樣化的記錄日志需求。

2.5.1 日志模塊簡介

運維工作有很多情況需要查問題、解決bug,而查問題和解決bug的過程離不開查看日志,我們編寫腳本或程序時總是需要有日志輸出,Python的logging模塊就是為記錄日志使用的,而且是線程安全的,意味著使用它完全不用擔心因日志模塊的異常導致程序崩潰。


【示例2-21】首先看一下日志模塊的第一個例子。簡單將日志打印到屏幕:

輸出為:

WARNING:root:warning message
ERROR:root:error message
CRITICAL:root:critical message

默認情況下,Python的logging模塊將日志打印到標準輸出中,而且只顯示大于等于WARNING級別的日志,這說明默認的日志級別設置為WARNING(日志級別等級CRITICAL> ERROR > WARNING > INFO > DEBUG)。默認的日志格式:日志級別為Logger,名稱為用戶輸出消息。

各日志級別代表的含義如下。


DEBUG:調試時的信息打印。

INFO:正常的日志信息記錄。

WARNING:發生了警告信息,但程序仍能正常工作。

ERROR:發生了錯誤,部分功能已不正常。

CRITICAL:發生嚴重錯誤,程序可能已崩潰。


上面的例子是非常簡單的,還不足以顯示logging模塊的強大,因為我們使用print函數也可以實現以上功能。下面來看第二個例子。


【示例2-22】將日志信息記錄至文件(文件名:lx_log1.py)。

執行以上代碼后發現,在當前目錄多了一個文件lx_log1.log,文件內容與第一個例子的輸出是一致的。多次執行lx_log1.py發現log文件的內容變多了,說明默認的寫log文件的方式是追加。

2.5.2 logging模塊的配置與使用

我們可以通過logging模塊的配置改變log文件的寫入方式、日志級別、時間戳等信息。例如下面的配置:

可見在logging.basicConfig()函數中可通過具體參數來更改logging模塊的默認行為。


filename:用指定的文件名創建FiledHandler,這樣日志會被存儲在指定的文件中。

filemode:文件打開方式,在指定了filename時使用這個參數,默認值為a,還可指定為w。

format:指定handler使用的日志顯示格式。

datefmt:指定日期時間格式。

level:設置rootlogger的日志級別。

stream:用指定的stream創建StreamHandler。可以指定輸出到sys.stderr,sys.stdout或者文件,默認為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字符串形式的當前時間。默認格式是“2013-07-08 16:49:45,896”。逗號后面的是毫秒。

%(thread)d線程ID,可能沒有。

%(threadName)s線程名,可能沒有。

%(process)d進程ID,可能沒有。

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


【示例2-23】例如以下代碼。

運行代碼后我們會看到lx_log1.py文件的內容如下:

2018-06-07 21:09:51 lx_log1.py[line:9] DEBUG debug message
2018-06-07 21:09:51 lx_log1.py[line:10] INFO info message
2018-06-07 21:09:51 lx_log1.py[line:11] WARNING warning message
2018-06-07 21:09:51 lx_log1.py[line:12] ERROR error message
2018-06-07 21:09:51 lx_log1.py[line:13] CRITICAL critical message

這樣的配置已基本滿足我們寫一些小程序或Python腳本的日志需求。然而這還不夠體現logging模塊的強大,畢竟以上功能通過自定義一個函數也可以方便實現。下面先介紹幾個概念以及它們之間的關系圖。


logger:記錄器,應用程序代碼能直接使用的接口。

handler:處理器,將(記錄器產生的)日志記錄發送至合適的目的地。

filter:過濾器,提供了更好的粒度控制,可以決定輸出哪些日志記錄。

formatter:格式化器,指明了最終輸出中日志記錄的布局。


日志事件信息在記錄器(logger)、處理器(handler)、過濾器(filter)、格式化器(formatter)之間通過一個日志記錄實例來傳遞。通過調用記錄器實例的方法來記錄日志,每一個記錄器實例都有一個名字,名字相當于其命名空間,是一個樹狀結構。例如,一個記錄器叫scan,記錄器scan.tex、scan.html、scan.pdf的父節點。記錄器的名稱。可以任意取,但一個比較好的實踐是通過下面的方式來命名一個記錄器。

logger = logging.getLogger(__name__)

上面這條語句意味著記錄器的名字會通過搜索包的層級來獲致,根記錄器叫root logger。記錄器通過debug()、info()、warning()、error()和critical()方法記錄相應級別的日志,根記錄器也一樣。

根記錄器root logger輸出的名稱是'root'。當然,日志的輸出位置可能是不同的,logging模塊支持將日志信息輸出到終端、文件、HTTP GET/POST請求、郵件、網絡sockets、隊列或操作系統級的日志等。日志的輸出位置在處理器handler類中進行配置,如果內建的hangler類無法滿足需求,則可以自定義hander類來實現自己特殊的需求。默認情況下,日志的輸出位置為終端(標準錯誤輸出),可以通過logging模塊的basicConfig()方法指定一個具體的位置來輸出日志,如終端或文件。

logger和hander的工作流程如圖2.16所示。

圖2.16 logging模塊的工作流程

現在讓我們從整體到局部來說明logger的日志記錄過程。

第一步:獲取logger的名稱。

logger = logging.getLogger(‘logger name’) #這里的logger name是自己定義的

第二步:配置logger。


1)配置該logger的輸出級別,如logger.setLevel(loging.INFO)。

2)添加該logger的輸出位置,即logger的handler,logger.addHandler(ch)。這里ch是我們自定義的handler,如ch=logging.StreamHandler,即輸出到終端。我們可以添加多個handler,一次性將日志輸出到不同的位置。日志的輸出格式是在handler中進行配置,如ch.setFormatter(formatter),formatter也我們自定義的,如formatter =logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')。不同的hander可以配置不同的格式化器,可以實現不同的輸出位置,不同的輸出格式,完全可能靈活配置。


第三步:在應用程序中記錄日志。

logger.debug('debug message')
logger.info('info message')
logger.warn('warn message')
logger.error('error message')
logger.critical('critical message')


【示例2-24】將日志信息顯示在終端的同時也在文件中記錄(lx_log2.py)。

在以上程序中我們設置了logger的日志級別為INFO,handler ch的日志級別為DEBUG,handler fh的日志級別為WARNING,這樣做是為了解釋它們之前的優先級。

handler的日志級別以logger的日志級為基礎,logger的日志級別為INFO,低于INFO級別的(如DEBUG)均不會在handler中出現。handler中的日志級別如果高于logger,則只顯示更高級別的日志信息,如fh應該只顯示WARNING及以上的日志信息;handler中的日志級別如果低于或等于logger的日志級別,則顯示logger的日志級別及以上信息,如ch應該顯示INFO及以上的日志信息。

下面運行程序進行驗證:執行python lx_log2.py得到如下結果。

lx_log2
2018-06-12 22:18:10,378 - lx_log2 - INFO - info message
2018-06-12 22:18:10,379 - lx_log2 - WARNING - warn message
2018-06-12 22:18:10,379 - lx_log2 - ERROR - error message
2018-06-12 22:18:10,380 - lx_log2 - CRITICAL - critical message

查看lx_log2.log文件,內容如下:

2018-06-12 22:18:10,379 - lx_log2 - WARNING - warn message
2018-06-12 22:18:10,379 - lx_log2 - ERROR - error message
2018-06-12 22:18:10,380 - lx_log2 - CRITICAL - critical message

從運行結果來看,符合我們的預期。除了StreamHandler和FileHandler外,logging模塊還提供了其他更為實用的Handler子類,它們都繼承在Handler基類,如下所示。


BaseRotatingHandler:是循環日志處理器的基類,不能直接被實例化,可使用RotatingFileHandler和TimedRotatingFileHandler。

RotatingFileHandler:將日志文件記錄至磁盤文件,可以設置每個日志文件的最大占用空間。

TimedRotatingFileHandler:將日志文件記錄至磁盤文件,按固定的時間間隔來循環記錄日志。

SocketHandler:可以將日志信息發送到TCP/IP套接字。

DatagramHandler:可以將日志信息發送到UDP套接字。

SMTPHandler:可以將日志文件發送至郵箱。

SysLogHandler:系統日志處理器,可以將日志文件發送至UNIX系統日志,也可以是一個遠程機器。

NTEventLogHandler:Windows系統事件日志處理器,可以將日志文件發送到Windows系統事件日志。

MemoryHandler:MemoryHandler實例向內存中的緩沖區發送消息,只要滿足特定的條件,緩沖區就會被刷新。

HTTPHandler:使用GET或POST方法向HTTP服務器發送消息。

WatchedFileHandler:WatchedFileHandler實例監視它們登錄到的文件。如果文件發生更改,則使用文件名關閉并重新打開。這個處理器只適用于類unix系統,Windows不支持使用的底層機制。

QueueHandler:QueueHandler實例向隊列發送消息,比如在隊列或多處理模塊中實現的消息。

NullHandler:NullHandler實例不使用錯誤消息。庫開發人員使用日志記錄,但希望避免在庫用戶未配置日志記錄時顯示“日志記錄器XXX無法找到任何處理程序”消息。


【示例2-25】日志的配置信息也可以來源于配置文件(lx_log3.py)。代碼如下:

下面是配置文件的信息logging.conf。

上面幾種常用的方法已經基本滿足我們的需求,如需要更為細致的了解,可參考logging模塊的官方文檔。

主站蜘蛛池模板: 绍兴市| 临朐县| 天镇县| 潼南县| 张北县| 克什克腾旗| 马关县| 师宗县| 达州市| 贵德县| 抚顺市| 刚察县| 娱乐| 三江| 万源市| 漳州市| 集贤县| 突泉县| 广宗县| 丹江口市| 湖北省| 大城县| 宁明县| 繁峙县| 措勤县| 台山市| 玉门市| 揭东县| 新民市| 芜湖市| 东安县| 绥棱县| 博罗县| 哈尔滨市| 安阳市| 华宁县| 若尔盖县| 阿坝| 藁城市| 仪征市| 任丘市|