- 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??