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 Servlets仕様で提供されるロギング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で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実装を、これらの欠点を addressed する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アプリケーションクラスローダーは実装します)を使用する場合、Webアプリケーション名、ホスト名、およびサービス名にそれぞれ置き換えられる${classloader.webappName}
、${classloader.hostName}
、および${classloader.serviceName}
のプロパティ置換も実行されます。- デフォルトでは、ロガーに関連付けられたハンドラーがある場合、ロガーは親に委任しません。これは、ブール値を受け入れる
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.FileHandler, \
2localhost.org.apache.juli.FileHandler, \
3manager.org.apache.juli.FileHandler, \
java.util.logging.ConsoleHandler
.handlers = 1catalina.org.apache.juli.FileHandler, java.util.logging.ConsoleHandler
############################################################
# Handler specific properties.
# Describes specific configuration info for Handlers.
############################################################
1catalina.org.apache.juli.FileHandler.level = FINE
1catalina.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
1catalina.org.apache.juli.FileHandler.prefix = catalina.
1catalina.org.apache.juli.FileHandler.maxDays = 90
1catalina.org.apache.juli.FileHandler.encoding = UTF-8
2localhost.org.apache.juli.FileHandler.level = FINE
2localhost.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
2localhost.org.apache.juli.FileHandler.prefix = localhost.
2localhost.org.apache.juli.FileHandler.maxDays = 90
2localhost.org.apache.juli.FileHandler.encoding = UTF-8
3manager.org.apache.juli.FileHandler.level = FINE
3manager.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
3manager.org.apache.juli.FileHandler.prefix = manager.
3manager.org.apache.juli.FileHandler.bufferSize = 16384
3manager.org.apache.juli.FileHandler.maxDays = 90
3manager.org.apache.juli.FileHandler.encoding = UTF-8
java.util.logging.ConsoleHandler.level = FINE
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.FileHandler
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].level = INFO
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].handlers = \
3manager.org.apache.juli.FileHandler
# 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
servlet-examples Webアプリケーションのlogging.propertiesの例。Webアプリケーション内の`WEB-INF/classes`に配置します。
handlers = org.apache.juli.FileHandler, java.util.logging.ConsoleHandler
############################################################
# Handler specific properties.
# Describes specific configuration info for Handlers.
############################################################
org.apache.juli.FileHandler.level = FINE
org.apache.juli.FileHandler.directory = ${catalina.base}/logs
org.apache.juli.FileHandler.prefix = ${classloader.webappName}.
java.util.logging.ConsoleHandler.level = FINE
java.util.logging.ConsoleHandler.formatter = java.util.logging.OneLineFormatter
ドキュメントリファレンス
詳細については、次のリソースを参照してください。
org.apache.juli
パッケージのApache Tomcat Javadoc。java.util.logging
パッケージのOracle Java 11 Javadoc。
本番環境での使用に関する考慮事項
以下の点に注意してください。
- 設定から
ConsoleHandler
を削除することを検討してください。デフォルトでは(.handlers
設定のおかげで)、ロギングはFileHandler
とConsoleHandler
の両方に行われます。後者の出力は通常、catalina.out
などのファイルに取り込まれます。したがって、同じメッセージが2つコピーされることになります。 - 使用しないアプリケーションの
FileHandler
を削除することを検討してください。たとえば、host-manager
用のものなどです。 - ハンドラは、デフォルトでシステムのデフォルトエンコーディングを使用してログファイルを書き込みます。
encoding
プロパティで設定できます。詳細はJavadocを参照してください。 - アクセスログの設定を検討してください。