成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

神器 Logging,你真的了解嗎?

開發 前端
logging 是 python 標準模塊,用于記錄和處理程序中的日志。功能很強大,官方文檔很詳細,網上也有大量的說明和教程,但是對很多初次接觸的同學來說,存在一些障礙。

[[434022]]

本文轉載自微信公眾號「Python技術」,作者派森醬。轉載本文請聯系Python技術公眾號。

logging 是 python 標準模塊,用于記錄和處理程序中的日志。

功能很強大,官方文檔很詳細,網上也有大量的說明和教程,但是對很多初次接觸的同學來說,存在一些障礙。

一是因為標準庫文檔太過繁瑣,需要較高的理論基礎,著急用時,常常被文檔搞暈。

二是大部分說明材料要么是官方文檔的羅列,要么是簡單的應用,對實際應用幫助不大。

今天,我們從應用上的一些問題開始,探討一下日志神器 logging 極其背后的原理,讓它能真正的幫助到我們。

該用 logging.debug 還是 logger.debug ?

debug 是日志模塊中的一個日志等級為 DEBUG 的日志生成方法,還有 info、warning、error、critial,這里用 debug 做為代表進行說明。

我們常會看到,一會兒用 logging.debug 記錄日志,一會兒又用 logger.debug 記錄日志,到底該用什么?

