不少程序都有記錄日誌的需求,而且日誌中包含的信息即有正常的程序訪問日誌,還可能有錯誤、警告等信息輸出,python的logging模塊提供了標準的日誌接口,你能夠經過它存儲各類格式的日誌,logging的日誌能夠分爲 debug(), info(), warning(), error() and critical()5個級別,下面咱們看一下怎麼用。css
import logging logging.warning("user [alex] attempted wrong password more than 3 times") logging.critical("server is down")
輸出python
WARNING:root:user [alex] attempted wrong password more than 3 times CRITICAL:root:server is down
看一下這幾個日誌級別分別表明什麼意思mysql
Level | When it’s used |
---|---|
DEBUG | Detailed information, typically of interest only when diagnosing problems. |
INFO | Confirmation that things are working as expected. |
WARNING | An indication that something unexpected happened, or indicative of some problem in the near future (e.g. ‘disk space low’). The software is still working as expected. |
ERROR | Due to a more serious problem, the software has not been able to perform some function. |
CRITICAL | A serious error, indicating that the program itself may be unable to continue running. |
import logging logging.basicConfig(filename='example.log',level=logging.INFO) logging.debug('This message should go to the log file') logging.info('So should this') logging.warning('And this, too')
其中下面這句中的level=loggin.INFO意思是,把日誌紀錄級別設置爲INFO,也就是說,只有比日誌是INFO或比INFO級別更高的日誌纔會被紀錄到文件裏,在這個例子, 第一條日誌是不會被紀錄的,若是但願紀錄debug的日誌,那把日誌級別改爲DEBUG就好了。web
logging.basicConfig(filename='example.log',level=logging.INFO)
感受上面的日誌格式忘記加上時間啦,日誌不知道時間怎麼行呢,下面就來加上!sql
import logging logging.basicConfig(format='%(asctime)s %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') logging.warning('is when this event was logged.') #輸出 12/12/2010 11:46:36 AM is when this event was logged.
除了加時間,還能夠自定義一大堆格式,下表就是全部支持的格式網絡
%(name)s | Logger的名字 |
---|---|
%(levelno)s | 數字形式的日誌級別 |
%(levelname)s | 文本形式的日誌級別 |
%(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 | 用戶輸出的消息 |
若是想同時把log打印在屏幕和文件日誌裏,就須要瞭解一點複雜的知識 了app
Python 使用logging模塊記錄日誌涉及四個主要類,使用官方文檔中的歸納最爲合適:svg
他們之間的關係是這樣的每一個組件的主要功能函數
每一個程序在輸出信息以前都要得到一個Logger。Logger一般對應了程序的模塊名,好比聊天工具的圖形界面模塊能夠這樣得到它的Logger:工具
LOG=logging.getLogger(」chat.gui」)
而核心模塊能夠這樣:
LOG=logging.getLogger(」chat.kernel」)
還能夠綁定handler和filters
Logger.setLevel(lel):指定最低的日誌級別,低於lel的級別將被忽略。debug是最低的內置級別,critical爲最高 Logger.addFilter(filt)、Logger.removeFilter(filt):添加或刪除指定的filter Logger.addHandler(hdlr)、Logger.removeHandler(hdlr):增長或刪除指定的handler
Logger.debug()、Logger.info()、Logger.warning()、Logger.error()、Logger.critical():能夠設置的日誌級別
handler對象負責發送相關的信息到指定目的地。Python的日誌系統有多種Handler可使用。有些Handler能夠把信息輸出到控制檯,有些Handler能夠把信息輸出到文件,還有些 Handler能夠把信息發送到網絡上。若是以爲不夠用,還能夠編寫本身的Handler。能夠經過addHandler()方法添加多個多handler
Handler.setLevel(lel):指定被處理的信息級別,低於lel級別的信息將被忽略 Handler.setFormatter():給這個handler選擇一個格式 Handler.addFilter(filt)、Handler.removeFilter(filt):新增或刪除一個filter對象
每一個Logger能夠附加多個Handler。接下來咱們就來介紹一些經常使用的Handler:
使用這個Handler能夠向相似與sys.stdout或者sys.stderr的任何文件對象(file object)輸出信息。
和StreamHandler 相似,用於向一個文件輸出日誌信息。不過FileHandler會幫你打開這個文件
這個Handler相似於上面的FileHandler,可是它能夠管理文件大小。當文件達到必定大小以後,它會自動將當前日誌文件更名,而後建立 一個新的同名日誌文件繼續輸出。好比日誌文件是chat.log。當chat.log達到指定的大小以後,RotatingFileHandler自動把 文件更名爲chat.log.1。不過,若是chat.log.1已經存在,會先把chat.log.1重命名爲chat.log.2。。。最後從新建立 chat.log,繼續輸出日誌信息。它的函數是:
RotatingFileHandler( filename[, mode[, maxBytes[, backupCount]]])
其中filename和mode兩個參數和FileHandler同樣。
這個Handler和RotatingFileHandler相似,不過,它沒有經過判斷文件大小來決定什麼時候從新建立日誌文件,而是間隔必定時間就 自動建立新的日誌文件。重命名的過程與RotatingFileHandler相似,不過新的文件不是附加數字,而是當前時間。它的函數是:
TimedRotatingFileHandler( filename [,when [,interval [,backupCount]]])
其中filename參數和backupCount參數和RotatingFileHandler具備相同的意義。
interval是時間間隔。 when參數是一個字符串。表示時間間隔的單位,不區分大小寫。它有如下取值: S 秒 M 分 H 小時 D 天 W 每星期(interval==0時表明星期一) midnight 天天凌晨
日誌的formatter是個獨立的組件,能夠跟handler組合
fh = logging.FileHandler("access.log") formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') fh.setFormatter(formatter) #把formmater綁定到fh上
若是你想對日誌內容進行過濾,就可自定義一個filter
class IgnoreBackupLogFilter(logging.Filter): """忽略帶db backup 的日誌""" def filter(self, record): #固定寫法 return "db backup" not in record.getMessage()
注意filter函數會返加True or False,logger根據此值決定是否輸出此日誌
而後把這個filter添加到logger中
logger.addFilter(IgnoreBackupLogFilter())
下面的日誌就會把符合filter條件的過濾掉
logger.debug("test ....") logger.info("test info ....") logger.warning("start to run db backup job ....") logger.error("test error ....")
一個同時輸出到屏幕、文件、帶filter的完成例子
import logging class IgnoreBackupLogFilter(logging.Filter): """忽略帶db backup 的日誌""" def filter(self, record): #固定寫法 return "db backup" not in record.getMessage() #console handler ch = logging.StreamHandler() ch.setLevel(logging.INFO) #file handler fh = logging.FileHandler('mysql.log') #fh.setLevel(logging.WARNING) #formatter formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') #bind formatter to ch ch.setFormatter(formatter) fh.setFormatter(formatter) logger = logging.getLogger("Mysql") logger.setLevel(logging.DEBUG) #logger 優先級高於其它輸出途徑的 #add handler to logger instance logger.addHandler(ch) logger.addHandler(fh) #add filter logger.addFilter(IgnoreBackupLogFilter()) logger.debug("test ....") logger.info("test info ....") logger.warning("start to run db backup job ....") logger.error("test error ....") 文件自動截斷例子 import logging from logging import handlers logger = logging.getLogger(__name__) log_file = "timelog.log" #fh = handlers.RotatingFileHandler(filename=log_file,maxBytes=10,backupCount=3) fh = handlers.TimedRotatingFileHandler(filename=log_file,when="S",interval=5,backupCount=3) formatter = logging.Formatter('%(asctime)s %(module)s:%(lineno)d %(message)s') fh.setFormatter(formatter) logger.addHandler(fh) logger.warning("test1") logger.warning("test12") logger.warning("test13") logger.warning("test14")