Play 2.5 配置日志
Play 使用log4j 作为日志,使用logback 作为日志引擎,可以查看 logback 的官网文档,了解详细配置:http://logback.qos.ch/manual/configuration.html
默认配置
1.在开发中,我们使用如下配置
<!--
~ Copyright (C) 2009-2016 Lightbend Inc. <https://www.lightbend.com>
-->
<!-- The default logback configuration that Play uses in dev mode if no other configuration is provided -->
<configuration>
<conversionRule conversionWord="coloredLevel" converterClass="play.api.libs.logback.ColoredLevel" />
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%coloredLevel %logger{15} - %message%n%xException{10}</pattern>
</encoder>
</appender>
<logger name="play" level="INFO" />
<logger name="application" level="DEBUG" />
<logger name="com.gargoylesoftware.htmlunit.javascript" level="OFF" />
<root level="WARN">
<appender-ref ref="STDOUT" />
</root>
</configuration>
2.在生产环境中,我们使用如下配置:
<!--
~Copyright (C) 2009-2016 Lightbend Inc. <https://www.lightbend.com>
-->
<!-- The default logback configurationthat Play uses if no other configuration is provided -->
<configuration>
<conversionRule conversionWord="coloredLevel" converterClass="play.api.libs.logback.ColoredLevel" />
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%coloredLevel %logger{15} -%message%n%xException{10}</pattern>
</encoder>
</appender>
<appender name="ASYNCSTDOUT" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="STDOUT" />
</appender>
<logger name="play" level="INFO" />
<logger name="application" level="INFO" />
<logger name="com.gargoylesoftware.htmlunit.javascript" level="OFF" />
<root level="WARN">
<appender-ref ref="ASYNCSTDOUT" />
</root>
</configuration>
3.关于这些配置,需要注意以下几项
1. 这些默认的配置,仅仅指定了在控制台输出10行栈异常
2. 用不同颜色的代码定义异常信息的级别
3. 在生产环境,默认的配置被定义在了logback的控制台,参见文档:http://logback.qos.ch/manual/appenders.html#AsyncAppender,有关性能影响的详细信息,请参加如下文档:https://blog.takipi.com/how-to-instantly-improve-your-java-logging-with-7-logback-tweaks/
4.生成日志文件,可在你的logback.xml 文件中添加如下信息
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>${application.home:-.}/logs/application.log</file>
<encoder>
<pattern>%date [%level] from %logger in %thread - %message%n%xException</pattern>
</encoder>
</appender>
5.(可选)使用异步的追加器
<appender name="ASYNCFILE" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="FILE" />
</appender>
6.将必要的,附加程序添加到根
<root level="WARN">
<appender-ref ref="ASYNCFILE" />
<appender-ref ref="ASYNCSTDOUT" />
</root>
使用自定义加载器
请注意,当使用不扩展默认GuiceApplicationLoader的自定义应用程序加载器时(例如,当使用编译时依赖注入时),需要手动调用LoggerConfigurator来拾取您的自定义配置。您可以使用下面的代码:
class MyApplicationLoaderWithInitialization extends ApplicationLoader {
def load(context: Context) = {
LoggerConfigurator(context.environment.classLoader).foreach {
_.configure(context.environment)
}
new MyComponents(context).application
}
}
自定义配置
对于任何的自定义配置,都需要指定你自己的 logback 配置
1.使用源项目中的配置文件
你可以通过提供一个 logback.xml文件来提供默认日志记录配置
2.使用外部配置文件
你也可以通过系统属性,指定配置文件。这对于可以在应用程序源之外管理配置文件的生产环境特别有用。
注意:日志记录系统首先指定由系统属性指定的配置文件,其次指向conf目录中的文件,最后指定为默认值。这允许您自定义应用程序的日志记录配置,并仍然覆盖特定环境或开发人员设置。
使用 -Dlogger.resource
从类路径指定要加载的配置文件 $ start -Dlogger.resource=prod-logger.xml
使用 -Dlogger.file
指定从文件系统中加载的配置文件 $ start -Dlogger.file=/opt/prod/logger.xml
3.例子
使用滚动的文件追加器配置
<configuration>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${user.dir}/web/logs/application.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- Daily rollover with compression -->
<fileNamePattern>application-log-%d{yyyy-MM-dd}.gz</fileNamePattern>
<!-- keep 30 days worth of history -->
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%date{yyyy-MM-dd HH:mm:ss ZZZZ} [%level] from %logger in %thread - %message%n%xException</pattern>
</encoder>
</appender>
<appender name="ACCESS_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${user.dir}/web/logs/access.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- daily rollover with compression -->
<fileNamePattern>access-log-%d{yyyy-MM-dd}.gz</fileNamePattern>
<!-- keep 1 week worth of history -->
<maxHistory>7</maxHistory>
</rollingPolicy>
<encoder>
<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"/>
</root>
</configuration>
这演示了一些有用的功能:
它使用RollingFileAppender,它可以帮助管理日益增长的日志文件。
它将日志文件写入应用程序外部的目录,以便它们不受升级等影响。
这个文件追加器使用扩展的消息格式,可以由第三方日志分析提供程序(如Sumo Logic)解析。
访问记录器使用ACCESS_FILE_APPENDER路由到单独的日志文件。
所有记录器都设置为INFO的阈值,INFO是生产日志记录的常用选项。
Akka 日志配置
Akka系统日志记录可以通过将akka记录器更改为INFO来完成。
<!-- Set logging for all Akka library classes to INFO -->
<logger name="akka" level="INFO" />
<!-- Set a specific actor to DEBUG -->
<logger name="actors.MyActor" level="DEBUG" />
您还可以为Akka记录器配置包含有用属性(例如线程和actor地址)的追加器。有关配置Akka日志记录的更多信息,包括Logback和Slf4j集成的详细信息,请参阅Akka文档。
http://doc.akka.io/docs/akka/current/scala/logging.html
使用自定义日志框架
Play默认使用logback作为日志框架,但是也可以通过配置使Play使用另外一些符合 slf4j 适配器的的日志框架。要做到这一点,PlayLogback SBT插件必须通过disablePlugins禁用:
lazy val root = (project in file("."))
.enablePlugins(PlayScala)
.disablePlugins(PlayLogback)
上边介绍了一个自定义框架的使用,下边介绍log4j 使用例子:
libraryDependencies ++= Seq(
"org.apache.logging.log4j" % "log4j-slf4j-impl" % "2.4.1",
"org.apache.logging.log4j" % "log4j-api" % "2.4.1",
"org.apache.logging.log4j" % "log4j-core" % "2.4.1"
)
加载库和SLF4J适配器后,可以像通常一样在命令行上设置log4j.configurationFile系统属性。
如果在Play做需要的模式上自定义,你可以使用LoggerConfigurator 进行其他的定义,为此可以添加一个 logger-configurator.properties 到classpath 下:
play.logger.configurator=Log4J2LoggerConfigurator
然后可以扩展LoggerConfigurator 做一些自定义
import java.io.File
import java.net.URL
import org.apache.logging.log4j.LogManager
import org.apache.logging.log4j.core._
import org.apache.logging.log4j.core.config.Configurator
import play.api.{Mode, Environment, LoggerConfigurator}
class Log4J2LoggerConfigurator extends LoggerConfigurator {
override def init(rootPath: File, mode: Mode.Mode): Unit = {
val properties = Map("application.home" -> rootPath.getAbsolutePath)
val resourceName = if (mode == Mode.Dev) "log4j2-dev.xml" else "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 = Map("application.home" -> env.rootPath.getAbsolutePath)
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)
}
}