「駑馬十駕」を信念に IT系情報を中心に調べた事をコツコツ綴っています。

Java開発におけるログ出力は、障害解析・性能改善・監査の三種の神器。長年使われてきた log4j 1.x に対し、後継の log4j2 は「高速・柔軟・安全」に大幅進化しています。本稿では、違いが直感的に分かる比較と、**失敗しない導入手順(Maven/Gradle、設定、非同期化、移行の落とし穴まで)**をまとめます。


1. log4j 1.x と log4j2 の要点比較

観点log4j 1.xlog4j2
パフォーマンス同期中心。大量ログでアプリに負荷LMAX Disruptorによる非同期ロガーで高速・低レイテンシ
設定形式properties / XML のみXML / JSON / YAML / properties、ホットリロード対応
非同期化AsyncAppenderのみAsyncAppender+Async Logger(全ロガー非同期も可)
GC負荷文字列連結が発生しやすくGC負担増遅延評価(ラムダ/プレースホルダ)で不要時は連結処理なし
拡張性限定的フィルタ / レイアウト / Appender が豊富(JSON出力、Failover等)
メンテナンスEoL(保守終了)現行バージョン維持(常に最新2.xを推奨)

結論:高負荷・可観測性重視の現場ほど log4j2 一択。


2. こんな場面で「log4j2」を選ぶ

  • 大量ログ(秒間1000件~万件)を裁くWeb/バッチ、IoT、決済、EC

  • 本番でログレベルを動的変更したい(再起動なしで即調査)

  • JSON出力で Elasticsearch / OpenSearch / Splunk / Datadog に流す

  • 遅延評価MDC(相関ID) で可観測性とパフォーマンスを両立したい


3. 導入手順(Maven/Gradle)――最短で“動く”まで

ここでは log4j2 を実装(Core)として使い、APIは SLF4J で書く構成を推奨します。
理由:ライブラリ間の共通言語として SLF4J がデファクト、実装差し替えも容易。

3.1 依存関係を追加

Maven(pom.xml)

<dependencies>
  <!-- SLF4J API -->
  <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
  </dependency>

  <!-- Log4j2 実装(Core)+ API -->
  <dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
  </dependency>
  <dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
  </dependency>

  <!-- SLF4J → Log4j2 バインド(SLF4J 2.x 用) -->
  <dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j2-impl</artifactId>
  </dependency>

  <!-- (任意)Async Logger 用:Disruptor -->
  <dependency>
    <groupId>com.lmax</groupId>
    <artifactId>disruptor</artifactId>
  </dependency>
</dependencies>

Gradle(Kotlin DSL) 

dependencies {
    implementation("org.slf4j:slf4j-api")
    implementation("org.apache.logging.log4j:log4j-core")
    implementation("org.apache.logging.log4j:log4j-api")
    implementation("org.apache.logging.log4j:log4j-slf4j2-impl")
    implementation("com.lmax:disruptor") // Async Logger を使うなら
}

重要:既存で引き込まれる logback-classicslf4j-log4j12除外してください(重複実装エラー&二重出力の原因)。

3.2 旧実装の衝突を避ける(例:Maven の除外) 

<dependency>
  <groupId>some.group</groupId>
  <artifactId>some-lib</artifactId>
  <exclusions>
    <exclusion>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
    </exclusion>
    <exclusion>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
    </exclusion>
    <exclusion>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
    </exclusion>
  </exclusions>
</dependency>

3.3 最小構成の設定ファイル(src/main/resources/log4j2.xml 

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" monitorInterval="30">
  <Appenders>
    <Console name="Console" target="SYSTEM_OUT">
      <PatternLayout pattern="%d{ISO8601} [%t] %-5level %logger - %msg%n"/>
    </Console>
  </Appenders>
  <Loggers>
    <Root level="INFO">
      <AppenderRef ref="Console"/>
    </Root>
  </Loggers>
</Configuration>
  • monitorInterval="30":30秒ごとに設定ファイルの変更を検知し、再起動なしで反映

3.4 SLF4J での利用コード 

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class App {
  private static final Logger log = LoggerFactory.getLogger(App.class);

  public static void main(String[] args) {
    String userId = "alice";
    log.info("Hello, {}", userId);           // プレースホルダで連結コスト削減
    log.debug("Detail: {}", () -> heavy());  // ラムダで遅延評価(DEBUGでなければ実行されない)
  }

  private static String heavy() { /* 重い処理 */ return "ok"; }
}

3.5 ローリングファイル+JSON(実戦向け) 

<Configuration status="WARN" monitorInterval="30">
  <Appenders>
    <RollingFile name="AppLog" fileName="logs/app.log"
                 filePattern="logs/app-%d{yyyy-MM-dd}-%i.log.gz">
      <JsonLayout complete="false" compact="true" eventEol="true"/>
      <Policies>
        <SizeBasedTriggeringPolicy size="50 MB"/>
        <TimeBasedTriggeringPolicy/>
      </Policies>
      <DefaultRolloverStrategy max="30"/>
    </RollingFile>
  </Appenders>
  <Loggers>
    <Root level="INFO">
      <AppenderRef ref="AppLog"/>
    </Root>
  </Loggers>
</Configuration>
  • JSON出力で可観測性基盤にそのまま投入可能。

  • max="30":古いファイルを30世代で自動削除。

3.6 非同期化の推奨設定(高スループット向け)

方法A:Async Appender(部分的に非同期)

<Appenders>
  <Async name="AsyncApp">
    <AppenderRef ref="AppLog"/>
  </Async>
</Appenders>
<Root level="INFO">
  <AppenderRef ref="AsyncApp"/>
</Root>

方法B:Async Logger(全ロガーを非同期化)

  1. 依存に disruptor を追加(前述)

  2. JVM 起動オプションに以下を付与

    -DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector

目安:秒間数千件以上のログ、遅延許容な処理では Async Logger が強力。
低遅延の必要なクリティカル処理(トランザクション境界直前など)は同期Appenderで分離も可。

3.7 現場で必須の“相関ID”(MDC/ThreadContext)

import org.slf4j.MDC; // または org.apache.logging.log4j.ThreadContext
MDC.put("traceId", traceId);   // リクエスト毎に設定
log.info("start");
MDC.clear();
<PatternLayout pattern="%d [%t] %-5level %X{traceId} %logger - %msg%n"/>
  • 分散トレーシングやバッチ内のジョブ相関に必須。

3.8 動的なログレベル変更(コード&設定)

  • コードで変更 

    import org.apache.logging.log4j.core.config.Configurator;
    import org.apache.logging.log4j.Level;
    Configurator.setLevel("com.example.service", Level.DEBUG);
    
  • 設定のホットリロードmonitorInterval でファイルを書き換えるだけ

3.9 他フレームワークのログを一本化(任意)

  • JUL(java.util.logging)→ Log4j2log4j-jul を追加し、

    -Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager
  • Commons Logging(JCL)→ Log4j2log4j-jcl を追加


4. 旧 log4j 1.x からの移行チェックリスト

  1. jar の置換と衝突解消

    • 1.x の log4j-1.2.x.jar を除去

    • log4j-api, log4j-core, log4j-slf4j2-impl を追加

    • 他実装(logback 等)を除外

  2. 設定ファイルを置き換え

    • log4j.propertieslog4j2.xml(or .json/.yaml) に構造変換

  3. コードの修正方針(推奨順)

    • SLF4J API へ書き換え(LoggerFactory.getLogger 等)

    • もしくは log4j2 API へ(org.apache.logging.log4j.LogManager.getLogger

    • 当面の暫定策として log4j-1.2-api(互換レイヤ)もあるが恒久利用は非推奨

  4. 性能と出力の検証

    • 期待QPSでのバックプレッシャディスク枯渇を確認

    • 非同期化の有無でレイテンシ差を測定

  5. 運用監視

    • -Dlog4j2.debug=true で起動し、設定解決やエラーを起動時に確認

    • ログローテーションと世代数の上限を監視に組み込み


5. 開発・運用の実用Tips

  • 重い toString() を直接連結しないlog.debug("x={}", () -> obj.heavyToString())

  • Failover Appender で出力先障害に備える(ネットワークストレージ等)

  • パターン設計:時刻、レベル、ロガー、メッセージ、%throwable、MDC を最低限

  • 本番では INFO 以上、詳細調査時のみ一時的に DEBUG/TRACE を開ける

  • 最新 2.x 系を採用(セキュリティ修正が継続されるため)


6. まとめ

  • log4j2 は “高速+柔軟+安全”。大量ログ・可観測性要件に強い。

  • 導入は依存追加 → 設定作成 → 非同期化の3ステップが核。

  • 移行は衝突除去と設定変換が肝。SLF4J API で書くと将来の実装差し替えも容易。

0 0
Article Rating
申し込む
注目する
guest
0 コメント一覧
最も古い
最新 高評価
インラインフィードバック
すべてのコメントを見る

Ads by Google

0 0
Article Rating
申し込む
注目する
guest
0 コメント一覧
最も古い
最新 高評価
インラインフィードバック
すべてのコメントを見る
0
あなたの考えが大好きです、コメントしてください。x