2020-02-15 日志記錄

1. 日志模塊簡(jiǎn)介

運(yùn)維工作有很多情況需要查問題、解決bug负蚊,而查問題和解決bug的過程離不開查看日志擂煞,我們編寫腳本或程序時(shí)總是需要有日志輸出拳昌,Python的logging模塊就是為記錄日志使用的,而且是線程安全的钳垮,意味著使用它完全不用擔(dān)心因日志模塊的異常導(dǎo)致程序崩潰惑淳。
將日志打印到屏幕:

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 message

默認(rèn)情況下,Python的logging模塊將日志打印到標(biāo)準(zhǔn)輸出中扔枫,而且只顯示大于等于WARNING級(jí)別的日志汛聚,這說明默認(rèn)的日志級(jí)別設(shè)置為WARNING(日志級(jí)別等級(jí)CRITICAL>ERROR>WARNING>INFO>DEBUG)
默認(rèn)的日志格式:日志級(jí)別為L(zhǎng)ogger,名稱為用戶輸出消息短荐。
各日志級(jí)別代表的含義如下:

  • DEBUG:調(diào)試時(shí)的信息打印倚舀。
  • INFO:正常的日志信息記錄叹哭。
  • WARNING:發(fā)生了警告信息,但程序仍能正常工作痕貌。
  • ERROR:發(fā)生了錯(cuò)誤风罩,部分功能已不正常。
  • CRITICAL:發(fā)生嚴(yán)重錯(cuò)誤舵稠,程序可能已崩潰超升。

將日志信息記錄至文件(文件名:lx_log1.py):

import logging
logging.basicConfig(filename='./lx_log1.log')
logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')

執(zhí)行以上代碼后發(fā)現(xiàn),在當(dāng)前目錄多了一個(gè)文件ls_log1.log哺徊,文件內(nèi)容與第一個(gè)例子的輸出是一致的室琢。多次執(zhí)行l(wèi)x_log1.py發(fā)現(xiàn)log文件的內(nèi)容變多了,說明默認(rèn)的寫log文件的方式是追加落追。

2. logging模塊的配置與使用

我們可以通過logging模塊的配置改變log文件的寫入方式盈滴、日志級(jí)別、時(shí)間戳等信息轿钠。

logging.basicConfig(level=logging.DEBUG,    ---設(shè)置日志的級(jí)別
format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',    ---日志的格式
    datefmt='%Y-%m-%d &H:%M:%S',    ---時(shí)間格式
    filename='./lx_log1.log',    ---指定文件位置
    filemode='w')    ---指定寫入方式

可見在logging.basicConfig()函數(shù)中可通過具體參數(shù)來更改logging模塊的默認(rèn)行為巢钓。

  • filename:用指定的文件名創(chuàng)建FileHandler,這樣日志會(huì)被存儲(chǔ)在指定的文件中疗垛。
  • filemode:文件打開方式症汹,在指定了filename時(shí)使用這個(gè)參數(shù),默認(rèn)值為a贷腕,還可指定為w背镇。
  • format:指定handler使用的日志顯示格式。
  • datefmt:指定日期時(shí)間格式花履。
  • level:設(shè)置rootlogger的日志級(jí)別芽世。
  • stream:用指定的stream創(chuàng)建StreamHandler」畋冢可以指定輸出到sys.stdout或者文件济瓢,默認(rèn)為sys.stderr。若同時(shí)列出了filename和stream兩個(gè)參數(shù)妹卿,則stream參數(shù)會(huì)被忽略旺矾。

format參數(shù)中可能用到的格式化串如下:

  • %(name)s Logger的名字。
  • %(levelno)s 數(shù)字形式的日志級(jí)別夺克。
  • %(levelname)s 文本形式的日志級(jí)別箕宙。
  • %(pathname)s 調(diào)用日志輸出函數(shù)的模塊的完整路徑名,可能沒有铺纽。
  • %(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)建以來的毫秒數(shù)爆安。
  • %(asctime)s 字符串形式的當(dāng)前時(shí)間。默認(rèn)格式是“2020-02-14 16:14:52,896”仔引。逗號(hào)后面的是毫秒扔仓。
  • %(thread)d 線程ID,可能沒有咖耘。
  • %(threadName)s 線程名翘簇,可能沒有。
  • %(process)d 進(jìn)程ID鲤看,可能沒有缘揪。
  • %(message)s 用戶輸出的消息。
