記錄python logging 模--使用自定義配置文件(conf)


logging 的基本知識參照:
Python日誌模塊-logging
Python日誌庫logging總結-可能是目前爲止將logging庫總結的最好的一篇文章
handler 參數設置

1、基本知識總結

1、日誌等級

默認分爲六種日誌級別(括號爲級別對應的數值)

日誌等級(level) 描述
NOTSET(0)
DEBUG(10) 最詳細的日誌信息,典型應用場景是 問題診斷
INFO(20) 信息詳細程度僅次於DEBUG,通常只記錄關鍵節點信息,用於確認一切都是按照我們預期的那樣進行工作
WARNING(30) 當某些不期望的事情發生時記錄的信息(如,磁盤可用空間較低),但是此時應用程序還是正常運行的
ERROR(40) 由於一個更嚴重的問題導致某些功能不能正常運行時記錄的信息
CRITICAL(50) 當發生嚴重錯誤,導致應用程序不能繼續運行時記錄的信息

我們自定義日誌級別時注意不要和默認的日誌級別數值相同,logging 執行時輸出大於等於設置的日誌級別的日誌信息,如設置日誌級別是 INFO,則 INFO、WARNING、ERROR、CRITICAL 級別的日誌都會輸出。

2、logging模塊定義的模塊級別的常用函數

函數 說明
logging.debug(msg, *args, **kwargs) 創建一條嚴重級別爲DEBUG的日誌記錄
logging.info(msg, *args, **kwargs) 創建一條嚴重級別爲INFO的日誌記錄
logging.warning(msg, *args, **kwargs) 創建一條嚴重級別爲WARNING的日誌記錄
logging.error(msg, *args, **kwargs) 創建一條嚴重級別爲ERROR的日誌記錄
logging.critical(msg, *args, **kwargs) 創建一條嚴重級別爲CRITICAL的日誌記錄
logging.log(level, *args, **kwargs) 創建一條嚴重級別爲level的日誌記錄
logging.basicConfig(**kwargs) 對root logger進行一次性配置

3、logging.basicConfig()函數包含參數說明

參數名稱 描述
filename 指定日誌輸出目標文件的文件名,可以寫文件名也可以寫文件的完整的絕對路徑,寫文件名日誌放執行文件目錄下,寫完整路徑按照完整路徑生成日誌文件),指定該設置項後日志信心就不會被輸出到控制檯了
filemode 指定日誌文件的打開模式,默認爲’a’。需要注意的是,該選項要在filename指定時纔有效 【r[+]、w[+]、a[+]】
format 指定日誌格式字符串,即指定日誌輸出時所包含的字段信息以及它們的順序。logging模塊定義的格式字段下面會列出。
datefmt 指定日期/時間格式。需要注意的是,該選項要在format中包含時間字段%(asctime)s時纔有效
level 指定日誌器的日誌級別
stream 指定日誌輸出目標stream,如sys.stdout、sys.stderr以及網絡stream。需要說明的是,stream和filename不能同時提供,否則會引發 ValueError異常
handles 定義處理器,用來創建 Handler 對象,不能和 filename 、stream 參數一起使用,否則也會拋出 ValueError 異常

4、logging定義好的formmat 格式

字段/屬性名稱 使用格式 描述
asctime %(asctime)s 將日誌的時間構造成可讀的形式,默認情況下是‘2016-02-08 12:00:00,123’精確到毫秒
name %(name)s 所使用的日誌器名稱,默認是’root’,因爲默認使用的是 rootLogger
filename %(filename)s 調用日誌輸出函數的模塊的文件名; pathname的文件名部分,包含文件後綴
funcName %(funcName)s 由哪個function發出的log, 調用日誌輸出函數的函數名
levelname %(levelname)s 日誌的最終等級(被filter修改後的)
message %(message)s 日誌信息, 日誌記錄的文本內容
lineno %(lineno)d 當前日誌的行號, 調用日誌輸出函數的語句所在的代碼行
levelno %(levelno)s 該日誌記錄的數字形式的日誌級別(10, 20, 30, 40, 50)
pathname %(pathname)s 完整路徑 ,調用日誌輸出函數的模塊的完整路徑名,可能沒有
process %(process)s 當前進程, 進程ID。可能沒有
processName %(processName)s 進程名稱,Python 3.1新增
thread %(thread)s 當前線程, 線程ID。可能沒有
threadName %(thread)s 線程名稱
module %(module)s 調用日誌輸出函數的模塊名, filename的名稱部分,不包含後綴即不包含文件後綴的文件名
created %(created)f 當前時間,用UNIX標準的表示時間的浮點數表示; 日誌事件發生的時間–時間戳,就是當時調用time.time()函數返回的值
relativeCreated %(relativeCreated)d 輸出日誌信息時的,自Logger創建以 來的毫秒數; 日誌事件發生的時間相對於logging模塊加載時間的相對毫秒數
msecs %(msecs)d 日誌事件發生事件的毫秒部分。logging.basicConfig()中用了參數datefmt,將會去掉asctime中產生的毫秒部分,可以用這個加上

