Log4j(ログ・フォー・ジェイ)は、Javaアプリケーションでログを出力しやすく管理しやすくするためのライブラリ(機能の塊)です。元々はApache Software Foundationが開発を進めてきたもので、「ログを取る」という行為を便利にするための道具のようなものだと思ってください。
このページでは、よく聞く「Log4j」って実際何なの?という疑問に対して諸々の前提知識を含め、新入社員を想定した0 to 1解説を行います。
前提知識として知っておきたい「ログ」とは?
まずはLog4jの話に入る前に、「ログって何?」というところを簡単におさえておきましょう。
もし不具合やエラーが起きたときには、ログが残っていると
を調べる手がかりになります。Javaでプログラムを書いているときに、デバッグ用にSystem.out.println("何かのメッセージ");
を使うことは多いと思います。しかし、これだけだと出力先を分けたいときや、「重要度」に応じてログの扱いを変えたいときなどに対応しづらいのが弱点です。
そこで登場するのがLog4jのような「ログ管理用のライブラリ」です。
Log4jとは何か?
Log4j(ログ・フォー・ジェイ)は、Javaアプリケーションでログを出力しやすく管理しやすくするためのライブラリ(機能の塊)です。元々はApache Software Foundationが開発を進めてきたもので、「ログを取る」という行為を便利にするための道具だと思ってください。
Log4jを使うメリット
- ログの重要度(レベル)を簡単に設定できる
- たとえば「開発時は細かいデバッグ情報をたくさん出す」「本番稼働では必要最低限の重要な情報だけに絞る」といった切り替えが容易。
- 出力先を自由に設定できる
- コンソール(標準出力)やファイル、データベースなど、いろいろな出力先に対応している。
- ログの形式を統一して読みやすくできる
- 「日付や時刻、ログレベル、スレッド名、メッセージ」などを好みのフォーマットで出力できる。
- ログファイルが大きくなりすぎないようにローテーションができる
- ログが大きくなりすぎるとサーバーのディスクを圧迫してしまうので、自動で古いログを圧縮・削除したりできる。
こういったメリットから、Javaでのログ出力にはLog4jや同様のライブラリが広く使われています。要するにログに関するあれこれはLog4jに任せておけばOKだね!といえるぐらい、なんでもやってくれるライブラリです。
ログの出力機能は、アプリケーションそのものの開発に比べてどうしても優先度が低くなりがちですが、Log4jを利用することで面倒な諸々を片付けることができる!というのが多くの現場で利用される理由の1つです。
Log4jのバージョン:1.xと2.xの違い
初心者がLog4jを使う場合は、Log4j 2.xの最新バージョンを導入しましょう。
Log4jの基本概念
Log4jを理解するうえで大事なキーワードを紹介します。
1. Logger(ロガー)
// クラス名を使ってLoggerを取得 private static final Logger logger = LogManager.getLogger(クラス名.class); public void sampleMethod() { logger.info("これはINFOレベルのログメッセージです"); logger.debug("これはDEBUGレベルのログメッセージです"); }
2. Log Level(ログレベル)
- ログの重要度や詳細度を表すもの。代表的なのは以下の6種類です。
- TRACE:もっとも詳細なログ。大抵の場合は使わないか、デバッグ専用。
- DEBUG:デバッグ用で詳細度高め。
- INFO:一般的な情報。アプリの起動・停止、操作イベントの通知など。
- WARN:警告。エラーには至らないがリスクのある事象。
- ERROR:エラーが起きた場合。
- FATAL:アプリが続行不能な重大エラー。
ログレベルをINFO
に設定した場合は、INFO以上(WARN、ERROR、FATAL)のログだけが実際に出力されます。DEBUG
やTRACE
は出力されません。
3. Appender(アペンダー)
4. Layout(レイアウト)
- ログをどんなフォーマット(形式)で出力するかを決める設定です。
- 例)
[%d{yyyy-MM-dd HH:mm:ss}] [%p] %c - %m%n
- ここでは
%d{...}
:日時を指定したフォーマットで表示%p
:ログレベル(INFOやDEBUGなど)%c
:ロガー名(通常はクラス名)%m
:ログメッセージ%n
:改行
- ここでは
- 例)
LoggerがAppenderへログを渡し、AppenderがLayoutに従って文字列を整形して最終的に出力する、というイメージです。
Log4jの動作の流れ
- コードでLoggerを呼び出す
logger.info("ユーザーがログインしました");
- 現在のログレベル設定を確認し、出力して良いかどうかを判定。
- 例:
INFO
レベルにしてあるなら、INFO
以上は出力OK。DEBUG
はスキップされる。
- 例:
- Appendersにログメッセージを渡す。
- どのAppenderを使うかは設定ファイルで決まる(コンソールやファイルなど)。
- AppenderがLayoutに従ってメッセージを整形し、出力先に書き込む。
このような仕組みのおかげで、コードに「logger.debug」などと書いておけば、設定ファイルでレベルを変えるだけで一括でログ出力をON/OFFできるというわけです。
よって、Log4jを利用するには設定ファイルの内容が重要になってきます。次に設定ファイルの記載方法について解説します。
Log4jの設定ファイル
Log4jを使う上で、設定ファイル(たとえば log4j2.xml
や log4j2.properties
)を用意するのが一般的です。ここでは最もよく使われる log4j2.xml
の例を示します。
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN"> <Appenders> <!-- コンソールに出力するAppender --> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss}] [%p] %c - %m%n"/> </Console> <!-- ログファイルに出力するAppender --> <RollingFile name="File" fileName="logs/app.log" filePattern="logs/app-%d{yyyy-MM-dd}-%i.log.gz"> <PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss}] [%p] %c - %m%n"/> <Policies> <!-- ログファイルのサイズが5MBを超えたらローテーションする例 --> <SizeBasedTriggeringPolicy size="5MB"/> </Policies> <!-- ローテーションで最大何世代(何ファイル)分を保持するか設定 --> <DefaultRolloverStrategy max="10"/> </RollingFile> </Appenders> <Loggers> <!-- ルートロガー:全てのクラスでのログ出力に適用するデフォルト設定 --> <Root level="info"> <AppenderRef ref="Console"/> <AppenderRef ref="File"/> </Root> </Loggers> </Configuration>
この例では、
こうした設定を変えるだけで、ログの出力先やフォーマット、保存ルールを簡単に切り替えできます。コードはそのままで設定ファイルを差し替えるだけで運用方法を変更できるのが大きな利点です。
詳細な設定内容は公式リファレンス等を確認して行いましょう
実際のコード例
以下は、JavaコードでLog4jを使うときの簡単な例です。MavenなどのビルドツールでLog4jの依存関係を追加している前提とします。
package com.example; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; public class SampleApp { // クラスごとにLoggerを作る。staticかつfinalにするのが定番 private static final Logger logger = LogManager.getLogger(SampleApp.class); public static void main(String[] args) { // INFOレベルのログ logger.info("アプリケーションが起動しました"); try { int result = 10 / 0; // 故意にエラーを起こす } catch (Exception e) { // ERRORレベルのログ logger.error("エラーが発生しました", e); } logger.info("アプリケーションを終了します"); } }
設定ファイルで Root レベルが info
なので、logger.debug("~")
をもし呼び出していたとしても、実行しても出力されません(抑制されます)。
使うときに気をつけたいこと
- ログレベルの使い分け
- 開発時:
DEBUG
やTRACE
を使って細かい情報を出す。 - 本番環境:
INFO
以上に抑えて、余計なログを出力しないようにする。 - これを守ると、余計なログがたまりすぎて分析が大変になるのを防ぐことができます。
- 開発時:
- ログファイルのローテーション
- ログファイルが延々と大きくなると、ディスクを圧迫したり読み込みが遅くなったりします。
- 定期的に古いものを圧縮・削除し、ファイルを分割しておくのが大切です。
- 脆弱性への注意
- 過去にLog4j 2.xで「Log4Shell」という大きな脆弱性が見つかりました。
- すでに最新版(2.17以降など)では修正されていますが、常に最新のバージョンを使うようにしましょう。
- 定期的にアップデート情報をチェックし、セキュリティアップデートを怠らないようにすることが重要です。
- クラウドやコンテナ環境
- Dockerなどのコンテナを使う場合は、ファイルではなく**標準出力(ConsoleAppender)**に書き出して、コンテナホストやクラウドのログ収集機能で管理するのが一般的です。