Tomcatでのロギング
目次
はじめに
Apache Tomcatの内部ロギングは、java.util.logging
フレームワークを使用するようにハードコードされている、Apache Commons Loggingのパッケージ名を変更したフォークであるJULIを使用しています。これにより、WebアプリケーションがApache Commons Loggingを使用している場合でも、Tomcatの内部ロギングとWebアプリケーションのロギングが独立したままであることが保証されます。
Tomcatが内部ロギングに代替ロギングフレームワークを使用するように設定するには、java.util.logging
を使用するアプリケーションのロギングをリダイレクトするための代替ロギングフレームワークが提供する指示に従ってください。これらの指示の一部へのリンクは、このページの最後に記載されています。代替ロギングフレームワークは、異なるクラスローダーに同じ名前の異なるロガーが存在する環境で動作できる必要があることに留意してください。
Apache Tomcat上で動作するWebアプリケーションは、次のことができます。
- 任意のロギングフレームワークを使用できます。
- システムロギングAPIである
java.util.logging
を使用できます。 - Javaサーブレット仕様で提供されるロギングAPI、
jakarta.servlet.ServletContext.log(...)
を使用できます。
異なるWebアプリケーションで使用されるロギングフレームワークは独立しています。詳細については、クラスローディングを参照してください。この規則の例外はjava.util.logging
です。もしロギングライブラリによって直接的または間接的に使用される場合、システムクラスローダーによってロードされるため、その要素はWebアプリケーション間で共有されます。
JavaロギングAPI — java.util.logging
Apache Tomcatは、java.util.logging
APIのいくつかの主要な要素について独自のJULIと呼ばれる実装を持っています。その主要なコンポーネントは、Tomcat上で動作する異なるWebアプリケーション(およびそれらの異なるクラスローダー)を認識するカスタムのLogManager実装です。これは、アプリケーションごとのプライベートなロギング設定をサポートします。また、WebアプリケーションがメモリからアンロードされるとTomcatから通知され、そのクラスへの参照がクリアされ、メモリリークが防止されます。
このjava.util.logging
実装は、Javaの起動時に特定のシステムプロパティを提供することで有効になります。Apache Tomcatの起動スクリプトはこれらを自動で行いますが、Tomcatを実行するために異なるツール(jsvcやIDE内からのTomcat実行など)を使用している場合は、ご自身でそれらの設定を行う必要があります。
java.util.loggingに関する詳細情報は、ご使用のJDKのドキュメントおよびjava.util.logging
パッケージのJavadocページで確認できます。
Tomcat JULIに関する詳細情報は、以下を参照してください。
サーブレットロギングAPI
ログメッセージを書き込むためのjakarta.servlet.ServletContext.log(...)
への呼び出しは、Tomcatの内部ロギングによって処理されます。これらのメッセージは、次のカテゴリにログが記録されます。
org.apache.catalina.core.ContainerBase.[${engine}].[${host}].[${context}]
このロギングはTomcatのロギング設定に従って実行されます。Webアプリケーションでこれを上書きすることはできません。
サーブレットロギングAPIは、現在Javaによって提供されているjava.util.logging
APIよりも古いものです。そのため、多くのオプションを提供しません。例えば、ログレベルを制御することはできません。ただし、Apache Tomcatの実装では、ServletContext.log(String)
またはGenericServlet.log(String)
への呼び出しはINFOレベルで、ServletContext.log(String, Throwable)
またはGenericServlet.log(String, Throwable)
への呼び出しはSEVEREレベルでログが記録されることに注意してください。
コンソール
Unix系OSでTomcatを実行している場合、コンソール出力は通常、catalina.out
という名前のファイルにリダイレクトされます。この名前は環境変数を使用して設定可能です(起動スクリプトを参照)。System.err/out
に書き込まれたものはすべてそのファイルにキャッチされます。これには以下が含まれる場合があります。
java.lang.ThreadGroup.uncaughtException(..)
によって出力された未処理の例外- システムシグナルを介して要求した場合のスレッドダンプ
Windowsでサービスとして実行している場合、コンソール出力もキャッチされリダイレクトされますが、ファイル名は異なります。
Apache Tomcatのデフォルトのロギング設定は、同じメッセージをコンソールとログファイルの両方に書き込みます。これは開発目的でTomcatを使用する場合には非常に便利ですが、通常、本番環境では必要ありません。
System.out
またはSystem.err
を依然として使用している古いアプリケーションは、ContextのswallowOutput
属性を設定することで対応できます。この属性がtrue
に設定されている場合、リクエスト処理中のSystem.out/err
への呼び出しはインターセプトされ、その出力はjakarta.servlet.ServletContext.log(...)
呼び出しを使用してロギングサブシステムに送られます。
注: swallowOutput
機能は実際には技巧であり、制限があります。これはSystem.out/err
への直接的な呼び出しでのみ機能し、リクエスト処理サイクル中のみです。アプリケーションによって作成される可能性のある他のスレッドでは機能しない場合があります。また、システムストリームに書き込むロギングフレームワーク自体をインターセプトするために使用することはできません。それらは早期に起動し、リダイレクトが行われる前にストリームへの直接参照を取得する可能性があるためです。
アクセスロギング
アクセスロギングは関連するが異なる機能であり、Valve
として実装されています。これは自己完結型のロジックを使用してログファイルを書き込みます。アクセスロギングの必須要件は、低オーバーヘッドで大量の連続データストリームを処理することであるため、デバッグメッセージにはApache Commons Loggingのみを使用します。この実装アプローチにより、追加のオーバーヘッドと潜在的に複雑な設定が回避されます。様々なレポート形式を含め、設定に関する詳細については、Valvesドキュメントを参照してください。
java.util.loggingの使用 (デフォルト)
JDKで提供されるjava.util.loggingのデフォルト実装は、実用的な用途には制限が多すぎます。主な制限は、設定がVMごとに設定されるため、Webアプリケーションごとのロギングができないことです。結果として、Tomcatはデフォルト設定で、デフォルトのLogManager実装を、これらの欠点を解消するコンテナフレンドリーなJULIと呼ばれる実装に置き換えます。
JULIは、プログラムによるアプローチまたはプロパティファイルを使用して、標準のJDK java.util.logging
と同じ設定メカニズムをサポートしています。主な違いは、クラスローダーごとのプロパティファイルを設定できること(これにより、再デプロイに適したWebアプリケーション設定が容易になります)と、プロパティファイルが、ハンドラーの定義とロガーへの割り当てにおいてより自由度を可能にする拡張された構文をサポートしていることです。
JULIはデフォルトで有効になっており、通常のグローバルなjava.util.logging設定に加えて、クラスローダーごとの設定をサポートしています。これにより、ロギングは以下のレイヤーで設定できます。
- グローバル。通常、
${catalina.base}/conf/logging.properties
ファイルで行われます。このファイルは、起動スクリプトによって設定されるjava.util.logging.config.file
システムプロパティによって指定されます。読み取り可能でないか、設定されていない場合、デフォルトではJRE内の${java.home}/lib/logging.properties
ファイルが使用されます。 - Webアプリケーション内。ファイルは
WEB-INF/classes/logging.properties
になります。
JREのデフォルトのlogging.properties
は、ロギングをSystem.errにルーティングするConsoleHandler
を指定します。Apache Tomcatのデフォルトのconf/logging.properties
も、ファイルに書き込む複数のAsyncFileHandler
を追加します。
ハンドラーのログレベルの閾値はデフォルトでINFO
であり、SEVERE
、WARNING
、INFO
、CONFIG
、FINE
、FINER
、FINEST
またはALL
を使用して設定できます。また、特定のパッケージをターゲットにしてロギングを収集し、レベルを指定することもできます。
Tomcatの内部の一部でデバッグロギングを有効にするには、適切なロガーとハンドラーの両方をFINEST
またはALL
レベルを使用するように設定する必要があります。例:
org.apache.catalina.session.level=ALL
java.util.logging.ConsoleHandler.level=ALL
デバッグロギングを有効にする際は、大量の情報を生成する可能性があるため、可能な限り最も狭いスコープで有効にすることをお勧めします。
JULIで使用される設定は、標準のjava.util.logging
でサポートされているものと同じですが、ロガーとハンドラーの設定における柔軟性を高めるためにいくつかの拡張機能を使用しています。主な違いは以下の通りです。
- ハンドラー名にプレフィックスを追加できます。これにより、単一クラスの複数のハンドラーをインスタンス化できます。プレフィックスは、数字で始まり、'.'で終わる文字列です。例えば、
22foobar.
は有効なプレフィックスです。 ${systemPropertyName}
を含むプロパティ値に対して、システムプロパティの置換が実行されます。org.apache.juli.WebappProperties
インターフェースを実装するクラスローダー(TomcatのWebアプリケーションクラスローダーなど)を使用している場合、${classloader.webappName}
、${classloader.hostName}
、${classloader.serviceName}
についてもプロパティ置換が実行され、それぞれWebアプリケーション名、ホスト名、サービス名に置き換えられます。- デフォルトでは、ロガーは関連するハンドラーを持っている場合、親に委譲しません。これは、真偽値を受け入れる
loggerName.useParentHandlers
プロパティを使用してロガーごとに変更できます。 - ルートロガーは、
.handlers
プロパティを使用してハンドラーのセットを定義できます。 - デフォルトでは、ログファイルはファイルシステムに
90
日間保持されます。これは、handlerName.maxDays
プロパティを使用してハンドラーごとに変更できます。プロパティの指定された値が≤0
の場合、ログファイルはファイルシステムに永久に保持され、それ以外の場合は、指定された最大日数保持されます。
Javaによって提供されるものと一緒に使用できる、いくつかの追加の実装クラスがあります。注目すべきは、org.apache.juli.FileHandler
とorg.apache.juli.AsyncFileHandler
です。
org.apache.juli.FileHandler
はログのバッファリングをサポートしています。バッファリングはデフォルトでは有効になっていません。設定するには、ハンドラーのbufferSize
プロパティを使用します。値0
はシステムデフォルトのバッファリングを使用します(通常8Kのバッファが使用されます)。値<0
は各ログ書き込み時にライターのフラッシュを強制します。値>0
は定義された値でBufferedOutputStreamを使用しますが、システムデフォルトのバッファリングも適用されることに注意してください。
org.apache.juli.AsyncFileHandler
は、ログメッセージをキューに入れ、非同期でログファイルに書き込むFileHandler
のサブクラスです。その追加の動作は、いくつかのシステムプロパティを設定することで構成できます。
$CATALINA_BASE/confに配置するlogging.propertiesファイルの例
handlers = 1catalina.org.apache.juli.AsyncFileHandler, \
2localhost.org.apache.juli.AsyncFileHandler, \
3manager.org.apache.juli.AsyncFileHandler, \
java.util.logging.ConsoleHandler
.handlers = 1catalina.org.apache.juli.AsyncFileHandler, java.util.logging.ConsoleHandler
############################################################
# Handler specific properties.
# Describes specific configuration info for Handlers.
############################################################
1catalina.org.apache.juli.AsyncFileHandler.level = ALL
1catalina.org.apache.juli.AsyncFileHandler.directory = ${catalina.base}/logs
1catalina.org.apache.juli.AsyncFileHandler.prefix = catalina.
1catalina.org.apache.juli.AsyncFileHandler.maxDays = 90
1catalina.org.apache.juli.AsyncFileHandler.encoding = UTF-8
2localhost.org.apache.juli.AsyncFileHandler.level = ALL
2localhost.org.apache.juli.AsyncFileHandler.directory = ${catalina.base}/logs
2localhost.org.apache.juli.AsyncFileHandler.prefix = localhost.
2localhost.org.apache.juli.AsyncFileHandler.maxDays = 90
2localhost.org.apache.juli.AsyncFileHandler.encoding = UTF-8
3manager.org.apache.juli.AsyncFileHandler.level = ALL
3manager.org.apache.juli.AsyncFileHandler.directory = ${catalina.base}/logs
3manager.org.apache.juli.AsyncFileHandler.prefix = manager.
3manager.org.apache.juli.AsyncFileHandler.bufferSize = 16384
3manager.org.apache.juli.AsyncFileHandler.maxDays = 90
3manager.org.apache.juli.AsyncFileHandler.encoding = UTF-8
java.util.logging.ConsoleHandler.level = ALL
java.util.logging.ConsoleHandler.formatter = java.util.logging.OneLineFormatter
java.util.logging.ConsoleHandler.encoding = UTF-8
############################################################
# Facility specific properties.
# Provides extra control for each logger.
############################################################
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].level = INFO
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].handlers = \
2localhost.org.apache.juli.AsyncFileHandler
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].level = INFO
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].handlers = \
3manager.org.apache.juli.AsyncFileHandler
# For example, set the org.apache.catalina.util.LifecycleBase logger to log
# each component that extends LifecycleBase changing state:
#org.apache.catalina.util.LifecycleBase.level = FINE
Webアプリケーション内のWEB-INF/classesに配置するservlet-examples Webアプリケーション用のlogging.propertiesの例
handlers = org.apache.juli.AsyncFileHandler, java.util.logging.ConsoleHandler
############################################################
# Handler specific properties.
# Describes specific configuration info for Handlers.
############################################################
org.apache.juli.AsyncFileHandler.level = ALL
org.apache.juli.AsyncFileHandler.directory = ${catalina.base}/logs
org.apache.juli.AsyncFileHandler.prefix = ${classloader.webappName}.
org.apache.juli.AsyncFileHandler.encoding = UTF-8
java.util.logging.ConsoleHandler.level = ALL
java.util.logging.ConsoleHandler.formatter = java.util.logging.OneLineFormatter
java.util.logging.ConsoleHandler.encoding = UTF-8
ドキュメント参照
追加情報については、以下のリソースを参照してください。
org.apache.juli
パッケージのApache Tomcat Javadoc。java.util.logging
パッケージのOracle Java 11 Javadoc。
本番環境での使用に関する考慮事項
以下の点に注意してください。
- 設定から
ConsoleHandler
を削除することを検討してください。デフォルトでは(.handlers
設定により)、ロギングはAsyncFileHandler
とConsoleHandler
の両方に出力されます。後者の出力は通常、catalina.out
などのファイルにキャプチャされます。したがって、同じメッセージが2つのコピーとして存在することになります。 - 使用しないアプリケーションの
AsyncFileHandler
を削除することを検討してください。例えば、host-manager
用などです。 - アクセスログの設定を検討してください。
Log4jの使用
Log4jプロジェクトは、Tomcatの内部ロギングにLog4Jを使用するための手順を提供しています。