python logging模塊詳解


一、簡單使用

#!/usr/local/bin/python
# -*- coding:utf-8 -*-
import logging

logging.debug('debug message')
logging.info('info message')
logging.warn('warn message')
logging.error('error message')
logging.critical('critical message') 

輸出:

WARNING:root:warn message
ERROR:root:error message
CRITICAL:root:critical message

默認情況下,logging模塊將日志打印到屏幕上(stdout),日志級別為WARNING(即只有日志級別高於WARNING的日志信息才會輸出),日志格式如下圖所示:

問題來了

日志級別等級及設置是怎樣的?
怎樣設置日志的輸出方式?比如輸出到日志文件中?

二、簡單配置

2.1 日志級別

級別 何時使用
DEBUG 詳細信息,典型地調試問題時會感興趣
INFO 證明事情按預期工作
WARNING 表明發生了一些意外,或者不久的將來會發生問題(如‘磁盤滿了’)。軟件還是在正常工作
ERROR 由於更嚴重的問題,軟件已不能執行一些功能了
CRITICAL 嚴重錯誤,表明軟件已不能繼續運行了

2.2 配置代碼

#!/usr/local/bin/python
# -*- coding:utf-8 -*-
import logging

# 通過下面的方式進行簡單配置輸出方式與日志級別
logging.basicConfig(filename='logger.log', level=logging.INFO)

logging.debug('debug message')
logging.info('info message')
logging.warn('warn message')
logging.error('error message')
logging.critical('critical message')

輸出:
標准輸出(屏幕)未顯示任何信息,發現當前工作目錄下生成了logger.log,內容如下:

INFO:root:info message
WARNING:root:warn message
ERROR:root:error message
CRITICAL:root:critical message

因為通過level=logging.INFO設置日志級別為INFO,所以所有的日志信息均輸出出來了。

問題又來了

通過上述配置方法都可以配置那些信息?

在解決以上問題之前,需要先了解幾個比較重要的概念,Logger,Handler,Formatter,Filter  

三、幾個重要的概念

  • Logger 記錄器,暴露了應用程序代碼能直接使用的接口。
  • Handler 處理器,將(記錄器產生的)日志記錄發送至合適的目的地。
  • Filter 過濾器,提供了更好的粒度控制,它可以決定輸出哪些日志記錄。
  • Formatter 格式化器,指明了最終輸出中日志記錄的布局。

3.1 Logger 記錄器

Logger是一個樹形層級結構,在使用接口debug,info,warn,error,critical之前必須創建Logger實例,即創建一個記錄器,如果沒有顯式的進行創建,則默認創建一個root logger,並應用默認的日志級別(WARN),處理器Handler(StreamHandler,即將日志信息打印輸出在標准輸出上),和格式化器Formatter(默認的格式即為第一個簡單使用程序中輸出的格式)。
創建方法: logger = logging.getLogger(logger_name)

創建Logger實例后,可以使用以下方法進行日志級別設置,增加處理器Handler。

  • logger.setLevel(logging.ERROR) # 設置日志級別為ERROR,即只有日志級別大於等於ERROR的日志才會輸出
  • logger.addHandler(handler_name) # 為Logger實例增加一個處理器
  • logger.removeHandler(handler_name) # 為Logger實例刪除一個處理器

3.2 Handler 處理器

Handler處理器類型有很多種,比較常用的有三個,StreamHandlerFileHandlerNullHandler,詳情可以訪問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實例。

 

參考文檔1:https://www.jianshu.com/p/feb86c06c4f4  

參考文檔2:https://blog.csdn.net/zyz511919766/article/details/25136485

  

  

  

  

  

  

  

  

  

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM