# 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')
```

`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?"不好使坯钦,異常了。"
```
輸出:

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