Configuring Logging

§Configuring Logging

Lagom uses SLF4J for logging, backed by Logback as its default logging engine. See the Logback documentation for details on configuration.

§Default configuration

If you don’t provide your own Logback configuration, Lagom uses the following default configuration in development:

<!--
  ~ Copyright (C) 2016-2019 Lightbend Inc. <https://www.lightbend.com>
  -->
<!-- The default logback configuration that Lagom uses in dev mode if no other configuration is provided -->
<configuration>

  <conversionRule conversionWord="coloredLevel" converterClass="com.lightbend.lagom.internal.logback.ColoredLevel" />

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%date{"HH:mm:ss.SSS"} %coloredLevel %logger [%mdc] - %msg%n</pattern>
    </encoder>
  </appender>

  <!-- Set logging for all Play library classes to INFO -->
  <logger name="play" level="INFO" />
  <!-- Set logging for all Akka library classes to INFO -->
  <logger name="akka" level="INFO" />
  <!-- Set logging for all Lagom library classes to INFO -->
  <logger name="com.lightbend.lagom" level="INFO" />

  <!-- Cassandra and the datasta driver are used by the Lagom event sourcing modules -->
  <logger name="org.apache.cassandra" level="ERROR" />
  <logger name="com.datastax.driver" level="ERROR" />
  <!-- Turning off connection error logging to avoid noise when services are forcibly stopped -->
  <logger name="com.datastax.driver.core.ControlConnection" level="OFF" />
  <!-- Turn down Kafka noise -->
  <logger name="org.apache.kafka" level="WARN" />

  <root level="INFO">
    <appender-ref ref="STDOUT" />
  </root>

</configuration>

While it uses the following one in production:

<!--
  ~ Copyright (C) 2016-2019 Lightbend Inc. <https://www.lightbend.com>
  -->
<!-- The default logback configuration that Lagom uses if no other configuration is provided -->
<configuration>

  <conversionRule conversionWord="coloredLevel" converterClass="com.lightbend.lagom.internal.logback.ColoredLevel" />

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%date{"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",UTC} %coloredLevel %logger [%mdc] - %msg%n</pattern>
    </encoder>
  </appender>

  <appender name="ASYNCSTDOUT" class="ch.qos.logback.classic.AsyncAppender">
    <appender-ref ref="STDOUT" />
  </appender>

  <!-- Set logging for all Play library classes to INFO -->
  <logger name="play" level="INFO" />
  <!-- Set logging for all Akka library classes to INFO -->
  <logger name="akka" level="INFO" />
  <!-- Set logging for all Lagom library classes to INFO -->
  <logger name="com.lightbend.lagom" level="INFO" />

  <!-- Cassandra and the datasta driver are used by the Lagom event sourcing modules -->
  <logger name="org.apache.cassandra" level="ERROR" />
  <logger name="com.datastax.driver" level="ERROR" />
  <!-- Turn down Kafka noise -->
  <logger name="org.apache.kafka" level="WARN" />

  <root level="INFO">
    <appender-ref ref="ASYNCSTDOUT" />
  </root>

</configuration>

A few things to note:

  • The logger logs full exception stack traces and full-qualified logger names.
  • Lagom uses ANSI color codes by default in level messages.
  • In production, Lagom puts the logger behind the logback AsyncAppender. For details on the performance implications on this, see this blog post.

§Custom configuration

For any custom configuration, you need to provide your own Logback configuration file.

§Using a configuration file from project source

You can provide a default logging configuration by creating a logback.xml file in the project’s resource folder. Furthermore, for testing purposes, you can also create a logback-test.xml and place it in the src/test/resources directory of your project. When both logback.xml and logback-test.xml are in the classpath, the latter has higher precedence.

§Using an external configuration file

You can also specify a configuration file via a System property. This is particularly useful for production environments where the configuration file may be managed outside of your application source.

Note: The logging system gives top preference to configuration files specified by system properties, secondly to files in the resource directory, and lastly to the default. This allows you to customize your application’s logging configuration and still override it for specific environments or developer setups.

§Using -Dlogger.resource

To specify a configuration file to be loaded from the classpath use the system property -Dlogger.resource, e.g., -Dlogger.resource=prod-logger.xml.

§Using -Dlogger.file

To specify a configuration file to be loaded from the file system use the system property -Dlogger.file, e.g., -Dlogger.file=/opt/prod/logger.xml.

§Play Lagom applications

When integrating a Play application in Lagom via the LagomPlay sbt plugin, the default Play logging module is used. The main difference, with respect to the Lagom logging module, is that the Play logging module provides different default logback configurations. Read the Play framework Configuring Logging documentation for details.

§Internal framework logging

It can be useful at times to gain more visibility on what’s happening inside Lagom.

§Lagom logging configuration

Lagom system logging can be done by changing the com.lightbend.lagom logger to DEBUG.

<!-- Set logging for all Lagom library classes to DEBUG -->
<logger name="com.lightbend.lagom" level="DEBUG" />

§Akka logging configuration

Akka system logging can be done by changing the akka logger to DEBUG.

<!-- Set logging for all Akka library classes to DEBUG -->
<logger name="akka" level="DEBUG" />
<!-- Set a specific actor to DEBUG -->
<logger name="actors.MyActor" level="DEBUG" />

And, you will also need to add the following in your project’s application.conf:

akka.loglevel=DEBUG

