Python Logging 日誌記錄入門

Python Logging原來真的遠比我想象的要複雜不少不少,學習路線堪比git。可是又繞不過去,alternatives又少,因此必需要予以重視,踏踏實實認認真真的來好好學學才行。

學習Logging的目的:
簡單腳本還好,print足夠。
可是稍微複雜點,哪怕是三四個文件加起來兩三百行代碼,調試也開始變複雜起來了。
再加上若是是後臺長期運行的那種腳本,運行信息的調查更是複雜起來。
一開始我還在各類查crontab的日誌查看,或者是python後臺運行查看,或者是python stdout的獲取等等,全都找錯了方向。
真正的解決方案在於正確的logging。
記錄好了的話,我不須要去找python的控制檯輸出stdout,也不須要找crontab的日誌,只須要查看log文件便可。
下面是python的logging學習記錄。python

最簡單的日誌輸出(無文件記錄)

import logging
 
logging.error("出現了錯誤")
logging.info("打印信息")
logging.warning("警告信息")

首先,忘掉logging.info()! 忘掉logging.basicConfig()!

網上各類關於python logging的文章實在是太不體諒新手了,logging這麼複雜的東西居然想表現得很簡單,還用各類簡單的東西作假象。
實際上咱們真正要用起來的日誌,絕對是不會直接用logging.info()logging.basicConfig()這樣的,這是此模塊的官方推出來迷惑人的——看似讓你一鍵上手,快速看到結果,可是跟實際真的不搭!
因此爲了後面解釋起來輕鬆,必須先警告這點:忘記它們倆!
記住,惟一要用到logging.什麼的,就只有logging.getLogger()這一次。git

瞭解logging的工做流

不想上流程圖一類的東西,那樣反而更迷糊。
簡單說吧:
logging模塊是會自動將你自定製的logger對象全局化的,
也就是說,
你在本身的模塊裏只要定義了一次某個logger,好比叫log,那麼只要是在同一個模塊中運行的其餘文件都能讀取到它。
好比說,你在主文件main.py中自定義了一個logger,可能設置了什麼輸出文件、輸出格式什麼的,而後你在main.py中會引用一些別的文件或模塊,好比sub.py,那麼在這個sub.py中你什麼都不用設置,只要用一句logger = logging.getLogger('以前在main.py定義的日誌名')便可得到以前的一切自定義設置。函數

固然,被調用的文件(先稱爲子模塊)中,用logging.getLogger('日誌名')時,最好在日誌名後加一個.子名稱這樣的,好比main.sub。這樣輸出的時候就會顯示出來某條日誌記錄是來自於這個文件裏了。固然,.前面的父級logger必須名字一致,是會被識別出來的!
而後,子日誌還能夠再子日誌,甚至一個子模塊能夠再讓全部函數各又一個子子日誌,好比main.sub.func1這樣的。logging都會根據.識別出來上下級關係的。學習

這樣一說,實際上也就是class類繼承的那種機制了。你按照父級名稱繼承,而後還能夠改寫本身的新設置等。測試

瞭解了這些概念之後,才能來談代碼。實際上也就好理解多了。調試

設置logger的方法

看來看去,這篇文章說得比較全面也最清楚,如下不少都參考到它的內容:Python 101: An Intro to logging日誌

通常想要自定義一個logger,好比讓它輸出信息時按照什麼格式顯示,輸出到哪一個文件,要不要輸出到屏幕一類,有三種方法能夠達到設置:code

  • 直接在python代碼裏設置
  • 用外部的config.ini文件配置
  • 用python的dict字典配置

三種達到的目的都是同樣的,字典用的人不多也不方便,配置文件比較好用只是.ini的語法不是很方便讀,且不容易作到變量的動態設置,因此通常直接在python代碼裏寫就好。orm

經常使用設置語句

如下是程序主入口文件的通用寫法,注意,必定要在主入口定義好logger,這樣其餘全部的子模塊纔可以繼承到。對象

#   main.py
import logging
import otherMod2   # 等下會調用到的子模塊

def main():
    """
    這個文件是程序的主入口
    """

    define_logger()

    log = logging.getLogger('exampleApp')

    # 輸出信息測試
    logger.info("Program started")
    result = otherMod2.add(7, 8)     # 這個是來自別的模塊的方法
    logger.info("Done!")

def define_logger():
    logger = logging.getLogger("exampleApp")
    logger.setLevel(logging.INFO)

    # 設置輸出格式
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
 
    # 設置日誌文件處理器
    fh = logging.FileHandler("new_snake.log")
    fh.setFormatter(formatter)    # 爲這個處理器添加格式

    # 設置屏幕stdout輸出處理器
    sh  = logging.StreamHandler(stream=None)
    sh.setFormatter(formatter)
 
    # 把處理器加到logger上
    logger.addHandler(fh)
    logger.addHandler(sh)
 
if __name__ == "__main__":
    main()

下面是子模塊中的調用方法(很簡單):

# otherMod2.py
import logging
 
module_logger = logging.getLogger("exampleApp.otherMod2")

def add(x, y):
    # 這裏一句`getLogger`就繼承到父級的logger了
    logger = logging.getLogger("exampleApp.otherMod2.add")

    # 輸出測試
    logger.info("added %s and %s to get %s" % (x, y, x+y))
    return x+y

注意,主文件中,在什麼地方定義logger均可以,能夠在main()裏也能夠在任何單獨的函數或類裏,無所謂。只要在調用子模塊以前定義好了就能夠了。一旦定義過,日誌名就會被記下來,而後子模塊就能夠輕鬆繼承到。

相關文章
相關標籤/搜索