The new structured logging support is great and provides all the necessary building blocks to create custom JSON log formats via JsonWriterStructuredLogFormatter.
However, JsonValueWriter.writeString() escapes /
as \/
in JSON keys, which causes issues when targeting platforms like Google Cloud Logging. GCP expects specific root-level keys such as:
{
"logging.googleapis.com/spanId": "abc",
"logging.googleapis.com/trace": "projects/my-project/traces/123"
}
But the current implementation renders them as:
{
"logging.googleapis.com\/spanId": "abc",
"logging.googleapis.com\/trace": "projects/my-project/traces/123"
}
example impl
public class GCPStructuredLogFormatter extends JsonWriterStructuredLogFormatter<ILoggingEvent> {
GCPStructuredLogFormatter(StackTracePrinter stackTracePrinter,
ContextPairs contextPairs,
ThrowableProxyConverter throwableProxyConverter,
StructuredLoggingJsonMembersCustomizer<?> customizer) {
super(GCPStructuredLogFormatter::jsonMembers, customizer);
}
private static void jsonMembers(JsonWriter.Members<ILoggingEvent> members) {
members.add("timestamp", ILoggingEvent::getInstant).as(GCPStructuredLogFormatter::asTimestamp);
members.add("message", ILoggingEvent::getFormattedMessage);
members.add("logger_name", ILoggingEvent::getLoggerName);
members.add("thread_name", ILoggingEvent::getThreadName);
members.add("level", ILoggingEvent::getLevel);
members.add("logging.googleapis.com/spanId", (e) -> UUID.randomUUID().toString());
members.add("logging.googleapis.com/trace", (e) -> UUID.randomUUID().toString());
}
private static String asTimestamp(Instant instant) {
OffsetDateTime offsetDateTime = OffsetDateTime.ofInstant(instant, ZoneId.systemDefault());
return DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(offsetDateTime);
}
}
This prevents GCP from recognizing the structured fields.
Request: Add a way to opt out of escaping /
in JSON keys when using structured logging.
This would avoid having to reimplement JSON rendering logic entirely and allow users to fully benefit from the structured logging infrastructure provided by Spring Boot.