Python的logging詳解

2021-03-02 iTesting

Print不用的好好的麼,為什麼要用logging?因為調試時,print語句需要改動代碼,調試完你還得刪除掉,萬一忘記怎麼辦?還有線上代碼運行時你想知道當時發生了什麼,logging是最好的辦法。

先看下logging的簡單用法:

import logginglogging.basicConfig(level=logging.DEBUG)logger = logging.getLogger(__name__)logger.info('Start logging')msg = 'test'logger.debug('message: %s', msg)logger.info('End logging')

logging主要由以下模塊組成:

Loggers: 可供程序直接調用的接口。可以直接向logger寫入日誌信息。logger並不是直接實例化使用的,而是通過logging.getLogger(name)來獲取對象,事實上logger對象是單例模式,logging是多線程安全的,也就是無論程序中哪裡需要打日誌獲取到的logger對象都是同一個。

每個logger都有一個日誌的級別。logging中定義了如下級別:

LevelNumeric valueCRITICAL50ERROR40WARNING30INFO20DEBUG10NOTSET0

那麼什麼時候用何種界別的log呢?

LevelWhen it’s usedDEBUGDetailed information, typically of interest only when diagnosing problems.INFOConfirmation that things are working as expected.WARNINGAn indication that something unexpected happened, or indicative of some problem in the near future (e.g. 『disk space low』). The software is still working as expected.ERRORDue to a more serious problem, the software has not been able to perform some function.CRITICALA serious error, indicating that the program itself may be unable to continue running.

當一個logger收到日誌信息後先判斷是否符合level,如果決定要處理就將信息傳遞給Handlers進行處理。

Handlers: 決定將日誌記錄分配至正確的目的地

將logger發過來的信息進行準確地分配,送往正確的地方。舉個慄子,送往控制臺或者文件或者both或者其他地方(進程管道之類的)。它決定了每個日誌的行為,是之後需要配置的重點區域。

每個Handler同樣有一個日誌級別,一個logger可以擁有多個handler也就是說logger可以根據不同的日誌級別將日誌傳遞給不同的handler。當然也可以相同的級別傳遞給多個handlers這就根據需求來靈活的設置了

Filters: 提供更細粒度的日誌是否輸出的判斷來決定日誌是否需要列印。原則上handler獲得一個日誌就必定會根據級別被統一處理,但是如果handler擁有一個Filter可以對日誌進行額外的處理和判斷。例如Filter能夠對來自特定源的日誌進行攔截or修改甚至修改其日誌級別(修改後再進行級別判斷)。

logger和handler都可以安裝filter甚至可以安裝多個filter串聯起來。

Formatters: 制定最終記錄列印的格式布局。Formatter會將傳遞來的信息拼接成一條具體的字符串,默認情況下Format只會將信息%(message)s直接列印出來。Format中有一些自帶的LogRecord屬性可以使用,如下表格:

Attribute nameFormatDescriptionasctime%(asctime)sHuman-readable time when the LogRecord was created. By default this is of the form 『2003-07-08 16:49:45,896』 (the numbers after the comma are millisecond portion of the time).created%(created)fTime when the LogRecord was created (as returned by time.time()).filename%(filename)sFilename portion of pathname.funcName%(funcName)sName of function containing the logging call.levelname%(levelname)sText logging level for the message ('DEBUG', 'INFO', 'WARNING','ERROR', 'CRITICAL').levelno%(levelno)sNumeric logging level for the message (DEBUG, INFO, WARNING, ERROR, CRITICAL).lineno%(lineno)dSource line number where the logging call was issued (if available).module%(module)sModule (name portion of filename).msecs%(msecs)dMillisecond portion of the time when the LogRecord was created.message%(message)sThe logged message, computed as msg % args. This is set whenFormatter.format() is invoked.name%(name)sName of the logger used to log the call.pathname%(pathname)sFull pathname of the source file where the logging call was issued (if available).process%(process)dProcess ID (if available).processName%(processName)sProcess name (if available).relativeCreated%(relativeCreated)dTime in milliseconds when the LogRecord was created, relative to the time the logging module was loaded.thread%(thread)dThread ID (if available).threadName%(threadName)sThread name (if available).

一個Handler只能擁有一個Formatter 因此如果要實現多種格式的輸出只能用多個Handler來實現。

如何使用logging模塊呢?

1. 定義formatter——決定輸出格式

2. 定義handler——決定輸出位置(console或者文件)

3. 定義logger——最終程序調用的日誌接口

4. 將formatter綁定到handler上。

