天天看點

python的logging日志子產品

一、簡單介紹

    很多程式都有記錄日志的需求,并且日志中包含的資訊即有正常的程式通路日志,還可能有錯誤、警告等資訊輸出,python的logging子產品提供了标準的日志接口,你可以通過它存儲各種格式的日志,logging的日志可以分為 debug(), info(), warning(), error() and critical()5個級别。

日志級别

LEVEL VALUE DESCRIPTION
DEBUG 10 指出細粒度資訊事件對調試應用程式是非常有幫助的
INFO 20 表明消息在粗粒度級别上突出強調應用程式的運作過程
WARNING 30 表明會出現潛在錯誤的情形
ERROR 40 指出雖然發生錯誤事件,但仍然不影響系統的繼續運作
CRITICAL 50 指出每個嚴重的錯誤事件将會導緻應用程式的退出

将日志輸出在控制台終端

import logging

logging.warning("user [tom] attempted wrong password more than 3 times")
logging.critical("server is down")
           

将日志記錄在檔案中

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')
           

日志格式

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.
           

除了加時間,還可以自定義一大堆格式,下表就是所有支援的格式

格式 描述
%(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 使用者輸出的消息

二、詳細使用

Python 使用logging子產品記錄日志涉及四個主要類,使用官方文檔中的概括最為合适:

logger提供了應用程式可以直接使用的接口;

handler将(logger建立的)日志記錄發送到合适的目的輸出;

filter提供了細度裝置來決定輸出哪條日志記錄;

formatter決定日志記錄的最終輸出格式。

這幾個類之間的使用關系:

python的logging日志子產品

每個元件的主要功能

1、logger

    每個程式在輸出資訊之前都要獲得一個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():可以設定的日志級别

2、handler

    handler對象負責發送相關的資訊到指定目的地。Python的日志系統有多種Handler可以使用。有些Handler可以把資訊輸出到控制台,有些Handler可以把資訊輸出到檔案,還有些 Handler可以把資訊發送到網絡上。如果覺得不夠用,還可以編寫自己的Handler。可以通過addHandler()方法添加多個多handler。

Handler.setLevel(lel):指定被處理的資訊級别,低于lel級别的資訊将被忽略

Handler.setFormatter():給這個handler選擇一個格式

Handler.addFilter(filt)、Handler.removeFilter(filt):新增或删除一個filter對象

常用的Handler:

logging.StreamHandler 使用這個Handler可以向類似與sys.stdout或者sys.stderr的任何檔案對象(file object)輸出資訊。

logging.FileHandler 和StreamHandler 類似,用于向一個檔案輸出日志資訊。不過FileHandler會幫你打開這個檔案

logging.handlers.RotatingFileHandler

    這個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]]])

    maxBytes用于指定日志檔案的最大檔案大小。如果maxBytes為0,意味着日志檔案可以無限大,這時上面描述的重命名過程就不會發生。

    backupCount用于指定保留的備份檔案的個數。比如,如果指定為2,當上面描述的重命名過程發生時,原有的chat.log.2并不會 被更名,而是被删除。

logging.handlers.TimedRotatingFileHandler

    這個Handler和RotatingFileHandler類似,不過,它沒有通過判斷檔案大小來決定何時重新建立日志檔案,而是間隔一定時間就 自動建立新的日志檔案。重命名的過程與RotatingFileHandler類似,不過新的檔案不是附加數字,而是目前時間。它的函數是:

TimedRotatingFileHandler( filename [,when [,interval [,backupCount]]])

其中filename參數和backupCount參數和RotatingFileHandler具有相同的意義。

interval是時間間隔。

when參數是一個字元串。表示時間間隔的機關,不區分大小寫。它有以下取值:

S 秒

M 分

H 小時

D 天

W 每星期(interval==0時代表星期一)

midnight 每天淩晨

3、formatter

日志的formatter是個獨立的元件,可以跟handler組合

fh = logging.FileHandler("access.log")

formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

fh.setFormatter(formatter) #把formmater綁定到fh上

4、filter

如果你想對日志内容進行過濾,就可自定義一個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())
logger.debug("test ....")
logger.info("test info ....")
logger.warning("start to run db backup job ....")
logger.error("test error ....")
           

三、示例

1、同時輸出到螢幕、檔案、帶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 ....")
           

2、檔案自動截斷例子

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")