Furthermore, you may also wish to configure an appender for the Akka loggers that includes useful properties such as thread and actor address. For more information about configuring Akka’s logging, including details on Logback and Slf4j integration, see the Akka documentation.

§Play logging configuration

Play system logging can be done by changing the play logger to DEBUG.

<!-- Set logging for all Play library classes to DEBUG -->
<logger name="play" level="DEBUG" />

§Default Log4j2 configuration

Similarly to the default logback configuration, when using the Log4j2 Lagom module, a default configuration is provided. In development, the following is used by default:

<!--
  ~ Copyright (C) 2016-2019 Lightbend Inc. <https://www.lightbend.com>
  -->
<!-- The default log4j2 configuration that Lagom uses in dev mode if no other configuration is provided -->
<Configuration name="DevelopmentLagomConfig">
  <Appenders>
    <Console name="STDOUT">
      <PatternLayout>
        <Pattern>%d{HH:mm:ss.SSS} %highlight{%level} %logger [%mdc] - %msg%n</Pattern>
      </PatternLayout>
    </Console>
  </Appenders>

  <Loggers>
    <!-- Set logging for all Play library classes to INFO -->
    <Logger name="play" level="INFO"/>
    <!-- Set logging for all Akka library classes to INFO -->
    <Logger name="akka" level="INFO"/>
    <!-- Set logging for all Lagom library classes to INFO -->
    <Logger name="com.lightbend.lagom" level="INFO"/>

    <!-- Cassandra and the datastax driver are used by the Lagom event sourcing modules -->
    <Logger name="org.apache.cassandra" level="ERROR"/>
    <Logger name="com.datastax.driver" level="ERROR"/>
    <!-- Turning off connection error logging to avoid noise when services are forcibly stopped -->
    <Logger name="com.datastax.driver.core.ControlConnection" level="OFF"/>
    <!-- Turn down Kafka noise -->
    <Logger name="org.apache.kafka" level="WARN"/>

    <AsyncRoot level="INFO">
      <AppenderRef ref="STDOUT"/>
    </AsyncRoot>
  </Loggers>

</Configuration>

And in production, the following is the default configuration:

<!--
  ~ Copyright (C) 2016-2019 Lightbend Inc. <https://www.lightbend.com>
  -->
<!-- The default log4j2 configuration that Lagom uses if no other configuration is provided -->
<Configuration name="DefaultLagomConfig">
  <Appenders>
    <Console name="STDOUT">
      <PatternLayout>
        <Pattern>%d{yyyy-MM-dd'T'HH:mm:ss.SSS'Z'}{GMT+0} %highlight{%level} %logger [%mdc] - %msg%n</Pattern>
      </PatternLayout>
    </Console>
  </Appenders>

  <Loggers>
    <!-- Set logging for all Play library classes to INFO -->
    <Logger name="play" level="INFO"/>
    <!-- Set logging for all Akka library classes to INFO -->
    <Logger name="akka" level="INFO"/>
    <!-- Set logging for all Lagom library classes to INFO -->
    <Logger name="com.lightbend.lagom" level="INFO"/>

    <!-- Cassandra and the datastax driver are used by the Lagom event sourcing modules -->
    <Logger name="org.apache.cassandra" level="ERROR"/>
    <Logger name="com.datastax.driver" level="ERROR"/>
    <!-- Turn down Kafka noise -->
    <Logger name="org.apache.kafka" level="WARN"/>

    <AsyncRoot level="INFO">
      <AppenderRef ref="STDOUT"/>
    </AsyncRoot>
  </Loggers>
</Configuration>

A few things to note:

  • A file appender that writes to logs/application.log is created.
  • The file appender logs full stack traces while the console logger limits it to 10 lines.
  • Console logging uses colored log levels by default.
  • In production, all loggers are configured to use async loggers by default using the LMAX Disruptor library.

§Custom configuration

Including a file named log4j2.xml in your project’s root will override the defaults. All other system properties specified for the logback integration above are also supported here.

§Using a Custom Logging Framework

Lagom uses Logback by default, but it is possible to configure Lagom to use another logging framework, as long as there is an SLF4J adapter for it.

If you’re using Maven, you simply need to remove the logback dependency from your projects dependencies. If using sbt, you need to disable the LagomLogback plugin in your sbt project:

lazy val portfolioImpl = (project in file("portfolioImpl"))
  .enablePlugins(LagomScala)
  // This avoids adding the Lagom logging module to the classpath
  .disablePlugins(LagomLogback)

From there, a custom logging framework can be used. Here, Log4J 2 is used as an example.

lazy val orderImpl = (project in file("orderImpl"))
  .enablePlugins(LagomScala)
  // This avoids adding the Lagom logging module to the classpath
  .disablePlugins(LagomLogback)
  .settings(
    libraryDependencies ++= Seq(
      "org.apache.logging.log4j" % "log4j-slf4j-impl" % "2.8.2",
      "org.apache.logging.log4j" % "log4j-api"        % "2.8.2",
      "org.apache.logging.log4j" % "log4j-core"       % "2.8.2",
      "com.lmax"                 % "disruptor"        % "3.3.6"
    )
  )

Once the libraries and the SLF4J adapter are loaded, the log4j.configurationFile system property can be set on the command line as usual.

Found an error in this documentation? The source code for this page can be found here. Please feel free to edit and contribute a pull request.