首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

自製簡易 Java Logger:MyLogger 實作教學

     編輯:Java 相關知識

前言:為什麼要自己寫 Logger?

在早期的 Java 開發中,log4j 雖然功能強大,但配置複雜,特別是在 Tomcat 環境下設定日誌檔案的相對路徑常讓開發者頭痛。此外,使用 main 方法進行單元測試時,log4j 有時也無法正常運作。為了解決這些痛點,筆者決定自行實作一個輕量級的 Logger——MyLogger,提供類似 log4j 的基本介面,卻擁有更簡單的配置方式。

核心設計概念

  • 單例模式管理:透過 HashMap 快取 Logger 實例,確保同名 Logger 僅建立一次。
  • 多層級日誌:支援 debug、info、warn、error 四個等級。
  • 雙重輸出:同時輸出至 Console(標準輸出)與 HTML 格式的日誌檔案。
  • 動態路徑解析:利用專案自訂的 SystemPath 類別自動取得專案根目錄下的 WEB-INF/logs/ 路徑。

原始碼解析

類別結構與靜態初始化

package net.ftiger.mis.tools.log;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import java.util.HashMap;
import net.ftiger.mis.tools.SystemPath;

public class MyLogger {
    private static HashMap instances = null;
    private String name;
    private static String logFilePath = "d:\\"; // 預設路徑,稍後會被覆寫
    private static int level = 0; // 預設記錄所有等級
    private static String[] sLevel = {"debug", "info ", "warn ", "error"};
    private static String[] sColor = {"#eeeeee", "green", "yellow", "red"}; // 保留欄位,可擴充 HTML 顏色

    private MyLogger(String name) {
        this.name = name;
    }
    // ... 以下省略 getter 方法
}

取得 Logger 實例(雙重檢查鎖定簡化版)

public synchronized static MyLogger getLogger(Class cls) {
    return getLogger(cls.getName());
}

public synchronized static MyLogger getLogger(String name) {
    if (instances == null) {
        init();
    }
    Object obj = instances.get(name);
    if (obj == null) {
        MyLogger instance = new MyLogger(name);
        instances.put(name, instance);
        return instance;
    }
    return (MyLogger) obj;
}

private static void init() {
    instances = new HashMap();
    // 關鍵:自動解析專案部署路徑下的 logs 目錄
    logFilePath = SystemPath.getSystemPath("\\WEB-INF\\logs\\");
}

核心寫入邏輯

private void log(String message, int iLevel) {
    if (iLevel < level) return; // 等級過濾

    Date now = new Date();
    StringBuffer sLog = new StringBuffer();
    sLog.append(now.toLocaleString());
    sLog.append(" [" + sLevel[iLevel] + "] ");
    sLog.append(message);
    sLog.append("[" + name + "]:");

    // 1. 輸出至 Console
    System.out.println(sLog.toString());

    // 2. 輸出至檔案 (HTML 格式)
    if (logFilePath == null) return;

    // 檔案命名規則:年_月_日log.htm
    String logFileName = logFilePath + now.getYear() + "_" + (now.getMonth() + 1) + "_" + now.getDate() + "log.htm";
    File logFile = new File(logFileName);

    if (!logFile.exists()) {
        createNewFile(logFileName); // 建立帶有基本 HTML 結構的新檔案
    }

    try (FileWriter writer = new FileWriter(logFileName, true);
         PrintWriter out = new PrintWriter(writer)) {
        out.println("<br>");
        out.println(now.toLocaleString() + "<br>");
        out.println(name + "<br>");
        out.println("[" + sLevel[iLevel] + "]<br>");
        out.println(message + "<br>");
    } catch (IOException e) {
        e.printStackTrace(System.out);
    }
}

建立新日誌檔案(初始化 HTML 結構)

private void createNewFile(String fileName) {
    try (FileWriter writer = new FileWriter(fileName, false);
         PrintWriter out = new PrintWriter(writer)) {
        out.println("<html><head><title>Log File</title></head><body>");
        // 可在此加入 CSS 樣式
        out.println("</body></html>");
    } catch (IOException e) {
        e.printStackTrace(System.out);
    }
}

公開 API 介面

public void debug(String message) { log(message, 0); }
public void info(String message)  { log(message, 1); }
public void warn(String message)  { log(message, 2); }
public void error(String message) { log(message, 3); }

使用範例

public class MyTest {
    private static MyLogger log = MyLogger.getLogger(MyTest.class);

    public static void main(String[] args) {
        log.debug("除錯訊息");
        log.info("一般資訊");
        log.warn("警告訊息");
        log.error("錯誤訊息");
    }
}

優缺點總結與現代替代方案

優點缺點
零配置檔案,開箱即用非執行緒安全的 HashMap(高併發下建議改用 ConcurrentHashMap)
自動處理相對路徑問題缺乏滾動檔案、非同步寫入等進階功能
HTML 輸出方便瀏覽器直接查看效能未優化,頻繁 I/O 可能影響主執行緒

現代建議:目前專案請直接使用 SLF4J + Logback 或 Log4j 2,它們解決了上述所有問題,且支援非同步記錄、動態配置熱載入、結構化日誌(JSON)等企業級特性。本範例僅供教學參考,理解 Logger 內部運作機制。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved