建立Logger執行個體後,可以使用以下方法進行日志級别設定,增加處理器Handler。
logger.setLevel(logging.ERROR) # 設定日志級别為ERROR,即隻有日志級别大于等于ERROR的日志才會輸出
logger.addHandler(handler_name) # 為Logger執行個體增加一個處理器
logger.removeHandler(handler_name) # 為Logger執行個體删除一個處理器
3.2 Handler 處理器
Handler處理器類型有很多種,比較常用的有三個,StreamHandler,FileHandler,NullHandler,詳情可以通路Python logging.handlers
建立StreamHandler之後,可以通過使用以下方法設定日志級别,設定格式化器Formatter,增加或删除過濾器Filter。
ch.setLevel(logging.WARN) # 指定日志級别,低于WARN級别的日志将被忽略
ch.setFormatter(formatter_name) # 設定一個格式化器formatter
ch.addFilter(filter_name) # 增加一個過濾器,可以增加多個
ch.removeFilter(filter_name) # 删除一個過濾器
3.2.1 StreamHandler
建立方法: sh = logging.StreamHandler(stream=None)
3.2.2 FileHandler
建立方法: fh = logging.FileHandler(filename, mode='a', encoding=None, delay=False)
3.2.3 NullHandler
NullHandler類位于核心logging包,不做任何的格式化或者輸出。
本質上它是個“什麼都不做”的handler,由庫開發者使用。
3.2.4 其他Handler介紹
3.2.4.1 handlers.RotatingFileHandler
類似于上面的FileHandler,但是它可以管理檔案大小。當檔案達到一定大小之後,它會自動将目前日志檔案改名,然後建立一個新的同名日志檔案繼續輸出。
3.2.4.2 handlers.TimedRotatingFileHandle
和RotatingFileHandler類似,不過,它沒有通過判斷檔案大小來決定何時重新建立日志檔案,而是間隔一定時間就自動建立新的日志檔案
3.2.4.3 handlers.SocketHandler
使用TCP協定,将日志資訊發送到網絡。
3.2.4.4 handlers.DatagramHandler
使用UDP協定,将日志資訊發送到網絡。
3.2.4.5 handlers.SysLogHandler
日志輸出到syslog
3.2.4.6 handlers.NTEventLogHandler
遠端輸出日志到Windows NT/2000/XP的事件日志
3.2.4.7 handlers.SMTPHandler
遠端輸出日志到郵件位址
3.2.4.8 handlers.MemoryHandler
日志輸出到記憶體中的制定buffer
3.2.4.9 handlers.HTTPHandler
通過"GET"或"POST"遠端輸出到HTTP伺服器
3.3 Formatter 格式化器
使用Formatter對象設定日志資訊最後的規則、結構和内容,預設的時間格式為%Y-%m-%d %H:%M:%S。
建立方法: formatter = logging.Formatter(fmt=None, datefmt=None)
其中,fmt是消息的格式化字元串,datefmt是日期字元串。如果不指明fmt,将使用'%(message)s'。如果不指明datefmt,将使用ISO8601日期格式。
代碼示範:
fmt = "%(asctime)-15s %(levelname)s %(filename)s %(lineno)d %(process)d %(message)s"
date_format_str = "%Y-%m-%d %H:%M:%S"
formatter = logging.Formatter(fmt, datefmt)
fmt請參考下文中的4.2.2
datefmt請參考下文中的4.2.3
3.4 Filter 過濾器
Handlers和Loggers可以使用Filters來完成比級别更複雜的過濾。Filter基類隻允許特定Logger層次以下的事件。例如用‘A.B’初始化的Filter允許Logger ‘A.B’, ‘A.B.C’, ‘A.B.C.D’, ‘A.B.D’等記錄的事件,logger‘A.BB’, ‘B.A.B’ 等就不行。 如果用空字元串來初始化,所有的事件都接受。
建立方法: filter = logging.Filter(name='')
以下是相關概念總結:
熟悉了這些概念之後,有另外一個比較重要的事情必須清楚,即Logger是一個樹形層級結構;
Logger可以包含一個或多個Handler和Filter,即Logger與Handler或Fitler是一對多的關系;
一個Logger執行個體可以新增多個Handler,一個Handler可以新增多個格式化器或多個過濾器,而且日志級别将會繼承。
四、Logging工作流程
第一次導入logging子產品或使用reload函數重新導入logging子產品,logging子產品中的代碼将被執行,這個過程中将産生logging日志系統的預設配置。
自定義配置(可選)。logging标準子產品支援三種配置方式: dictConfig,fileConfig,listen。其中,dictConfig是通過一個字典進行配置Logger,Handler,Filter,Formatter;fileConfig則是通過一個檔案進行配置;而listen則監聽一個網絡端口,通過接收網絡資料來進行配置。當然,除了以上集體化配置外,也可以直接調用Logger,Handler等對象中的方法在代碼中來顯式配置。
使用logging子產品的全局作用域中的getLogger函數來得到一個Logger對象執行個體(其參數即是一個字元串,表示Logger對象執行個體的名字,即通過該名字來得到相應的Logger對象執行個體)。
使用Logger對象中的debug,info,error,warn,critical等方法記錄日志資訊。
4.1 logging子產品處理流程
判斷日志的等級是否大于Logger對象的等級,如果大于,則往下執行,否則,流程結束。
産生日志。第一步,判斷是否有異常,如果有,則添加異常資訊。第二步,處理日志記錄方法(如debug,info等)中的占位符,即一般的字元串格式化處理。
使用注冊到Logger對象中的Filters進行過濾。如果有多個過濾器,則依次過濾;隻要有一個過濾器傳回假,則過濾結束,且該日志資訊将丢棄,不再處理,而處理流程也至此結束。否則,處理流程往下執行。
在目前Logger對象中查找Handlers,如果找不到任何Handler,則往上到該Logger對象的父Logger中查找;如果找到一個或多個Handler,則依次用Handler來處理日志資訊。但在每個Handler處理日志資訊過程中,會首先判斷日志資訊的等級是否大于該Handler的等級,如果大于,則往下執行(由Logger對象進入Handler對象中),否則,處理流程結束。
執行Handler對象中的filter方法,該方法會依次執行注冊到該Handler對象中的Filter。如果有一個Filter判斷該日志資訊為假,則此後的所有Filter都不再執行,而直接将該日志資訊丢棄,處理流程結束。
使用Formatter類格式化最終的輸出結果。 注:Formatter同上述第2步的字元串格式化不同,它會添加額外的資訊,比如日志産生的時間,産生日志的源代碼所在的源檔案的路徑等等。
真正地輸出日志資訊(到網絡,檔案,終端,郵件等)。至于輸出到哪個目的地,由Handler的種類來決定。
5 配置擷取方式
顯式建立記錄器Logger、處理器Handler和格式化器Formatter,并進行相關設定;
通過簡單方式進行配置,使用basicConfig()函數直接進行配置;
通過配置檔案進行配置,使用fileConfig()函數讀取配置檔案;
通過配置字典進行配置,使用dictConfig()函數讀取配置資訊;
通過網絡進行配置,使用listen()函數進行網絡配置。
5.1 basicConfig關鍵字參數
關鍵字
描述
filename
建立一個FileHandler,使用指定的檔案名,而不是使用StreamHandler
filemode
如果指明了檔案名,指明打開檔案的模式(如果沒有指明filemode,預設為'a')
format
handler使用指明的格式化字元串
datefmt
使用指明的日期/時間格式
level
指明根logger的級别
stream
使用指明的流來初始化StreamHandler。該參數與'filename'不相容,如果兩個都有,'stream'被忽略
5.1.1 有用的format格式
格式
描述
%(levelno)s
列印日志級别的數值
%(levelname)s
列印日志級别名稱
%(pathname)s
列印目前執行程式的路徑
%(filename)s
列印目前執行程式名稱
%(funcName)s
列印日志的目前函數
%(lineno)d
列印日志的目前行号
%(asctime)s
列印日志的時間
%(thread)d
列印線程id
%(threadName)s
列印線程名稱
%(process)d
列印程序ID
%(message)s
列印日志資訊
5.1.2 有用的datefmt格式
格式
描述
%y
兩位數的年份表示(00-99)
%Y
四位數的年份表示(000-9999)
%m
月份(01-12)
%d
月内中的一天(0-31)
%H
24小時制小時數(0-23)
%I
12小時制小時數(01-12)
%M
分鐘數(00=59)
%S
秒(00-59)
%a
本地簡化星期名稱
%A
本地完整星期名稱
%b
本地簡化的月份名稱
%B
本地完整的月份名稱
%c
本地相應的日期表示和時間表示
%j
年内的一天(001-366)
%p
本地A.M.或P.M.的等價符
%U
一年中的星期數(00-53)星期天為星期的開始
%w
星期(0-6),星期天為星期的開始
%W
一年中的星期數(00-53)星期一為星期的開始
%x
本地相應的日期表示
%X
本地相應的時間表示
%Z
目前時區的名稱
%%
%号本身
五、代碼示例
5.1 示例1
# -*- coding: utf-8 -*-
# @File : log.py
# Create Time: 12/24/2019 10:16 AM
# Usage, put your example for your API
#
#
# Create by : JunPing Ge
# changelog:
#
import logging
logger_name = 'example'
logger = logging.getLogger(logger_name)
logger.setLevel(logging.DEBUG)
log_path = './log.log'
file_handler = logging.FileHandler(log_path)
file_handler.setLevel(logging.WARNING)
stream_handler = logging.StreamHandler()
stream_handler.setLevel(logging.DEBUG)
format_str = "%(asctime)-15s %(levelname)s %(filename)s %(lineno)d %(message)s"
date_format_str = "%Y-%m-%d %H:%M:%S"
formatter = logging.Formatter(format_str,date_format_str)
file_handler.setFormatter(formatter)
stream_handler.setFormatter(formatter)
logger.addHandler(file_handler)
logger.addHandler(stream_handler)
logger.info('info message')
logger.debug('debug message')
logger.warning('warn message')
logger.error('error message')
logger.critical('critical message')
cmd列印資訊如下:
2019-12-24 14:22:54 INFO log.py 31 info message
2019-12-24 14:22:54 DEBUG log.py 32 debug message
2019-12-24 14:22:54 WARNING log.py 33 warn message
2019-12-24 14:22:54 ERROR log.py 34 error message
2019-12-24 14:22:54 CRITICAL log.py 35 critical message
log.log檔案列印資訊如下:
2019-12-24 14:22:54 WARNING log.py 33 warn message
2019-12-24 14:22:54 ERROR log.py 34 error message
2019-12-24 14:22:54 CRITICAL log.py 35 critical message
5.2 從檔案中讀取配置資訊
logging.conf代碼如下:
[loggers]
keys=root,simpleExample
[handlers]
keys=consoleHandler
[formatters]
keys=simpleFormatter
[logger_root]
level=DEBUG
handlers=consoleHandler
[logger_simpleExample]
level=DEBUG
handlers=consoleHandler
qualname=simpleExample
propagate=0
[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=simpleFormatter
args=(sys.stdout,)
[formatter_simpleFormatter]
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
datefmt=
主程式代碼如下:
# -*- coding: utf-8 -*-
import logging
import logging.config
logging.config.fileConfig("logging.conf") # 采用配置檔案
# create logger
logger = logging.getLogger("simpleExample")
# "application" code
logger.debug("debug message")
logger.info("info message")
logger.warning("warn message")
logger.error("error message")
logger.critical("critical message")
cmd列印資訊如下:
C:\ProgramData\Miniconda3\python.exe G:/gejunping/extract_bin/Merge_bin/read_logging.py
2019-12-24 14:28:39,524 - simpleExample - DEBUG - debug message
2019-12-24 14:28:39,524 - simpleExample - INFO - info message
2019-12-24 14:28:39,524 - simpleExample - WARNING - warn message
2019-12-24 14:28:39,524 - simpleExample - ERROR - error message
2019-12-24 14:28:39,524 - simpleExample - CRITICAL - critical message
5.3 多子產品使用logging
同一個python解釋器内,多次調用logging.getLogger('log_name')都會傳回同一個logger執行個體。