程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

Python的日志輸出

編輯:Python

目錄
  • logging模塊
    • 一、 基礎使用
      • 1、 簡介
      • 2、 常用函數
      • 3、 日志配置
    • 二、 日志進階
      • 1、 四大組件
      • 2、 Logger組件
        • 2.1 常用方法
        • 2.2 獲取對象
        • 2.3 層級等級
      • 3、 Handler組件
        • 3.1 組件用途
        • 3.2 組件方法
      • 4、 Formater組件
        • 4.1 用途語法
        • 4.2 使用案例
      • 5、 Filter組件
    • 三、 配置文件
      • 1、 conf文件
      • 2、 yaml文件

logging模塊

一、 基礎使用

1、 簡介

程序都有記錄日志的需求,並且日志中包含的信息既有正常的程序訪問日志,還可能有錯誤、警告等信息輸出。
python的logging模塊提供了標准的日志接口,可以通過它存儲各種格式的日志,logging的日志分為debug(), info(), warning(), error() and critical()5個級別。
python默認只打印warning級別以上的日志

日志基礎:

兩種記錄日志的方式:

  • 第一種方式是使用logging提供的模塊級別的函數
  • 第二種方式是使用Logging日志系統的四大組件

其實模塊級別的日志記錄函數也是對logging日志系統相關類的封裝。

2、 常用函數

模塊級別的常用函數

函數說明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進行一次性配置

默認只有warning級別以上的日志會打印

3、 日志配置

basicConfig所有參數信息

參數名稱描述filename指定日志輸出目標文件的文件名filemode指定日志文件的打開模式,默認'a'format指定日志格式字符串datefmt指定日期/時間格式,需format中包含%(asctime)s字段level指定日志器的日志級別stream指定日志輸出目標,如sys.stdoutsys.stderr以及網絡streamstreamfilename不能共存style指定format格式字符串的風格,可取值為'%'、'{'和'$',默認為'%'handlers該選項如果應該是一個創建了多個Handler的可迭代對象,這些handler將會被添加到root logger

format所有參數列表

字段/屬性名稱使用格式描述asctime%(asctime)s字符串形式的當前時間。默認格式是 “2003-07-08 16:49:45,896”created%(created)f時間戳,就是調用time.time()函數返回的值msecs%(msecs)d日志發生時間的毫秒部分levelname%(levelname)s文字形式的日志級別levelno%(levelno)s數字形式的日志級別(10, 20, 30, 40, 50)name%(name)s使用的日志器名稱,默認是'root'message%(message)s日志記錄的文本內容,msg % args計算得到的pathname%(pathname)s調用日志記錄函數的源碼文件的全路徑filename%(filename)spathname的文件名部分,含文件後綴module%(module)sfilename的名稱部分,不包含後綴lineno%(lineno)d調用日志記錄函數的源代碼所在的行號funcName%(funcName)s調用日志記錄函數的函數名process%(process)d進程IDprocessName%(processName)s進程名稱thread%(thread)d線程IDthreadName%(thread)s線程名稱

示例:

#!/usr/bin/python3
# -*- coding: UTF-8 -*-
__author__ = "A.L.Kun"
__file__ = "demo01.py"
__time__ = "2022/8/4 10:38"
import logging
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s | %(levelname)s | %(message)s', datefmt='%Y-%m-%d %I:%M:%S %p')
# level 配置最低打印的日志級別
# format 格式化輸出子讓孩子信息
logging.error("error")
logging.log(logging.DEBUG, "%s is %s old", 'Tom', '12') # 如果信息裡面有變量,可以通過增加參數數量的方法來輸出完整內容

注意:

  • logging.debug()等方法的定義中,除了msgargs參數外,還有一個**kwargs參數。它們支持3個關鍵字參數:exc_info, stack_info, extra,下面對這幾個關鍵字參數作個說明。
    • exc_info: 其值為布爾值,如果該參數的值設置為True,則會將異常信息添加到日志消息中。如果沒有異常信息則添加None到日志信息中
    • stack_info:其值也為布爾值,默認值為False。如果該參數的值設置為True,棧信息將會被添加到日志信息中
    • extra:這是一個字典(dict)參數,它可以用來自定義消息格式中所包含的字段,但是它的key不能與logging模塊定義的字段沖突

二、 日志進階

1、 四大組件

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

組件之間的關系

  • 日志器(logger)需要通過處理器(handler)將日志信息輸出到目標位置,如:文件、sys.stdout、網絡等
  • 不同的處理器(handler)可以將日志輸出到不同的位置
  • 日志器(logger)可以設置多個處理器(handler)將同一條日志記錄輸出到不同的位置
  • 每個處理器(handler)都可以設置自己的過濾器(filter)實現日志過濾,從而只保留感興趣的日志
  • 每個處理器(handler)都可以設置自己的格式器(formatter)實現同一條日志以不同的格式輸出到不同的地方

日志器(logger)是入口,真正干活兒的是處理器(handler),處理器(handler)還可以通過過濾器(filter)和格式器(formatter)對要輸出的日志內容做過濾和格式化等處理操作

