Log4j

Apache Log4j是一個基於Java的日誌記錄工具。它是由瑞士程式設計師Ceki Gülcü於2001年開發的，現在則是Apache軟體基金會的一個項目。Log4j是幾種Java日誌框架之一。

Gülcü此後開創了SLF4J和Logback 項目，想使其成為Log4j的繼任者。

Log4j團隊創建了Log4j的繼任者，版本號為2.0的新版本。Log4j 2.0著重於Log4j 1.2、1.3、java.util.logging和logback中的問題，並解決這些框架中的架構問題。此外，Log4j 2.0提供了一個插件架構，這使得其更可擴展。Log4j 2.0不是與1.x向後兼容的版本，雖然有一個「適配器」可用。

2021年12月9日，Log4j 2.0的一個零日遠程代碼執行漏洞被報告，其被稱為「Log4Shell」，公共漏洞和暴露編號為CVE-2021-44228。它被定性為「過去十年來最大、最關鍵的漏洞」。

## log4j 1的日誌等級

下表中定義的log4j 1的日誌級別和消息，以嚴重性遞減排序。左欄列出了log4j的日誌級別定義，右列提供了每個日誌級別的簡要說明。

級別｜描述

OFF｜最高級別，用於關閉日誌記錄。

FATAL｜導致應用程式提前終止的嚴重錯誤。一般這些資訊將立即呈現在狀態控制台上。

ERROR｜其他運行時錯誤或意外情況。一般這些資訊將立即呈現在狀態控制台上。

WARN｜使用已過時的API，API的濫用，潛在錯誤，其他不良的或意外的運行時的狀況（但不一定是錯誤的）。一般這些資訊將立即呈現在狀態控制台上。

INFO｜令人感興趣的運行時事件（啟動/關閉）。一般這些資訊將立即呈現在狀態控制台上，因而要保守使用，並保持到最低限度。

DEBUG｜流經系統的詳細資訊。一般這些資訊只記錄到日誌文件中。

TRACE｜最詳細的資訊。一般這些資訊只記錄到日誌文件中。自版本1.2.12。

## 配置Log4j 1.2

有三種方法來配置log4j：通過.properties文件，通過XML文件，通過Java代碼。通過上述任意方法，你可以定義log4j的三個主要組件：Logger、Appender和Layout。通過文件配置log4j，具有無需修改應用即可打開或關閉日誌的好處。例如，應用程式可以在日誌關閉的情況下運行，直到問題出現後，再日誌功能可以簡單地通過修改配置文件重新打開。

Logger（記錄器）是日誌的邏輯文件名。其使用已知的Java應用程式的名稱。每個記錄器當前以什麼日誌記錄級別（FATAL、ERROR等）記錄是獨立配置的。在log4j的早期版本中，這些被稱為類別（category）和優先級（priority），但現在他們分別被稱為logger（記錄器）和level（級別）。

實際的輸出是通過Appender（輸出源）。有許多可用的Appender，比如FileAppender、ConsoleAppender、SocketAppender、SyslogAppender、NTEventLogAppender，甚至SMTPAppender。多個Appender可以被關聯到任何Logger上，所以可以到多個輸出文件上記錄相同的資訊，例如同時到一個本地文件和通過套接字監聽器到另一台電腦上。

Appender使用Layout（布局）格式化日誌條目。常用的格式化為「一次一行」式日誌文件的布局是PatternLayout，其使用一個模式字串，就像C/C++函數printf那樣。此外還有HTMLLayout和XMLLayout，使用HTML或XML格式的時候會更方便。

要調試一個表現異常的配置文件，使用Java VM參數`-Dlog4j.debug`通過標準輸出輸出Log4j自身的資訊。要獲知log4j.propeties的路徑，檢查`getClass().getResource("/log4j.properties")`或`getClass().getResource("/log4j.xml")`。

log4j還有一個隱含的「未配置」配置，即一個缺乏log4j的配置但使用了log4j的Java應用程式。這將把一個警告（該程序未配置log4j）列印到標準輸出，並提供log4j網站的URL，在那裡可以找到警告和配置的詳細資訊。除了列印此警告，未配置的log4j的應用程式不會列印INFO、DEBUG或TRACE級別的消息，而且還可能不輸出更高級別的消息。

### log4j 1.2 配置示例

```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration PUBLIC "-//LOGGER" "http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/xml/doc-files/log4j.dtd">
<log4j:configuration>
    <!--
         appender指定输出目的地，如控制台或文件。
         appender的名称任意
    -->
    <appender name="stdout" class="org.apache.log4j.ConsoleAppender">
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern"
                value="%d{ABSOLUTE} %5p %c{1}:%L - %m%n" />
        </layout>
    </appender>

    <!--
         category（类别）为'org.springframework'的logger只记录level为“info”或更高级别的消息。
         即：如果您使用的类名获取logger（如Logger.getLogger(AClass.class)）
         而且AClass是org.springframework包的一部分，则它属于这一category
    -->
    <logger name="org.springframework">
        <level value="info"/>
    </logger>

    <!--
         spring的所有日志消息都被设置为“info”等级，但对于类PropertyEditorRegistrySupport。
         我们想将其日志消息设置为“debug”等级
    -->
    <logger name="org.springframework.beans.PropertyEditorRegistrySupport">
        <level value="debug"/>
    </logger>

    <logger name="org.acegisecurity">
        <level value="info"/>
    </logger>


    <root>
        <!--
            所有日志消息的级别为“debug”或更高的将被记录，除非另有定义
            所有日志消息将都记录到appender “stdout”中，除非另有定义
        -->
        <level value="debug" />
        <appender-ref ref="stdout" />
    </root>
</log4j:configuration>
```

## TTCC

TTCC是log4j使用的消息格式。TTCC是Time Thread Category Component（時間、線程、類別、組件）的縮寫。例如，採用以下模式（pattern）：

```
 `%r [%t] %-5p %c %x - %m%n`
```

模式轉換表為：

模式參數｜描述

%r｜用於輸出從layout（布局）的構建到日誌事件創建所經過的毫秒數。

%t｜用來輸出生成該日誌事件的線程的名稱。

%p｜用於輸出日誌事件的優先級。

%c｜用於輸出日誌事件的category（類別）。

%x｜用於輸出與產生該日誌事件的線程相關聯的 NDC（嵌套診斷上下文，nested diagnostic context）。

%X{key}｜用於輸出與產生指定的key的日誌事件的線程相關聯的 MDC （映射診斷上下文，mapped diagnostic context）

%m｜用於輸出與日誌記錄事件相關聯的應用程式提供的消息。

%n｜用來輸出該其所在的特定平台的換行字符。

示例輸出467 main INFO org.apache.log4j.examples.Sort - Exiting main method.

## 移植

- log4c——一個C語言下的移植。最新的版本為2013年發布的1.2.4版。該項目已不再活躍。
- log4js——一個JavaScript下的移植。最新的版本為2008年發布的1.1版。
- log4javascript ——JavaScript下的另一個移植。最新的版本為2014年5月發布的1.4.6版。
- JSNLog ——JavaScript下的另一移植。在2014年7月，最新的版本為2.7.1，並且定期更新。
- Apache Log4net——微軟.NET Framework下的移植。最新的版本為2013年發布的1.2.13。
- log4perl ——log4j日誌軟體包在一個Perl下的移植。最新的版本為2014年5月發布的1.44。
- log4r——一個Ruby下的「移植」。
- PL-SQL-Logging-Utility ——log4j在PL/SQL下的一種實現。
- Log4db2 ——一個為使用SQL命令和SQL PL代碼的DB2 LUW的日誌記錄工具

## Apache Log4j 2

Apache Log4j 2是Log4j 1的繼任者，2014年7月其GA版本（正式發布版）發布。該框架被從頭重寫，並從現有的日誌解決方案中獲得靈感（包括Log4j 1和JUL）。該版本與Log4j 1的主要差異是：

- 改進的配置語法
- 支持XML和JSON配置
- 改進的過濾器
- 屬性（Property）支持
- 標記
- 提高速度
- 模塊化：Log4j 2支持插件系統
- 提高了可靠性
- 配置自動重裝

Log4j 2的最被認可的特點之一是「異步記錄器」的性能。Log4j 2利用了 LMAX Disruptor。例如，在相同的環境下，Log4j 2可以寫每秒超過18,000,000條資訊，而其他框架（像Logback和Log4j 1）每秒只能寫< 2,000,000條消息。

Log4j 2提供對SLF4J、Commons Logging、Apache Flume和Log4j 1的支持。

## 參見

- Chainsaw
- Log4Shell——2021年Log4j 2.0發現的最嚴重的漏洞

## 基本資料

- 日語原文：Apache log4j
- 開發者：Apache軟體基金會
- 發行日期：2001年1月8日
- 作業系統：跨平台
- 程式語言：Java
- 類型：日誌工具
- 許可協議：Apache許可證 2.0版
- 網站：http://logging.apache.org/log4j