5. 將handler綁定至logger上

這樣就可以使用logger對象進行輸出日誌了。舉例如下:

#encoding: UTF-8import multiprocessingimport loggingimport randomclass LogHandler(object):    def __init__(self, log_level, log_file):        self.log_name = __name__        self.log_level = log_level.upper()        self.log_file = log_file    def get_logger(self):        # 1.定義handler的輸出格式(formatter)        formatter = logging.Formatter('%(asctime)s - %(name)s - %(funcName)s - %(levelname)s - %(message)s')        # 2. 創建一個handler,用於寫入日誌文件        fh = logging.FileHandler(self.log_file)        fh.setLevel(self.log_level)        # 再創建一個handler,用於輸出到控制臺        ch = logging.StreamHandler()        ch.setLevel(self.log_level)        # 3. 創建一個logger        logger = logging.getLogger(self.log_name)        logger.setLevel(self.log_level)        # 4. 綁定formatter到handle上        fh.setFormatter(formatter)        ch.setFormatter(formatter)        # 5.綁定handler到logger上        logger.addHandler(fh)        logger.addHandler(ch)        return loggerdef func():    log_handle.info("test starts")    log_handle.debug("111")    product = random.randint(0, 10)    msg = "test finished %s" %product    log_handle.warn(msg)    try:        open("c:\notexist.rt")    except:        log_handle.error('af', exc_info=True)if __name__ == "__main__":    log_handle = LogHandler( "info", r"c:\1.txt").get_logger()    func()

我們看下輸出:

2016-12-01 16:19:58,017 - __main__ - func - INFO - test starts

2016-12-01 16:19:58,019 - __main__ - func - WARNING - test finished 0

2016-12-01 16:19:58,019 - __main__ - func - ERROR - af

Traceback (most recent call last):

  File "E:/qa_report_auto_generator/l2.py", line 47, in func

    open("c:\notexist.rt")

IOError: [Errno 22] invalid mode ('r') or filename: 'c:\notexist.rt'

因為我們log level 設置的是info,所以看到紅色部分debug未列印出,黃色高亮部分是為了把traceback信息dump到logger裡, 這個很有用處。

__init__self.log_name = __name__ 這句話是把當前的module名作為log名字。

舉例來說,如果你把func函數放到另外一個test.pyfile裡,那麼引用它列印出來的log name就

是test.

歡迎關注 iTesting. 
iTesting致力於軟體測試技術分享, 包括不限於 Web測試, Mobile測試, API測試, 性能測試以及測試職位推薦.

長按下圖二維碼,在彈出菜單中選擇「識別圖中二維碼」關注本公眾號.


更多內容,敬請期待

相關焦點

  • python中logging模塊詳解
    為什麼需要logging模塊用python寫代碼的時候,想看哪裡的輸出直接print就可以了。
  • Python logging 模塊詳解
    logging# 列印日誌級別def test_logging(): logging.debug('Python debug') logging.info('Python info') logging.warning('Python warning') logging.error('Python Error') logging.critical('Python
  • Python之日誌處理(logging模塊)
    Logging 中幾種級別:DEBUG < INFO < WARNING < ERROR < CRITICALlogging模塊是python內置的標準模塊,主要用於輸出運行日誌,可以設置輸出日誌的等級、日誌保存路徑、日誌文件和回滾等;可以說,logging模塊主要由4部分組成:
  • python學習之日誌輸出格式logging.basicConfig函數的使用
    python的logging.basicConfig函數 ,使用時粘貼到用例前,就可以打log了。logging模塊是python內置的標準模塊,主要用於輸出運行日誌,可以設置輸出日誌的等級,日誌保存路徑,日誌文件回滾等日誌等級:(從低到高)debug:調試代碼用的,信息比較詳細info:輸出正確的信息,按照正常的代碼運行
  • Python Logging 模塊完全解讀
    你也可以在 logging 中包含 traceback 信息。不管是小項目還是大項目,都推薦在 Python 程序中使用 logging。本文將簡單清晰地介紹如何使用 logging 模塊。為什麼使用 logging?當你運行一個 Python 腳本時,你可能想要知道腳本的哪個部分在執行,並且檢視變量的當前值。通常,可以只使用 print() 列印出你想要的信息。
  • python乾貨分享:使用logging記錄日誌信息
    StreamHandler發送錯誤信息到流,而FileHandler類用於向文件輸出日誌信息,這兩個handler定義在logging的核心模塊中c其他的handler定義在logging.handles 模塊中,如 HTTPHandler、SocketHandler。
  • 有了它,可以把Python裡Logging模塊扔掉了!
    原來我們在 Python 中寫日誌,使用的是 Python 自帶的 log
  • 詳解Python的裝飾器
    (參見https://betacat.online/posts/2016-10-23/python-closure/)帶參數的裝飾器假設我們前文的裝飾器需要完成的功能不僅僅是能在進入某個函數後打出log信息,而且還需指定log的級別,那麼裝飾器就會是這樣的。
  • Python與SEO應用第二期
    一、講義說明本期培訓主要是面向想通過python來提高SEO工作效率的SEOer或者是對python爬蟲感興趣的目標人群。培訓的主要內容是學習如何通過python來開發各種SEO工具,以及python爬蟲的開發。
  • 致Python愛好者:你要的Python,Pandas和Tensorflow的秘笈來了
    概要:不管你是python大牛,小牛,總會在無論是數據分析,還是人工智慧工作中遇到問題。無論你是數據分析還是深度學習,都需要一些獨門秘笈來解決自己的問題。本文就是為你而量身定製。, formatter = formatter_log) …… if mode == tf.estimator.ModeKeys.EVAL: return tf.estimator.EstimatorSpec(mode, loss = loss, evaluation_hooks = [logging_hook])
  • Python每天一分鐘:pass與assert語句詳解
    下面將為大家詳細介紹python中的pass和assert語句的功能與示例。python中的pass和assert語句pass語句詳解很多程式語言都提供了「空語句」支持,如C/C++/JAVAPython 也不例外,但由於Python的設計中剔除了分號作為終結代碼語句的支持, 所以python設計了單獨的關鍵字來支持空語句,即pass 語句.下面為大家演示pass語句的代碼:
  • 史上最全的 python 基礎知識匯總篇,沒有比這再全面的了,建議收藏
    爬蟲(五十九)正則表達式語法(五十)定投的好處爬蟲(五十八)正則表達式(四十九)定投,做一個聰明的『懶人』爬蟲(五十七)通用標準庫 logging類和對象object (二十二)爬蟲 (三十) python 類和對象object (二十一)爬蟲 (二十九) 命名空間和作用域 (二十)爬蟲 (二十八) 九淺一深 lambda 函數 (十九)
  • 【Python】建立gRPC服務端與.Net Core 客戶端
    1.更新pip python -m pip install --upgrade pip2.安裝grpc python -m pip install grpcio3.安裝gRPC-tool python服務端代碼 cd python-dirpython -m grpc_tools.protoc -I ..
  • python:pop函數詳解 - 二進位01
    pop函數詳解今天我為大家講解python中pop函數的使用。#python#簡介——pop()函數是python解釋器的內置方法,可作用於列表,字典。popitem喜歡python的小夥伴關注我吧
  • 【python】命令行參數argparse用法詳解
    憂慮的;不安的;敏悟的;知曉的推薦閱讀:精彩知識回顧【珍藏版】長文詳解python正則表達式這些神經網絡調參細節,你都了解了嗎談談我在自然語言處理入門的一些個人拙見大數定律和中心極限定理的區別和聯繫深度學習之激活函數詳解深度學習之卷積神經網絡CNN理論與實踐詳解深度學習之RNN、LSTM及正向反向傳播原理
  • Python中break語句用法詳解!
    這篇文章主要介紹了詳解Python中break語句的用法,是Python入門的呼出知識,需要的朋友可以參考下 在Python中的break
  • Python函數詳解一(函數參數、變量作用域)
    Python函數函數是python程序的重要組成部分。所謂函數就是實現某一特定功能的代碼段,可重複使用,提高了代碼的利用率。
  • Python 裝飾器填坑指南 | 最常見的報錯信息、原因和解決方案
    裝飾器學習資料,推薦參考 RealPythonhttps://realpython.com/primer-on-python-decorators/本文主要匯總記錄 Python 裝飾器的常見踩坑經驗,列舉報錯信息、原因和解決方案,供大家參考。
  • 【python】讀取json文件
    JSON在python中分別由list和dict組成。這是用於序列化的兩個模塊:json: 用於字符串和python數據類型間進行轉換pickle: 用於python特有的類型和python的數據類型間進行轉換Json模塊提供了四個功能:dumps、dump、loads、loadpickle模塊提供了四個功能:dumps、dump、loads、load細節注意:
  • 一個入門級python爬蟲教程詳解
    這篇文章主要介紹了一個入門級python爬蟲教程詳解,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑑價值,需要的朋友可以參考下