2、 Logger組件

2.1 常用方法

Logger對象有三個任務要做:

  • 向應用程序代碼暴露幾個方法,使應用程序可以在運行時記錄日志消息
  • 基於日志嚴重等級(默認的過濾設施)或filter對象來決定要對哪些日志進行後續處理
  • 將日志消息傳送給所有感興趣的日志handlers

Logger對象最常用的方法分為兩類:配置方法 和 發送方法

配置方法描述Logger.setLevel()設置日志器將會處理的日志消息的最低嚴重級別Logger.addHandler()Logger.removeHandler()為該logger對象添加 和 移除一個handler對象Logger.addFilter() Logger.removeFilter()為該logger對象添加 和 移除一個filter對象發送方法描述Logger.debug(), Logger.info(), Logger.warning(), Logger.error(), Logger.critical()創建一個與它們的方法名對應等級的日志記錄Logger.exception()創建一個類似於Logger.error()的日志消息Logger.log()需要獲取一個明確的日志level參數來創建一個日志記錄

Logger.exception()Logger.error()的區別在於:Logger.exception()將會輸出堆棧追蹤信息,另外一個通常只是在一個exception handler中調用該方法

2.2 獲取對象

一種方式是通過Logger類的實例化方法創建一個Logger類的實例,更通常的方法是用logging.getLogger()方法
logging.getLogger()方法有一個可選參數name,該參數表示將要返回的日志器的名稱標識,如果不提供該參數,則其值為'root'。若以相同的name參數值多次調用getLogger()方法,將會返回指向同一個logger對象的引用。

# 聊天工具的圖形界面模塊可以這樣獲得它的Logger:
LOG = logging.getLogger(”chat.gui”)
# 核心模塊可以這樣:
LOG = logging.getLogger(”chat.kernel”)

2.3 層級等級

logger的層級結構與有效等級:

  • 層級結構
    logger的名稱是一個以'.'分割的層級結構,每個'.'後面的logger都是'.'前面的loggerchildren
  • 有效等級
    如果一個logger上沒有被明確設置一個level,那麼該logger就是使用它parentlevel,直到找到個一個明確設置了level的祖先為止。root logger總是會有一個明確的level設置(默認為 WARNING)。當決定是否去處理一個已發生的事件時,logger的有效等級將會被用來決定是否將該事件傳遞給該loggerhandlers進行處理
  • 繼承關系
    child loggers在完成對日志消息的處理後,默認會將日志消息傳遞給與它們的祖先loggers相關的handlers。因此不必所有loggers定義和配置handlers,只需要為一個頂層的logger配置handlers,然後按照需要創建child loggers就可足夠了。可以通過將一個loggerpropagate屬性設置為False來關閉這種傳遞機制,默認為True

3、 Handler組件

3.1 組件用途

Handler對象的作用是(基於日志消息的level)將消息分發到handler指定的位置(文件、網絡、郵件等)。Logger對象可以通過addHandler()方法為自己添加0個或者更多個handler對象。比如,一個應用程序可能想要實現以下幾個日志需求:

  • 把所有日志都發送到一個日志文件中
  • 把所有嚴重級別大於等於error的日志發送到stdout(標准輸出)
  • 把所有嚴重級別為critical的日志發送到一個email郵件地址

這種場景就需要3個不同的handlers,每個handler負責發送一個特定級別的日志到一個特定的位置

3.2 組件方法

方法描述Handler.setLevel()設置handler將會處理的日志消息的最低嚴重級別Handler.setFormatter()為handler設置一個格式器對象Handler.addFilter()Handler.removeFilter()為handler添加 和 刪除一個過濾器對象

應用程序代碼不應該直接實例化和使用Handler實例。因為Handler是一個基類,它只定義了所有handlers都應該有的接口

常用的Handler

Handler描述logging.StreamHandler將日志消息發送到輸出到Stream,如std.out, std.err或任何file-like對象。logging.FileHandler將日志消息發送到磁盤文件,默認情況下文件大小會無限增長logging.handlers.RotatingFileHandler將日志消息發送到磁盤文件,並支持日志文件按大小切割logging.hanlders.TimedRotatingFileHandler將日志消息發送到磁盤文件,並支持日志文件按時間切割logging.handlers.HTTPHandler將日志消息以GET或POST的方式發送給一個HTTP服務器logging.handlers.SMTPHandler將日志消息發送給一個指定的email地址logging.NullHandler該Handler實例會忽略error messages

具體使用可以參照官方文檔:https://docs.python.org/zh-cn/3/library/logging.handlers.html

4、 Formater組件

4.1 用途語法

日志的formatter是個獨立的組件,可以跟handler組合。Formater對象用於配置日志信息的最終順序、結構和內容。
Formatter類的構造方法定義如下:

logging.Formatter.__init__(fmt=None, datefmt=None, style='%')

參數:

  • fmt:指定消息格式化字符串,如果不指定該參數則默認使用message的原始值
  • datefmt:指定日期格式字符串,如果不指定該參數則默認使用"%Y-%m-%d %H:%M:%S"
  • style:可取值為 '%', '{'和 '$',如果不指定該參數則默認使用'%'

