搞掂python日志的應(yīng)用补履,同事面前裝個(gè)13

# Python日志處理

日志是在軟件開發(fā)中記錄程序運(yùn)行情況的一種重要方式箫锤,它對(duì)于錯(cuò)誤排查和系統(tǒng)運(yùn)維非常有幫助谚攒。Python標(biāo)準(zhǔn)庫自帶了強(qiáng)大的logging日志模塊馏臭,被廣泛應(yīng)用于各種Python模塊中括儒。

## 1. 小試牛刀

### 1.1 簡單使用

```python

import?logging

#?默認(rèn)的warning級(jí)別帮寻,只輸出warning以上的

#?使用basicConfig()來指定日志級(jí)別和相關(guān)信息

logging.basicConfig(

????level=logging.DEBUG,??#?設(shè)置級(jí)別规婆,根據(jù)等級(jí)顯示

????format='%(asctime)s-[%(filename)s-->line:%(lineno)d]-%(levelname)s:%(message)s',??#?設(shè)置輸出格式

????datefmt="%Y-%m-%d?%H:%M:%S"??#?時(shí)間輸出的格式

)

logging.debug("This?is?a?DEBUG?message")

logging.info("This?is?an?INFO?message")

logging.warning("This?is?a?WARNING?message")

logging.error("This?is?an?ERROR?message")

logging.critical("This?is?a?CRITICAL?message")

```

輸出結(jié)果:

```plaintext

2023-06-09?10:22:39-[ts.py-->line:11]-DEBUG:DEBUG

2023-06-09?10:22:39-[ts.py-->line:12]-INFO:INFO

2023-06-09?10:22:39-[ts.py-->line:13]-WARNING:WARNING

2023-06-09?10:22:39-[ts.py-->line:14]-ERROR:TERROR

2023-06-09?10:22:39-[ts.py-->line:15]-CRITICAL:CRITICAL

```

### 1.2 日志級(jí)別

五種日志等級(jí)掘鄙,不同情況輸出不同等級(jí)的日志操漠。

| 日志等級(jí)(level) | 描述? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? |

| ------------------- | ------------------------------------------------------------------------------------------ |

| DEBUG? ? ? ? ? ? | 調(diào)試信息浊伙,通常在診斷問題的時(shí)候用得著? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? |

| INFO? ? ? ? ? ? ? | 普通信息嚣鄙,確認(rèn)程序按照預(yù)期運(yùn)行? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? |

| WARNING? ? ? ? ? | 警告信息哑子,表示發(fā)生意想不到的事情卧蜓,或者指示接下來可能會(huì)出現(xiàn)一些問題把敞,但是程序還是繼續(xù)運(yùn)行 |

| ERROR? ? ? ? ? ? | 錯(cuò)誤信息奋早,程序運(yùn)行中出現(xiàn)了一些問題伸蚯,程序某些功能不能執(zhí)行? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? |

| CRITICAL? ? ? ? ? | 危險(xiǎn)信息,一個(gè)嚴(yán)重的錯(cuò)誤,導(dǎo)致程序無法繼續(xù)運(yùn)行? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? |

過濾掉低于自定義設(shè)置的日志等級(jí)挥萌。

```python

import?logging

#?默認(rèn)的warning級(jí)別引瀑,只輸出warning以上的

#?使用basicConfig()來指定日志級(jí)別和相關(guān)信息

logging.basicConfig(

????level=logging.ERROR,??#?設(shè)置級(jí)別憨栽,根據(jù)等級(jí)顯示

????format='%(asctime)s-[%(filename)s-->line:%(lineno)d]-%(levelname)s:%(message)s',??#?設(shè)置輸出格式

????datefmt="%Y-%m-%d?%H:%M:%S"??#?時(shí)間輸出的格式

)

logging.debug("調(diào)試等級(jí)不輸出")

logging.info("普通信息等級(jí)不會(huì)輸出")

logging.warning("警告不會(huì)輸出)

logging.error("輸出錯(cuò)誤等級(jí)")

logging.critical("輸出崩潰等級(jí)")

```

輸出結(jié)果:

