§ロギングの設定
PlayはロギングにSLF4Jを使用し、デフォルトのロギングエンジンとしてLogbackをサポートしています。設定の詳細については、Logbackのドキュメントを参照してください。
§デフォルト設定
開発モードでは、Playは次のデフォルト設定を使用します
<?xml version="1.0" encoding="UTF-8" ?>
<!--
Copyright (C) from 2022 The Play Framework Contributors <https://github.com/playframework>, 2011-2021 Lightbend Inc. <https://www.lightbend.com>
-->
<!DOCTYPE configuration>
<!-- The default logback configuration that Play uses in dev mode if no other configuration is provided -->
<configuration>
<import class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"/>
<import class="ch.qos.logback.core.ConsoleAppender"/>
<appender name="STDOUT" class="ConsoleAppender">
<encoder class="PatternLayoutEncoder">
<pattern>%highlight(%-5level) %logger{15} - %message%n%xException{10}</pattern>
</encoder>
</appender>
<logger name="play" level="INFO"/>
<logger name="com.gargoylesoftware.htmlunit.javascript" level="OFF"/>
<root level="WARN">
<appender-ref ref="STDOUT"/>
</root>
</configuration>
本番環境では、Playは次のデフォルト設定を使用します
<?xml version="1.0" encoding="UTF-8" ?>
<!--
Copyright (C) from 2022 The Play Framework Contributors <https://github.com/playframework>, 2011-2021 Lightbend Inc. <https://www.lightbend.com>
-->
<!DOCTYPE configuration>
<!-- The default logback configuration that Play uses if no other configuration is provided -->
<configuration>
<import class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"/>
<import class="ch.qos.logback.classic.AsyncAppender"/>
<import class="ch.qos.logback.core.ConsoleAppender"/>
<appender name="STDOUT" class="ConsoleAppender">
<encoder class="PatternLayoutEncoder">
<pattern>%highlight(%-5level) %logger{15} - %message%n%xException{10}</pattern>
</encoder>
</appender>
<appender name="ASYNCSTDOUT" class="AsyncAppender">
<!-- increases the default queue size -->
<queueSize>512</queueSize>
<!-- don't discard messages -->
<discardingThreshold>0</discardingThreshold>
<!-- block when queue is full -->
<neverBlock>false</neverBlock>
<appender-ref ref="STDOUT"/>
</appender>
<logger name="play" level="INFO"/>
<logger name="com.gargoylesoftware.htmlunit.javascript" level="OFF"/>
<root level="WARN">
<appender-ref ref="ASYNCSTDOUT"/>
</root>
</configuration>
これらの設定に関する注意事項
- これらのデフォルト設定は、例外スタックトレースの10行のみを出力するコンソールロガーのみを指定します。
- Playは、レベルメッセージにデフォルトでANSIカラーコードを使用します。
- 本番環境では、デフォルト設定ではコンソールロガーがLogbackのAsyncAppenderの背後に配置されます。これによるパフォーマンスへの影響の詳細については、この記事記事を参照してください。
ファイルロガーを追加するには、次のアペンダーをconf/logback.xml
ファイルに追加します
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>${application.home:-.}/logs/application.log</file>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%date [%level] from %logger in %thread - %message%n%xException</pattern>
</encoder>
</appender>
必要に応じて、非同期アペンダーを使用してFileAppender
をラップします
<appender name="ASYNCFILE" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="FILE" />
</appender>
必要なアペンダーをルートに追加します
<root level="WARN">
<appender-ref ref="ASYNCFILE" />
<appender-ref ref="ASYNCSTDOUT" />
</root>
§セキュリティロギング
Playのセキュリティ関連操作のためにセキュリティマーカーが追加され、失敗したセキュリティチェックは、セキュリティマーカーが設定された状態でWARNレベルでログに記録されるようになりました。これにより、開発者は特定のリクエストが失敗した理由を常に把握できます。これは、Playでセキュリティフィルターがデフォルトで有効になっているため重要です。
セキュリティマーカーを使用すると、通常のロギングとは別にセキュリティ障害をトリガーまたはフィルターすることもできます。たとえば、SECURITYマーカーが設定されているすべてのロギングを無効にするには、次の行をlogback.xml
ファイルに追加します
<turboFilter class="ch.qos.logback.classic.turbo.MarkerFilter">
<Marker>SECURITY</Marker>
<OnMatch>DENY</OnMatch>
</turboFilter>
さらに、セキュリティマーカーを使用したログイベントは、セキュリティ情報とイベント管理(SEIM)エンジンにメッセージをトリガーして、さらに処理することもできます。
§カスタムアプリケーションローダーの使用
デフォルトのGuiceApplicationLoader
を拡張しないカスタムアプリケーションローダーを使用する場合(たとえば、コンパイル時依存性注入を使用する場合)、カスタム設定を取得するためにLoggerConfigurator
を手動で呼び出す必要があります。これは、次のコードで実行できます
class MyApplicationLoaderWithInitialization extends ApplicationLoader {
def load(context: Context) = {
LoggerConfigurator(context.environment.classLoader).foreach {
_.configure(context.environment, context.initialConfiguration, Map.empty)
}
new MyComponents(context).application
}
}
§カスタム設定
カスタム設定を行うには、独自のLogback設定ファイルを指定する必要があります。
§プロジェクトソースからの設定ファイルの使用
conf/logback.xml
ファイルを指定することで、デフォルトのロギング設定を提供できます。
§外部設定ファイルの使用
システムプロパティを介して設定ファイルを指定することもできます。これは、設定ファイルがアプリケーションソースの外部で管理される可能性のある本番環境で特に役立ちます。
注:ロギングシステムは、システムプロパティで指定された設定ファイル、次に
conf
ディレクトリ内のファイル、最後にデフォルトの設定ファイルを優先します。これにより、アプリケーションのロギング設定をカスタマイズし、特定の環境または開発者の設定でオーバーライドすることができます。
§-Dlogger.resource
の使用
クラスパスからロードする設定ファイルを指定します
$ start -Dlogger.resource=prod-logger.xml
§-Dlogger.file
の使用
ファイルシステムからロードする設定ファイルを指定します
$ start -Dlogger.file=/opt/prod/logger.xml
注:使用されているファイルを確認するには、システムプロパティをデバッグ用に設定します:
-Dlogback.debug=true
。
§例
ローリングファイルアペンダーと、アクセスログを出力するための別のアペンダーを使用する設定の例を次に示します
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration>
<configuration>
<import class="ch.qos.logback.classic.boolex.OnMarkerEvaluator"/>
<import class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"/>
<import class="ch.qos.logback.core.rolling.RollingFileAppender"/>
<import class="ch.qos.logback.core.filter.EvaluatorFilter"/>
<import class="ch.qos.logback.core.FileAppender"/>
<import class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"/>
<appender name="FILE" class="RollingFileAppender">
<file>${application.home:-.}/logs/application.log</file>
<rollingPolicy class="TimeBasedRollingPolicy">
<!-- Daily rollover with compression -->
<fileNamePattern>${application.home:-.}/logs/application-log-%d{yyyy-MM-dd}.gz</fileNamePattern>
<!-- keep 30 days worth of history -->
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder class="PatternLayoutEncoder">
<pattern>%date{yyyy-MM-dd HH:mm:ss ZZZZ} [%level] from %logger in %thread - %message%n%xException</pattern>
</encoder>
</appender>
<appender name="SECURITY_FILE" class="FileAppender">
<filter class="EvaluatorFilter">
<evaluator class="OnMarkerEvaluator">
<marker>SECURITY</marker>
</evaluator>
<onMismatch>DENY</onMismatch>
<onMatch>ACCEPT</onMatch>
</filter>
<file>${application.home:-.}/logs/security.log</file>
<encoder class="PatternLayoutEncoder">
<pattern>%date [%level] [%marker] from %logger in %thread - %message%n%xException</pattern>
</encoder>
</appender>
<appender name="ACCESS_FILE" class="RollingFileAppender">
<file>${application.home:-.}/logs/access.log</file>
<rollingPolicy class="TimeBasedRollingPolicy">
<!-- daily rollover with compression -->
<fileNamePattern>${application.home:-.}/logs/access-log-%d{yyyy-MM-dd}.gz</fileNamePattern>
<!-- keep 1 week worth of history -->
<maxHistory>7</maxHistory>
</rollingPolicy>
<encoder class="PatternLayoutEncoder">
<pattern>%date{yyyy-MM-dd HH:mm:ss ZZZZ} %message%n</pattern>
<!-- this quadruples logging throughput -->
<immediateFlush>false</immediateFlush>
</encoder>
</appender>
<!-- additivity=false ensures access log data only goes to the access log -->
<logger name="access" level="INFO" additivity="false">
<appender-ref ref="ACCESS_FILE"/>
</logger>
<root level="INFO">
<appender-ref ref="FILE"/>
<appender-ref ref="SECURITY_FILE"/>
</root>
</configuration>
これは、いくつかの便利な機能を示しています
- 増大するログファイルを管理するのに役立つ
RollingFileAppender
を使用します。詳細については、こちらを参照してください。 - ログファイルをアプリケーションの外部のディレクトリに書き込むため、アップグレードなどの影響を受けません。
FILE
アペンダーは、Sumo Logicなどのサードパーティのログ分析プロバイダーで解析できる拡張メッセージ形式を使用します。access
ロガーは、ACCESS_FILE
アペンダーを使用して別のログファイルにルーティングされます。- 「SECURITY」マーカーが添付されたログメッセージはすべて、EvaluatorFilterとOnMarkerEvaluatorを使用して
security.log
ファイルに記録されます。 - すべてのロガーのしきい値は、本番環境のロギングで一般的な選択肢である
INFO
に設定されています。
注:
file
タグは省略可能であり、ファイルの名前変更を避けたい場合は省略できます。詳細については、Logbackドキュメントを参照してください。
§プロパティのインクルード
デフォルトでは、プロパティapplication.home
のみがロギングフレームワークにエクスポートされます。つまり、ファイルはPlayアプリケーションを基準にして参照できます
<file>${application.home:-}/example.log</file>
application.conf
ファイルで定義されているプロパティを参照する場合は、application.conf
ファイルにplay.logger.includeConfigProperties=true
を追加します。アプリケーションの起動時に、設定で定義されているすべてのプロパティがロガーで使用できるようになります
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>context = ${my.property.defined.in.application.conf} %message%n</pattern>
</encoder>
</appender>
§Akkaロギング設定
Akkaシステムのロギングは、org.apache.pekko
ロガーをINFOに変更することで実行できます。
<!-- Set logging for all Pekko library classes to INFO -->
<logger name="org.apache.pekko" level="INFO" />
<!-- Set a specific actor to DEBUG -->
<logger name="actors.MyActor" level="DEBUG" />
スレッドやアクターアドレスなどの有用なプロパティを含むAkkaロガーのアペンダーを設定することもできます。LogbackとSlf4jの統合の詳細を含む、Akkaのロギングの設定の詳細については、Akkaのドキュメントを参照してください。
§カスタムロギングフレームワークの使用
PlayはデフォルトでLogbackを使用しますが、SLF4Jアダプターがあれば、Playを別のロギングフレームワークを使用するように設定できます。これを行うには、disablePlugins
を使用してPlayLogback
sbtプラグインを無効にする必要があります
lazy val root = (project in file("."))
.enablePlugins(PlayScala)
.disablePlugins(PlayLogback)
そこから、カスタムロギングフレームワークを使用できます。ここでは、Log4J 2を例として使用します。
libraryDependencies ++= Seq(
"org.apache.logging.log4j" % "log4j-slf4j-impl" % "2.19.0",
"org.apache.logging.log4j" % "log4j-api" % "2.19.0",
"org.apache.logging.log4j" % "log4j-core" % "2.19.0"
)
ライブラリとSLF4Jアダプターがロードされると、通常どおりコマンドラインでlog4j.configurationFile
システムプロパティを設定できます。
Playのモードに依存するカスタム設定が必要な場合は、LoggerConfigurator
を使用して追加のカスタマイズを行うことができます。これを行うには、logger-configurator.properties
をクラスパスに追加します。
play.logger.configurator=Log4J2LoggerConfigurator
そして、LoggerConfiguratorをカスタマイズして拡張します
- Java
-
import com.typesafe.config.Config; import com.typesafe.config.ConfigFactory; import java.io.File; import java.net.URISyntaxException; import java.net.URL; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Optional; import org.slf4j.ILoggerFactory; import org.slf4j.LoggerFactory; import play.Environment; import play.LoggerConfigurator; import play.Mode; import play.api.PlayException; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.core.*; import org.apache.logging.log4j.core.config.Configurator; public class JavaLog4JLoggerConfigurator implements LoggerConfigurator { private ILoggerFactory factory; @Override public void init(File rootPath, Mode mode) { Map<String, String> properties = new HashMap<>(); properties.put("application.home", rootPath.getAbsolutePath()); String resourceName = "log4j2.xml"; URL resourceUrl = this.getClass().getClassLoader().getResource(resourceName); configure(properties, Optional.ofNullable(resourceUrl)); } @Override public void configure(Environment env) { Map<String, String> properties = LoggerConfigurator.generateProperties(env, ConfigFactory.empty(), Collections.emptyMap()); URL resourceUrl = env.resource("log4j2.xml"); configure(properties, Optional.ofNullable(resourceUrl)); } @Override public void configure( Environment env, Config configuration, Map<String, String> optionalProperties) { // LoggerConfigurator.generateProperties enables play.logger.includeConfigProperties=true Map<String, String> properties = LoggerConfigurator.generateProperties(env, configuration, optionalProperties); URL resourceUrl = env.resource("log4j2.xml"); configure(properties, Optional.ofNullable(resourceUrl)); } @Override public void configure(Map<String, String> properties, Optional<URL> config) { try { LoggerContext loggerContext = (LoggerContext) LogManager.getContext(false); loggerContext.setConfigLocation(config.get().toURI()); factory = LoggerFactory.getILoggerFactory(); } catch (URISyntaxException ex) { throw new PlayException( "log4j2.xml resource was not found", "Could not parse the location for log4j2.xml resource", ex); } } @Override public ILoggerFactory loggerFactory() { return factory; } @Override public void shutdown() { LoggerContext loggerContext = (LoggerContext) LogManager.getContext(); Configurator.shutdown(loggerContext); } }
- Scala
-
import java.io.File import java.net.URI import java.net.URL import play.api.{Mode, Configuration, Environment, LoggerConfigurator} import org.slf4j.ILoggerFactory import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.core._ import org.apache.logging.log4j.core.config.Configurator import org.slf4j.ILoggerFactory import org.slf4j.LoggerFactory import play.api.Configuration import play.api.Environment import play.api.LoggerConfigurator import play.api.Mode class Log4J2LoggerConfigurator extends LoggerConfigurator { private var factory: ILoggerFactory = _ override def init(rootPath: File, mode: Mode): Unit = { val properties = Map("application.home" -> rootPath.getAbsolutePath) val resourceName = "log4j2.xml" val resourceUrl = Option(this.getClass.getClassLoader.getResource(resourceName)) configure(properties, resourceUrl) } override def shutdown(): Unit = { val context = LogManager.getContext().asInstanceOf[LoggerContext] Configurator.shutdown(context) } override def configure(env: Environment): Unit = { val properties = LoggerConfigurator.generateProperties(env, Configuration.empty, Map.empty) val resourceUrl = env.resource("log4j2.xml") configure(properties, resourceUrl) } override def configure( env: Environment, configuration: Configuration, optionalProperties: Map[String, String] ): Unit = { // LoggerConfigurator.generateProperties enables play.logger.includeConfigProperties=true val properties = LoggerConfigurator.generateProperties(env, configuration, optionalProperties) val resourceUrl = env.resource("log4j2.xml") configure(properties, resourceUrl) } override def configure(properties: Map[String, String], config: Option[URL]): Unit = { val context = LogManager.getContext(false).asInstanceOf[LoggerContext] context.setConfigLocation(config.get.toURI) factory = LoggerFactory.getILoggerFactory } override def loggerFactory: ILoggerFactory = factory }
このドキュメントに誤りを見つけましたか?このページのソースコードはこちらにあります。ドキュメントガイドラインをお読みいただいた後、プルリクエストを送信してください。質問やアドバイスがありましたら、コミュニティフォーラムにアクセスして、コミュニティとの会話を始めてください。