Hello.
In my company, they expect us that the JSON messages we log must always contain the event.kind
entry while forwarding out messages to Elastic.
Given that such property can take specific useful values, my idea was to provide a default value event
in case it was not provided and to overwrite such default with another value when needed.
As such, I configured my Spring Boot 3.5.6 (Java 25) application as follows:
logging:
structured:
format.console: ecs
ecs.service.environment: dev
json.add:
event.kind: event
deployment.environment.name: dev
level:
root: info
org.hibernate.validator.internal.util.Version: warn
and, to test the overwrite, I just wrote a line like
var logger = LoggerFactory.getLogger(getClass());
logger.atInfo().addKeyValue("event.kind", "metric").log("This is a log entry on INFO level");
but then this fails with
13:47:47,369 |-ERROR in ch.qos.logback.core.ConsoleAppender[CONSOLE] - Appender [CONSOLE] failed to append. java.lang.IllegalStateException: The name 'event' has already been written
at java.lang.IllegalStateException: The name 'event' has already been written
at at org.springframework.util.Assert.state(Assert.java:101)
at at org.springframework.boot.json.JsonValueWriter.writePair(JsonValueWriter.java:252)
at at java.base/java.util.LinkedHashMap.forEach(LinkedHashMap.java:987)
at at org.springframework.boot.logging.structured.ContextPairs$Pairs.nested(ContextPairs.java:196)
at at org.springframework.boot.json.JsonWriter$Member.lambda$getValueToWrite$4(JsonWriter.java:655)
at at org.springframework.boot.json.JsonValueWriter.writePairs(JsonValueWriter.java:242)
at at org.springframework.boot.json.JsonWriter$Member.lambda$getValueToWrite$5(JsonWriter.java:655)
which is the same as https://github.com/spring-projects/spring-boot/issues/45217, just the usage context is different. /cc @philwebb given he's already looking and the mentioned similar issue.
Comment From: cdprete
@philwebb it seems it happens for the entire event
object.
I've the class
public class StructuredLoggingPingTask implements Runnable {
private static final Logger logger = LoggerFactory.getLogger(StructuredLoggingPingTask.class);
static final String EVENT_CATEGORY_KEY = "event.category";
static final String EVENT_CATEGORY_VALUE = "process";
static final String EVENT_TYPE_KEY = "event.type";
static final String EVENT_TYPE_VALUE = "info";
static final String EVENT_OUTCOME_KEY = "event.outcome";
static final String EVENT_OUTCOME_VALUE = "success";
private final StructuredLoggingPingProperties properties;
public StructuredLoggingPingTask(StructuredLoggingPingProperties properties) {
this.properties = properties;
}
@Override
public void run() {
logger.atInfo()
.addKeyValue(EVENT_CATEGORY_KEY, EVENT_CATEGORY_VALUE)
.addKeyValue(EVENT_TYPE_KEY, EVENT_TYPE_VALUE)
.addKeyValue(EVENT_OUTCOME_KEY, EVENT_OUTCOME_VALUE)
.log(properties.message());
}
}
and even for different keys (category, type and outcome) under event
I get back
11:40:43,447 |-ERROR in ch.qos.logback.core.ConsoleAppender[CONSOLE] - Appender [CONSOLE] failed to append. java.lang.IllegalStateException: The name 'event' has already been written
at java.lang.IllegalStateException: The name 'event' has already been written
at at org.springframework.util.Assert.state(Assert.java:101)
at at org.springframework.boot.json.JsonValueWriter.writePair(JsonValueWriter.java:252)
at at java.base/java.util.LinkedHashMap.forEach(Unknown Source)
at at org.springframework.boot.logging.structured.ContextPairs$Pairs.nested(ContextPairs.java:196)
at at org.springframework.boot.json.JsonWriter$Member.lambda$getValueToWrite$4(JsonWriter.java:655)
at at org.springframework.boot.json.JsonValueWriter.writePairs(JsonValueWriter.java:242)
at at org.springframework.boot.json.JsonWriter$Member.lambda$getValueToWrite$5(JsonWriter.java:655)
Moreover, what's worse is that the ECS format is not followed anymore, as you can see, making the forward of those logs not even possible actually. The situation is therefore way more problematic than expected. Are there any potential temporary workarounds possible?
Comment From: cdprete
Current workaround from my side:
- Configure
logback
by hand and uselogback-ecs-encoder
as dependency - Extend the workaround in https://github.com/elastic/ecs-logging-java/issues/49 to provide the
event.kind
if it's not already in there