spring-boot icon indicating copy to clipboard operation
spring-boot copied to clipboard

JSON logging as alternative to pattern layout logging

Open mp911de opened this issue 9 years ago • 15 comments

Spring Boot offers logging using a pattern for various log frameworks. In scenarios, where more context details would be useful, users need to adopt the pattern. Each value from the MDC needs to be configured independently which is a consistent source of work. It would be great to opt-in for a JSON log format that is used instead of the pattern layout to have a flexible field schema for later processing within log aggregators such as Splunk, Graylog, or Logstash.

Use-cases

  • Using MDC to store contextual details helps while tracing and debugging applications. Currently, the pattern layout is configured in a static way (in config files) while MDC values can be added dynamically. Adding dynamically values to the JSON structure from the MDC does not necessarily require additional configuration each time a new MDC entry is added to the application. That's actually the use case from which the power comes.
  • Log forwarders need to be adopted for each change of the log format. Adding Spring Clouds Sleuth to use the slf4j span logger requires for instance adoption of the log format.
  • Multiline logging: Configuring log forwarders for parsing multiline logs is challenging. Exceptions can be nicely wrapped within a JSON field; The syntax of JSON makes it easy because no additional multiline configuration needs to be set up
  • JSON logs can be either picked up from stdout by an online-forwarder or written into a file that is read by logstash forwarder (or other tools)

See https://github.com/mp911de/logstash-gelf for examples.

mp911de avatar Mar 24 '16 10:03 mp911de

This would be a nice addition. I had to customize https://github.com/logstash/logstash-logback-encoder project to integrate with Logentries which is also supporting JSON logs.

Please note that logstash-logback-encoder is general-purpose JSON logging mechanism project.

cemo avatar Mar 24 '16 11:03 cemo

@mp911de Is there anything that's currently preventing JSON logging from working for you? I'm not sure that we really want to take on too much more responsibility in this area. We already have quite a maintenance burden trying to support three different logging systems.

philwebb avatar Apr 16 '16 06:04 philwebb

There's nothing which prevents JSON logging/log forwarding. It's more about the barrier to configure logging and set up conditional JSON logging. Usually, in dev, one does not want to have JSON logs but would enable JSON logging in staging/production. Using different logging config files and specifying logging.config=(my config file) per environment increases the complexity.

I fully understand the maintenance efforts from your side. I'm considering maybe another approach with building/providing a starter in my own repo as I did JSON logging earlier. This way an extension existed one could use, and you don't have the maintenance hassle.

mp911de avatar Apr 16 '16 08:04 mp911de

That would certainly be better from our point of view. We could always add other extension points if needed.

philwebb avatar Apr 16 '16 14:04 philwebb

I'll follow that path then, thanks for your feedback.

mp911de avatar Apr 16 '16 15:04 mp911de

@mp911de have you gotten to implement the spring boot starter you mentioned?

imjorge avatar Feb 24 '17 00:02 imjorge

@imjorge I haven't been doing much on that end.

mp911de avatar Feb 24 '17 12:02 mp911de

Hi @cemo When you say that you include the log stash plugin : https://github.com/logstash/logstash-logback-encoder How did you plug Logentries with the LoggingEventCompositeJsonEncoder from this lib ?

Here is an extract of my logback conf:

    <appender name="loggly" class="com.rapid7.logback.LogentriesAppender">
        <Token>MY_TOKEN</Token>
        <Region>eu</Region>
        <Debug>False</Debug>
        <Ssl>True</Ssl>
        <facility>USER</facility>
        <!--<layout>-->
            <!--<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>-->
        <!--</layout>-->

        <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
            <providers>
                <!-- Log all StructuredArgument instances -->
                <arguments/>
                <!-- Log all MDC fields except the ones from Sleuth - we add them below
                under cleaned up names -->
                <mdc>
                    <excludeMdcKeyName>X-B3-TraceId</excludeMdcKeyName>
                    <excludeMdcKeyName>X-B3-SpanId</excludeMdcKeyName>
                    <excludeMdcKeyName>X-B3-ParentSpanId</excludeMdcKeyName>
                    <excludeMdcKeyName>X-Span-Export</excludeMdcKeyName>
                </mdc>
                <!-- Include Exception stack traces -->
                <stackTrace/>
                <timestamp>
                    <timeZone>UTC</timeZone>
                </timestamp>
                <!-- Assign logger fields to JSON object -->
                <pattern>
                    <pattern>
                        {
                        "component": "BackendJava",
                        "endpoint": "%mdc{method} | %mdc{url}",
                        "severity": "%level",
                        "params": "%mdc{params}",
                        "mcdTest": "%mdc{mdcData}",
                        "thread": "%thread",
                        "logger": "%logger",
                        "message": "%message"
                        }
                    </pattern>
                </pattern>
            </providers>
        </encoder>

    </appender>

