How to extract traceId and spanId using logstash-logback-encoder with Springboot

42 Views Asked by At
  • Details about my goal:

I would like to have traceId and spanId as top level key values of JSON objects.

  • What I have tried:

I have a SpringBoot 3+ app with Micrometer and tracing enabled (I can see traces working). I use logstash-logback-encoder configured as below to forward logs to Logstash

The pipeline looks like SpringBoot -> logstash-logback-encoder -> Logstash -> Elasticsearch

Here is the logback-spring.xml

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

    <springProperty scope="context" name="name" source="spring.application.name"/>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} ${PID} %-5level --- [%thread] [${name},%X{traceId:-},%X{spanId:-}] %logger{36} : %msg%n
            </pattern>
        </encoder>
        <additionalFields>name=${name}</additionalFields>
    </appender>

    <appender name="LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
        <encoder class="net.logstash.logback.encoder.LogstashEncoder"/>
        <destination>127.0.0.1:5000</destination>
    </appender>

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

</configuration>

Here is the logstash.conf

input {
  tcp {
    port => 5000
  }
}

output {
    elasticsearch {
        hosts => "hostname"
        data_stream => "true"
    }
}

Here is the pom:

 <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>io.opentelemetry</groupId>
            <artifactId>opentelemetry-exporter-otlp</artifactId>
        </dependency>
        <dependency>
            <groupId>io.micrometer</groupId>
            <artifactId>micrometer-registry-otlp</artifactId>
        </dependency>
        <dependency>
            <groupId>io.micrometer</groupId>
            <artifactId>micrometer-tracing-bridge-otel</artifactId>
        </dependency>
        <dependency>
            <groupId>net.logstash.logback</groupId>
            <artifactId>logstash-logback-encoder</artifactId>
            <version>7.4</version>
        </dependency>
    </dependencies>
  • Actual result: With above, I am getting this result in Elasticsearch.
{
  "fields": {
    "@timestamp": 1710244682513,
    "@version": "1",
    "message": "{\"@timestamp\":\"2024-03-12T19:58:02.512659601+08:00\",\"@version\":\"1\",\"message\":\"I wish to have the trace id and spanid top level\",\"logger_name\":\"com.example.Controller\",\"thread_name\":\"http-nio-8080-exec-1\",\"level\":\"INFO\",\"level_value\":20000,\"name\":\"testapp\",\"traceId\":\"98409fb5e48b068aa8f53ea33c20afd4\",\"spanId\":\"056d385f3ebd277a\"}",
    "port": 40742
  },
  "_ts": "2024-03-12T11:58:02.513Z"
}
  • Describe the expected result:

With the above setup, I would have expected the log inside Elasticsearch to look like this. Please note I wish traceId spanId to be top level object of the JSON.

{
  "fields": {
    "@timestamp": 1710244682513,
    "@version": "1",
    "message": "{\"@timestamp\":\"2024-03-12T19:58:02.512659601+08:00\",\"@version\":\"1\",\"message\":\"I wish to have the trace id and spanid top level\",\"logger_name\":\"com.example.Controller\",\"thread_name\":\"http-nio-8080-exec-1\"}",
"level":"INFO",
"name":"testapp",
"traceId":"98409fb5e48b068aa8f53ea33c20afd4",
"spanId":"056d385f3ebd277a",
    "port": 40742
  },
  "_ts": "2024-03-12T11:58:02.513Z"
}

As you can see in this JSON, the traceId spanId are still inside message, not as top level object.

  • Question:

How to change, maybe the logback-spring.xml file, or the logstash forwader config logstash.cong, to have traceId spanId top level of the JSON??

0

There are 0 best solutions below