<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
提供紀錄檔記錄的介面和眾多處理模組,供使用者儲存各種格式的紀錄檔,幫助偵錯程式或者記錄程式執行過程中的輸出資訊。
logging 紀錄檔等級分為五個等級,優先順序從高到低依次是 :
**CRITICAL; ** 程式嚴重錯誤
**ERROR; **程式錯誤/部分功能錯誤
**WARNING; **程式有發生錯誤的可能
**INFO; **程式正常執行時的資訊
DEBUG程式偵錯資訊
預設的紀錄檔的記錄等級為 WARNING, 即當紀錄檔的等級大於獲等於 WARNING 時才會被記錄。
一般常用的記錄等級為 INFO,其用於記錄程式的正常執行的一些資訊(類似於print)。
當紀錄檔的等級達到 WARNING 以上時,表明此時程式不能正常執行;
logging.basicConfig(**kwargs)
在沒有顯式的進行建立記錄器(logger)時,會預設建立一個root logger,而logging.basicConfig(**kwargs) 可以建立帶有預設的Formatter的streamHandle並將其新增到根紀錄檔記錄器中來初始化基本設定。
比如
import logging logging.debug('Debug code!') logging.info('Run code!') logging.warning('Watch out!') logging.error('This is an error') logging.critical('This is a ciritical')
上面程式碼中 logging 並沒有顯式的建立logger( logging.getLogger ), 其在直接使用debug(), info(), warning(), error(), critical() 時會使用預設的 root logger,並會自動呼叫 自定義的或者預設的logging.basicConfig(**kwargs) 初始化 root logger。
自定義的 logging.basicConfig(**kwargs) 中的引數 有以下的主要的選項:
引數 | 功能 |
---|---|
filename | 指定儲存紀錄檔的檔名,用指定檔名建立一個FileHandler,記錄的紀錄檔會儲存到該檔案中 |
format | 指定輸出的格式和內容,預設是以冒號分割的levalname、name 和 message |
datefmt | 使用指定的日期/時間格式,與 time.strftime() 所接受的格式相同。 |
level | 指定根紀錄檔記錄器級別,預設為 logging.WARNING |
stream | 指定紀錄檔的輸出流,可以指定輸出到sys.stderr,std.stdout 或 檔案,預設輸出到sys.stderr。使用指定的流初始化StramHandler,注意:stream和filename引數不相容,如果兩者同時使用,則會引發ValueError 錯誤 |
例如下面通過自定義 logging.basicConfig(**kwargs) 來初始化 root logger 來獲得DEBUG級別及以上的紀錄檔記錄並儲存到 log.txt 檔案中。
import logging logging.basicConfig(filename='./log.txt', format='%(asctime)s-%(name)s-%(levelname)s-%(message)s-%(funcName)s:%(lineno)d', level=logging.DEBUG) logging.debug('Debug code!') logging.info('Run code!') logging.warning('Watch out!') logging.error('This is an error') logging.critical('This is a ciritical')
Logger
除了根記錄器(root logger)外,最主要的是可以自己建立紀錄檔記錄器。
通過模組級別的函數 logging.getLogger(name)
範例化記錄器
預設情況下,記錄器採用層級結構,通過 .
來區分不同的層級。比如 有個名叫 foo
的記錄器 則 foo.a
和 foo.b
都是 foo
的子級記錄器。當然,最開始的或者說最上層的記錄器就是 root logger。如果 name=None,構建的是root logger。
可以直接用當前模組的名稱當作記錄器的名字 logging.getLogger(__name__)
子級記錄器通常不需要單獨設定紀錄檔級別以及 Handler,如果子級記錄器沒有單獨設定,則它的行為會委託給父級。比如說,記錄器foo
的級別為INFO,而foo.a
和 foo.b
都不設定紀錄檔級別。此時foo.a
和 foo.b
會遵循foo
的級別設定,即只記錄大於等於INFO級別的紀錄檔;而如果foo也沒設定的話,就會找到根記錄器root logger,root預設的級別為WARGING。
logger類的一些常用的方法
方法 | 功能描述 |
---|---|
Logger.setLevel() | 設定紀錄檔器(Logger)將會處理的紀錄檔訊息級別 |
Logger.addHandler() | 新增一個handler物件 |
Logger.removeHandler() | 移除一個handler物件 |
Logger.addFilter() | 新增一個filter物件 |
Logger.removeFilter() | 移除一個filter物件 |
Logger.debug() | 設定DEBUG級別的紀錄檔記錄 |
Logger.info() | 設定INFO級別的紀錄檔記錄 |
Logger.warning() | 設定WARNING級別的紀錄檔記錄 |
Logger.error() | 設定ERROR級別的紀錄檔記錄 |
Logger.critical() | 設定CRITICAL級別的紀錄檔記錄 |
Logger.exception() | 輸出堆疊追蹤資訊 |
Logger.log() | 設定一個自定義的level引數來建立一個紀錄檔記錄 |
logger 結合 後面要介紹的其他的三個元件可以實現以下的功能:
Handle
處理器;其可以控制記錄的紀錄檔輸出到什麼地方(標準輸出/檔案/...),同時處理器也可以新增 過濾器(filter)和格式控制器(formatter)來控制輸出的內容和輸出的格式。
其具有幾種常見的處理器:
handle 類的一些常用的方法
Handler.setLevel() | 設定處理器將會處理的紀錄檔訊息的最低嚴重級別 |
Handler.setFormatter() | 為處理器設定一個格式物件 |
Handler.addFilter() | 為處理器新增一個過濾器物件 |
Handler.removeFilter() | 為處理器刪除一個過濾器物件 |
logging.StramHandler() | 將紀錄檔訊息傳送到輸出Stream,如std.out,std.err |
logging.FilterHandler() | 將紀錄檔訊息傳送到磁碟檔案,預設情況檔案大小會無線增長 |
RotationFileHandler() | 將紀錄檔訊息傳送到磁碟檔案,支援紀錄檔檔案按大小切割 |
TimeRotatingFileHandler() | 將紀錄檔訊息傳送到磁碟檔案,並支援紀錄檔檔案按時間切割 |
logging.handers.HTTPHandler() | 將紀錄檔訊息通過GET或POST的方式傳送給一個HTTP伺服器 |
logging.handlers.SMTPHandler() | 將紀錄檔訊息傳送email地址 |
Filter
filter元件用來過濾 logger 物件,一個 filter 可以直接新增到 logger物件上,也可以新增到 handler 物件上,而如果在logger和handler中都設定了filter,則紀錄檔是先通過logger的filter,再通過handler的filter。由於所有的資訊都可以經過filter,所以filter不僅可以過濾資訊,還可以增加資訊。
Filter 類的範例化物件可以通過 logging.Filter(name) 來建立,其中name 為 記錄器的名字,如果沒有建立過該名字的記錄器,就不會輸出任何紀錄檔:
filter = logging.Filter("foo.a")
基本過濾器類只允許低於指定的紀錄檔記錄器層級結構中低於特定層級的事件,例如 這個用 foo.a
初始化的過濾器,則foo.a.b
;foo.a.c
等紀錄檔記錄器記錄的紀錄檔都可以通過過濾器,而foo.c
; a.foo
等就不能通過。如果name為空字串,則所有的紀錄檔都能通過。
Filter 類 有 三個方法 :
Formatter
格式化紀錄檔的輸出;範例化:formatter = logging.Formatter(fmt=None,datefmt=None)
; 如果不指明 fmt,將預設使用 ‘%(message)s’ ,如果不指明 datefmt,將預設使用 ISO8601 日期格式。
其中 fmt 引數 有以下選項:
%(name)s | Logger的名字 |
---|---|
%(levelno)s | 數位形式的紀錄檔級別 |
%(levelname)s | 文字形式的紀錄檔級別;如果是logger.debug則它是DEBUG,如果是logger.error則它是ERROR |
%(pathname)s | 呼叫紀錄檔輸出函數的模組的完整路徑名,可能沒有 |
%(filename)s | 呼叫紀錄檔輸出函數的模組的檔名 |
%(module)s | 呼叫紀錄檔輸出函數的模組名 |
%(funcName)s | 呼叫紀錄檔輸出函數的函數名 |
%(lineno)d | 呼叫紀錄檔輸出函數的語句所在的程式碼行 |
%(created)f | 當前時間,用UNIX標準的表示時間的浮 點數表示 |
%(relativeCreated)d | 輸出紀錄檔資訊時的,自Logger建立以 來的毫秒數 |
%(asctime)s | 字串形式的當前時間。預設格式是 “2003-07-08 16:49:45,896”。逗號後面的是毫秒 |
%(thread)d | 執行緒ID。可能沒有 |
%(threadName)s | 執行緒名。可能沒有 |
%(process)d | 程序ID。可能沒有 |
%(message)s | 使用者輸出的訊息; 假如有logger.warning("NO Good"),則在%(message)s位置上是字串NO Good |
例如:
formatter = logging.Formatter('%(asctime)s %(levelname)-8s: %(message)s') # -表示右對齊 8表示取8位元
handler.formatter = formatter
datefmt 引數 有以下選項:
引數 | 含義 |
---|---|
%y | 兩位數的年份表示(00-99) |
%Y | 四位數的年份表示(000-9999) |
%m | 月份(01-12) |
%d | 月內中的一天(0-31) |
%H | 24小時制小時數(0-23) |
%I | 12小時制小時數(01-12) |
%M | 分鐘數(00=59) |
%S 秒 | (00-59) |
例如:
formatter = logging.Formatter('%(asctime)s %(levelname)-8s: %(message)s') # -表示右對齊 8表示取8位元 handler.formatter = formatter
datefmt 引數 有以下選項:
引數 | 含義 |
---|---|
%y | 兩位數的年份表示(00-99) |
%Y | 四位數的年份表示(000-9999) |
%m | 月份(01-12) |
%d | 月內中的一天(0-31) |
%H | 24小時制小時數(0-23) |
%I | 12小時制小時數(01-12) |
%M | 分鐘數(00=59) |
%S 秒 | (00-59) |
例子:
formatter = logging.Formatter("%(asctime)s %(levelname)s %(message)s","%Y%m%d-%H:%M:%S") handler.formatter = formatter
在 loguser.conf 中 寫入相關的資訊
[loggers] keys=root,fileLogger,rotatingFileLogger [handlers] keys=consoleHandler,fileHandler,rotatingFileHandler [formatters] keys=simpleFormatter [logger_root] level=INFO handlers=consoleHandler [logger_fileLogger] level=INFO handlers=fileHandler qualname=fileLogger propagate=0 [logger_rotatingFileLogger] level=INFO handlers=consoleHandler,rotatingFileHandler qualname=rotatingFileLogger propagate=0 [handler_consoleHandler] class=StreamHandler level=INFO formatter=simpleFormatter args=(sys.stdout,) [handler_fileHandler] class=FileHandler level=INFO formatter=simpleFormatter args=("logs/fileHandler_test.log", "a") [handler_rotatingFileHandler] class=handlers.RotatingFileHandler level=WARNING formatter=simpleFormatter args=("logs/rotatingFileHandler.log", "a", 10*1024*1024, 50) [formatter_simpleFormatter] format=%(asctime)s - %(module)s - %(levelname)s -%(thread)d : %(message)s datefmt=%Y-%m-%d %H:%M:%S
from logging import config with open('./loguser.conf', 'r', encoding='utf-8') as f: ## 載入設定 config.fileConfig(f) ## 建立同名Logger,其按照組態檔的handle,formatter,filter方法初始化 logger = logging.getLogger(name="fileLogger")
在 loguser.yaml檔案 中 設定相關資訊
version: 1 disable_existing_loggers: False # formatters設定了紀錄檔輸出時的樣式 # formatters定義了一組formatID,有不同的格式; formatters: brief: format: "%(asctime)s - %(message)s" simple: format: "%(asctime)s - [%(name)s] - [%(levelname)s] :%(levelno)s: %(message)s" datefmt: '%F %T' # handlers設定了需要處理的紀錄檔資訊,logging模組的handler只有streamhandler和filehandler handlers: console: class : logging.StreamHandler formatter: brief level : DEBUG stream : ext://sys.stdout info_file_handler: class : logging.FileHandler formatter: simple level: ERROR filename: ./logs/debug_test.log error_file_handler: class: logging.handlers.RotatingFileHandler level: ERROR formatter: simple filename: ./logs/errors.log maxBytes: 10485760 # 10MB #1024*1024*10 backupCount: 50 encoding: utf8 loggers: #fileLogger, 就是在程式碼中通過logger = logging.getLogger("fileLogger")來獲得該型別的logger my_testyaml: level: DEBUG handlers: [console, info_file_handler,error_file_handler] # root為預設情況下的輸出設定, 當logging.getLogger("fileLoggername")裡面的fileLoggername沒有傳值的時候, # 就是用的這個預設的root,如logging.getLogger(__name__)或logging.getLogger() root: level: DEBUG handlers: [console]
同樣的可以通過匯入 yaml 檔案載入設定
with open('./loguser.yaml', 'r', encoding='utf-8') as f: yaml_config = yaml.load(stream=f, Loader=yaml.FullLoader) config.dictConfig(config=yaml_config) root = logging.getLogger() # 子記錄器的名字與組態檔中loggers欄位內的保持一致 # loggers: # my_testyaml: # level: DEBUG # handlers: [console, info_file_handler,error_file_handler] my_testyaml = logging.getLogger("my_testyaml")
看起來logging要比print複雜多了,那麼為什麼推薦在專案中使用 logging 記錄紀錄檔而不是使用print 輸出程式資訊呢。
相比與print logging 具有以下優點:
https://blog.csdn.net/weixin_41010198/article/details/89356417
https://www.cnblogs.com/chenyibai/p/10676574.html
到此這篇關於Python 內建logging 使用詳細講的文章就介紹到這了,更多相關Python 內建logging內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45