| 類型 | 架構 | 特點 | 典型代表 |
|---|---|---|---|
| 服務進程型 | 獨立進程,訊息佇列通訊 | 異步、跨進程、統一管理 | Windows Event Log, Syslog |
| 系統調用型 | 進程內庫,同步/異步寫入 | 低延遲、嵌入式、適合除錯 | Log4j, JUL, Logback, 本文框架 |
本文框架屬進程內異步寫入類型:同步接收日誌 → 非同步批量落盤 → 靈活格式/過濾/多輸出。
// 日誌記錄模組(前端)
Logger ←→ LoggerLevel ←→ LogItem → AppenderManager → Appender
// 日誌輸出模組(後端)
AbstractAppender
├── ConsoleAppender (System.out/err)
└── FileAppender (高速緩衝 + 專屬執行緒)


public class Logger {
private static final Map loggers = new ConcurrentHashMap<>();
private final String name;
private LoggerLevel level = LoggerLevel.DEBUG;
private Logger(String name) { this.name = name; }
// 工廠方法:按名稱獲取/建立
public static Logger getLogger(String name) {
return loggers.computeIfAbsent(name, Logger::new);
}
// 便利方法:按類別獲取
public static Logger getLogger(Class> clazz) {
return getLogger(clazz.getName());
}
// 五大級別輸出介面
public void debug(String msg) { log(LoggerLevel.DEBUG, msg); }
public void info(String msg) { log(LoggerLevel.INFO, msg); }
public void warn(String msg) { log(LoggerLevel.WARN, msg); }
public void error(String msg) { log(LoggerLevel.ERROR, msg); }
public void fatal(String msg) { log(LoggerLevel.FATAL, msg); }
private void log(LoggerLevel level, String msg) {
if (this.level.compareTo(level) <= 0) { // 級別過濾
LogItem item = new LogItem(this.name, level, msg,
captureCallerInfo()); // 捕獲堆疊資訊
AppenderManager.dispatch(item); // 分派給後端
}
}
}
public class LogItem {
private final String loggerName;
private final LoggerLevel level;
private final String message;
private final long timestamp;
private final String threadName;
private final String className;
private final String methodName;
private final int lineNumber;
// ... getter
}
private StackTraceElement captureCallerInfo() {
// 拋出並捕獲異常獲取堆疊
try { throw new Exception(); }
catch (Exception e) {
StackTraceElement[] stack = e.getStackTrace();
// 跳過 log 內部調用層,定位業務調用處
return stack[CALLER_DEPTH];
}
}
public abstract class AbstractAppender {
protected LoggerLevel threshold = LoggerLevel.DEBUG;
// 過濾邏輯:級別、Logger 名稱、訊息內容等
public boolean doFilter(LogItem item) { ... }
// 子類實現具體寫入
protected abstract void doAppend(LogItem item);
public final void append(LogItem item) {
if (doFilter(item)) doAppend(item);
}
}
// 控制台輸出:簡單同步
public class ConsoleAppender extends AbstractAppender {
@Override
protected void doAppend(LogItem item) {
System.out.println(formatter.format(item));
}
}
public class FileAppender extends AbstractAppender {
private final Vector buffer = new Vector<>(); // 執行緒安全
private final FileWriter writer;
private final WorkerThread worker = new WorkerThread();
private final int bufferSize = 1000;
private final long flushInterval = 2000; // 2 秒
public FileAppender(String filePath) {
this.writer = new FileWriter(filePath, true);
worker.start();
}
@Override
protected void doAppend(LogItem item) {
buffer.add(item); // 極快,無 IO 阻塞
if (buffer.size() >= bufferSize) {
synchronized (buffer) { buffer.notify(); } // 喚醒寫入
}
}
class WorkerThread extends Thread {
@Override
public void run() {
while (true) {
List batch;
synchronized (buffer) {
while (buffer.isEmpty()) {
try { buffer.wait(flushInterval); } catch (InterruptedException e) { return; }
}
batch = new ArrayList<>(buffer);
buffer.clear();
}
// 批量寫入
for (LogItem item : batch) {
writer.write(formatter.format(item));
}
writer.flush();
// 可在此處理日誌切割、壓縮、上傳等
}
}
}
}

| 模式 | 應用場景 |
|---|---|
| 工廠方法 | Logger.getLogger() 建立/獲取 Logger 實例 |
| 策略模式 | AbstractAppender + ConsoleAppender/FileAppender 可換輸出 |
| 單例模式 | Logger 管理、AppenderManager、Cleaner 執行緒 |
| 生產者消費者 | FileAppender 緩衝區 + WorkerThread |
| 命令模式 | LogItem 封裝日誌操作 |
| 框架 | 定位 | 優勢 | 建議場景 |
|---|---|---|---|
| Logback | Log4j 繼任者 | 效能最強、原生 SLF4J、配置熱載入 | 絕大多數新專案首選 |
| Log4j2 | 下一代 | 非同步 Loggers (LMAX Disruptor)、GC 無壓力 | 極高吞吐、低延遲系統 |
| SLF4J + Logback | 門面 + 實現 | 解耦 API、遷移零成本 | 標準企業級專案 |
| JUL (java.util.logging) | JDK 內建 | 零依賴、模組化支援 | 嵌入式、無第三方依賴限制 |
優秀日誌框架核心在於:前端極速接收(級別過濾、上下文捕獲)+ 後端非同步批量落盤(緩衝、專屬執行緒、格式化)。理解此架構有助於:排查日誌效能瓶頸、自定義 Appender 整合 Kafka/ES、設計結構化日誌規範。現代專案直接使用 Logback/Log4j2 + SLF4J,專注於配置調優與業務埋點規範,而非重複造輪子。