您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關logger模塊怎么在python中使用,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。
logging模塊介紹
Python的logging模塊提供了通用的日志系統,熟練使用logging模塊可以方便開發者開發第三方模塊或者是自己的Python應用。同樣這個模塊提供不同的日志級別,并可以采用不同的方式記錄日志,比如文件,HTTP、GET/POST,SMTP,Socket等,甚至可以自己實現具體的日志記錄方式。下文我將主要介紹如何使用文件方式記錄log。
logging模塊包括logger,handler,filter,formatter這四個基本概念。
logging模塊與log4j的機制是一樣的,只是具體的實現細節不同。模塊提供logger,handler,filter,formatter。
logger:提供日志接口,供應用代碼使用。logger最長用的操作有兩類:配置和發送日志消息。可以通過logging.getLogger(name)獲取logger對象,如果不指定name則返回root對象,多次使用相同的name調用getLogger方法返回同一個logger對象。
handler:將日志記錄(log record)發送到合適的目的地(destination),比如文件,socket等。一個logger對象可以通過addHandler方法添加0到多個handler,每個handler又可以定義不同日志級別,以實現日志分級過濾顯示。
filter:提供一種優雅的方式決定一個日志記錄是否發送到handler。
formatter:指定日志記錄輸出的具體格式。formatter的構造方法需要兩個參數:消息的格式字符串和日期字符串,這兩個參數都是可選的。
與log4j類似,logger,handler和日志消息的調用可以有具體的日志級別(Level),只有在日志消息的級別大于logger和handler的級別。
import logging logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s', datefmt='%a, %d %b %Y %H:%M:%S', filename='myapp.log', filemode='w') ################################################################################################# #定義一個StreamHandler,將INFO級別或更高的日志信息打印到標準錯誤,并將其添加到當前的日志處理對象# console = logging.StreamHandler() console.setLevel(logging.INFO) formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s') console.setFormatter(formatter) logging.getLogger('').addHandler(console) ################################################################################################# logging.debug('This is debug message') logging.info('This is info message') logging.warning('This is warning message') 屏幕上打印: root : INFO This is info message root : WARNING This is warning message ./myapp.log文件中內容為: Sun, 24 May 2009 21:48:54 demo2.py[line:11] DEBUG This is debug message Sun, 24 May 2009 21:48:54 demo2.py[line:12] INFO This is info message Sun, 24 May 2009 21:48:54 demo2.py[line:13] WARNING This is warning message
logging.StreamHandler: 日志輸出到流,可以是sys.stderr、sys.stdout或者文件
logging.FileHandler: 日志輸出到文件
日志回滾方式,實際使用時用RotatingFileHandler和TimedRotatingFileHandler
logging.handlers.BaseRotatingHandler
logging.handlers.RotatingFileHandler
logging.handlers.TimedRotatingFileHandler
logging.handlers.SocketHandler: 遠程輸出日志到TCP/IP sockets
logging.handlers.DatagramHandler: 遠程輸出日志到UDP sockets
logging.handlers.SMTPHandler: 遠程輸出日志到郵件地址
logging.handlers.SysLogHandler: 日志輸出到syslog
logging.handlers.NTEventLogHandler: 遠程輸出日志到Windows NT/2000/XP的事件日志
logging.handlers.MemoryHandler: 日志輸出到內存中的制定buffer
logging.handlers.HTTPHandler: 通過"GET"或"POST"遠程輸出到HTTP服務器
import logging import sys # 獲取logger實例,如果參數為空則返回root logger logger = logging.getLogger("AppName") # 指定logger輸出格式 formatter = logging.Formatter('%(asctime)s %(levelname)-8s: %(message)s') # 文件日志 file_handler = logging.FileHandler("test.log") file_handler.setFormatter(formatter) # 可以通過setFormatter指定輸出格式 # 控制臺日志 console_handler = logging.StreamHandler(sys.stdout) console_handler.formatter = formatter # 也可以直接給formatter賦值 # 為logger添加的日志處理器,可以自定義日志處理器讓其輸出到其他地方 logger.addHandler(file_handler) logger.addHandler(console_handler) # 指定日志的最低輸出級別,默認為WARN級別 logger.setLevel(logging.INFO) # 輸出不同級別的log logger.debug('this is debug info') logger.info('this is information') logger.warn('this is warning message') logger.error('this is error message') logger.fatal('this is fatal message, it is same as logger.critical') logger.critical('this is critical message') # 2016-10-08 21:59:19,493 INFO : this is information # 2016-10-08 21:59:19,493 WARNING : this is warning message # 2016-10-08 21:59:19,493 ERROR : this is error message # 2016-10-08 21:59:19,493 CRITICAL: this is fatal message, it is same as logger.critical # 2016-10-08 21:59:19,493 CRITICAL: this is critical message # 移除一些日志處理器 logger.removeHandler(file_handler)
python:logging模塊
10 DECEMBER 2015
概述
python的logging模塊(logging是線程安全的)給應用程序提供了標準的日志信息輸出接口。logging不僅支持把日志輸出到文件,還支持把日志輸出到TCP/UDP服務器,EMAIL服務器,HTTP服務器,UNIX的syslog系統等。在logging中主要有四個概念:logger、handler、filter和formatter,下面會分別介紹。
logger
Logger對象扮演了三重角色:
它給應用程序暴漏了幾個方法,以便應用程序能在運行時記錄日志。
Logger對象根據日志的級別或根據Filter對象,來決定記錄哪些日志。
Logger對象負責把日志信息傳遞給相關的handler。
在Logger對象中,最常使用的方法分為兩類:configuration,message sending。 configuration方法包括:
setLevel(level)
setLevel(level)方法用來設置logger的日志級別,如果日志的級別低于setLevel(level)方法設置的值,那么logger不會處理它。logging模塊內建的日志級別有:
CRITICAL = 50 FATAL = CRITICAL ERROR = 40 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0 (數值越大級別越高) addFilter(filter) removeFilter(filter) addHandler(handler) removeHandler(handler)
message sending方法包括:
debug(log_message, [*args[, **kwargs]])
使用DEBUG級別,記錄log_message % args。
為了記錄異常信息,需要將關鍵字參數exc_info設置為一個true值。
比如:
logger.debug("Houston, we have a %s", "thorny problem", exc_info=1) info(log_message, [*args[, **kwargs]])
使用INFO級別,記錄log_message % args。
為了記錄異常信息,需要將關鍵字參數exc_info設置為一個true值。
比如:
logger.info("Houston, we have a %s", "interesting problem", exc_info=1) warning(log_message, [*args[, **kwargs]])
使用WARNING級別,記錄log_message % args。
為了記錄異常信息,需要將關鍵字參數exc_info設置為一個true值。
比如:
logger.warning("Houston, we have a %s", "bit of a problem", exc_info=1) error(log_message, [*args[, **kwargs]])
使用Error級別,記錄log_message % args。
為了記錄異常信息,需要將關鍵字參數exc_info設置為一個true值。
比如:
logger.error("Houston, we have a %s", "major problem", exc_info=1) critical(log_message, [*args[, **kwargs]])
使用CRITICAL級別,記錄log_message % args。
為了記錄異常信息,需要將關鍵字參數exc_info設置為一個true值。
比如:
logger.critical("Houston, we have a %s", "major disaster", exc_info=1) exception(message[, *args]) self.error(*((msg,) + args), **{'exc_info': 1}) log(log_level, log_message, [*args[, **kwargs]])
使用整型的級別level,記錄log_message % args。
為了記錄異常信息,需要將關鍵字參數exc_info設置為一個true值。
比如:
logger.log(level, "We have a %s", "mysterious problem", exc_info=1) logging.getLogger([name])
方法返回一個Logger實例的引用,如果提供了name參數,那么它就是這個Logger實例的名稱,如果沒提供name參數,那么這個Logger實例的名稱是root。
可以通過Logger實例的name屬性,來查看Logger實例的名稱。
Logger實例的名稱是使用句號(.)分隔的多級結構。
在這種命名方式中,后面的logger是前面的logger的子(父子logger只是簡單的通過命名來識別),比如:有一個名稱為foo的logger,那么諸如foo.bar、foo.bar.baz和foo.bam這樣的logger都是foo這個logger的子logger。
子logger會自動繼承父logger的定義和配置。
使用相同的名稱多次調用logging.getLogger([name])方法,會返回同一個logger對象的引用。
這個規則不僅僅在同一個module有效,而且對在同一個Python解釋器進程的多個module也有效。
因此應用程序可以在一個module中定義一個父logger,然后在其他module中繼承這個logger,而不必把所有的logger都配置一遍。
handler
handler實例負責把日志事件分發到具體的目的地。logger對象可以使用addHandler()方法,添加零個或多個handler對象到它自身。一個常見的場景是:應用程序可能希望把所有的日志都記錄到一個log文件,所有的ERROR及以上級別的日志都記錄到stdout,所有的CRITICAL級別的日志都發送到一個email地址。這個場景需要三個獨立的handler,每個handler負責把特定級別的日志發送到特定的地方。
下面是logging模塊內置的handler:
StreamHandler FileHandler RotatingFileHandler TimedRotatingFileHandler SocketHandler DatagramHandler SysLogHandler NTEventLogHandler SMTPHandler MemoryHandler HTTPHandler
內置的handler提供了下面的配置方法:
setLevel(level)
handler對象的setLevel()方法,與logger對象的setLevel()方法一樣,也是用于設置一個日志級別,如果日志的級別低于
setLevel()方法設置的值,那么handler不會處理它。
setFormatter(formatter)
addFilter(filter)
removeFilter(filter)
應用程序代碼不應該直接實例化和使用handler。logging.Handler是一個定義了所有的handler都應該實現的接口和建立了子類能夠使用(或重寫)的一些默認行為的基類。
自定義Handler 自定義的handler必須繼承自logging.Handler,且實現下面的方法:
class Handler(Filterer): def emit(self, record): """ Do whatever it takes to actually log the specified logging record. This version is intended to be implemented by subclasses and so raises a NotImplementedError. """ raise NotImplementedError, 'emit must be implemented '\ 'by Handler subclasses' def flush(self): """ Ensure all logging output has been flushed. This version does nothing and is intended to be implemented by subclasses. """ pass def close(self): """ Tidy up any resources used by the handler. This version does removes the handler from an internal list of handlers which is closed when shutdown() is called. Subclasses should ensure that this gets called from overridden close() methods. """ #get the module data lock, as we're updating a shared structure. _acquireLock() try: #unlikely to raise an exception, but you never know... if self in _handlers: del _handlers[self] if self in _handlerList: _handlerList.remove(self) finally: _releaseLock()
其中,emit(record)方法負責執行真正地記錄日志所需的一切事情,在logging.Handler的子類中必須實現這個方法。close()方法負責清理handler所使用的資源(在Python解釋器退出的時候,會調用所有的handler的flush()和close()方法),logging.Handler的子類應該確保在重寫close()方法的時候,調用父類的該方法。
下面分析logging.StreamHandler的源代碼:
class StreamHandler(Handler): def __init__(self, strm=None): Handler.__init__(self) if strm is None: strm = sys.stderr self.stream = strm def flush(self): if self.stream and hasattr(self.stream, "flush"): self.stream.flush() def emit(self, record): try: msg = self.format(record) stream = self.stream fs = "%s\n" if not hasattr(types, "UnicodeType"): #if no unicode support... stream.write(fs % msg) else: try: if (isinstance(msg, unicode) and getattr(stream, 'encoding', None)): fs = fs.decode(stream.encoding) try: stream.write(fs % msg) except UnicodeEncodeError: #Printing to terminals sometimes fails. For example, #with an encoding of 'cp1251', the above write will #work if written to a stream opened or wrapped by #the codecs module, but fail when writing to a #terminal even when the codepage is set to cp1251. #An extra encoding step seems to be needed. stream.write((fs % msg).encode(stream.encoding)) else: stream.write(fs % msg) except UnicodeError: stream.write(fs % msg.encode("UTF-8")) self.flush() except (KeyboardInterrupt, SystemExit): raise except: self.handleError(record)
在構造函數中,如果提供了strm參數,那么它就是要輸出到的流,如果沒提供,那么就會將日志輸出到標準錯誤輸出流sys.stderr。
flush()方法的作用是:刷新self.stream內部的I/O緩沖區。每次emit日志之后都會調用這個方法,將日志從I/O緩沖區sync到self.stream。
emit(record)方法的作用是:將LogRecord對象(record)記錄到self.stream。emit(record)方法首先調用基類logging.Handler提供的format(record)方法,該方法會根據設置的Formatter對象來格式化record對象,得到要記錄的字符串msg。然后對fs(fs其實就是在msg的尾部增加一個換行'\n')進行一系列的編碼解碼,將它寫入到self.stream。最后再刷新self.stream。在emit(record)調用期間發生的異常,應該調用logging.Handler提供的handleError(record)方法來處理。
filter
Filter對象用于對LogRecord對象執行過濾,logger和handler都可以使用filter來過濾record。下面用一個列子來說明Filter基類的作用:
如果使用A.B實例化一個filter,那么它允許名稱為A.B,A.B.C,A.B.C.D這樣的logger記錄的日志通過,不允許名稱為A.BB,B.A.B這樣的logger記錄的日志通過。
如果使用空字符串實例化一個filter,那么它允許所有的事件通過。
Filter基類有一個方法叫filter(record),它用來決定指定的record(LogRecord對象)是否被記錄。如果該方法返回0,則不記錄record;返回非0則記錄record。
Filterer(注意:不是Filter)是logger和handler的基類。它提供了方法來添加和刪除filter,并且提供了filter(record)方法用于過濾record,該方法默認允許record被記錄,但是任何filter都可以否決這個默認行為,如果想要丟棄record,filter(record)方法應該返回0,否則應該返回非0。
formatter
Formatter對象用于把一個LogRecord對象轉換成文本,它定義了日志的格式、結構。與logging.Handler類不同,應用程序可以直接實例化Formatter類,如果需要也可以子類化Formatter,以便定制一些行為。
Formatter的構造函數接受兩個參數:第一個參數是用于日志信息的格式化字符串;第二個參數是用于日期的格式化字符串。第二個參數可選的,默認值是%Y-%m-%d %H:%M:%S。
日志信息的格式化字符串用%(<dictionary key>)s風格的字符串做替換。
下面是替換字符串和它們所代表的含義:
%(name)s logger的名稱 %(levelno)s 日志級別的數字表現形式 %(levelname)s 日志級別的文本表現形式 %(pathname)s 調用logging的源文件的全路徑名 %(filename)s pathname的文件名部分 %(module)s 模塊名(filename的名稱部分) %(lineno)d 調用logging的行號 %(funcName)s 函數名 %(created)f LogRecord的創建時間(time.time()的返回值) %(asctime)s LogRecord的創建時間的文本表現形式 %(msecs)d 創建時間的毫秒部分 %(relativeCreated)d LogRecord的創建時間,單位是毫秒。這個時間是相對logging模塊被加載的時間的(通常就是應用程序啟動的時間)。 %(thread)d 線程ID %(threadName)s 線程名稱 %(process)d 進程ID %(message)s record.getMessage()的返回結果。
配置logging
下面是一個簡單的例子,它會向標準輸出打印日志:
import logging import sys logger = logging.getLogger(__name__) filter = logging.Filter(__name__) formatter = logging.Formatter("%(asctime)s|%(name)-12s|%(message)s", "%F %T") stream_handler = logging.StreamHandler(sys.stdout) stream_handler.addFilter(filter) stream_handler.setLevel(logging.DEBUG) stream_handler.setFormatter(formatter) logger.setLevel(logging.DEBUG) logger.addFilter(filter) logger.addHandler(stream_handler) if __name__ == "__main__": logger.info("info")
運行這個腳本,輸出結果是:
2015-12-16 13:52:17|__main__ |info
使用配置文件,配置logging
下面是一個使用配置文件,配置logging的例子:
import logging import logging.config logging.config.fileConfig("logging.conf") if __name__ == "__main__": logger = logging.getLogger("test_logging.sublogger") logger.info("info")
logging.conf如下:
[loggers] keys = root,logger [handlers] keys = stream_handler [formatters] keys = formatter [logger_root] handlers = stream_handler [logger_logger] handlers = stream_handler level = DEBUG propagate = 1 qualname = test_logging [handler_stream_handler] class = StreamHandler args = (sys.stdout,) formatter = formatter level = DEBUG [formatter_formatter] format = %(asctime)s|%(name)-12s|%(message)s datefmt = %F %T
需要解釋的地方有兩處:第一個是logger_xxxsection中的propagate選項,在logger對象把record傳遞給所有相關的handler的時候,會(逐級向上)尋找這個logger和它所有的父logger的全部handler。在尋找過程中,如果logger對象的propagate屬性被設置為1,那么就繼續向上尋找;如果某個logger的propagate屬性被設置為0,那么就會停止搜尋。
第二個是logger_xxxsection中的qualname選項,它其實就是logger的名稱。
使用配置文件的時候,必須定義root logger。
最酷的listen(port)函數
logging.config.listen(port)函數可以讓應用程序在一個socket上監聽新的配置信息,達到在運行時改變配置,而不用重啟應用程序的目的。
監聽程序:
import logging.config import logging import time logging.config.fileConfig("logging.conf") logger = logging.getLogger("test_logging.listen") t = logging.config.listen(9999) t.setDaemon(True) t.start() try: while True: logger.info('running.') time.sleep(3) except (KeyboardInterrupt, SystemExit, Exception): logging.config.stopListening()
發送新的配置信息程序:
import socket import struct HOST = 'localhost' PORT = 9999 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((HOST, PORT)) print "connected..." data_to_send = open("logging.conf").read() s.send(struct.pack(">L", len(data_to_send))) s.send(data_to_send) print "closing..." s.close()
關于logger模塊怎么在python中使用就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。