先看代碼:

  1. import logging 
  2.  
  3. logging.debug('調試信息'
  4.  
  5. logger = logging.getLogger() 
  6.  
  7. logger.debug('調試信息'

首先 logging 是作為一個模塊被引入的。logging.debug 用的是 logging 模塊的模塊方法。

logger 是用 logging.getLogger() 生成的,是一個 日志對象,logger.debug 調用的是 logger 這個日志對象的方法。

上面的代碼中 logging.debug 和 logger.debug 的效果完全是一樣的。

這是因為,為了讓開發者方便使用,logging 模塊提供了一些列模塊方法,如 debug,在引入模塊后,就可以直接使用。這樣開發者就不必關心日志模塊的細節,像用 print 一樣輸出日志。

如果需要對日志輸出進行定制化,比如將日志輸出到文件中,過濾某些級別的日志,就需要創建或者得到一個實際的日志對象來處理,如上面代碼中通過 getLogger 方法得到的日志對象。

我們知道,程序設計里要避免重復的設計,如果模塊方法采用一套機制,日志對象上的方法采用另一套機制,就會出現重復造輪子的問題。

所以在使用模塊方法,logging 其實創建了一個日志對象 —— root logger。

也就是 logging.debug 這個調用,實質上是調用 root logger 的日志方法。

相當于默認情況下 root logger 會作為日志處理對象。

如何獲得 root logger 對象呢?

通過不帶參數的 logging.getLogger() 方法獲得。

那么 logging.debug 和 rootLogger.debug 是一會事,可以理解(但不嚴謹)為 logging.debug 是 rootlogger.debug 的快捷方式。

日志樹

稍加留意就會觀察到,程序是有層次結構的,通過相互引用,調用形成一個樹狀結構。

程序加載的地方是樹根,比如 python 中要運行的代碼文件,我們稱之為 main。從樹根開始長出其他枝葉。對于一個模塊來說,又會形成一個自己的樹。

如何用日志清楚地記錄層次結構呢?

雖然直接打印出調用堆棧也可以看到調用結構,不過不太直觀,缺乏業務邏輯描述。

而用 print 來打印出層次結構,需要編寫大量的代碼才能反射出(通過運行狀態獲取代碼狀態的一種方式)調用環境。

logging 提供了完畢的解決方案。

前面提到的 root logger 就是整個日志樹的根,其他所有的 logger 都是從 root logger 伸展出來的枝葉。只要通過 getLogger(loggername) 方法獲得的 logger 對象,都是伸展自 root logger 的。

如何向下伸展呢?

很簡單,就像引用模塊的層次關系一樣,用 . 分隔層次就好了,例如:

  1. logger = logging.getLogger('mod1.mod2.mod3'
  2.  
  3. logger.debug("調試信息"

語句 logging.getLogger('mod1.mod2.mod3') 實際上創建了三個 logger,名稱分別是 mod1、mod1.mod2 和 mod1.mod2.mod3

mod1 為根,mod1.mod2 為子,mod1.mod2.mod3 為孫。

如果在 mod1 上設置了日志處理器(handler),那么其他兩個的日志對象都會用到這個處理器。

這樣不但記錄的日志更清晰而且,可以為同一個根的日志對象設置可以共享的日志處理方式。

這樣感覺也不方便,需要些那么多層次,如何才能更方便呢?在下面的 實踐參考 里會有說明。

logging.basicConfig 的功與過

說完了日志模塊的樹狀結構,來看看一個很常用的設置方法 basicConfig。

它可以方便的設置日志處理和記錄方式,如沒必要,不用為每個日志對象單獨設置。

根據第一節的分析,我們知道,直接使用模塊方法,用的其實是 root logger,那么就能明白 basicConfig 設置了 root logger 的日志處理方式。

這就意味著:

一旦設置了通過 logging.basicConfig 設置了日志處理方式,其他所有日志都很受到影響。

另外 basicConfig 是個一次性方法,即:

只有第一次設置有效,其后設置無效

本來是個一勞永逸的方法。

但用錯了地方,就會很麻煩。

看下例子:

  1. __all__ = ['Connection''ConnectionPool''logger'
  2.  
  3. warnings.filterwarnings('error', category=pymysql.err.Warning) 
  4. # use logging module for easy debug 
  5. logging.basicConfig(format='%(asctime)s %(levelname)8s: %(message)s', datefmt='%m-%d %H:%M:%S'
  6. logger = logging.getLogger(__name__) 
  7. logger.setLevel('WARNING'

這段代碼中,用 logging.basicConfig 對日志做了設置,意思是后面的日志都按照這樣的方式輸出。

但它是一個底層模塊 —— pymysqlpool[1]。

pymysqlpool 封裝了 pymysql[2] 模塊,提供了鏈接池特性,在多線程處理數據庫場景下很有用。

也就是說,pymysqlpool 只會被引用加載,不會作為 main 被加載,這就比較尷尬了,因為 main 中對日志的設置就沒有效果。

作為一個服務類模塊(相對于業務的底層模塊),不要通過 basicConfig 來設置日志模式,要么通過自己專屬的日志對象來設置,要么不去設置,統一交給 main 去設置,例如:

  1. logger = logging.getLogger(__name__) 
  2.  
  3. fmt = logging.Formatter("%(asctime)s %(levelname)8s: %(message)s", datefmt='%m-%d %H:%M:%S'
  4. hdl = logging.StreamHandler() 
  5. hdl.setFormatter(fmt) 
  6. logger.addHandler(hdl) 
  7.  
  8. logger.setLevel('WARNING'

如果為了測試,可以在測試的初始化方法中,使用 basicConfig 來設置,因為測試時,模塊往往是被作為程序入庫加載的。

實踐參考

了解了日志模塊的一下特性,和其中的原理之后,這里有幾條實踐參考。

  • 不要再子模塊中使用 logging.basicConfig 設置日志模式
  • 強烈建議在任何模塊中通過 logger = logging.getLogger(__name__) 來創建日志對象 因為 __name__ 代表的就是模板被加載的引用名稱。

例如 from a.b.c import b 模塊 c 中的 __name__ 值就為 a.b.c。

  • 而且這個引用名稱剛好符合 logger 定義的層次結構。

通過命令行參數設置不同類型的日志,見代碼:

  1. import logging 
  2. import argparse 
  3. logger = logging.getLogger(__name__) 
  4.  
  5. def create_args_parse(): 
  6.     parser = argparse.ArgumentParser(description="參數列表"
  7.     parser.add_argument('-d''--debug'action='store_true', help='調試模式'
  8.     # 加入其他命令行參數 
  9.          
  10.     return parser 
  11.  
  12. def set_logger(debug): 
  13.     formatter = logging.Formatter('%(asctime)s - %(levelname)8s - %(name)s - %(filename)s:%(lineno)d - %(thread)d- %(funcName)s:\t%(message)s'
  14.     if debug: 
  15.         hd = logging.StreamHandler() 
  16.         logger.setLevel(logging.DEBUG) 
  17.         hd.setFormatter(formatter) 
  18.     else
  19.         hd = logging.FileHandler(f'{__name__}.log''a', encoding='utf-8'
  20.         logger.setLevel(logging.INFO) 
  21.         hd.setFormatter(formatter) 
  22.     logger.addHandler(hd) 
  23.  
  24. if __name__ == '__main__'
  25.    parser = create_args_parse() 
  26.    args = parser.parse_args() 
  27.    debug = args.debug 
  28.    set_logger(debug) 
  29.    ... 

代碼有點長,但不難懂。

  • create_args_parse 方法用于解析命令行參數,其中定義了一個 debug 參數,表示開啟調試模式
  • set_logger 方法接收一個是否為調試模式的參數,根據是否為調試模式,設置不同的日志模式
  • main 中,首先調用 create_args_parse 獲得命令行參數對象,然后從中解析出參數,提取 debug 模式,傳送給 set_logger 方法,設置日志模式
  • 這樣只需要在運行程序時,加上參數 -d 就可以讓日志打印到終端上,不加,日志就會自動去 __main__.log 日志文件中去了。

總結

python 為我們提供了很多便利的功能,有些需要真的用到才能有所體會,所以在遇到問題時,需要多研究一下,找到其中的特點和內在的原理或機制,這樣就能更好的應用了。

在我理解了 logging 的原理之后,已經在我的很多項目中發揮了巨大作用,而且再也不必糾結于怎么用,如何更合理等這些問題了。

期望這篇文章也能對你有所幫助,比心。

參考資料

[1]pymysqlpool: https://pypi.org/project/pymysql-pool/

[2]pymysql: https://pypi.org/project/PyMySQL/

 

責任編輯:武曉燕 來源: Python技術
相關推薦

2022-07-26 00:00:22

HTAP系統數據庫

2014-04-17 16:42:03

DevOps

2021-01-15 07:44:21

SQL注入攻擊黑客

2014-11-28 10:31:07

Hybrid APP

2023-03-16 10:49:55

2020-02-27 10:49:26

HTTPS網絡協議TCP

2019-09-16 08:40:42

2012-05-31 09:56:54

云安全

2023-10-24 08:53:24

FutureTas并發編程

2019-11-06 09:52:01

JavaScript單線程非阻塞

2022-03-14 07:53:27

ELTETL大數據

2022-12-12 08:46:11

2015-07-31 10:35:18

實時計算

2017-10-18 22:01:12

2025-01-03 08:09:15

2024-02-02 08:50:20

Node.js元數據自動化

2021-11-26 08:07:16

MySQL SQL 語句數據庫

2022-06-29 10:21:33

3d打印輔助工具

2023-11-01 13:48:00

反射java

2016-01-13 10:34:57

物聯網物聯網技術
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩高清一区 | 在线观看中文视频 | 草久久免费视频 | 7777在线| 在线观看亚洲专区 | 狠狠操电影 | 午夜爽爽爽男女免费观看影院 | 性做久久久久久免费观看欧美 | 亚洲成人精品一区 | 欧美日高清 | 美女三区 | dy天堂| 国产精品网址 | 天堂网av在线 | 色视频www在线播放国产人成 | 国产高清视频一区 | 一区二区高清在线观看 | 另类视频在线 | 毛片一级网站 | 中文字幕 在线观看 | 在线视频91 | 91精品久久久久久久久久入口 | 国产精品久久久久久亚洲调教 | 一区二区三区免费在线观看 | 国产精品视频免费看 | 97超碰人人| 日本不卡一区二区三区在线观看 | 欧美a区 | 亚洲人一区| 日韩欧美视频在线 | 97国产精品| 三区四区在线观看 | 精品欧美一区二区精品久久久 | 日韩在线一区二区三区 | www视频在线观看 | 在线播放精品视频 | 国产美女永久免费无遮挡 | 国产高清av免费观看 | 久久久精品一区 | 狠狠干综合视频 | 97精品久久 |