This is an automated email from the ASF dual-hosted git repository. ramanathan1504 pushed a commit to branch json-template-layout-resolvers in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
commit e29ed4dec5d69543e0b647131d7938c3072db294 Author: Ramanathan <[email protected]> AuthorDate: Mon Jul 6 01:14:52 2026 +0530 Add W3C trace metadata resolvers for json template layout --- .../template/json/resolver/TraceResolverTest.java | 87 ++++++++++++++++++++++ .../log4j/layout/template/json/package-info.java | 2 +- .../{package-info.java => SpanIdResolver.java} | 41 ++++++++-- ...ackage-info.java => SpanIdResolverFactory.java} | 34 +++++++-- .../{package-info.java => TraceFlagsResolver.java} | 41 ++++++++-- .../json/resolver/TraceFlagsResolverFactory.java | 46 ++++++++++++ .../{package-info.java => TraceIdResolver.java} | 41 ++++++++-- ...ckage-info.java => TraceIdResolverFactory.java} | 34 +++++++-- .../template/json/resolver/package-info.java | 2 +- 9 files changed, 296 insertions(+), 32 deletions(-) diff --git a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/TraceResolverTest.java b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/TraceResolverTest.java new file mode 100644 index 0000000000..0de00e22d8 --- /dev/null +++ b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/resolver/TraceResolverTest.java @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.logging.log4j.layout.template.json.resolver; + +import static org.apache.logging.log4j.layout.template.json.TestHelpers.CONFIGURATION; +import static org.apache.logging.log4j.layout.template.json.TestHelpers.asMap; +import static org.apache.logging.log4j.layout.template.json.TestHelpers.usingSerializedLogEventAccessor; +import static org.apache.logging.log4j.layout.template.json.TestHelpers.writeJson; +import static org.assertj.core.api.Assertions.assertThat; + +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.impl.Log4jLogEvent; +import org.apache.logging.log4j.layout.template.json.JsonTemplateLayout; +import org.junit.jupiter.api.Test; + +class TraceResolverTest { + + @Test + void should_resolve_trace_metadata() { + + // Create the event template using JTL TestHelpers + final String eventTemplate = writeJson(asMap( + "traceId", asMap("$resolver", "traceId"), + "spanId", asMap("$resolver", "spanId"), + "traceFlags", asMap("$resolver", "traceFlags"))); + + // Create the layout + final JsonTemplateLayout layout = JsonTemplateLayout.newBuilder() + .setConfiguration(CONFIGURATION) + .setEventTemplate(eventTemplate) + .build(); + + // Create the log event with active tracing data + final LogEvent logEvent = Log4jLogEvent.newBuilder() + .setTraceId("4bf92f3577b34da6a3ce929d0e0e4736") + .setSpanId("00f067aa0ba902b7") + .setTraceFlags("01") + .build(); + + // Check the serialized event parses the JSON correctly + usingSerializedLogEventAccessor(layout, logEvent, accessor -> { + assertThat(accessor.getString("traceId")).isEqualTo("4bf92f3577b34da6a3ce929d0e0e4736"); + assertThat(accessor.getString("spanId")).isEqualTo("00f067aa0ba902b7"); + assertThat(accessor.getString("traceFlags")).isEqualTo("01"); + }); + } + + @Test + void should_resolve_empty_metadata_safely() { + + // Create the event template + final String eventTemplate = writeJson(asMap( + "traceId", asMap("$resolver", "traceId"), + "spanId", asMap("$resolver", "spanId"), + "traceFlags", asMap("$resolver", "traceFlags"))); + + // Create the layout + final JsonTemplateLayout layout = JsonTemplateLayout.newBuilder() + .setConfiguration(CONFIGURATION) + .setEventTemplate(eventTemplate) + .build(); + + // Create the log event with NO tracing data (simulating default behavior) + final LogEvent logEvent = Log4jLogEvent.newBuilder().build(); + + // Check the serialized event does not throw exceptions and handles missing fields safely + usingSerializedLogEventAccessor(layout, logEvent, accessor -> { + assertThat(accessor.getString("traceId")).isNullOrEmpty(); + assertThat(accessor.getString("spanId")).isNullOrEmpty(); + assertThat(accessor.getString("traceFlags")).isNullOrEmpty(); + }); + } +} diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/package-info.java b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/package-info.java index ab2e6c5b08..e60735571b 100644 --- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/package-info.java +++ b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/package-info.java @@ -16,7 +16,7 @@ */ @Export @Open("org.apache.logging.log4j.core") -@Version("2.21.0") +@Version("2.22.0") package org.apache.logging.log4j.layout.template.json; import aQute.bnd.annotation.jpms.Open; diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/package-info.java b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/SpanIdResolver.java similarity index 54% copy from log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/package-info.java copy to log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/SpanIdResolver.java index 376a67bd33..4325a44725 100644 --- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/package-info.java +++ b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/SpanIdResolver.java @@ -14,11 +14,40 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@Export -@Open("org.apache.logging.log4j.core") -@Version("2.21.0") package org.apache.logging.log4j.layout.template.json.resolver; -import aQute.bnd.annotation.jpms.Open; -import org.osgi.annotation.bundle.Export; -import org.osgi.annotation.versioning.Version; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.layout.template.json.util.JsonWriter; + +/** + * Resolves the W3C standard span ID. + * + * <h3>Examples</h3> + * + * Resolve the span ID: + * + * <pre> + * { + * "$resolver": "spanId" + * } + * </pre> + */ +public final class SpanIdResolver implements EventResolver { + + private static final SpanIdResolver INSTANCE = new SpanIdResolver(); + + SpanIdResolver() {} + + static SpanIdResolver getInstance() { + return INSTANCE; + } + + static String getName() { + return "spanId"; + } + + @Override + public void resolve(final LogEvent logEvent, final JsonWriter jsonWriter) { + jsonWriter.writeString(logEvent.getSpanId()); + } +} diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/package-info.java b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/SpanIdResolverFactory.java similarity index 50% copy from log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/package-info.java copy to log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/SpanIdResolverFactory.java index 376a67bd33..520452be52 100644 --- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/package-info.java +++ b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/SpanIdResolverFactory.java @@ -14,11 +14,33 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@Export -@Open("org.apache.logging.log4j.core") -@Version("2.21.0") package org.apache.logging.log4j.layout.template.json.resolver; -import aQute.bnd.annotation.jpms.Open; -import org.osgi.annotation.bundle.Export; -import org.osgi.annotation.versioning.Version; +import org.apache.logging.log4j.core.config.plugins.Plugin; +import org.apache.logging.log4j.core.config.plugins.PluginFactory; + +/** + * {@link SpanIdResolver} factory. + */ +@Plugin(name = "SpanIdResolverFactory", category = TemplateResolverFactory.CATEGORY) +public final class SpanIdResolverFactory implements EventResolverFactory { + + private static final SpanIdResolverFactory INSTANCE = new SpanIdResolverFactory(); + + private SpanIdResolverFactory() {} + + @PluginFactory + public static SpanIdResolverFactory getInstance() { + return INSTANCE; + } + + @Override + public String getName() { + return SpanIdResolver.getName(); + } + + @Override + public SpanIdResolver create(final EventResolverContext context, final TemplateResolverConfig config) { + return SpanIdResolver.getInstance(); + } +} diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/package-info.java b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/TraceFlagsResolver.java similarity index 53% copy from log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/package-info.java copy to log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/TraceFlagsResolver.java index 376a67bd33..23d46227d3 100644 --- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/package-info.java +++ b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/TraceFlagsResolver.java @@ -14,11 +14,40 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@Export -@Open("org.apache.logging.log4j.core") -@Version("2.21.0") package org.apache.logging.log4j.layout.template.json.resolver; -import aQute.bnd.annotation.jpms.Open; -import org.osgi.annotation.bundle.Export; -import org.osgi.annotation.versioning.Version; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.layout.template.json.util.JsonWriter; + +/** + * Resolves the W3C standard trace flags. + * + * <h3>Examples</h3> + * + * Resolve the trace flags: + * + * <pre> + * { + * "$resolver": "traceFlags" + * } + * </pre> + */ +public final class TraceFlagsResolver implements EventResolver { + + private static final TraceFlagsResolver INSTANCE = new TraceFlagsResolver(); + + TraceFlagsResolver() {} + + static TraceFlagsResolver getInstance() { + return INSTANCE; + } + + static String getName() { + return "traceFlags"; + } + + @Override + public void resolve(final LogEvent logEvent, final JsonWriter jsonWriter) { + jsonWriter.writeString(logEvent.getTraceFlags()); + } +} diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/TraceFlagsResolverFactory.java b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/TraceFlagsResolverFactory.java new file mode 100644 index 0000000000..29955b81d5 --- /dev/null +++ b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/TraceFlagsResolverFactory.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.logging.log4j.layout.template.json.resolver; + +import org.apache.logging.log4j.core.config.plugins.Plugin; +import org.apache.logging.log4j.core.config.plugins.PluginFactory; + +/** + * {@link TraceFlagsResolver} factory. + */ +@Plugin(name = "TraceFlagsResolverFactory", category = TemplateResolverFactory.CATEGORY) +public final class TraceFlagsResolverFactory implements EventResolverFactory { + + private static final TraceFlagsResolverFactory INSTANCE = new TraceFlagsResolverFactory(); + + private TraceFlagsResolverFactory() {} + + @PluginFactory + public static TraceFlagsResolverFactory getInstance() { + return INSTANCE; + } + + @Override + public String getName() { + return TraceFlagsResolver.getName(); + } + + @Override + public TraceFlagsResolver create(final EventResolverContext context, final TemplateResolverConfig config) { + return TraceFlagsResolver.getInstance(); + } +} diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/package-info.java b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/TraceIdResolver.java similarity index 54% copy from log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/package-info.java copy to log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/TraceIdResolver.java index 376a67bd33..894a253d37 100644 --- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/package-info.java +++ b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/TraceIdResolver.java @@ -14,11 +14,40 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@Export -@Open("org.apache.logging.log4j.core") -@Version("2.21.0") package org.apache.logging.log4j.layout.template.json.resolver; -import aQute.bnd.annotation.jpms.Open; -import org.osgi.annotation.bundle.Export; -import org.osgi.annotation.versioning.Version; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.layout.template.json.util.JsonWriter; + +/** + * Resolves the W3C standard trace ID. + * + * <h3>Examples</h3> + * + * Resolve the trace ID: + * + * <pre> + * { + * "$resolver": "traceId" + * } + * </pre> + */ +public final class TraceIdResolver implements EventResolver { + + private static final TraceIdResolver INSTANCE = new TraceIdResolver(); + + TraceIdResolver() {} + + static TraceIdResolver getInstance() { + return INSTANCE; + } + + static String getName() { + return "traceId"; + } + + @Override + public void resolve(final LogEvent logEvent, final JsonWriter jsonWriter) { + jsonWriter.writeString(logEvent.getTraceId()); + } +} diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/package-info.java b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/TraceIdResolverFactory.java similarity index 50% copy from log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/package-info.java copy to log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/TraceIdResolverFactory.java index 376a67bd33..1ba0951781 100644 --- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/package-info.java +++ b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/TraceIdResolverFactory.java @@ -14,11 +14,33 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@Export -@Open("org.apache.logging.log4j.core") -@Version("2.21.0") package org.apache.logging.log4j.layout.template.json.resolver; -import aQute.bnd.annotation.jpms.Open; -import org.osgi.annotation.bundle.Export; -import org.osgi.annotation.versioning.Version; +import org.apache.logging.log4j.core.config.plugins.Plugin; +import org.apache.logging.log4j.core.config.plugins.PluginFactory; + +/** + * {@link TraceIdResolver} factory. + */ +@Plugin(name = "TraceIdResolverFactory", category = TemplateResolverFactory.CATEGORY) +public final class TraceIdResolverFactory implements EventResolverFactory { + + private static final TraceIdResolverFactory INSTANCE = new TraceIdResolverFactory(); + + private TraceIdResolverFactory() {} + + @PluginFactory + public static TraceIdResolverFactory getInstance() { + return INSTANCE; + } + + @Override + public String getName() { + return TraceIdResolver.getName(); + } + + @Override + public TraceIdResolver create(final EventResolverContext context, final TemplateResolverConfig config) { + return TraceIdResolver.getInstance(); + } +} diff --git a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/package-info.java b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/package-info.java index 376a67bd33..3b704adbc0 100644 --- a/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/package-info.java +++ b/log4j-layout-template-json/src/main/java/org/apache/logging/log4j/layout/template/json/resolver/package-info.java @@ -16,7 +16,7 @@ */ @Export @Open("org.apache.logging.log4j.core") -@Version("2.21.0") +@Version("2.22.0") package org.apache.logging.log4j.layout.template.json.resolver; import aQute.bnd.annotation.jpms.Open;