import logging
logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S',
    filename='./lx_log1.log',
    filemode='w',
)
logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')

運(yùn)行代碼后我們會(huì)看到lx_log1.log文件的內(nèi)容如下:

2020-02-15 01:58:20 lx_log1.py[line:9] DEBUG debug message
2020-02-15 01:58:20 lx_log1.py[line:10] INFO info message
2020-02-15 01:58:20 lx_log1.py[line:11] WARNING warning message
2020-02-15 01:58:20 lx_log1.py[line:12] ERROR error message
2020-02-15 01:58:20 lx_log1.py[line:13] CRITICAL critical message

這樣的配置已基本滿足我們歇寫一些小程序或Python腳本的日志需求义桂。然而這還不夠體現(xiàn)logging模塊的強(qiáng)大,畢竟以上功能通過自定義一個(gè)函數(shù)也可以方便實(shí)現(xiàn)蹈垢。下面的是幾個(gè)概念以及他們之間的關(guān)系圖慷吊。

  • logger:記錄器,應(yīng)用程序代碼能直接使用的接口曹抬。
  • handler:處理器溉瓶,將(記錄器產(chǎn)生的)日志記錄發(fā)送至合適的目的地。
  • filter:過濾器谤民,提供了更好的粒度控制堰酿,可以決定輸出哪些日志記錄。
  • formatter:格式化器张足,指明了最終輸出中日志記錄的布局触创。

日志事件信息在記錄器(logger)、處理器(handler)为牍、過濾器(filter)哼绑、格式化器(formatter)之間通過一個(gè)日志記錄實(shí)例來傳遞。通過調(diào)用記錄器實(shí)例的方法來記錄日志碉咆,每一個(gè)記錄器實(shí)例都有一個(gè)名字抖韩,名字相當(dāng)于其命名空間,是一個(gè)樹狀結(jié)構(gòu)疫铜。例如茂浮,一個(gè)記錄器叫scan,記錄器scan.tex、scan.html席揽、scan.pdf的夫節(jié)點(diǎn)顽馋。記錄器的名稱【阅幔可以任意取趣避,但一個(gè)比較好的實(shí)踐是通過下面的方式來命名一個(gè)記錄器。

logger = logging.getLogger(__name__)

上面這條語(yǔ)句意味著記錄器的名字會(huì)通過搜索包的層級(jí)來獲致新翎,根記錄器叫root logger程帕。記錄器通過debug()、info()地啰、warning()愁拭、error()和critical()方法記錄相應(yīng)級(jí)別的日志,根記錄器也一樣亏吝。
根記錄器root logger輸出的名稱是'root'岭埠。當(dāng)然,日志的輸出位置可能是不同的蔚鸥,logging模塊支持將日志信息輸出到終端惜论、文件、HTTP GET/POST請(qǐng)求止喷、郵件馆类、網(wǎng)絡(luò)sockets、隊(duì)列或操作系統(tǒng)級(jí)的日志等弹谁。日志的輸出位置在處理器handler類中進(jìn)行配置乾巧,如果內(nèi)建的handler類無法滿足需求,則可以自定義handler類來實(shí)現(xiàn)自己特殊的需求预愤。默認(rèn)情況下沟于,日志的輸出位置為終端(標(biāo)準(zhǔn)錯(cuò)誤輸出),可以通過logging模塊的basicConfig()方法指定一個(gè)具體的位置來輸出日志植康,如終端或文件旷太。
logger和handler的工作流程如下:

logging模塊的工作流程

現(xiàn)在讓我們從整體到局部來說明logger的日志記錄過程。
第一步:獲取logger的名稱向图。

logger = logging.getLogger('logger name')    ---這里的logger name是自己定義的

第二步:配置logger泳秀。
1)配置該logger的輸出級(jí)別,如logger.setLevel(loging.INFO)榄攀。
2)添加該logger的輸出位置嗜傅,即logger的handler,logger.addHandler(ch)檩赢。這里的ch是我們自定義的handler吕嘀,如ch=logging.StreamHandler违寞,即輸出到終端。我們可以添加多個(gè)handler偶房,一次性將日志輸出到不同的位置趁曼。日志的輸出格式是在handler中進(jìn)行配置,如ch.setFormatter(formatter)棕洋,formatter也是我們自定義的挡闰,如formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')。不同的handler可以配置不同的格式化器掰盘,可以實(shí)現(xiàn)不同的輸出位置摄悯,不同的輸出格式,完全可能靈活配置愧捕。
第三步:在應(yīng)用程序中記錄日志奢驯。

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

