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を使用している古いアプリケーションは、ContextswallowOutput属性を設定することでだますことができます。属性が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であり、SEVEREWARNINGINFOCONFIGFINEFINERFINEST、または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.FileHandlerorg.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

ドキュメントリファレンス

詳細については、次のリソースを参照してください。

本番環境での使用に関する考慮事項

以下の点に注意してください。

  • 設定からConsoleHandlerを削除することを検討してください。デフォルトでは(.handlers設定のおかげで)、ロギングはFileHandlerConsoleHandlerの両方に行われます。後者の出力は通常、catalina.outなどのファイルに取り込まれます。したがって、同じメッセージが2つコピーされることになります。
  • 使用しないアプリケーションのFileHandlerを削除することを検討してください。たとえば、host-manager用のものなどです。
  • ハンドラは、デフォルトでシステムのデフォルトエンコーディングを使用してログファイルを書き込みます。 encodingプロパティで設定できます。詳細はJavadocを参照してください。
  • アクセスログの設定を検討してください。