-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Description
As noted in this comment here:
When upgrading to Spring Boot 3.4.2, we got the following error
java.lang.IllegalStateException: java.lang.IllegalStateException: Logback configuration error detected: ERROR in net.logstash.logback.composite.loggingevent.LoggingEventPatternJsonProvider@120bb5b5 - Invalid [pattern]: Invalid JSON property '//version' (was '%replace(%property{build.version}){'null',''}'): class java.lang.String cannot be cast to class java.util.function.Supplier (java.lang.String and java.util.function.Supplier are in module java.base of loader 'bootstrap') net.logstash.logback.pattern.AbstractJsonPatternParser$JsonPatternException: Invalid JSON property '//version' (was '%replace(%property{build.version}){'null',''}'): class java.lang.String cannot be cast to class java.util.function.Supplier (java.lang.String and java.util.function.Supplier are in module java.base of loader 'bootstrap')
And our configuration looks like
provider {
isOmitEmptyFields = true
this.pattern = """
{
"type": "Service",
"name": "%mdc{component}",
"version": "%replace(%property{build.version}){'null',''}"
}
"""
}
We are also observing that on upgrade to Spring Boot 3.4.2+ or 3.3.8+, Logstash Logback Encoder no longer works correctly for %property{some.system.property}
patterns.
This seems to be due to a breaking change introduced by logback-core in version 1.5.13 and after.
Here's the line where it's breaking:
Supplier<DynamicConverter> supplier = converterMap.get(keyword);
The root of the issue appears to be that the legacy conversion added within logback-core does not apply to the instanceConverterMap
which logback-logstash-encoder uses to register its EnhancedPropertyConverter
class.
public Map<String, Supplier<DynamicConverter>> getEffectiveConverterMap() {
Map<String, Supplier<DynamicConverter>> effectiveMap = new HashMap<>();
// ... removed for brevity ...
caterForLegacyConverterMaps(effectiveMap);
// ... removed for brevity ...
// set the most specific map last
effectiveMap.putAll(instanceConverterMap);
return effectiveMap;
}
Note that the caterForLegacyConverterMaps(effectiveMap)
method is called before the instanceConverterMap
is added to the map.
And see here for how logstash-logback-encoder is adding its value to instanceConverterMap
:
@Override
protected PatternLayoutBase<ILoggingEvent> createLayout() {
PatternLayoutBase<ILoggingEvent> layout = new PatternLayout();
layout.getInstanceConverterMap().put("property", EnhancedPropertyConverter.class.getName());
return layout;
}
It's adding the class name as a String, which is the legacy way to do it, and nothing in logback-core is fixing that.
This means that when instanceConverterMap
is added to effectiveMap
, the value is a raw String and not a Supplier, hence the error shown by @jackie-linz above: class java.lang.String cannot be cast to class java.util.function.Supplier
Assuming I've understood the problem correctly, it seems like logback-core needs to release a fix to handle this case since a breaking change was introduced in a patch version. Although it could be fixed in logstash-logback-encoder as well, that would mean that logstash-logback-encoder would have to make a breaking change as well to fix the breaking change introduced by logback-core and that seems less ideal, and it would mean that logstash-logback-encoder would have to maintain parallel versions, one that works with the older logback-core and one that works with the newer logback-core.