§組態記錄
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 中預設啟用。
安全性標記也允許安全性失敗觸發或篩選與一般記錄不同的部分。例如,若要停用設定安全性標記的所有記錄,請將下列行新增到 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
檔中定義的屬性,你可以將 play.logger.includeConfigProperties=true
新增到你的 application.conf 檔。當應用程式啟動時,組態中定義的所有屬性都將可供記錄器使用
<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>
§Pekko 記錄組態
Pekko 系統記錄可透過將 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" />
您可能也希望為 Pekko 記錄器設定一個附加程式,其中包含有用屬性,例如執行緒和動作員地址。如需 Pekko 記錄設定的詳細資訊,包括 Logback 和 Slf4j 整合的詳細資料,請參閱 Pekko 文件。
§使用自訂記錄架構
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 }
下一步:設定 WS SSL
在此文件發現錯誤?此頁面的原始程式碼可以在 這裡 找到。在閱讀 文件指南 後,請隨時提交拉取請求。有問題或建議要分享?請前往 我們的社群論壇 與社群展開對話。