```plaintext

2023-06-09?10:27:16-[ts.py-->line:13]-ERROR:輸出錯(cuò)誤等級(jí)

2023-06-09?10:27:16-[ts.py-->line:14]-CRITICAL:輸出崩潰等級(jí)

```

在上面的示例中屡萤,我們將日志級(jí)別設(shè)置為`ERROR`死陆,因此只有`ERROR`和`CRITICAL`級(jí)別的日志被輸出措译,`DEBUG`领虹、`INFO`和`WARNING`級(jí)別的日志被過濾掉求豫。

### 1.3 日志格式

通過`format`參數(shù)可以自定義日志輸出的格式注祖。在格式字符串中是晨,可以使用以下占位符來表示不同的日志信息:

* ? `%(asctime)s`:日志記錄的時(shí)間(默認(rèn)格式為`YYYY-MM-DD HH:MM:SS`)

* ? `%(levelname)s`:日志級(jí)別

* ? `%(message)s`:日志消息

* ? `%(name)s`:日志器的名稱

* ? `%(filename)s`:包含當(dāng)前日志記錄的源文件的文件名

* ? `%(lineno)d`:當(dāng)前日志記錄所在的行號(hào)

設(shè)置自定義的日志格式:

```python

import?logging

logging.basicConfig(

????level=logging.DEBUG,?#?設(shè)置最低過濾級(jí)別

????format='%(asctime)s?-?%(levelname)s?-?%(message)s',

????datefmt='%Y-%m-%d?%H:%M:%S'?#?使用指定的日期/時(shí)間格式蚊逢,與?time.strftime()?所接受的格式相同烙荷。

)

logging.debug('勇哥?debug?')

logging.info('勇哥?info')

logging.warning('勇哥?warning?')

logging.error('勇哥?error?')

logging.critical('勇哥?critical?')

```

輸出結(jié)果:

```plaintext

2023-06-09?10:33:08?-?DEBUG?-?勇哥?debug?

2023-06-09?10:33:08?-?INFO?-?勇哥?info

2023-06-09?10:33:08?-?WARNING?-?勇哥?warning?

2023-06-09?10:33:08?-?ERROR?-?勇哥?error?

2023-06-09?10:33:08?-?CRITICAL?-?勇哥?critical

```

## 2. 磨磨牛刀

`日志處理器(Log Handlers)`用于指定日志的輸出位置终抽,例如控制臺(tái)昼伴、文件或網(wǎng)絡(luò)等圃郊。

### 2.1 控制臺(tái)處理器

`StreamHandler`是一個(gè)將日志輸出到控制臺(tái)的處理器女蜈。它可以將日志消息打印到標(biāo)準(zhǔn)輸出或標(biāo)準(zhǔn)錯(cuò)誤色瘩。

將日志輸出到控制臺(tái):

```python

import?logging

logging.basicConfig(level=logging.DEBUG)

console_handler?=?logging.StreamHandler()

console_handler.setLevel(logging.DEBUG)

formatter?=?logging.Formatter('%(asctime)s?-?%(levelname)s?-?%(message)s')

console_handler.setFormatter(formatter)

logger?=?logging.getLogger(__name__)

logger.addHandler(console_handler)

logger.debug('勇哥?debug?')

logger.info('勇哥?info?')

logger.warning('勇哥?warning')

logger.error('勇哥?error')

logger.critical('勇哥?critical')

```

輸出結(jié)果:

```plaintext

2023-06-09?10:52:56,493?-?DEBUG?-?勇哥?debug?

DEBUG:__main__:勇哥?debug?

2023-06-09?10:52:56,493?-?INFO?-?勇哥?info?

INFO:__main__:勇哥?info?

2023-06-09?10:52:56,493?-?WARNING?-?勇哥?warning

WARNING:__main__:勇哥?warning

2023-06-09?10:52:56,494?-?ERROR?-?勇哥?error

ERROR:__main__:勇哥?error

2023-06-09?10:52:56,494?-?CRITICAL?-?勇哥?critical

CRITICAL:__main__:勇哥?critical

```

