[Python]使用logging創造改良版日誌紀錄器,不重複紀錄

更新於 發佈於 閱讀時間約 11 分鐘

呈上篇,若是在大型系統中使用,重複被調用時,在每次紀錄時都會創建一個新的 FileHandler,這會導致日誌處理器不斷累積,從而使日誌重複記錄。

[Python]使用logging創建兩個以上的日誌紀錄

使用__new__的方法來避免重複調用

改良後

setup_logger 方法中創建一次 FileHandler,並確保不重複創建它。可以在類別中新增一個來initialized確保 FileHandler 只被創建一次。

import os
import logging
import inspect
from datetime import datetime
from threading import Lock

class WriteLogTxt:
_instances = {}
_lock = Lock()

def __new__(cls, file_path, file_name):
with cls._lock:
key = (file_path, file_name)
if key not in cls._instances:
instance = super(WriteLogTxt, cls).__new__(cls)
cls._instances[key] = instance
instance.__initialized = False
return cls._instances[key]

def __init__(self, file_path, file_name):
if self.__initialized:
return
self.file_path = file_path
self.file_name = file_name
self.logger = None
self.logger_initialized = False
self.__initialized = True

def setup_logger(self):
if not self.logger_initialized:
now = datetime.now()
year_month = now.strftime("%Y/%m")
log_folder = os.path.join(self.file_path, year_month)
if not os.path.exists(log_folder):
os.makedirs(log_folder)
log_format = '%(asctime)s [%(levelname)s] %(msg)s'
file_handler = logging.FileHandler(os.path.join(log_folder, f"{self.file_name}_{now.date()}.log"))
file_handler.setLevel(logging.INFO)
file_handler.setFormatter(logging.Formatter(log_format, datefmt='%Y/%m/%d %H:%M:%S'))

self.logger = logging.getLogger(f"{self.file_path}/{self.file_name}")
self.logger.setLevel(logging.INFO)
self.logger.addHandler(file_handler)
self.logger_initialized = True

def write_log_info(self, log_content):
self.setup_logger()
caller_frame = inspect.stack()[1]
caller_filename = caller_frame.filename
caller_lineno = caller_frame.lineno
match = os.path.basename(caller_filename)
self.logger.info(f"[File name :{match}][Line :{caller_lineno}]{log_content}")

def write_log_warning(self, log_content):
self.setup_logger()
caller_frame = inspect.stack()[1]
caller_filename = caller_frame.filename
caller_lineno = caller_frame.lineno
match = os.path.basename(caller_filename)
self.logger.warning(f"[File name :{match}][Line :{caller_lineno}]{log_content}")


# 創建並設置日誌記錄器
for i in range(10):
    log_obj1 = WriteLogTxt('D:/crab/crab/log', 'Log')
    log_obj1.setup_logger()
    log_obj1.write_log_info("This is a log message")

即使不斷重複被調用類別,也只會被創建一次,不會在有重複紀錄的bug

raw-image

針對__new__ 方法與__init__ 方法 更詳細的說明

在 Python 中,__new__ 方法負責創建一個新的實例。這個方法在 __init__ 方法之前被調用,它允許我們控制對象的創建過程。

這段程式碼使用 __new__ 方法來實現單例模式,以確保每個 file_pathfile_name 組合只會創建一個實例。

詳細說明如下:

__new__ 方法

def __new__(cls, file_path, file_name):
with cls._lock:
key = (file_path, file_name)
if key not in cls._instances:
instance = super(WriteLogTxt, cls).__new__(cls)
cls._instances[key] = instance
instance.__initialized = False
return cls._instances[key]
  • cls: 代表這個類本身,它在類方法中被用作第一個參數。
  • file_pathfile_name: 用於唯一標識每個日誌實例的路徑和文件名。

步驟解析

  1. 加鎖with cls._lock: 使用 Lock 來確保此方法在多線程環境下是線程安全的。
  2. 生成唯一鍵key = (file_path, file_name),通過組合 file_pathfile_name 來生成一個唯一鍵。
  3. 檢查實例存在if key not in cls._instances:,如果這個唯一鍵不在 _instances 字典中,則創建一個新的實例。
  4. 創建實例instance = super(WriteLogTxt, cls).__new__(cls) 使用 super() 調用基類(即 object)的 __new__ 方法來創建實例。
  5. 存儲實例cls._instances[key] = instance 將新創建的實例存儲在 _instances 字典中。
  6. 設置初始化標記instance.__initialized = False,設置 __initialized 標記為 False,表示實例尚未被初始化。
  7. 返回實例return cls._instances[key] 返回對應鍵的實例,保證每個鍵只有一個實例。


