Skip to content

Commit f4e5ff3

Browse files
Update LoggingEventJsonPatternParser to fix breaking logback change (#1061)
Maintain PatternLayout compatibility with logback <= 1.5.12 In logback 1.5.13, PatternLayoutBase.getInstanceConverterMap changed from `Map<String, String>` to `Map<String, Supplier<DynamicConverter>` To maintain compatibility with logback <= 1.5.12, use reflection to determine the type of the Map, and add entries appropriately. Fixes #1060 Co-authored-by: Jordan Jennings <[email protected]>
1 parent 83aa0fe commit f4e5ff3

File tree

4 files changed

+102
-8
lines changed

4 files changed

+102
-8
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,8 @@ For example, to ensure that maven doesn't pick different versions of logback-cor
139139

140140
```xml
141141
<properties>
142-
<logback-classic.version>1.5.6</logback-classic.version>
143-
<logback-access.version>2.0.2</logback-access.version>
142+
<logback-classic.version>1.5.18</logback-classic.version>
143+
<logback-access.version>2.0.6</logback-access.version>
144144
</properties>
145145
<dependencyManagement>
146146
<dependencies>
@@ -156,7 +156,7 @@ For example, to ensure that maven doesn't pick different versions of logback-cor
156156
</dependency>
157157
<dependency>
158158
<groupId>ch.qos.logback.access</groupId>
159-
<artifactId>common</artifactId>
159+
<artifactId>logback-access-common</artifactId>
160160
<version>${logback-access.version}</version>
161161
</dependency>
162162
</dependencies>

pom.xml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@
2525
<!-- runtime dependencies -->
2626
<jackson.version>2.17.2</jackson.version>
2727
<java-uuid-generator.version>5.1.0</java-uuid-generator.version>
28-
<logback-core.version>1.5.6</logback-core.version>
29-
<logback-access.version>2.0.2</logback-access.version>
28+
<logback-core.version>1.5.18</logback-core.version>
29+
<logback-access.version>2.0.6</logback-access.version>
3030

3131
<!-- shaded runtime dependencies -->
3232
<disruptor.version>3.4.4</disruptor.version>
@@ -155,7 +155,7 @@
155155
</dependency>
156156
<dependency>
157157
<groupId>ch.qos.logback.access</groupId>
158-
<artifactId>common</artifactId>
158+
<artifactId>logback-access-common</artifactId>
159159
<version>${logback-access.version}</version>
160160
<!--
161161
Required for logging IAccessEvents for access logs.
@@ -545,7 +545,7 @@
545545
<links>
546546
<link>https://javadoc.io/doc/ch.qos.logback/logback-core/${logback-core.version}</link>
547547
<link>https://javadoc.io/doc/ch.qos.logback/logback-classic/${logback-core.version}</link>
548-
<link>https://javadoc.io/doc/ch.qos.logback.access/common/${logback-access.version}</link>
548+
<link>https://javadoc.io/doc/ch.qos.logback.access/logback-access-common/${logback-access.version}</link>
549549

550550
<link>https://javadoc.io/doc/com.fasterxml.jackson.core/jackson-core/${jackson.version}</link>
551551
<link>https://javadoc.io/doc/com.fasterxml.jackson.core/jackson-databind/${jackson.version}</link>

src/main/java/net/logstash/logback/pattern/LoggingEventJsonPatternParser.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ public LoggingEventJsonPatternParser(final Context context, final JsonFactory js
3838
@Override
3939
protected PatternLayoutBase<ILoggingEvent> createLayout() {
4040
PatternLayoutBase<ILoggingEvent> layout = new PatternLayout();
41-
layout.getInstanceConverterMap().put("property", EnhancedPropertyConverter.class.getName());
41+
PatternLayoutCompatibilityUtil.registerConverter(
42+
layout, "property", EnhancedPropertyConverter.class, EnhancedPropertyConverter::new);
4243
return layout;
4344
}
4445

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
* Copyright 2013-2023 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package net.logstash.logback.pattern;
17+
18+
import java.lang.reflect.Method;
19+
import java.lang.reflect.ParameterizedType;
20+
import java.lang.reflect.Type;
21+
import java.util.Map;
22+
import java.util.function.Supplier;
23+
24+
import ch.qos.logback.classic.spi.ILoggingEvent;
25+
import ch.qos.logback.core.pattern.DynamicConverter;
26+
import ch.qos.logback.core.pattern.PatternLayoutBase;
27+
28+
/**
29+
* Utilities for working around backwards incompatibilities introduced in logback's
30+
* PatternLayout related classes to maintain support for multiple logback versions.
31+
*
32+
* <p>This can be removed in a major version of logstash-logback-encoder,
33+
* which bumps the minimum logback version to >= 1.5.13.</p>
34+
*/
35+
class PatternLayoutCompatibilityUtil {
36+
37+
/**
38+
* Registers the given converter in the layout's {@link PatternLayoutBase#getInstanceConverterMap()}.
39+
*
40+
* @param layout the layout to which to add the converter
41+
* @param converterName the name of the converter
42+
* @param converterClass the class of the converter
43+
* @param converterSupplier a supplier of instances of the converter
44+
* @param <E> type of object converted by the converter
45+
* @param <C> type of converter
46+
*/
47+
static <E, C extends DynamicConverter<E>> void registerConverter(
48+
PatternLayoutBase<ILoggingEvent> layout,
49+
String converterName,
50+
Class<C> converterClass,
51+
Supplier<C> converterSupplier) {
52+
53+
try {
54+
Method method = PatternLayoutBase.class.getDeclaredMethod("getInstanceConverterMap");
55+
ParameterizedType type = (ParameterizedType) method.getGenericReturnType();
56+
Type valueType = type.getActualTypeArguments()[1];
57+
58+
if (valueType.getTypeName().equals("java.lang.String")) {
59+
/*
60+
* In logback <= 1.5.12, getInstanceConverterMap() is a Map<String, String>.
61+
* key = converter name
62+
* value = name of converter class
63+
*/
64+
putUnchecked(layout.getInstanceConverterMap(), converterName, converterClass.getName());
65+
} else if (valueType.getTypeName().equals("java.util.function.Supplier<ch.qos.logback.core.pattern.DynamicConverter>")) {
66+
/*
67+
* In logback >= 1.5.13, getInstanceConverterMap() is a Map<String, Supplier<DynamicConverter>.
68+
* key = converter name
69+
* value = supplier of converter instances
70+
*
71+
* Related issues:
72+
* https://github.com/qos-ch/logback/issues/803
73+
* https://github.com/qos-ch/logback/issues/931
74+
* https://github.com/qos-ch/logback/issues/932
75+
*/
76+
putUnchecked(layout.getInstanceConverterMap(), converterName, converterSupplier);
77+
} else {
78+
throw new IncompatibleClassChangeError(
79+
"Unexpected return type found for PatternLayoutBase.getInstanceConverterMap(), logback-core dependency version is not compatible");
80+
}
81+
82+
} catch (NoSuchMethodException e) {
83+
throw new IncompatibleClassChangeError(
84+
"Method PatternLayoutBase.getInstanceConverterMap() not found, logback-core dependency version is not compatible");
85+
}
86+
}
87+
88+
@SuppressWarnings({"rawtypes", "unchecked"})
89+
private static void putUnchecked(Map map, String key, Object value) {
90+
map.put(key, value);
91+
}
92+
93+
}

0 commit comments

Comments
 (0)