Skip to content

Commit ef9dea9

Browse files
authored
Support parents in MarkerResolver (#1381)
1 parent 9e1a437 commit ef9dea9

File tree

4 files changed

+184
-10
lines changed

4 files changed

+184
-10
lines changed

log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/TestHelpers.java

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@
1616
*/
1717
package org.apache.logging.log4j.layout.template.json;
1818

19+
import java.util.LinkedHashMap;
20+
import java.util.Map;
21+
import java.util.function.BiConsumer;
22+
import java.util.function.Consumer;
23+
1924
import org.apache.logging.log4j.Level;
2025
import org.apache.logging.log4j.core.Layout;
2126
import org.apache.logging.log4j.core.LogEvent;
@@ -31,11 +36,6 @@
3136
import org.apache.logging.log4j.layout.template.json.util.JsonWriter;
3237
import org.apache.logging.log4j.layout.template.json.util.MapAccessor;
3338

34-
import java.util.LinkedHashMap;
35-
import java.util.Map;
36-
import java.util.function.BiConsumer;
37-
import java.util.function.Consumer;
38-
3939
public final class TestHelpers {
4040

4141
public static final Configuration CONFIGURATION = new DefaultConfiguration();
@@ -74,11 +74,18 @@ public static void usingSerializedLogEventAccessor(
7474
final LogEvent logEvent,
7575
final Consumer<MapAccessor> accessorConsumer) {
7676
final String serializedLogEventJson = layout.toSerializable(logEvent);
77-
@SuppressWarnings("unchecked")
78-
final Map<String, Object> deserializedLogEvent =
79-
(Map<String, Object>) readJson(serializedLogEventJson);
80-
final MapAccessor serializedLogEventAccessor = new MapAccessor(deserializedLogEvent);
81-
accessorConsumer.accept(serializedLogEventAccessor);
77+
78+
try {
79+
@SuppressWarnings("unchecked")
80+
final Map<String, Object> deserializedLogEvent =
81+
(Map<String, Object>) readJson(serializedLogEventJson);
82+
83+
final MapAccessor serializedLogEventAccessor = new MapAccessor(deserializedLogEvent);
84+
accessorConsumer.accept(serializedLogEventAccessor);
85+
} catch (Exception e) {
86+
throw new RuntimeException("failed to deserialize log event (" + e
87+
+ "). Serialized Log Event:\n" + serializedLogEventJson);
88+
}
8289
}
8390

8491
public static Object readJson(final String json) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache license, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the license for the specific language governing permissions and
15+
* limitations under the license.
16+
*/
17+
package org.apache.logging.log4j.layout.template.json.resolver;
18+
19+
import java.util.Arrays;
20+
21+
import org.apache.logging.log4j.Marker;
22+
import org.apache.logging.log4j.MarkerManager;
23+
import org.apache.logging.log4j.core.LogEvent;
24+
import org.apache.logging.log4j.core.impl.Log4jLogEvent;
25+
import org.apache.logging.log4j.layout.template.json.JsonTemplateLayout;
26+
import org.junit.jupiter.api.Test;
27+
28+
import static org.apache.logging.log4j.layout.template.json.TestHelpers.*;
29+
import static org.assertj.core.api.Assertions.assertThat;
30+
31+
class MarkerResolverTest {
32+
33+
@Test
34+
void should_have_a_marker_name() {
35+
final String eventTemplate = writeJson(asMap(
36+
"marker",
37+
asMap(
38+
"$resolver", "marker",
39+
"field", "name"
40+
)
41+
));
42+
43+
// Create the layout.
44+
final JsonTemplateLayout layout = JsonTemplateLayout
45+
.newBuilder()
46+
.setConfiguration(CONFIGURATION)
47+
.setEventTemplate(eventTemplate)
48+
.build();
49+
50+
// Create the log event.
51+
final Marker marker = MarkerManager.getMarker("MARKER");
52+
final LogEvent logEvent = Log4jLogEvent
53+
.newBuilder()
54+
.setMarker(marker)
55+
.build();
56+
57+
// Check the serialized event.
58+
usingSerializedLogEventAccessor(layout, logEvent, accessor -> {
59+
assertThat(accessor.getString("marker")).isEqualTo("MARKER");
60+
});
61+
}
62+
63+
@Test
64+
void should_list_parents_as_array() {
65+
final String eventTemplate = writeJson(asMap(
66+
"parents",
67+
asMap(
68+
"$resolver", "marker",
69+
"field", "parents"
70+
)
71+
));
72+
73+
// Create the layout.
74+
final JsonTemplateLayout layout = JsonTemplateLayout
75+
.newBuilder()
76+
.setConfiguration(CONFIGURATION)
77+
.setEventTemplate(eventTemplate)
78+
.build();
79+
80+
// Create the log event.
81+
final Marker PARENT_MARKER_1 = MarkerManager.getMarker("PARENT_MARKER_NAME_1");
82+
final Marker PARENT_MARKER_2 = MarkerManager.getMarker("PARENT_MARKER_NAME_2");
83+
final Marker CHILD_MARKER = MarkerManager.getMarker("CHILD_MARKER_NAME");
84+
CHILD_MARKER.setParents(PARENT_MARKER_1, PARENT_MARKER_2);
85+
86+
final LogEvent logEvent = Log4jLogEvent
87+
.newBuilder()
88+
.setMarker(CHILD_MARKER)
89+
.build();
90+
91+
// Check the serialized event.
92+
usingSerializedLogEventAccessor(layout, logEvent, accessor -> {
93+
assertThat(accessor.getList("parents", String.class)).hasSize(2);
94+
assertThat(accessor.getList("parents", String.class)).containsAll(
95+
Arrays.asList(
96+
"PARENT_MARKER_NAME_1",
97+
"PARENT_MARKER_NAME_2"
98+
)
99+
);
100+
});
101+
}
102+
103+
}

log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/MarkerResolver.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
*
2828
* <pre>
2929
* config = "field" -> "name"
30+
* config = "field" -> "parents"
3031
* </pre>
3132
*
3233
* <h3>Examples</h3>
@@ -39,6 +40,15 @@
3940
* "field": "name"
4041
* }
4142
* </pre>
43+
*
44+
* Resolve the marker's parents names:
45+
*
46+
* <pre>
47+
* {
48+
* "$resolver": "marker",
49+
* "field": "parents"
50+
* }
51+
* </pre>
4252
*/
4353
public final class MarkerResolver implements EventResolver {
4454

@@ -52,6 +62,27 @@ public final class MarkerResolver implements EventResolver {
5262
}
5363
};
5464

65+
private static final TemplateResolver<LogEvent> PARENTS_RESOLVER =
66+
(final LogEvent logEvent, final JsonWriter jsonWriter) -> {
67+
final Marker marker = logEvent.getMarker();
68+
if (marker == null || !marker.hasParents()) {
69+
jsonWriter.writeNull();
70+
return;
71+
}
72+
73+
final Marker[] parents = marker.getParents();
74+
75+
jsonWriter.writeArrayStart();
76+
for (int i = 0; i < parents.length; i++) {
77+
if (i > 0) {
78+
jsonWriter.writeSeparator();
79+
}
80+
final Marker parentMarker = parents[i];
81+
jsonWriter.writeString(parentMarker.getName());
82+
}
83+
jsonWriter.writeArrayEnd();
84+
};
85+
5586
private final TemplateResolver<LogEvent> internalResolver;
5687

5788
MarkerResolver(final TemplateResolverConfig config) {
@@ -61,9 +92,15 @@ public final class MarkerResolver implements EventResolver {
6192
private TemplateResolver<LogEvent> createInternalResolver(
6293
final TemplateResolverConfig config) {
6394
final String fieldName = config.getString("field");
95+
6496
if ("name".equals(fieldName)) {
6597
return NAME_RESOLVER;
6698
}
99+
100+
if ("parents".equals(fieldName)) {
101+
return PARENTS_RESOLVER;
102+
}
103+
67104
throw new IllegalArgumentException("unknown field: " + config);
68105
}
69106

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
Licensed to the Apache Software Foundation (ASF) under one or more
4+
contributor license agreements. See the NOTICE file distributed with
5+
this work for additional information regarding copyright ownership.
6+
The ASF licenses this file to You under the Apache License, Version 2.0
7+
(the "License"); you may not use this file except in compliance with
8+
the License. You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing, software
13+
distributed under the License is distributed on an "AS IS" BASIS,
14+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
See the License for the specific language governing permissions and
16+
limitations under the License.
17+
-->
18+
<entry xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
19+
xmlns="http://logging.apache.org/log4j/changelog"
20+
xsi:schemaLocation="http://logging.apache.org/log4j/changelog https://logging.apache.org/log4j/changelog-0.1.1.xsd"
21+
type="changed">
22+
<author id="eherot"/>
23+
<description format="asciidoc">
24+
PatternLayout can display the marker's parents with `%marker`.
25+
This will add that same capability to JSON Template Layout
26+
</description>
27+
</entry>

0 commit comments

Comments
 (0)