But I always get this error: A "net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder" object is not assignable to a "ch.qos.logback.classic.encoder.PatternLayoutEncoder" variable.

Thanks

pinfrederic avatar Feb 23 '18 10:02 pinfrederic

Imho it is quite a common practice to have logs in json format, so it can be easily digested by logstash, graylog, splunk, etc.

I think would be nice If spring boot would provide a simple option to switch the log format to json (and disable the banner at the same time). Currently you need to add some dependencies and override the entire log configuration. It would be nice to have a starter and a switch for it. The switch would be useful to change the setting for local development vs. deployment.

Logback

You currently need to add the net.logstash.logback:logstash-logback-encoder dependency, and override the entire logback configuration. If you include org/springframework/boot/logging/logback/base.xml you have the problem that you can't remove the appenders already included there. Also in contrast to the DefaultLogbackConfiguration a file appender is instantiated writing to some temp file (which may be undesirable in container environments). The DefaultLogbackConfiguration itself is not customizable and if you want to make the logback.xml configuration conditional on some property you need to also include the org.codehaus.janino:janino dependency.

Log4j2

you need to add jackson as dependency. And replace the entire configuration using an appender using the JsonLayout loosing all the defaults from spring boot if not duplicated. For having a switch you can add Routing to the configuration.

joshiste avatar Jun 26 '20 13:06 joshiste

Log4j 2.14.0 will include a new component, JsonTemplateLayout that uses a template to describe the format of the JSON. It was donated by the author of https://github.com/vy/log4j2-logstash-layout who is now a committer on the Log4j project. As I recall the implementation does not require Jackson, although I would be surprised if Jackson is an issue for anyone using Spring Boot.

rgoers avatar Sep 19 '20 07:09 rgoers

We have had requests for integration with log tooling in Azure for JSON pattern layout. Is this going to be making it into an upcoming release?

csterwa avatar Dec 15 '21 19:12 csterwa

@csterwa ahead of that it's possible to do it ie via https://www.jvt.me/posts/2021/05/31/spring-boot-structured-logging/

jamietanna avatar Dec 15 '21 20:12 jamietanna

@csterwa No imminent plans I'm afraid. Boot 3 / Framework 6 work will be taking priority.

philwebb avatar Dec 15 '21 22:12 philwebb

@philwebb Activating a profile would bring this a long way in order to be able to do something like:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>

  <include resource="org/springframework/boot/logging/logback/defaults.xml" />
  <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator" />

  <springProfile name="kubernetes">
    <appender name="jsonAppender" class="ch.qos.logback.core.ConsoleAppender">
      <encoder class="net.logstash.logback.encoder.LogstashEncoder"/>
    </appender>
  </springProfile>

  <springProfile name="!kubernetes">
    <include resource="org/springframework/boot/logging/logback/console-appender.xml" />
  </springProfile>

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

</configuration>

I am aware that spring-cloud-kubernetes can define the profile, but I want to avoid pulling all of that in. I am also aware of https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/cloud/CloudPlatform.html - but AFAIK that can't be used for toggling in spring-logback.xml.

WDYT?

davidkarlsen avatar Mar 18 '22 00:03 davidkarlsen

See https://github.com/spring-projects/spring-boot/issues/39814 for an example of a subtle bug that can occur with certain json logging configurations.

wilkinsona avatar Mar 12 '24 09:03 wilkinsona

Re-opening to address the test failures on Windows and to remind us to add something to the release notes.

wilkinsona avatar Jul 15 '24 12:07 wilkinsona