`StreamHandler`對(duì)象添加到日志器處理器中。設(shè)置處理器的級(jí)別和格式史辙,控制輸出的日志級(jí)別和格式聊倔。

### 2.2 文件處理器

`FileHandler`將日志輸出到文件的處理器耙蔑,將日志消息寫入指定的文件甸陌。

將日志輸出到文件:

```python

import?logging

logging.basicConfig(level=logging.DEBUG)

file_handler?=?logging.FileHandler('app.log',?encoding='utf8')?#?不帶編碼會(huì)出現(xiàn)中文亂碼

file_handler.setLevel(logging.DEBUG)

formatter?=?logging.Formatter('%(asctime)s?-?%(levelname)s?-?%(message)s')

file_handler.setFormatter(formatter)

logger?=?logging.getLogger(__name__)

logger.addHandler(file_handler)

logger.debug('勇哥?debug?')

logger.info('勇哥?info?')

logger.warning('勇哥?warning')

logger.error('勇哥?error')

logger.critical('勇哥?critical')

```

![](https://gitee.com/chenyongzhiaaron_admin/image/raw/master/img/log.png)

`FileHandler`對(duì)象添加到日志器中钱豁。日志消息寫入名為`app.log`的文件中牲尺。

### 2.3 其他處理器

除了控制臺(tái)處理器和文件處理器,`logging`模塊還提供了其他處理器溢豆,例如:

* ? `SMTPHandler`:將日志消息通過電子郵件發(fā)送漩仙。

* ? `SocketHandler`:將日志消息發(fā)送到網(wǎng)絡(luò)套接字垮兑。

* ? `SysLogHandler`:將日志消息發(fā)送到系統(tǒng)日志。

* ? 等等雀哨。

你可以根據(jù)需要選擇適合的處理器,并根據(jù)需要配置其級(jí)別衬浑、格式和其他屬性工秩。

## 3. 鍍膜牛刀

`日志過濾器(Log Filters)`用于對(duì)日志進(jìn)行過濾助币,只輸出滿足特定條件的日志消息螟碎。通過添加日志過濾器俭缓,我們可以進(jìn)一步控制哪些日志消息應(yīng)該被處理器處理酥郭。

使用過濾器將日志消息限制在特定級(jí)別的范圍內(nèi):

```python

import?logging

class?LevelFilter(logging.Filter):

????def?__init__(self,?level):

????????super().__init__()

????????self.level?=?level

????def?filter(self,?record):

????????return?record.levelno?>=?self.level

logging.basicConfig(level=logging.DEBUG)

console_handler?=?logging.StreamHandler()

console_handler.setLevel(logging.DEBUG)

formatter?=?logging.Formatter('%(asctime)s?-?%(levelname)s?-?%(message)s')

console_handler.setFormatter(formatter)

logger?=?logging.getLogger(__name__)

logger.addHandler(console_handler)

level_filter?=?LevelFilter(logging.WARNING)

logger.addFilter(level_filter)

logger.debug('勇哥?debug')

logger.info('勇哥?info')

logger.warning('勇哥?warning')

logger.error('勇哥?error')

logger.critical('勇哥?critical')

```

`LevelFilter`自定義過濾器惜姐。該過濾器接受一個(gè)日志級(jí)別作為參數(shù)载弄,在`filter`方法中根據(jù)日志記錄的級(jí)別判斷是否應(yīng)該處理該日志記錄撵颊。然后宇攻,我們將過濾器添加到控制臺(tái)處理器中,從而限制了只輸出`WARNING`級(jí)別及以上的日志消息倡勇。

輸出結(jié)果:

```plaintext

2023-06-09?11:17:16,546?-?WARNING?-?勇哥?warning

WARNING:__main__:勇哥?warning

2023-06-09?11:17:16,546?-?ERROR?-?勇哥?error

ERROR:__main__:勇哥?error

2023-06-09?11:17:16,546?-?CRITICAL?-?勇哥?critical

CRITICAL:__main__:勇哥?critical

```

`DEBUG`和`INFO`級(jí)別的日志消息被過濾掉了逞刷。

## 牛刀裝鞘

封裝日志功能來提供更方便和可復(fù)用的日志記錄接口

```python

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

#?@Time?:?2019/11/18?10:17

#?@Author?:?勇哥

#?@Email?:?262667641@qq.com

#?@File?:?logger.py.py

#?@Project?:?risk_api_project

import?logging

import?time

from?logging?import?handlers

from?common.base_datas?import?BaseDates

class?MyLog:

????level_relations?=?{

????????"debug":?logging.DEBUG,

????????"info":?logging.INFO,

????????"warning":?logging.WARNING,

????????"error":?logging.ERROR,

????????"critic":?logging.CRITICAL

????}??#?日志級(jí)別關(guān)系映射

????def?my_log(self,?msg,?level="error",?when="D",?back_count=10):

????????"""

????????實(shí)例化?TimeRotatingFileHandler

????????interval?是時(shí)間間隔,?backupCount?是備份文件的個(gè)數(shù)妻熊,如果超過這個(gè)個(gè)數(shù)夸浅,就會(huì)自動(dòng)刪除,when?是間隔的時(shí)間單位扔役,單位有以下幾種

????????S?秒

????????M?分

????????H?小時(shí)

????????D?天

????????每星期(interval?==?0?時(shí)代表星期一

????????midnight?每天凌晨

????????"""

????????file_name?=?BaseDates.log_path

????????my_logger?=?logging.getLogger()??#?定義日志收集器?my_logger

????????my_logger.setLevel(self.level_relations.get(level))??#?設(shè)置日志級(jí)別

????????format_str?=?logging.Formatter(

????????????"%(asctime)s-%(levelname)s-%(filename)s-[?line:%(lineno)d?]?-?日志信息:%(message)s")??#?設(shè)置日志格式

????????#?創(chuàng)建輸出渠道

????????sh?=?logging.StreamHandler()??#?往屏幕輸出

????????sh.setFormatter(format_str)??#?設(shè)置屏幕上顯示的格式

????????current?=?time.strftime("%Y-%m-%d",?time.localtime())??#?設(shè)置當(dāng)前日期

????????if?level?==?"error":

????????????th?=?handlers.TimedRotatingFileHandler(filename=f'{file_name}/{current}_{level}.log',?when=when,

???????????????????????????????????????????????????backupCount=back_count,?encoding="utf-8")

????????else:

????????????th?=?handlers.TimedRotatingFileHandler(filename=file_name?+?"/{}_info.log".format(current),?when=when,

???????????????????????????????????????????????????backupCount=back_count,

???????????????????????????????????????????????????encoding="utf-8")??#?往文件里寫日志

????????th.setFormatter(format_str)??#?設(shè)置文件里寫入的格式

????????my_logger.addHandler(sh)??#?將對(duì)象加入logger里

????????my_logger.addHandler(th)

????????if?level?==?"debug":

????????????my_logger.debug(msg)

????????elif?level?==?"error":

????????????my_logger.error(msg)

????????elif?level?==?"info":

????????????my_logger.info(msg)

????????elif?level?==?"warning":

????????????my_logger.warning(msg)

????????else:

????????????my_logger.critical(msg)

????????my_logger.removeHandler(sh)

????????my_logger.removeHandler(th)

????????logging.shutdown()

????def?decorator_log(self,?msg=None):

????????def?warp(fun):

????????????def?inner(*args,?**kwargs):

????????????????try:

????????????????????return?fun(*args,?**kwargs)

????????????????except?Exception?as?e:

????????????????????self.my_log(f"{msg}:?{e}",?"error")

????????????return?inner

????????return?warp

if?__name__?==?'__main__':

????#?for?i?in?range(2):

????#?????MyLog().my_log("hhhh{}".format(i),?"info")

????#?????time.sleep(0.04)

????@MyLog().decorator_log(“”知錯(cuò)了嘛?)

????def?add():

????????print("試一下")

????????raise?"不好使坯钦,異常了。"

```

輸出:

![](https://gitee.com/chenyongzhiaaron_admin/image/raw/master/img/Snipaste_2023-06-09_11-28-54.png)

## 總結(jié)

以上就是勇哥今天為各位小伙伴準(zhǔn)備的內(nèi)容,如果你想了解更多關(guān)于Python自動(dòng)化測(cè)試的知識(shí)和技巧,歡迎關(guān)注我: 公眾號(hào)\博客\CSDN\B站:測(cè)試玩家勇哥;我會(huì)不定期地分享更多的精彩內(nèi)容。感謝你的閱讀和支持粘室!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌埠啃,老刑警劉巖叹螟,帶你破解...
    沈念sama閱讀 219,589評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異明垢,居然都是意外死亡溯革,警方通過查閱死者的電腦和手機(jī)俱尼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門货矮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來劫灶,“玉大人枪汪,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 165,933評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵跛蛋,是天一觀的道長此衅。 經(jīng)常有香客問我墨微,道長谴分,這世上最難降的妖魔是什么翘魄? 我笑而不...
    開封第一講書人閱讀 58,976評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮捡多,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘憎账。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,999評(píng)論 6 393
  • 文/花漫 我一把揭開白布蒋情。 她就那樣靜靜地躺著沟沙,像睡著了一般。 火紅的嫁衣襯著肌膚如雪哟绊。 梳的紋絲不亂的頭發(fā)上铣耘,一...
    開封第一講書人閱讀 51,775評(píng)論 1 307
  • 那天踪区,我揣著相機(jī)與錄音缎岗,去河邊找鬼眷细。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播仙蛉,決...
    沈念sama閱讀 40,474評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼荠瘪,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起哀墓,我...
    開封第一講書人閱讀 39,359評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤趁餐,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后麸祷,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體澎怒,經(jīng)...
    沈念sama閱讀 45,854評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,007評(píng)論 3 338
  • 正文 我和宋清朗相戀三年阶牍,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了喷面。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,146評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡走孽,死狀恐怖惧辈,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情磕瓷,我是刑警寧澤盒齿,帶...
    沈念sama閱讀 35,826評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站困食,受9級(jí)特大地震影響边翁,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜硕盹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,484評(píng)論 3 331
  • 文/蒙蒙 一符匾、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧瘩例,春花似錦啊胶、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至聘惦,卻和暖如春某饰,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背部凑。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評(píng)論 1 272
  • 我被黑心中介騙來泰國打工露乏, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人涂邀。 一個(gè)月前我還...
    沈念sama閱讀 48,420評(píng)論 3 373
  • 正文 我出身青樓瘟仿,卻偏偏與公主長得像,于是被迫代替她去往敵國和親比勉。 傳聞我的和親對(duì)象是個(gè)殘疾皇子劳较,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,107評(píng)論 2 356

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

  • 一驹止、給路由添加正則表達(dá)式 給路由參數(shù)添加正則表達(dá)式的原因:在實(shí)際開發(fā)時(shí),url中往往會(huì)帶有很多的參數(shù)观蜗,例如:/ad...
    IIronMan閱讀 1,629評(píng)論 1 12
  • From:Python之日志處理(logging模塊) - 云游道士 - 博客園 https://www.cnbl...
    vigny的先生閱讀 2,686評(píng)論 3 5
  • 本文翻譯自logging howto 基礎(chǔ)教程 日志是跟蹤軟件運(yùn)行時(shí)發(fā)生事件的一種手段臊恋。Python開發(fā)者在代碼中...
    大蟒傳奇閱讀 4,255評(píng)論 0 17
  • 日志 日志是跟蹤軟件運(yùn)行時(shí)所發(fā)生的事件的一種方法。軟件開發(fā)者在代碼中調(diào)用日志函數(shù)墓捻,表明發(fā)生了特定的事件抖仅。事件由描述...
    桃子味的白開水閱讀 236評(píng)論 0 0
  • 一、logging模塊 日志的作用可以簡單總結(jié)為以下3點(diǎn):1砖第、程序調(diào)試2撤卢、了解軟件程序運(yùn)行情況,是否正常3梧兼、軟件程...
    oopp8閱讀 5,017評(píng)論 0 2