4.2 使用案例

#!/usr/bin/python3
# -*- coding: UTF-8 -*-
__author__ = "A.L.Kun"
__file__ = "demo01.py"
__time__ = "2022/8/4 10:38"
import logging
LOG = logging.getLogger()
fh = logging.FileHandler("access.log")
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setFormatter(formatter) # 把formater綁定到fh上
LOG.addHandler(fh)
LOG.warning("test")

5、 Filter組件

Filter可以被Handler和Logger用來做比level更細粒度的、更復雜的過濾功能。Filter是一個過濾器基類,它只允許某個logger層級下的日志事件通過過濾。該類定義如下:

class logging.Filter(name='A.B')
filter(record)

一個filter實例化時傳遞的name參數值為'A.B',那麼該filter將只允許名稱為類似'A.B','A.B,C','A.B.C.D','A.B.D'loggers產生的日志記錄通過過濾。如果name為空字符串,則允許所有的日志事件通過過濾。

filter方法用於具體控制傳遞的record記錄是否能通過過濾,如果該方法返回值為0表示不能通過過濾,返回值為非0表示可以通過過濾。

若需要,可以在filter(record)方法內部改變該record,比如添加、刪除或修改一些屬性
還可以通過filter做一些統計工作,如計算一個特殊的loggerhandler所處理的record數量等

使用示例:

class IgnoreBackupLogFilter(logging.Filter):
"""忽略帶db backup 的日志"""
def filter(self, record): # 固定寫法
return "db backup" not in record.getMessage()
logger.addFilter(IgnoreBackupLogFilter()) # 自定義過濾器
logger.warning("start to run db backup job ....")
logger.error("test error ....")

三、 配置文件

  1. 使用配置方法的 Python 代碼顯式創建記錄器,處理程序和格式化程序
  2. 創建日志記錄配置文件並使用該fileConfig()功能讀取它
  3. 創建配置信息字典並將其傳遞給 dictConfig()函數

1、 conf文件

[loggers] # 設置兩個日志記錄器,root和core,用來區分運行的文件
keys=root, core
[handlers] # 設置handles
keys=consoleHandler,fileHandler
[formatters] # 設置格式化處理
keys=simpleFormatter
[logger_root] # 配置root日志輸出
level=DEBUG
handlers=fileHandler
[logger_core] # 配置core的日志輸出
level=DEBUG
# 輸出最低級別為debug
handlers=consoleHandler,fileHandler
# 添加控制台輸出和文件輸出
qualname=core
# 配置輸出名字,一定要和日志輸出的同名,相當於實例化中的參數name,root可以不用配置
propagate=0
# 是否要傳遞給祖先處理器,如果為1,則會輸出多遍,父類也會輸出
[handler_consoleHandler] # 配置控制台輸出consoleHandler
class=StreamHandler
level=WARNING
formatter=simpleFormatter
args=(sys.stdout,)
[handler_fileHandler] # 配置文件輸出fileHandler
class=FileHandler
level=DEBUG
formatter=simpleFormatter
args=('test.log','a+')
[formatter_simpleFormatter] # 配置輸出格式化simpleFormatter
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
datefmt=%Y-%m-%d %I:%M:%S %p

使用方法:

#!/usr/bin/python3
# -*- coding: UTF-8 -*-
__author__ = "A.L.Kun"
__file__ = "demo.py"
__time__ = "2022/8/4 11:42"
import logging
from logging.config import fileConfig, dictConfig
fileConfig("config.conf")
LOG = logging.getLogger("core")
LOG.error("這個是core對象的輸出哦")
LOG = logging.getLogger()
LOG.error("這個是root對象輸出哦")

2、 yaml文件

環境配置:pip install PyYAML

我們先把上面的conf文件轉換為yaml文件

version: 1.0
formatters:
simpleFormatter:
format: '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
datefmt: '%Y-%m-%d %I:%M:%S %p'
handlers:
fileHandler:
class: logging.FileHandler
level: DEBUG
formatter: simpleFormatter
filename: test.log
mode: a
encoding: utf8
consoleHandler:
class: logging.StreamHandler
level: WARNING
formatter: simpleFormatter
stream: ext://sys.stdout # 注意這個哦
loggers:
root:
level: DEBUG
handlers: [fileHandler]
core:
level: DEBUG
handlers: [consoleHandler,fileHandler]
qualname: core
propagate: 0

使用方法:

#!/usr/bin/python3
# -*- coding: UTF-8 -*-
__author__ = "A.L.Kun"
__file__ = "demo.py"
__time__ = "2022/8/4 11:42"
import yaml
import logging
from logging.config import fileConfig, dictConfig
# fileConfig("config.conf")
with open("config.yaml", 'r', encoding='utf-8') as f:
config = yaml.load(f.read(), yaml.FullLoader)
dictConfig(config)
LOG = logging.getLogger("core")
LOG.error("這個是core對象的輸出哦")

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved