Apache Log4j (Legacy)
Apache財団による歴史あるJavaロギングフレームワーク。多くのJavaアプリケーションで長年使用されてきたが、セキュリティ脆弱性(Log4Shell)の発見により、現在は Log4j2 への移行が強く推奨されている。
GitHub概要
スター868
ウォッチ110
フォーク576
作成日:2009年5月21日
言語:Java
ライセンス:Apache License 2.0
トピックス
log4j
スター履歴
データ取得日時: 2025/10/22 04:10
ライブラリ
Apache Log4j
概要
Apache Log4jはJava界で最も歴史と実績のあるロギングライブラリです。「汎用性が高く、機能豊富、効率的なJavaロギングAPI」として設計され、スタンドアロンアプリケーションからエンタープライズシステムまで幅広い用途で使用されています。ファイル、ネットワーク、データベース、SMTP等への豊富な出力先と柔軟なフォーマット機能を提供します。
詳細
Apache Log4j 2.25.0は2025年6月にリリースされた最新版で、GraalVMネイティブイメージの完全サポートやパフォーマンス改善が含まれています。モジュラー設計によりAPI、実装、デプロイメント支援コンポーネントに分かれており、高い拡張性とカスタマイズ性を実現。Java 8以上をサポートし、モダンなJavaアプリケーション開発で幅広く使用されています。
主な特徴
- 豊富なAppender: ファイル、ネットワーク、データベース、SMTP、JMS等多数の出力先
- 柔軟なLayout: CSV、HTML、JSON、Syslog等のフォーマットサポート
- 高性能なフィルター: レートベース、正規表現、スクリプト、時間等による高度なフィルタリング
- 動的設定リロード: 設定ファイル変更時の自動リロード(ログイベント故失なし)
- GraalVMサポート: ネイティブイメージ生成の完全サポート
- ガベージコレクターフリー: ガベージコレクションに負担をかけない高性能設計
メリット・デメリット
メリット
- Java界で最も歴史と実績のあるロガー(20年以上の開発実績)
- Apache Software Foundationによる安定したガバナンスとサポート
- 豊富なエコシステム(Spring Boot、Hibernate等との連携)
- エンタープライズグレードの機能(非同期ロギング、クラスタリング等)
- 高性能でスケーラブル(ガベージコレクターフリー設計)
- 充実したドキュメントと活発なコミュニティ
デメリット
- 初期設定が複雑で学習コストが高い
- XML設定ファイルが詳細で管理が難しい場合がある
- モダンなJavaのアノテーションベース設定が他ライブラリより遅れている
- デバッグ時のエラーメッセージが分かりにくいことがある
- 多機能ゆえのメモリ使用量がやや多い
- 軽量なログ出力にはオーバースペックの場合がある
参考ページ
書き方の例
基本的なセットアップ
<!-- Maven依存関係 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.25.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.25.0</version>
</dependency>
<!-- SLF4Jブリッジ(既存アプリでSLF4J使用時) -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j2-impl</artifactId>
<version>2.25.0</version>
</dependency>
// Gradle依存関係
implementation 'org.apache.logging.log4j:log4j-core:2.25.0'
implementation 'org.apache.logging.log4j:log4j-api:2.25.0'
シンプルなロガー使用
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class MyApp {
// ロガーの取得
private static final Logger logger = LogManager.getLogger(MyApp.class);
public static void main(String[] args) {
// 基本的なログ出力
logger.trace("トレースメッセージ");
logger.debug("デバッグメッセージ");
logger.info("情報メッセージ");
logger.warn("警告メッセージ");
logger.error("エラーメッセージ");
// パラメータ付きログ出力
String userId = "user123";
int age = 25;
logger.info("ユーザー情報: ID={}, 年齢={}", userId, age);
// 例外ログ出力
try {
int result = 10 / 0;
} catch (Exception e) {
logger.error("計算エラーが発生しました", e);
}
}
}
基本的なXML設定(log4j2.xml)
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<!-- コンソール出力 -->
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
<!-- ファイル出力 -->
<File name="FileAppender" fileName="logs/app.log">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</File>
<!-- ローリングファイル -->
<RollingFile name="RollingFileAppender" fileName="logs/app.log"
filePattern="logs/app.%d{yyyy-MM-dd}.%i.log.gz">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
<Policies>
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="10 MB"/>
</Policies>
<DefaultRolloverStrategy max="10"/>
</RollingFile>
</Appenders>
<Loggers>
<!-- 特定パッケージのログレベル設定 -->
<Logger name="com.example.database" level="DEBUG" additivity="false">
<AppenderRef ref="FileAppender"/>
</Logger>
<!-- ルートロガー -->
<Root level="INFO">
<AppenderRef ref="Console"/>
<AppenderRef ref="RollingFileAppender"/>
</Root>
</Loggers>
</Configuration>
非同期ロギング設定
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<!-- 非同期ロガー設定 -->
<AsyncLogger name="com.example.performance" level="INFO" additivity="false">
<AppenderRef ref="FileAppender"/>
</AsyncLogger>
<!-- 完全非同期モード -->
<AsyncRoot level="INFO">
<AppenderRef ref="Console"/>
<AppenderRef ref="FileAppender"/>
</AsyncRoot>
<!-- LMAX Disruptor依存関係が必要 -->
<!--
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
<version>3.4.4</version>
</dependency>
-->
</Configuration>
プログラマティック設定
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.ConfigurationFactory;
import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.apache.logging.log4j.core.config.builder.api.*;
import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
public class ProgrammaticConfig {
public static void main(String[] args) {
// Configuration Builderを使用したプログラマティック設定
ConfigurationBuilder<BuiltConfiguration> builder = ConfigurationBuilderFactory.newConfigurationBuilder();
// Console Appenderの設定
AppenderComponentBuilder consoleAppender = builder.newAppender("Console", "CONSOLE")
.addAttribute("target", "SYSTEM_OUT")
.add(builder.newLayout("PatternLayout")
.addAttribute("pattern", "%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"));
// File Appenderの設定
AppenderComponentBuilder fileAppender = builder.newAppender("File", "File")
.addAttribute("fileName", "logs/programmatic.log")
.add(builder.newLayout("PatternLayout")
.addAttribute("pattern", "%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"));
builder.add(consoleAppender);
builder.add(fileAppender);
// Root Loggerの設定
RootLoggerComponentBuilder rootLogger = builder.newRootLogger("INFO")
.add(builder.newAppenderRef("Console"))
.add(builder.newAppenderRef("File"));
builder.add(rootLogger);
// 設定の適用
LoggerContext context = (LoggerContext) LogManager.getContext(false);
Configuration config = builder.build();
context.start(config);
// ロガーの使用
Logger logger = LogManager.getLogger(ProgrammaticConfig.class);
logger.info("プログラマティック設定でのログ出力");
}
}
フィルターとマーカーの使用
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
<!-- レベルフィルター -->
<ThresholdFilter level="WARN" onMatch="ACCEPT" onMismatch="DENY"/>
</Console>
<File name="ErrorFile" fileName="logs/error.log">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
<!-- エラーレベルのみ -->
<LevelRangeFilter minLevel="ERROR" maxLevel="ERROR" onMatch="ACCEPT" onMismatch="DENY"/>
</File>
<File name="SecurityFile" fileName="logs/security.log">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
<!-- マーカーフィルター -->
<MarkerFilter marker="SECURITY" onMatch="ACCEPT" onMismatch="DENY"/>
</File>
</Appenders>
<Loggers>
<Root level="DEBUG">
<AppenderRef ref="Console"/>
<AppenderRef ref="ErrorFile"/>
<AppenderRef ref="SecurityFile"/>
</Root>
</Loggers>
</Configuration>
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.MarkerManager;
public class FilterExample {
private static final Logger logger = LogManager.getLogger(FilterExample.class);
private static final Marker SECURITY_MARKER = MarkerManager.getMarker("SECURITY");
private static final Marker PERFORMANCE_MARKER = MarkerManager.getMarker("PERFORMANCE");
public static void main(String[] args) {
// 通常のログ
logger.info("アプリケーションが開始されました");
// セキュリティマーナー付きログ(security.logに出力される)
logger.warn(SECURITY_MARKER, "不正なアクセス試行を検知しました: IP={}", "192.168.1.100");
// パフォーマンスマーカー付きログ
logger.debug(PERFORMANCE_MARKER, "DBクエリ実行時間: {}ms", 150);
// エラーログ(error.logに出力される)
logger.error("データベース接続エラーが発生しました");
}
}
Spring Boot統合
<!-- Spring Bootではdefaultでlogbackが使用されるため、Log4j2に変更 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
# application.yml
logging:
config: classpath:log4j2-spring.xml
level:
com.example: DEBUG
org.springframework: INFO
root: WARN
// Spring Bootアプリケーションでの使用
@RestController
@Slf4j // Lombokを使用する場合
public class UserController {
private static final Logger logger = LogManager.getLogger(UserController.class);
@GetMapping("/users/{id}")
public ResponseEntity<User> getUser(@PathVariable Long id) {
logger.info("ユーザー情報取得リクエスト: userId={}", id);
try {
User user = userService.findById(id);
logger.debug("ユーザー情報取得成功: {}", user);
return ResponseEntity.ok(user);
} catch (UserNotFoundException e) {
logger.warn("ユーザーが見つかりません: userId={}", id);
return ResponseEntity.notFound().build();
} catch (Exception e) {
logger.error("ユーザー情報取得中にエラーが発生しました: userId={}", id, e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
}