__init__ 方法

__init__ 方法負責初始化新創建的實例。

當一個實例被創建後(即調用了 __new__ 方法後),__init__ 方法被調用來初始化該實例。詳細說明如下:

def __init__(self, file_path, file_name):
if self.__initialized:
return
self.file_path = file_path
self.file_name = file_name
self.logger = None
self.logger_initialized = False
self.__initialized = True

步驟解析

  1. 檢查是否已初始化if self.__initialized: 如果 __initialized 標記為 True,表示這個實例已經被初始化過了,直接返回,不做重複初始化。
  2. 設置屬性
    • self.file_path = file_path:設置實例的文件路徑屬性。
    • self.file_name = file_name:設置實例的文件名屬性。
    • self.logger = None:初始化 logger 屬性為 None。
    • self.logger_initialized = False:初始化 logger_initialized 標記為 False,表示日誌記錄器尚未初始化。
  3. 設置初始化標記self.__initialized = True,設置 __initialized 標記為 True,表示實例已經被初始化。



留言
avatar-img
留言分享你的想法!
avatar-img
螃蟹_crab的沙龍
151會員
297內容數
本業是影像辨識軟體開發,閒暇時間進修AI相關內容,將學習到的內容寫成文章分享。 興趣是攝影,踏青,探索未知領域。 人生就是不斷的挑戰及自我認清,希望老了躺在床上不會後悔自己什麼都沒做。
螃蟹_crab的沙龍的其他內容
2025/04/15
在軟體開發或部署過程中,我們經常需要對多個 .ini 設定檔進行批次修改,例如將某個舊的參數名稱或路徑名稱,替換成新的命名。 這就像記事本的「全部取代」功能,但你不需要一個個打開檔案慢慢點——你可以用 Python 自動完成這些事! 本文將介紹一個 Python 函式:search_and_re
2025/04/15
在軟體開發或部署過程中,我們經常需要對多個 .ini 設定檔進行批次修改,例如將某個舊的參數名稱或路徑名稱,替換成新的命名。 這就像記事本的「全部取代」功能,但你不需要一個個打開檔案慢慢點——你可以用 Python 自動完成這些事! 本文將介紹一個 Python 函式:search_and_re
2025/04/11
🐶 什麼是 Watchdog? Watchdog 是一個 Python 套件,用來即時監控檔案系統的變化。它可以在資料夾內有「新增」、「修改」、「刪除」等事件時,立即觸發事件處理函式,不需要手動輪詢 (polling),效率高又省資源。 ✅ Watchdog 的特點: 採用 OS 層級的檔案
2025/04/11
🐶 什麼是 Watchdog? Watchdog 是一個 Python 套件,用來即時監控檔案系統的變化。它可以在資料夾內有「新增」、「修改」、「刪除」等事件時,立即觸發事件處理函式,不需要手動輪詢 (polling),效率高又省資源。 ✅ Watchdog 的特點: 採用 OS 層級的檔案
2025/01/12
用 PyInstaller 打包一個簡單計算機應用 (GUI 使用 PyQt5) 本教學將帶您使用 PyQt5 建立一個簡單的計算機應用,並透過 PyInstaller 將其打包成執行檔(EXE)。 1. 安裝所需環境 在開始之前,請確保您已安裝以下工具: 必要套件 Python: 建
Thumbnail
2025/01/12
用 PyInstaller 打包一個簡單計算機應用 (GUI 使用 PyQt5) 本教學將帶您使用 PyQt5 建立一個簡單的計算機應用,並透過 PyInstaller 將其打包成執行檔(EXE)。 1. 安裝所需環境 在開始之前,請確保您已安裝以下工具: 必要套件 Python: 建
Thumbnail
看更多
你可能也想看
Thumbnail
嗨!歡迎來到 vocus vocus 方格子是台灣最大的內容創作與知識變現平台,並且計畫持續拓展東南亞等等國際市場。我們致力於打造讓創作者能夠自由發表、累積影響力並獲得實質收益的創作生態圈!「創作至上」是我們的核心價值,我們致力於透過平台功能與服務,賦予創作者更多的可能。 vocus 平台匯聚了
Thumbnail
嗨!歡迎來到 vocus vocus 方格子是台灣最大的內容創作與知識變現平台,並且計畫持續拓展東南亞等等國際市場。我們致力於打造讓創作者能夠自由發表、累積影響力並獲得實質收益的創作生態圈!「創作至上」是我們的核心價值,我們致力於透過平台功能與服務,賦予創作者更多的可能。 vocus 平台匯聚了
Thumbnail
呈上篇,若是在大型系統中使用,重複被調用時,在每次紀錄時都會創建一個新的 FileHandler,這會導致日誌處理器不斷累積,從而使日誌重複記錄。 [Python]使用logging創建兩個以上的日誌紀錄 使用__new__的方法來避免重複調用 改良後 setup_logger 方法中創建一
Thumbnail
呈上篇,若是在大型系統中使用,重複被調用時,在每次紀錄時都會創建一個新的 FileHandler,這會導致日誌處理器不斷累積,從而使日誌重複記錄。 [Python]使用logging創建兩個以上的日誌紀錄 使用__new__的方法來避免重複調用 改良後 setup_logger 方法中創建一
Thumbnail
打開 jupyter notebook 寫一段 python 程式,可以完成五花八門的工作,這是玩程式最簡便的方式,其中可以獲得很多快樂,在現今這種資訊發達的時代,幾乎沒有門檻,只要願意,人人可享用。 下一步,希望程式可以隨時待命聽我吩咐,不想每次都要開電腦,啟動開發環境,只為完成一個重複性高
Thumbnail
打開 jupyter notebook 寫一段 python 程式,可以完成五花八門的工作,這是玩程式最簡便的方式,其中可以獲得很多快樂,在現今這種資訊發達的時代,幾乎沒有門檻,只要願意,人人可享用。 下一步,希望程式可以隨時待命聽我吩咐,不想每次都要開電腦,啟動開發環境,只為完成一個重複性高
Thumbnail
在網路速度有限的情況下,依序記錄不斷產生的資訊,能統計使用者在頁面上操作了哪些功能。
Thumbnail
在網路速度有限的情況下,依序記錄不斷產生的資訊,能統計使用者在頁面上操作了哪些功能。
Thumbnail
瞭解如何在Xcode15及以上使用Logger進行更好的程式debug。Logger可以更好的組織Log,但也有一些缺點需要注意。本文將介紹Logger的基本使用方式,以及一些注意事項。
Thumbnail
瞭解如何在Xcode15及以上使用Logger進行更好的程式debug。Logger可以更好的組織Log,但也有一些缺點需要注意。本文將介紹Logger的基本使用方式,以及一些注意事項。
Thumbnail
工具功能 (1) 彈性任意查詢檔案,如對來源目錄設定,檔案修改日期 設定,檔名特定字串或副檔名設定後,自動查出明細,並可展開至各階子目錄處理     (2) 依查詢後結果,可產出 LIST ,提供查詢結果之確認,再依此對檔案作複 (3) 可對檔案作移動,複製至別處,刪除處理,使電腦可騰出硬碟空間
Thumbnail
工具功能 (1) 彈性任意查詢檔案,如對來源目錄設定,檔案修改日期 設定,檔名特定字串或副檔名設定後,自動查出明細,並可展開至各階子目錄處理     (2) 依查詢後結果,可產出 LIST ,提供查詢結果之確認,再依此對檔案作複 (3) 可對檔案作移動,複製至別處,刪除處理,使電腦可騰出硬碟空間
Thumbnail
呈上次使用logging來撰寫日誌,利用類別包裝的方式,可實現多個日誌紀錄器,但發現這樣就失去它原先,可以回傳是誰呼叫他並記錄行數的功能。 [Python]使用logging創建兩個以上的日誌紀錄 若開啟函式名稱、行數及訊息的功能,就會像這樣,幾乎都是記錄到,我定義中類別的函式
Thumbnail
呈上次使用logging來撰寫日誌,利用類別包裝的方式,可實現多個日誌紀錄器,但發現這樣就失去它原先,可以回傳是誰呼叫他並記錄行數的功能。 [Python]使用logging創建兩個以上的日誌紀錄 若開啟函式名稱、行數及訊息的功能,就會像這樣,幾乎都是記錄到,我定義中類別的函式
Thumbnail
logging 是 Python 中用於記錄程式運行時信息的模組,它可以幫助你在開發過程中更好地管理和追蹤程式的執行狀態和錯誤信息。 本文較著重使用兩種不同的方法來創建日誌紀錄。 其他有關logging的教學,我推薦以下文章,他介紹蠻詳細的,我就不多贅述了。
Thumbnail
logging 是 Python 中用於記錄程式運行時信息的模組,它可以幫助你在開發過程中更好地管理和追蹤程式的執行狀態和錯誤信息。 本文較著重使用兩種不同的方法來創建日誌紀錄。 其他有關logging的教學,我推薦以下文章,他介紹蠻詳細的,我就不多贅述了。
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News