本篇文章為大家展示了Python 日志模塊詳解及怎么應用,內容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。
目前創(chuàng)新互聯已為千余家的企業(yè)提供了網站建設、域名、網頁空間、網站托管運營、企業(yè)網站設計、金寨網站維護等服務,公司將堅持客戶導向、應用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長,共同發(fā)展。日志概述
百度百科的日志概述:
Windows網絡操作系統(tǒng)都設計有各種各樣的日志文件,如應用程序日志,安全日志、系統(tǒng)日志、Scheduler服務日志、FTP日志、WWW日志、DNS服務器日志等等,這些根據你的系統(tǒng)開啟的服務的不同而有所不同。我們在系統(tǒng)上進行一些操作時,這些日志文件通常會記錄下我們操作的一些相關內容,這些內容對系統(tǒng)安全工作人員相當有用。比如說有人對系統(tǒng)進行了IPC探測,系統(tǒng)就會在安全日志里迅速地記下探測者探測時所用的IP、時間、用戶名等,用FTP探測后,就會在FTP日志中記下IP、時間、探測所用的用戶名等。
我映像中的日志:
查看日志是開發(fā)人員日常獲取信息、排查異常、發(fā)現問題的最好途徑,日志記錄中通常會標記有異常產生的原因、發(fā)生時間、具體錯誤行數等信息,這極大的節(jié)省了我們的排查時間,無形中提高了編碼效率。
日志分類
我們可以按照輸出終端進行分類,也可以按照日志級別進行分類。輸出終端指的是將日志在控制臺輸出顯示和將日志存入文件;日志級別指的是 Debug、Info、WARNING、ERROR以及CRITICAL等嚴重等級進行劃分。
Python 的 logging
logging提供了一組便利的日志函數,它們分別是:debug()、 info()、 warning()、 error() 和 critical()。logging函數根據它們用來跟蹤的事件的級別或嚴重程度來命名。標準級別及其適用性描述如下(以嚴重程度遞增排序):
每個級別對應的數字值為
CRITICAL:50,ERROR:40,WARNING:30,INFO:20,DEBUG:10,NOTSET:0。
Python 中日志的默認等級是 WARNING,DEBUG 和 INFO 級別的日志將不會得到顯示,在 logging 中更改設置。
使用 logging 在控制臺打印日志,這里我們用 Pycharm 編輯器來觀察:
import logging
logging.debug('崔慶才丨靜覓、韋世東丨奎因')
logging.warning('邀請你關注微信公眾號【進擊的 Coder】')
logging.info('和大佬一起coding、共同進步')
有什么辦法可以改變默認的日志級別呢?
當然是有的,logging 中提供了 basicConfig 讓使用者可以適時調節(jié)默認日志級別,我們可以將上面的代碼改為:
import logging
logging.basicConfig(level=logging.DEBUG)
logging.debug('崔慶才丨靜覓、韋世東丨奎因')
logging.warning('邀請你關注微信公眾號【進擊的 Coder】')
logging.info('和大佬一起coding、共同進步')
在 basicConfig 中設定 level 參數的級別即可。
思考:如果設定級別為 logging.INFO,那 DEBUG 信息能夠顯示么?
剛才演示了如何在控制臺輸出日志內容,并且自由設定日志的級別,那現在就來看看如何將日志保存到文件。依舊是強大的 basicConfig,我們再將上面的代碼改為:
import logging
logging.basicConfig(level=logging.DEBUG, filename='coder.log', filemode='a')
logging.debug('崔慶才丨靜覓、韋世東丨奎因')
logging.warning('邀請你關注微信公眾號【進擊的 Coder】')
logging.info('和大佬一起coding、共同進步')
通過簡單的代碼設置,我們就完成了日志文件在控制臺和文件中的輸出。那既在控制臺顯示又能保存到文件中呢?
logging所提供的模塊級別的日志記錄函數是對logging日志系統(tǒng)相關類的封裝
logging 模塊提供了兩種記錄日志的方式:
使用logging提供的模塊級別的函數
使用Logging日志系統(tǒng)的四大組件
這里提到的級別函數就是上面所用的 DEBGE、ERROR 等級別,而四大組件則是指 loggers、handlers、filters 和 formatters 這幾個組件,下圖簡單明了的闡述了它們各自的作用:
下面介紹下與logging四大組件相關的類:Logger, Handler, Filter, Formatter。
Logger類
Logger 對象有3個工作要做:
1)向應用程序代碼暴露幾個方法,使應用程序可以在運行時記錄日志消息;
2)基于日志嚴重等級(默認的過濾設施)或filter對象來決定要對哪些日志進行后續(xù)處理;
3)將日志消息傳送給所有感興趣的日志handlers。
Logger對象最常用的方法分為兩類:配置方法 和 消息發(fā)送方法
最常用的配置方法如下:
關于Logger.setLevel()方法的說明:
內建等級中,級別最低的是DEBUG,級別最高的是CRITICAL。例如setLevel(logging.INFO),此時函數參數為INFO,那么該logger將只會處理INFO、WARNING、ERROR和CRITICAL級別的日志,而DEBUG級別的消息將會被忽略/丟棄。
logger對象配置完成后,可以使用下面的方法來創(chuàng)建日志記錄:
logging.getLogger()方法有一個可選參數name,該參數表示將要返回的日志器的名稱標識,如果不提供該參數,則其值為'root'。若以相同的name參數值多次調用getLogger()方法,將會返回指向同一個logger對象的引用。
關于logger的層級結構與有效等級的說明:
logger的名稱是一個以'.'分割的層級結構,每個'.'后面的logger都是'.'前面的logger的children,例如,有一個名稱為 foo 的logger,其它名稱分別為 foo.bar, foo.bar.baz 和 foo.bam都是 foo 的后代。
logger有一個"有效等級(effective level)"的概念。如果一個logger上沒有被明確設置一個level,那么該logger就是使用它parent的level;如果它的parent也沒有明確設置level則繼續(xù)向上查找parent的parent的有效level,依次類推,直到找到個一個明確設置了level的祖先為止。需要說明的是,root logger總是會有一個明確的level設置(默認為 WARNING)。當決定是否去處理一個已發(fā)生的事件時,logger的有效等級將會被用來決定是否將該事件傳遞給該logger的handlers進行處理。
child loggers在完成對日志消息的處理后,默認會將日志消息傳遞給與它們的祖先loggers相關的handlers。因此,我們不必為一個應用程序中所使用的所有l(wèi)oggers定義和配置handlers,只需要為一個頂層的logger配置handlers,然后按照需要創(chuàng)建child loggers就可足夠了。我們也可以通過將一個logger的propagate屬性設置為False來關閉這種傳遞機制。
Handler
Handler對象的作用是(基于日志消息的level)將消息分發(fā)到handler指定的位置(文件、網絡、郵件等)。Logger對象可以通過addHandler()方法為自己添加0個或者更多個handler對象。比如,一個應用程序可能想要實現以下幾個日志需求:
1)把所有日志都發(fā)送到一個日志文件中;
2)把所有嚴重級別大于等于error的日志發(fā)送到stdout(標準輸出);
3)把所有嚴重級別為critical的日志發(fā)送到一個email郵件地址。
這種場景就需要3個不同的handlers,每個handler復雜發(fā)送一個特定嚴重級別的日志到一個特定的位置。
一個handler中只有非常少數的方法是需要應用開發(fā)人員去關心的。對于使用內建handler對象的應用開發(fā)人員來說,似乎唯一相關的handler方法就是下面這幾個配置方法:
Formater
Formater對象用于配置日志信息的最終順序、結構和內容。與logging.Handler基類不同的是,應用代碼可以直接實例化Formatter類。另外,如果你的應用程序需要一些特殊的處理行為,也可以實現一個Formatter的子類來完成。
Formatter類的構造方法定義如下:
logging.Formatter.__init__(fmt=None, datefmt=None, style='%')
該構造方法接收3個可選參數:
fmt:指定消息格式化字符串,如果不指定該參數則默認使用message的原始值
datefmt:指定日期格式字符串,如果不指定該參數則默認使用"%Y-%m-%d %H:%M:%S"
style:Python 3.2新增的參數,可取值為 '%', '{'和 '$',如果不指定該參數則默認使用'%'
Filter
Filter可以被Handler和Logger用來做比level更細粒度的、更復雜的過濾功能。Filter是一個過濾器基類,它只允許某個logger層級下的日志事件通過過濾。該類定義如下:
class logging.Filter(name='')
filter(record)
比如,一個filter實例化時傳遞的name參數值為'A.B',那么該filter實例將只允許名稱為類似如下規(guī)則的loggers產生的日志記錄通過過濾:'A.B','A.B,C','A.B.C.D','A.B.D',而名稱為'A.BB', 'B.A.B'的loggers產生的日志則會被過濾掉。如果name的值為空字符串,則允許所有的日志事件通過過濾。
filter方法用于具體控制傳遞的record記錄是否能通過過濾,如果該方法返回值為0表示不能通過過濾,返回值為非0表示可以通過過濾。
說明:
如果有需要,也可以在filter(record)方法內部改變該record,比如添加、刪除或修改一些屬性。
我們還可以通過filter做一些統(tǒng)計工作,比如可以計算下被一個特殊的logger或handler所處理的record數量等。
上面文縐縐的說了(復制/粘貼)那么多,現在應該動手實踐了。
現在我需要既將日志輸出到控制臺、又能將日志保存到文件,我應該怎么辦?
利用剛才所學的知識,我們可以構思一下:
看起來好像也不難,挺簡單的樣子,但是實際如此嗎?
在實際的工作或應用中,我們或許還需要指定文件存放路徑、用隨機數作為日志文件名、顯示具體的信息輸出代碼行數、日志信息輸出日期和日志寫入方式等內容。再構思一下:
import os
import logging
import uuid
from logging import Handler, FileHandler, StreamHandler
class PathFileHandler(FileHandler):
def __init__(self, path, filename, mode='a', encoding=None, delay=False):
filename = os.fspath(filename)
if not os.path.exists(path):
os.mkdir(path)
self.baseFilename = os.path.join(path, filename)
self.mode = mode
self.encoding = encoding
self.delay = delay
if delay:
Handler.__init__(self)
self.stream = None
else:
StreamHandler.__init__(self, self._open())
class Loggers(object):
# 日志級別關系映射
level_relations = {
'debug': logging.DEBUG, 'info': logging.INFO, 'warning': logging.WARNING,
'error': logging.ERROR, 'critical': logging.CRITICAL
}
def __init__(self, filename='{uid}.log'.format(uid=uuid.uuid4()), level='info', log_dir='log',
fmt='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s'):
self.logger = logging.getLogger(filename)
abspath = os.path.dirname(os.path.abspath(__file__))
self.directory = os.path.join(abspath, log_dir)
format_str = logging.Formatter(fmt) # 設置日志格式
self.logger.setLevel(self.level_relations.get(level)) # 設置日志級別
stream_handler = logging.StreamHandler() # 往屏幕上輸出
stream_handler.setFormatter(format_str)
file_handler = PathFileHandler(path=self.directory, filename=filename, mode='a')
file_handler.setFormatter(format_str)
self.logger.addHandler(stream_handler)
self.logger.addHandler(file_handler)
if __name__ == "__main__":
txt = "關注公眾號【進擊的 Coder】,回復『日志代碼』可以領取文章中完整的代碼以及流程圖"
log = Loggers(level='debug')
log.logger.info(4)
log.logger.info(5)
log.logger.info(txt)
文件保存后運行,運行結果如下圖所示:
日志確實在控制臺輸出了,再來看一下目錄內是否生成有指定的文件和文件夾:
文件打開后可以看到里面輸出的內容:
上述內容就是Python 日志模塊詳解及怎么應用,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注創(chuàng)新互聯-成都網站建設公司行業(yè)資訊頻道。