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;

Reply via email to