5、日誌輸出格式

日誌的輸出格式可以認爲設置,默認格式爲下圖所示。在這裏插入圖片描述

6、loggin 的四大組件

組件名稱 對應類名 功能描述
日誌器 Logger 提供了應用程序可一直使用的接口
處理器 Handler 將logger創建的日誌記錄發送到合適的目的輸出
過濾器 Filter 提供了更細粒度的控制工具來決定輸出哪條日誌記錄,丟棄哪條日誌記錄
格式器 Formatter 決定日誌記錄的最終輸出格式

7、常用的配置方法

方法 描述
Logger.setLevel() 設置日誌器將會處理的日誌消息的最低嚴重級別
Logger.addHandler() 和 Logger.removeHandler() 爲該logger對象添加 和 移除一個handler對象
Logger.addFilter() 和 Logger.removeFilter() 爲該logger對象添加 和 移除一個filter對象

7.1 logger對象配置完成後,可以使用下面的方法來創建日誌記錄:

方法 描述
Logger.debug(), Logger.info(), Logger.warning(), Logger.error(), Logger.critical() 創建一個與它們的方法名對應等級的日誌記錄
Logger.exception() 創建一個類似於Logger.error()的日誌消息
Logger.log() 需要獲取一個明確的日誌level參數來創建一個日誌記錄

8、Handler類: 配置日誌輸出位置

輸出方向
1、日誌文件
2、標準輸出
3、Email

Handler.setLevel(lel):指定被處理的信息級別,低於lel級別的信息將被忽略
Handler.setFormatter():給這個handler選擇一個格式
Handler.addFilter(filt)、Handler.removeFilter(filt):新增或刪除一個filter對象
Logger.addHandler()和Logger.removeHandler()從記錄器對象中添加和刪除處理程序對象。處理器詳見Handlers。

8.1 Handlers

應用程序代碼不應該直接實例化和使用Handler實例。因爲Handler是一個基類,它只定義了素有handlers都應該有的接口,同時提供了一些子類可以直接使用或覆蓋的默認行爲。下面是一些常用的Handler:

Handler 描述
logging.StreamHandler 控制檯輸出,將日誌消息發送到輸出到Stream,如std.out, std.err或任何file-like對象。
logging.FileHandler 將日誌消息發送到磁盤文件,默認情況下文件大小會無限增長
logging.handlers.RotatingFileHandler 將日誌消息發送到磁盤文件,並支持日誌文件按大小切割,達到指定文件大小,重新生成文件,並重新命名 前面的文件 (caht.log.1、caht.log.2)
logging.hanlders.TimedRotatingFileHandler 將日誌消息發送到磁盤文件,並支持日誌文件按時間切割
logging.handlers.HTTPHandler 將日誌消息以GET或POST的方式發送給一個HTTP服務器
logging.handlers.SMTPHandler 將日誌消息發送給一個指定的email地址
logging.NullHandler 該Handler實例會忽略error messages,通常被想使用logging的library開發者使用來避免’No handlers could be found for logger XXX’信息的出現。

9、自定義配置

我們知道創建一個 Logger 對象所需的配置了,以前直接硬編碼在程序中配置對象,配置還可以從字典類型的對象和配置文件獲取。打開 logging.config Python 文件,可以看到其中的配置解析轉換函數。

9.1、硬編碼配置

def log2():
    LOG_FORMAT = "%(asctime)s %(name)s %(filename)s %(funcName)s %(levelname)s %(pathname)s %(message)s "  # 配置輸出日誌格式
    DATE_FORMAT = '%Y-%m-%d  %H:%M:%S %a '  # 配置輸出時間的格式,注意月份和天數不要搞亂了
    logging.basicConfig(level=logging.DEBUG,
                        format=LOG_FORMAT,
                        datefmt=DATE_FORMAT,
                        filename=r"./ab.log"  # 有了filename參數就不會直接輸出顯示到控制檯,而是直接寫入文件
                        )
	# 創建log 日誌信息
    logging.debug("msg1")
    logging.info("msg2")
    logging.warning("msg3")
    logging.error("msg4")
    logging.critical("msg5")
import logging
def log():
    #創建logger,如果參數爲空則返回root logger
    logger = logging.getLogger("nick")
    logger.setLevel(logging.DEBUG)  #設置logger日誌等級
​
    #這裏進行判斷,如果logger.handlers列表爲空,則添加,否則,直接去寫日誌
    if not logger.handlers:
        #創建兩個handler
        fh = logging.FileHandler("test.log",encoding="utf-8")
        ch = logging.StreamHandler()
​
        #設置輸出日誌格式
        formatter = logging.Formatter(
            fmt="%(asctime)s %(name)s %(filename)s %(message)s",
            datefmt="%Y/%m/%d %X"
            )
​
        #爲兩個handler指定輸出格式
        fh.setFormatter(formatter)
        ch.setFormatter(formatter)
