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("警告信息")
網上各類關於python logging的文章實在是太不體諒新手了,logging這麼複雜的東西居然想表現得很簡單,還用各類簡單的東西作假象。
實際上咱們真正要用起來的日誌,絕對是不會直接用logging.info()
和logging.basicConfig()
這樣的,這是此模塊的官方推出來迷惑人的——看似讓你一鍵上手,快速看到結果,可是跟實際真的不搭!
因此爲了後面解釋起來輕鬆,必須先警告這點:忘記它們倆!
記住,惟一要用到logging.
什麼的,就只有logging.getLogger()
這一次。git
不想上流程圖一類的東西,那樣反而更迷糊。
簡單說吧: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類繼承的那種機制了。你按照父級名稱繼承,而後還能夠改寫本身的新設置等。測試
瞭解了這些概念之後,才能來談代碼。實際上也就好理解多了。調試
看來看去,這篇文章說得比較全面也最清楚,如下不少都參考到它的內容:Python 101: An Intro to logging日誌
通常想要自定義一個logger,好比讓它輸出信息時按照什麼格式顯示,輸出到哪一個文件,要不要輸出到屏幕一類,有三種方法能夠達到設置:code
三種達到的目的都是同樣的,字典用的人不多也不方便,配置文件比較好用只是.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()
裏也能夠在任何單獨的函數或類裏,無所謂。只要在調用子模塊以前定義好了就能夠了。一旦定義過,日誌名
就會被記下來,而後子模塊就能夠輕鬆繼承到。