將日志信息顯示在終端的同時(shí)也在文件中記錄(lx_log2.py)。

# -*- coding: utf-8 -*-

import logging

# 創(chuàng)建logger次绘,其名稱為aimple_example瘪阁,名稱為任意,也可為空
logger = logging.getLogger("simple_example")
# 打印logger的名稱
print(logger.name)
# 設(shè)置logger的日志級(jí)別
logger.setLevel(logger.INFO)

# 創(chuàng)建兩個(gè)handler邮偎,一個(gè)負(fù)責(zé)將日志輸出到終端管跺,一個(gè)負(fù)責(zé)輸出到文件,并分別設(shè)置它們的日志級(jí)別
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
fh = logging.FileHandler(filename="simple.log", mode="a", encoding="utf*8")
fh.setLevel(logging.WARNING)
# 創(chuàng)建一個(gè)格式化器禾进,可以創(chuàng)建不同的格式化器用于不同的handler伙菜,這里我們使用一個(gè)
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")

# 設(shè)置兩個(gè)handler的格式化器
ch.setFormatter(formatter)
fh.setFormatter(formatter)
# 為logger添加兩個(gè)handler
logger.addHandler(ch)
logger.addHandler(fh)

# 在程序中記錄日志
logger.debug("debug message")
logger.info("info message")
logger.warning("warning message")
logger.error("error message")
logger.critical("critical message")

在以上程序中我們?cè)O(shè)置了logger的日志級(jí)別為INFO,handler ch的日志級(jí)別為DEBUG命迈,handler fh的日志級(jí)別為WARNING,這樣做是為了解釋它們之前的優(yōu)先級(jí)火的。
handler的日志級(jí)別以logger的日志為基礎(chǔ)壶愤,logger的日志級(jí)別為INFO,低于INFO級(jí)別的(如DEBUG)均不會(huì)在handler中出現(xiàn)馏鹤。handler中的日志級(jí)別如果高于logger征椒,則只顯示更高級(jí)別的日志信息,如fh應(yīng)該只顯示W(wǎng)ARNING及以上的日志信息湃累;handler中的日志級(jí)別如果低于或等于logger的日志級(jí)別勃救,則顯示logger的日志級(jí)別及以上信息,如ch應(yīng)該顯示INFO及以上的日志信息治力。
執(zhí)行python lx_log2.py得到如下結(jié)果:

simple_example
2020-02-15 14:54:29,459 - simple_example - INFO - info message
2020-02-15 14:54:29,459 - simple_example - WARNING - warning message
2020-02-15 14:54:29,459 - simple_example - ERROR - error message
2020-02-15 14:54:29,459 - simple_example - CRITICAL - critical message

查看simple.log文件蒙秒,內(nèi)容如下:

2020-02-15 14:54:29,459 - simple_example - WARNING - warning message
2020-02-15 14:54:29,459 - simple_example - ERROR - error message
2020-02-15 14:54:29,459 - simple_example - CRITICAL - critical message