​
        #爲logger添加的日誌處理器
        logger.addHandler(fh)
        logger.addHandler(ch)return logger #直接返回logger
​
logger = log()
logger.warning("泰拳警告")
logger.info("提示")
logger.error("錯誤")
logger.debug("查錯")

9.2、從配置文件中獲取配置信息:

常見的配置文件有 ini 格式、yaml 格式、JSON 格式,或者從網絡中獲取都是可以的,只要有相應的文件解析器解析配置即可,下面只展示了 ini 格式和 yaml 格式的配置。

注意: 在使用配置文件的時候不能出現中文,否則會報錯。在使用的時候需要將配置文件中的中文去掉

UnicodeDecodeError: 'gbk' codec can't decode byte 0xab in position 492: illegal multibyte sequence
9.2.1 int 文件

test.ini 文件

[loggers] # loggers 對象列表
keys=root,main


[handlers] # handlers 對象列表
keys=consoleHandler,fileHandler

[formatters] # formatters 對象列表
keys=fmt

[logger_root]# 配置 logger_root :設置日誌級別、輸出位置(控制檯和文件)
level=DEBUG
handlers=consoleHandler,fileHandler

[logger_main]# 配置 logger_main :設置日誌級別、輸出位置(文件)、除開root logger 對象其餘的logger對象 qualname 參數不能少
level = DEBUG
handlers = fileHandler
qualname=main
propagate=0


[handler_consoleHandler] # consoleHandler 控制器輸出方向、級別、輸出格式、參數
class = StreamHandler
level = DEBUG
formatter = fmt
args = (sys.stdout,)

[handler_fileHandler]#  fileHandler 控制器輸出方向、級別、輸出格式、參數
class = logging.handlers.RotatingFileHandler
level = DEBUG
formatter = fmt
args = ('test.log', 'a', 10000, 3,)
#args = ("test.log", mode="w", maxBytes=1000, backupCount=3, encoding="utf-8")

[formatter_fmt]
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
datefmt=

testinit.py 文件

import logging.config
  # 配置 root logger
    logging.config.fileConfig(fname='test.ini', disable_existing_loggers=False)
    # 獲取logger 對象
    logger = logging.getLogger("sampleLogger")
    # 創建日誌信息
    logger.info("HELLO 智障")
  
9.2.2 conf文件

testlog.conf 文件

[loggers] # loggers 對象列表
        keys=root,main

[handlers] # handlers 對象列表
        keys=consoleHandlers,fileHandlers

[formatters] # formatters 列表
        keys=fmt

[logger_root]
        level=DEBUG
        handlers=consoleHandlers,fileHandlers

[logger_main] # main logger
        level = DEBUG
        handlers = fileHandlers
        qualname=main
        propagate=0

[handler_consoleHandlers]# consoleHandlers 指定控制器的輸出方向、級別、輸出格式、參數
        class = StreamHandler
        level = DEBUG
        formatter = fmt
        args = (sys.stdout,)

[handler_fileHandlers]]# 循環日誌文件 以文件大小來 分割# 每隔 1000 Byte 劃分一個日誌文件,備份文件爲 3 個
        class = logging.handlers.RotatingFileHandler
        level = DEBUG
        formatter = fmt
        args = ('test.log', 'a', 10000, 3, 'UTF-8')

[formatter_fmt] # fmt 格式
        format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
        datefmt=

testinit.py 文件

import logging.config
 	# 讀取配置文件 # 採用配置文件
    logging.config.fileConfig("testlog.conf")
    # 創建logger
    logger = logging.getLogger('main')
    # 日誌生成
    logger.debug(' Hello tom')

擴展

日誌文件按照時間劃分或者按照大小劃分

如果將日誌保存在一個文件中,那麼時間一長,或者日誌一多,單個日誌文件就會很大,既不利於備份,也不利於查看。我們會想到能不能按照時間或者大小對日誌文件進行劃分呢?答案肯定是可以的,並且還很簡單,logging 考慮到了我們這個需求。logging.handlers 文件中提供了 TimedRotatingFileHandler 和 RotatingFileHandler 類分別可以實現按時間和大小劃分。打開這個 handles 文件,可以看到還有其他功能的 Handler 類,它們都繼承自基類 BaseRotatingHandler。

TimedRotatingFileHandler 類構造函數

def __init__(self, filename, when='h', interval=1, backupCount=0, encoding=None, delay=False, utc=False, atTime=None):

RotatingFileHandler 類的構造函數

def __init__(self, filename, mode='a', maxBytes=0, backupCount=0, encoding=None, delay=False)

示例代碼如下:

# 每隔 1000 Byte 劃分一個日誌文件,備份文件爲 3 個
file_handler = logging.handlers.RotatingFileHandler("test.log", mode="w", maxBytes=1000, backupCount=3, encoding="utf-8")
# 每隔 1小時 劃分一個日誌文件,interval 是時間間隔,備份文件爲 10 個
handler2 = logging.handlers.TimedRotatingFileHandler("test.log", when="H", interval=1, backupCount=10)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章