從運(yùn)行結(jié)果來看,符合我們的預(yù)期宵统。除了StreamHandler和FileHandler外晕讲,logging模塊還提供了其他更為實(shí)用的Handler子類,它們都繼承在Handler基類,如下所示瓢省。

  • BaseRotatingHandler:是循環(huán)日志處理器的基類弄息,不能直接被實(shí)例化,可使用RotatingFileHandler和TimeRotatingFileHandler勤婚。
  • RotatingFileHandler:將日志文件記錄至磁盤文件摹量,可以設(shè)置每個(gè)日志文件的最大占用空間。
  • TimeRotatingFileHandler:將日志文件記錄至磁盤文件馒胆,按固定的時(shí)間間隔來循環(huán)記錄日志缨称。
  • SocketHandler:可以將日志信息發(fā)送到TCP/IP套接字。
  • DatagramHandler:可以將日志信息發(fā)送到UDP套接字国章。
  • SMTPHandler:可以將日志文件發(fā)送至郵箱具钥。
  • SysLogHandler:系統(tǒng)日志處理器,可以將日志文件發(fā)送至UNIX系統(tǒng)日志液兽,也可以是一個(gè)遠(yuǎn)程機(jī)器骂删。
  • NTEventLogHandler:Windows系統(tǒng)事件日志處理器,可以將日志文件發(fā)送到Windows系統(tǒng)事件日志四啰。
  • MemoryHandler:MemoryHandler實(shí)例向內(nèi)存中的緩沖區(qū)發(fā)送消息宁玫,只要滿足特定的條件,緩沖區(qū)就會(huì)被刷新柑晒。
  • HTTPHandlerL:使用GET或POST方法向HTTP服務(wù)器發(fā)送消息欧瘪。
  • WatchedFileHandler:WatchedFileHandler實(shí)例監(jiān)視它們登錄到的文件。如果文件發(fā)生更改匙赞,則使用文件名關(guān)閉并重新打開佛掖。這個(gè)處理器只適用于類unix系統(tǒng),Windows不支持使用的底層機(jī)制涌庭。
  • QueueHandler:QueueHandler實(shí)例向隊(duì)列發(fā)送消息芥被,比如在隊(duì)列或多處理模塊中實(shí)現(xiàn)的消息。
  • NullHandler:NullHandler實(shí)例不使用錯(cuò)誤消息坐榆。庫(kù)開發(fā)人員使用日志記錄拴魄,但希望避免在庫(kù)用戶未配置日志記錄時(shí)顯示“日志記錄器XXX無法找到任何處理程序”消息。

日志的配置信息也可以來源于配置文件(lx_log3.py):

import logging
import logging.config

logging.config.fileConfig('logging.conf')

# 創(chuàng)建一個(gè)logger
logger = logging.getLogger('simpleExample')

# 日志記錄
logger.debug("debug message")
logger.info("info message")
logger.warning("warning message")
logger.error("error message")
logger.critical("critical message")

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

[loggers]
keys=root,simpleExample

[handlers]
keys=fileHandler,consoleHandler

[formatters]
keys=simpleFormatter

[logger_root]
level=DEBUG
handlers=fileHandler

[logger_simpleExample]
level=DEBUG
handlers=consoleHandler
qualname=simpleExample
propagate=0

[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=simpleFormatter
args=(sys.stdout,)

[formatter_simpleFormatter]
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
datefmt=%Y-%m-%d %H:%M:%S

上面幾種常用的方法已經(jīng)基本滿足我們的需求席镀。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末匹中,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子豪诲,更是在濱河造成了極大的恐慌顶捷,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件跛溉,死亡現(xiàn)場(chǎng)離奇詭異焊切,居然都是意外死亡扮授,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門专肪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來刹勃,“玉大人,你說我怎么就攤上這事嚎尤±笕剩” “怎么了?”我有些...
    開封第一講書人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵芽死,是天一觀的道長(zhǎng)乏梁。 經(jīng)常有香客問我,道長(zhǎng)关贵,這世上最難降的妖魔是什么遇骑? 我笑而不...
    開封第一講書人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮揖曾,結(jié)果婚禮上落萎,老公的妹妹穿的比我還像新娘。我一直安慰自己炭剪,他們只是感情好练链,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著奴拦,像睡著了一般媒鼓。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上错妖,一...
    開封第一講書人閱讀 49,950評(píng)論 1 291
  • 那天绿鸣,我揣著相機(jī)與錄音,去河邊找鬼暂氯。 笑死枚驻,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的株旷。 我是一名探鬼主播,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼尔邓,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼晾剖!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起梯嗽,我...
    開封第一講書人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤齿尽,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后灯节,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體循头,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡绵估,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了卡骂。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片国裳。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖全跨,靈堂內(nèi)的尸體忽然破棺而出缝左,到底是詐尸還是另有隱情,我是刑警寧澤浓若,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布渺杉,位于F島的核電站,受9級(jí)特大地震影響挪钓,放射性物質(zhì)發(fā)生泄漏是越。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一碌上、第九天 我趴在偏房一處隱蔽的房頂上張望倚评。 院中可真熱鬧,春花似錦绍赛、人聲如沸蔓纠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)腿倚。三九已至,卻和暖如春蚯妇,著一層夾襖步出監(jiān)牢的瞬間敷燎,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工箩言, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留硬贯,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓陨收,卻偏偏與公主長(zhǎng)得像饭豹,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子务漩,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容