You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by ra...@apache.org on 2026/07/04 13:23:24 UTC
(logging-log4j2) 01/05: Add tracing fields to RingBufferLogEvent and related classes
This is an automated email from the ASF dual-hosted git repository.
ramanathan1504 pushed a commit to branch fix-trace-metadata-1976
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
commit e70ac38d43350ebcc63fd5374b3fa669899f32e2
Author: Ramanathan <ra...@gmail.com>
AuthorDate: Thu Jul 2 15:09:13 2026 +0530
Add tracing fields to RingBufferLogEvent and related classes
---
.../logging/log4j/spi/TraceContextProvider.java | 41 ++++++
.../org/apache/logging/log4j/spi/package-info.java | 2 +-
.../log4j/core/async/RingBufferLogEventTest.java | 45 ++++++
.../logging/log4j/core/impl/Log4jLogEventTest.java | 149 ++++++++++++++++++++
.../log4j/core/impl/MutableLogEventTest.java | 29 ++++
.../org/apache/logging/log4j/core/LogEvent.java | 20 +++
.../log4j/core/async/RingBufferLogEvent.java | 71 +++++++++-
.../core/async/RingBufferLogEventTranslator.java | 54 +++++++-
.../logging/log4j/core/async/package-info.java | 2 +-
.../logging/log4j/core/impl/Log4jLogEvent.java | 153 +++++++++++++++++++--
.../logging/log4j/core/impl/MutableLogEvent.java | 47 ++++++-
.../logging/log4j/core/impl/package-info.java | 2 +-
.../apache/logging/log4j/core/package-info.java | 2 +-
.../core/util/TraceContextProviderService.java | 72 ++++++++++
.../logging/log4j/core/util/package-info.java | 2 +-
.../log4j/perf/jmh/AsyncTraceContextBenchmark.java | 133 ++++++++++++++++++
16 files changed, 799 insertions(+), 25 deletions(-)
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/TraceContextProvider.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/TraceContextProvider.java
new file mode 100644
index 0000000000..3c1ef5b8c1
--- /dev/null
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/TraceContextProvider.java
@@ -0,0 +1,41 @@
+/*
+ * 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.spi;
+
+/**
+ * Service Provider Interface (SPI) for retrieving standard W3C tracing metadata from the active context.
+ * Placed in the API module to allow third-party providers to compile against it with minimal dependencies.
+ *
+ * @since 2.27.0
+ */
+public interface TraceContextProvider {
+
+ /**
+ * Returns the standard trace ID from the active context, or {@code null}.
+ */
+ String getTraceId();
+
+ /**
+ * Returns the standard span ID from the active context, or {@code null}.
+ */
+ String getSpanId();
+
+ /**
+ * Returns the standard trace flags from the active context, or {@code null}.
+ */
+ String getTraceFlags();
+}
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/package-info.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/package-info.java
index 3b6b5c2585..0956aad003 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/package-info.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/package-info.java
@@ -19,7 +19,7 @@
* API classes.
*/
@Export
-@Version("2.25.0")
+@Version("2.26.0")
package org.apache.logging.log4j.spi;
import org.osgi.annotation.bundle.Export;
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java
index 5377040565..26044686fe 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java
@@ -16,10 +16,12 @@
*/
package org.apache.logging.log4j.core.async;
+import static org.apache.logging.log4j.core.util.ClockFactory.getClock;
import static org.assertj.core.api.Assertions.as;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
import static org.assertj.core.api.Assertions.fail;
+import static org.junit.jupiter.api.Assertions.assertNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -31,6 +33,7 @@ import org.apache.logging.log4j.MarkerManager;
import org.apache.logging.log4j.ThreadContext;
import org.apache.logging.log4j.ThreadContext.ContextStack;
import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.impl.ContextDataFactory;
import org.apache.logging.log4j.core.impl.ThrowableProxy;
import org.apache.logging.log4j.core.time.internal.FixedPreciseClock;
import org.apache.logging.log4j.core.util.Clock;
@@ -468,4 +471,46 @@ class RingBufferLogEventTest {
// Verify interaction exhaustion
verifyNoMoreInteractions(asyncLogger, message, throwable, contextData, contextStack);
}
+
+ @Test
+ void testRingBufferLogEventTracingFieldsAndClear() {
+ final RingBufferLogEvent event = new RingBufferLogEvent();
+
+ // 1. Check initial state
+ assertThat(event.getTraceId()).isNull();
+ assertThat(event.getSpanId()).isNull();
+ assertThat(event.getTraceFlags()).isNull();
+
+ // 2. Initialize with trace fields inside 18-parameter setValues
+ event.setValues(
+ null,
+ "TestLogger",
+ null,
+ "FQCN",
+ Level.INFO,
+ new SimpleMessage("msg"),
+ null,
+ ContextDataFactory.createContextData(),
+ ThreadContext.EMPTY_STACK,
+ 123L,
+ "thread-name",
+ 5,
+ null,
+ getClock(),
+ new DummyNanoClock(),
+ "trace-id-ringbuffer",
+ "span-id-ringbuffer",
+ "01");
+
+ // 3. Assert values are retrievable
+ assertThat(event.getTraceId()).isEqualTo("trace-id-ringbuffer");
+ assertThat(event.getSpanId()).isEqualTo("span-id-ringbuffer");
+ assertThat(event.getTraceFlags()).isEqualTo("01");
+
+ // 4. Verify clearing wipes tracing state to avoid leakage on slot reuse
+ event.clear();
+ assertNull(event.getTraceId());
+ assertNull(event.getSpanId());
+ assertNull(event.getTraceFlags());
+ }
}
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventTest.java
index bc90e594d2..ce7cf8d769 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventTest.java
@@ -18,6 +18,7 @@ package org.apache.logging.log4j.core.impl;
import static org.apache.logging.log4j.test.junit.SerialUtil.deserialize;
import static org.apache.logging.log4j.test.junit.SerialUtil.serialize;
+import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
@@ -29,6 +30,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.lang.reflect.Field;
+import java.util.Map;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.MarkerManager;
@@ -36,6 +38,8 @@ import org.apache.logging.log4j.ThreadContext;
import org.apache.logging.log4j.ThreadContext.ContextStack;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.config.plugins.convert.Base64Converter;
+import org.apache.logging.log4j.core.time.Instant;
+import org.apache.logging.log4j.core.time.MutableInstant;
import org.apache.logging.log4j.core.util.Clock;
import org.apache.logging.log4j.core.util.ClockFactory;
import org.apache.logging.log4j.core.util.ClockFactoryTest;
@@ -45,6 +49,7 @@ import org.apache.logging.log4j.message.ObjectMessage;
import org.apache.logging.log4j.message.ReusableMessage;
import org.apache.logging.log4j.message.ReusableObjectMessage;
import org.apache.logging.log4j.message.SimpleMessage;
+import org.apache.logging.log4j.util.ReadOnlyStringMap;
import org.apache.logging.log4j.util.SortedArrayStringMap;
import org.apache.logging.log4j.util.StringMap;
import org.apache.logging.log4j.util.Strings;
@@ -541,4 +546,148 @@ public class Log4jLogEventTest {
// Throws an NPE in 2.6.2
assertNotNull(new Log4jLogEvent().toString());
}
+
+ @Test
+ public void testCustomLegacyLogEventDefaultBehavior() {
+ // Create an anonymous/stub class implementing LogEvent without implementing getTraceId/getSpanId/getTraceFlags
+ final LogEvent legacyEvent = new LogEvent() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public LogEvent toImmutable() {
+ return this;
+ }
+
+ @Override
+ @Deprecated
+ public Map<String, String> getContextMap() {
+ return java.util.Collections.emptyMap();
+ }
+
+ @Override
+ public ReadOnlyStringMap getContextData() {
+ return ContextDataFactory.emptyFrozenContextData();
+ }
+
+ @Override
+ public ThreadContext.ContextStack getContextStack() {
+ return ThreadContext.EMPTY_STACK;
+ }
+
+ @Override
+ public String getLoggerFqcn() {
+ return null;
+ }
+
+ @Override
+ public Level getLevel() {
+ return Level.INFO;
+ }
+
+ @Override
+ public String getLoggerName() {
+ return "LegacyLogger";
+ }
+
+ @Override
+ public Marker getMarker() {
+ return null;
+ }
+
+ @Override
+ public Message getMessage() {
+ return new SimpleMessage("Legacy msg");
+ }
+
+ @Override
+ public long getTimeMillis() {
+ return 0;
+ }
+
+ @Override
+ public Instant getInstant() {
+ return new MutableInstant();
+ }
+
+ @Override
+ public StackTraceElement getSource() {
+ return null;
+ }
+
+ @Override
+ public String getThreadName() {
+ return "main";
+ }
+
+ @Override
+ public long getThreadId() {
+ return 1;
+ }
+
+ @Override
+ public int getThreadPriority() {
+ return 5;
+ }
+
+ @Override
+ public Throwable getThrown() {
+ return null;
+ }
+
+ @Override
+ @Deprecated
+ public ThrowableProxy getThrownProxy() {
+ return null;
+ }
+
+ @Override
+ public boolean isEndOfBatch() {
+ return false;
+ }
+
+ @Override
+ public boolean isIncludeLocation() {
+ return false;
+ }
+
+ @Override
+ public void setEndOfBatch(boolean endOfBatch) {}
+
+ @Override
+ public void setIncludeLocation(boolean locationRequired) {}
+
+ @Override
+ public long getNanoTime() {
+ return 0;
+ }
+ };
+
+ // Assert Java 8 default method fallbacks return null without throwing abstract method exceptions
+ assertNull(legacyEvent.getTraceId());
+ assertNull(legacyEvent.getSpanId());
+ assertNull(legacyEvent.getTraceFlags());
+ }
+
+ @Test
+ void testTracingFieldsInBuilderAndCopy() {
+ final Log4jLogEvent originalEvent = Log4jLogEvent.newBuilder()
+ .setLoggerName("TestLogger")
+ .setLevel(Level.DEBUG)
+ .setMessage(new org.apache.logging.log4j.message.SimpleMessage("Test message"))
+ .setTraceId("4bf92f3577b34da6a3ce929d0e0e4736")
+ .setSpanId("00f067aa0ba902b7")
+ .setTraceFlags("01")
+ .build();
+
+ // 1. Verify getters on original
+ assertThat(originalEvent.getTraceId()).isEqualTo("4bf92f3577b34da6a3ce929d0e0e4736");
+ assertThat(originalEvent.getSpanId()).isEqualTo("00f067aa0ba902b7");
+ assertThat(originalEvent.getTraceFlags()).isEqualTo("01");
+
+ // 2. Verify Builder Copy Constructor
+ final Log4jLogEvent copiedEvent = new Log4jLogEvent.Builder(originalEvent).build();
+ assertThat(copiedEvent.getTraceId()).isEqualTo("4bf92f3577b34da6a3ce929d0e0e4736");
+ assertThat(copiedEvent.getSpanId()).isEqualTo("00f067aa0ba902b7");
+ assertThat(copiedEvent.getTraceFlags()).isEqualTo("01");
+ }
}
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/MutableLogEventTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/MutableLogEventTest.java
index 092c2133e2..87c032fa71 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/MutableLogEventTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/MutableLogEventTest.java
@@ -366,4 +366,33 @@ class MutableLogEventTest {
final Log4jLogEvent immutable = mutable.toImmutable();
assertThat(immutable.getSource()).isEqualTo(source);
}
+
+ @Test
+ void testMutableLogEventTracingFieldsPropagationAndClear() {
+ final Log4jLogEvent sourceEvent = Log4jLogEvent.newBuilder()
+ .setLoggerName("SourceLogger")
+ .setTraceId("trace-xyz-123")
+ .setSpanId("span-abc-456")
+ .setTraceFlags("01")
+ .build();
+
+ final MutableLogEvent mutableEvent = new MutableLogEvent();
+
+ // 1. Initially empty
+ assertThat(mutableEvent.getTraceId()).isNull();
+ assertThat(mutableEvent.getSpanId()).isNull();
+ assertThat(mutableEvent.getTraceFlags()).isNull();
+
+ // 2. Verify propagation via initFrom
+ mutableEvent.initFrom(sourceEvent);
+ assertThat(mutableEvent.getTraceId()).isEqualTo("trace-xyz-123");
+ assertThat(mutableEvent.getSpanId()).isEqualTo("span-abc-456");
+ assertThat(mutableEvent.getTraceFlags()).isEqualTo("01");
+
+ // 3. Verify clearing removes tracking state to prevent leakage on pool reuse
+ mutableEvent.clear();
+ assertThat(mutableEvent.getTraceId()).isNull();
+ assertThat(mutableEvent.getSpanId()).isNull();
+ assertThat(mutableEvent.getTraceFlags()).isNull();
+ }
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/LogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/LogEvent.java
index 63daa9d3bb..50d947ed34 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/LogEvent.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/LogEvent.java
@@ -241,4 +241,24 @@ public interface LogEvent extends Serializable {
* @since Log4J 2.4
*/
long getNanoTime();
+ /**
+ * Returns the standard Trace ID.
+ */
+ default String getTraceId() {
+ return null;
+ }
+
+ /**
+ * Returns the standard Span ID.
+ */
+ default String getSpanId() {
+ return null;
+ }
+
+ /**
+ * Returns the standard Trace Flags.
+ */
+ default String getTraceFlags() {
+ return null;
+ }
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java
index 2afb007387..8a46be100e 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java
@@ -91,6 +91,9 @@ public class RingBufferLogEvent implements LogEvent, ReusableMessage, CharSequen
private String fqcn;
private StackTraceElement location;
private ContextStack contextStack;
+ private String traceId;
+ private String spanId;
+ private String traceFlags;
private transient AsyncLogger asyncLogger;
@@ -109,7 +112,10 @@ public class RingBufferLogEvent implements LogEvent, ReusableMessage, CharSequen
final int threadPriority,
final StackTraceElement aLocation,
final Clock clock,
- final NanoClock nanoClock) {
+ final NanoClock nanoClock,
+ final String traceId,
+ final String spanId,
+ final String traceFlags) {
this.threadPriority = threadPriority;
this.threadId = threadId;
this.level = aLevel;
@@ -125,9 +131,50 @@ public class RingBufferLogEvent implements LogEvent, ReusableMessage, CharSequen
this.contextData = mutableContextData;
this.contextStack = aContextStack;
this.asyncLogger = anAsyncLogger;
+ this.traceId = traceId;
+ this.spanId = spanId;
+ this.traceFlags = traceFlags;
this.populated = true;
}
+ public void setValues(
+ final AsyncLogger anAsyncLogger,
+ final String aLoggerName,
+ final Marker aMarker,
+ final String theFqcn,
+ final Level aLevel,
+ final Message msg,
+ final Throwable aThrowable,
+ final StringMap mutableContextData,
+ final ContextStack aContextStack,
+ final long threadId,
+ final String threadName,
+ final int threadPriority,
+ final StackTraceElement aLocation,
+ final Clock clock,
+ final NanoClock nanoClock) {
+ setValues(
+ anAsyncLogger,
+ aLoggerName,
+ aMarker,
+ theFqcn,
+ aLevel,
+ msg,
+ aThrowable,
+ mutableContextData,
+ aContextStack,
+ threadId,
+ threadName,
+ threadPriority,
+ aLocation,
+ clock,
+ nanoClock,
+ null, // traceId default
+ null, // spanId default
+ null // traceFlags default
+ );
+ }
+
private void initTime(final Clock clock) {
if (message instanceof TimestampMessage) {
instant.initFromEpochMilli(((TimestampMessage) message).getTimestamp(), 0);
@@ -399,6 +446,21 @@ public class RingBufferLogEvent implements LogEvent, ReusableMessage, CharSequen
return nanoTime;
}
+ @Override
+ public String getTraceId() {
+ return traceId;
+ }
+
+ @Override
+ public String getSpanId() {
+ return spanId;
+ }
+
+ @Override
+ public String getTraceFlags() {
+ return traceFlags;
+ }
+
/**
* Release references held by ring buffer to allow objects to be garbage-collected.
*/
@@ -415,6 +477,9 @@ public class RingBufferLogEvent implements LogEvent, ReusableMessage, CharSequen
this.location = null;
this.contextStack = null;
this.asyncLogger = null;
+ this.traceId = null;
+ this.spanId = null;
+ this.traceFlags = null;
}
private void clearMessage() {
@@ -499,6 +564,8 @@ public class RingBufferLogEvent implements LogEvent, ReusableMessage, CharSequen
.setThreadPriority(threadPriority) //
.setThrown(getThrown()) // may deserialize from thrownProxy
.setInstant(instant) //
- ;
+ .setTraceId(traceId)
+ .setSpanId(spanId)
+ .setTraceFlags(traceFlags);
}
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEventTranslator.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEventTranslator.java
index f6fee9fcf5..b694c9e013 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEventTranslator.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEventTranslator.java
@@ -24,7 +24,9 @@ import org.apache.logging.log4j.core.ContextDataInjector;
import org.apache.logging.log4j.core.impl.ContextDataInjectorFactory;
import org.apache.logging.log4j.core.util.Clock;
import org.apache.logging.log4j.core.util.NanoClock;
+import org.apache.logging.log4j.core.util.TraceContextProviderService;
import org.apache.logging.log4j.message.Message;
+import org.apache.logging.log4j.spi.TraceContextProvider;
import org.apache.logging.log4j.util.ReadOnlyStringMap;
import org.apache.logging.log4j.util.StringMap;
@@ -51,6 +53,9 @@ public class RingBufferLogEventTranslator implements EventTranslator<RingBufferL
private StackTraceElement location;
private Clock clock;
private NanoClock nanoClock;
+ private String traceId;
+ private String spanId;
+ private String traceFlags;
// Due to the usage pattern of this class, these are effectively final
private long threadId = Thread.currentThread().getId();
@@ -79,7 +84,10 @@ public class RingBufferLogEventTranslator implements EventTranslator<RingBufferL
threadPriority,
location,
clock,
- nanoClock);
+ nanoClock,
+ traceId,
+ spanId,
+ traceFlags);
} finally {
clear(); // clear the translator
}
@@ -100,7 +108,10 @@ public class RingBufferLogEventTranslator implements EventTranslator<RingBufferL
null, // contextStack
null, // location
null, // clock
- null // nanoClock
+ null, // nanoClock
+ null, // traceId
+ null, // spanId
+ null // traceFlags
);
}
@@ -115,7 +126,10 @@ public class RingBufferLogEventTranslator implements EventTranslator<RingBufferL
final ContextStack aContextStack,
final StackTraceElement aLocation,
final Clock aClock,
- final NanoClock aNanoClock) {
+ final NanoClock aNanoClock,
+ final String traceId,
+ final String spanId,
+ final String traceFlags) {
this.asyncLogger = anAsyncLogger;
this.loggerName = aLoggerName;
this.marker = aMarker;
@@ -127,8 +141,42 @@ public class RingBufferLogEventTranslator implements EventTranslator<RingBufferL
this.location = aLocation;
this.clock = aClock;
this.nanoClock = aNanoClock;
+ this.traceId = traceId;
+ this.spanId = spanId;
+ this.traceFlags = traceFlags;
}
+ public void setBasicValues(
+ final AsyncLogger anAsyncLogger,
+ final String aLoggerName,
+ final Marker aMarker,
+ final String theFqcn,
+ final Level aLevel,
+ final Message msg,
+ final Throwable aThrowable,
+ final ContextStack aContextStack,
+ final StackTraceElement aLocation,
+ final Clock aClock,
+ final NanoClock aNanoClock) {
+
+ final TraceContextProvider provider = TraceContextProviderService.getActiveProvider();
+
+ setBasicValues(
+ anAsyncLogger,
+ aLoggerName,
+ aMarker,
+ theFqcn,
+ aLevel,
+ msg,
+ aThrowable,
+ aContextStack,
+ aLocation,
+ aClock,
+ aNanoClock,
+ provider.getTraceId(),
+ provider.getSpanId(),
+ provider.getTraceFlags());
+ }
/**
* @deprecated since 2.25.0. {@link RingBufferLogEventTranslator} instances should only be used on the thread that
* created it.
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/package-info.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/package-info.java
index 24e9b7643f..e8e8a9189d 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/package-info.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/package-info.java
@@ -18,7 +18,7 @@
* Provides Asynchronous Logger classes and interfaces for low-latency logging.
*/
@Export
-@Version("2.26.0")
+@Version("2.27.0")
package org.apache.logging.log4j.core.async;
import org.osgi.annotation.bundle.Export;
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java
index 471b1cd5be..b7b99bd60e 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java
@@ -38,11 +38,13 @@ import org.apache.logging.log4j.core.util.Clock;
import org.apache.logging.log4j.core.util.ClockFactory;
import org.apache.logging.log4j.core.util.DummyNanoClock;
import org.apache.logging.log4j.core.util.NanoClock;
+import org.apache.logging.log4j.core.util.TraceContextProviderService;
import org.apache.logging.log4j.message.LoggerNameAwareMessage;
import org.apache.logging.log4j.message.Message;
import org.apache.logging.log4j.message.ReusableMessage;
import org.apache.logging.log4j.message.SimpleMessage;
import org.apache.logging.log4j.message.TimestampMessage;
+import org.apache.logging.log4j.spi.TraceContextProvider;
import org.apache.logging.log4j.status.StatusLogger;
import org.apache.logging.log4j.util.ReadOnlyStringMap;
import org.apache.logging.log4j.util.StackLocatorUtil;
@@ -94,6 +96,10 @@ public class Log4jLogEvent implements LogEvent {
// 5. Deprecated fields, only used for serialization
private ThrowableProxy thrownProxy;
+ // 6. Tracing fields
+ private final String traceId;
+ private final String spanId;
+ private final String traceFlags;
/** LogEvent Builder helper class. */
public static class Builder implements org.apache.logging.log4j.core.util.Builder<LogEvent> {
@@ -123,9 +129,28 @@ public class Log4jLogEvent implements LogEvent {
private StringMap contextData;
private ThreadContext.ContextStack contextStack;
+ private String traceId = Strings.EMPTY;
+ private String spanId = Strings.EMPTY;
+ private String traceFlags = Strings.EMPTY;
+
public Builder() {
this.contextData = createContextData((List<Property>) null);
this.contextStack = ThreadContext.getImmutableStack();
+
+ final TraceContextProvider provider = TraceContextProviderService.getActiveProvider();
+
+ final String tId = provider.getTraceId();
+ if (tId != null) {
+ this.traceId = tId;
+ }
+ final String sId = provider.getSpanId();
+ if (sId != null) {
+ this.spanId = sId;
+ }
+ final String flags = provider.getTraceFlags();
+ if (flags != null) {
+ this.traceFlags = flags;
+ }
}
/**
@@ -159,6 +184,10 @@ public class Log4jLogEvent implements LogEvent {
// but since we are copying the event, we want to call it.
this.source = other.getSource();
+ this.traceId = other.getTraceId();
+ this.spanId = other.getSpanId();
+ this.traceFlags = other.getTraceFlags();
+
Message message = other.getMessage();
this.message = message instanceof ReusableMessage
? ((ReusableMessage) message).memento()
@@ -175,6 +204,21 @@ public class Log4jLogEvent implements LogEvent {
this.contextStack = other.getContextStack();
}
+ public Builder setTraceId(String traceId) {
+ this.traceId = traceId;
+ return this;
+ }
+
+ public Builder setSpanId(String spanId) {
+ this.spanId = spanId;
+ return this;
+ }
+
+ public Builder setTraceFlags(String traceFlags) {
+ this.traceFlags = traceFlags;
+ return this;
+ }
+
public Builder setLevel(final Level level) {
this.level = level;
return this;
@@ -303,7 +347,10 @@ public class Log4jLogEvent implements LogEvent {
source,
instant.getEpochMillisecond(),
instant.getNanoOfMillisecond(),
- nanoTime);
+ nanoTime,
+ traceId,
+ spanId,
+ traceFlags);
result.setIncludeLocation(includeLocation);
result.setEndOfBatch(endOfBatch);
return result;
@@ -339,7 +386,10 @@ public class Log4jLogEvent implements LogEvent {
0,
null,
CLOCK,
- nanoClock.nanoTime());
+ nanoClock.nanoTime(),
+ Strings.EMPTY,
+ Strings.EMPTY,
+ Strings.EMPTY);
}
/**
@@ -363,7 +413,10 @@ public class Log4jLogEvent implements LogEvent {
null,
timestamp,
0,
- nanoClock.nanoTime());
+ nanoClock.nanoTime(),
+ Strings.EMPTY,
+ Strings.EMPTY,
+ Strings.EMPTY);
}
/**
@@ -420,7 +473,10 @@ public class Log4jLogEvent implements LogEvent {
0, // thread priority
null, // StackTraceElement source
CLOCK, //
- nanoClock.nanoTime());
+ nanoClock.nanoTime(),
+ Strings.EMPTY,
+ Strings.EMPTY,
+ Strings.EMPTY);
}
/**
@@ -457,7 +513,10 @@ public class Log4jLogEvent implements LogEvent {
0, // thread priority
source, // StackTraceElement source
CLOCK, //
- nanoClock.nanoTime());
+ nanoClock.nanoTime(),
+ Strings.EMPTY,
+ Strings.EMPTY,
+ Strings.EMPTY);
}
/**
@@ -503,7 +562,10 @@ public class Log4jLogEvent implements LogEvent {
location,
timestampMillis,
0,
- nanoClock.nanoTime());
+ nanoClock.nanoTime(),
+ Strings.EMPTY,
+ Strings.EMPTY,
+ Strings.EMPTY);
}
/**
@@ -552,7 +614,10 @@ public class Log4jLogEvent implements LogEvent {
location,
timestamp,
0,
- nanoClock.nanoTime());
+ nanoClock.nanoTime(),
+ Strings.EMPTY,
+ Strings.EMPTY,
+ Strings.EMPTY);
return result;
}
@@ -590,7 +655,10 @@ public class Log4jLogEvent implements LogEvent {
final StackTraceElement source,
final long timestampMillis,
final int nanoOfMillisecond,
- final long nanoTime) {
+ final long nanoTime,
+ final String traceId,
+ final String spanId,
+ final String traceFlags) {
this(
loggerName,
marker,
@@ -604,7 +672,10 @@ public class Log4jLogEvent implements LogEvent {
threadName,
threadPriority,
source,
- nanoTime);
+ nanoTime,
+ traceId,
+ spanId,
+ traceFlags);
final long millis =
message instanceof TimestampMessage ? ((TimestampMessage) message).getTimestamp() : timestampMillis;
instant.initFromEpochMilli(millis, nanoOfMillisecond);
@@ -624,7 +695,10 @@ public class Log4jLogEvent implements LogEvent {
final int threadPriority,
final StackTraceElement source,
final Clock clock,
- final long nanoTime) {
+ final long nanoTime,
+ final String traceId,
+ final String spanId,
+ final String traceFlags) {
this(
loggerName,
marker,
@@ -638,7 +712,10 @@ public class Log4jLogEvent implements LogEvent {
threadName,
threadPriority,
source,
- nanoTime);
+ nanoTime,
+ traceId,
+ spanId,
+ traceFlags);
if (message instanceof TimestampMessage) {
instant.initFromEpochMilli(((TimestampMessage) message).getTimestamp(), 0);
} else {
@@ -659,7 +736,10 @@ public class Log4jLogEvent implements LogEvent {
final String threadName,
final int threadPriority,
final StackTraceElement source,
- final long nanoTime) {
+ final long nanoTime,
+ final String traceId,
+ final String spanId,
+ final String traceFlags) {
this.loggerName = loggerName;
this.marker = marker;
this.loggerFqcn = loggerFQCN;
@@ -676,6 +756,9 @@ public class Log4jLogEvent implements LogEvent {
((LoggerNameAwareMessage) message).setLoggerName(loggerName);
}
this.nanoTime = nanoTime;
+ this.traceId = traceId;
+ this.spanId = spanId;
+ this.traceFlags = traceFlags;
}
private static StringMap createContextData(final Map<String, String> contextMap) {
@@ -985,7 +1068,10 @@ public class Log4jLogEvent implements LogEvent {
proxy.source,
proxy.timeMillis,
proxy.nanoOfMillisecond,
- proxy.nanoTime);
+ proxy.nanoTime,
+ proxy.traceId,
+ proxy.spanId,
+ proxy.traceFlags);
result.setEndOfBatch(proxy.isEndOfBatch);
result.setIncludeLocation(proxy.isLocationRequired);
return result;
@@ -1093,6 +1179,15 @@ public class Log4jLogEvent implements LogEvent {
if (thrown != null ? !thrown.equals(that.thrown) : that.thrown != null) {
return false;
}
+ if (traceId != null ? !traceId.equals(that.traceId) : that.traceId != null) {
+ return false;
+ }
+ if (spanId != null ? !spanId.equals(that.spanId) : that.spanId != null) {
+ return false;
+ }
+ if (traceFlags != null ? !traceFlags.equals(that.traceFlags) : that.traceFlags != null) {
+ return false;
+ }
return true;
}
@@ -1116,10 +1211,27 @@ public class Log4jLogEvent implements LogEvent {
result = 31 * result + (source != null ? source.hashCode() : 0);
result = 31 * result + (includeLocation ? 1 : 0);
result = 31 * result + (endOfBatch ? 1 : 0);
+ result = 31 * result + (traceId != null ? traceId.hashCode() : 0);
+ result = 31 * result + (spanId != null ? spanId.hashCode() : 0);
+ result = 31 * result + (traceFlags != null ? traceFlags.hashCode() : 0);
// Check:ON: MagicNumber
return result;
}
+ @Override
+ public String getTraceId() {
+ return traceId;
+ }
+
+ @Override
+ public String getSpanId() {
+ return spanId;
+ }
+
+ @Override
+ public String getTraceFlags() {
+ return traceFlags;
+ }
/**
* Proxy pattern used to serialize the LogEvent.
*/
@@ -1160,6 +1272,10 @@ public class Log4jLogEvent implements LogEvent {
/** @since 2.4 */
private final transient long nanoTime;
+ private final String traceId;
+ private final String spanId;
+ private final String traceFlags;
+
public LogEventProxy(final Log4jLogEvent event, final boolean includeLocation) {
this.loggerFQCN = event.loggerFqcn;
this.marker = event.marker;
@@ -1180,6 +1296,9 @@ public class Log4jLogEvent implements LogEvent {
this.isLocationRequired = includeLocation;
this.isEndOfBatch = event.endOfBatch;
this.nanoTime = event.nanoTime;
+ this.traceId = event.getTraceId();
+ this.spanId = event.getSpanId();
+ this.traceFlags = event.getTraceFlags();
}
public LogEventProxy(final LogEvent event, final boolean includeLocation) {
@@ -1210,6 +1329,9 @@ public class Log4jLogEvent implements LogEvent {
this.isLocationRequired = includeLocation;
this.isEndOfBatch = event.isEndOfBatch();
this.nanoTime = event.getNanoTime();
+ this.traceId = event.getTraceId();
+ this.spanId = event.getSpanId();
+ this.traceFlags = event.getTraceFlags();
}
private static Message memento(final ReusableMessage message) {
@@ -1257,7 +1379,10 @@ public class Log4jLogEvent implements LogEvent {
source,
timeMillis,
nanoOfMillisecond,
- nanoTime);
+ nanoTime,
+ traceId,
+ spanId,
+ traceFlags);
result.setEndOfBatch(isEndOfBatch);
result.setIncludeLocation(isLocationRequired);
result.thrownProxy = thrownProxy;
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java
index 9a99eae624..83736894be 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java
@@ -30,12 +30,14 @@ import org.apache.logging.log4j.core.time.MutableInstant;
import org.apache.logging.log4j.core.util.Clock;
import org.apache.logging.log4j.core.util.Constants;
import org.apache.logging.log4j.core.util.NanoClock;
+import org.apache.logging.log4j.core.util.TraceContextProviderService;
import org.apache.logging.log4j.message.Message;
import org.apache.logging.log4j.message.ParameterConsumer;
import org.apache.logging.log4j.message.ParameterVisitable;
import org.apache.logging.log4j.message.ReusableMessage;
import org.apache.logging.log4j.message.SimpleMessage;
import org.apache.logging.log4j.message.TimestampMessage;
+import org.apache.logging.log4j.spi.TraceContextProvider;
import org.apache.logging.log4j.util.ReadOnlyStringMap;
import org.apache.logging.log4j.util.StackLocatorUtil;
import org.apache.logging.log4j.util.StringBuilders;
@@ -71,6 +73,9 @@ public class MutableLogEvent implements LogEvent, ReusableMessage, ParameterVisi
StackTraceElement source;
private ThreadContext.ContextStack contextStack;
transient boolean reserved = false;
+ private String traceId;
+ private String spanId;
+ private String traceFlags;
public MutableLogEvent() {
// messageText and the parameter array are lazily initialized
@@ -133,6 +138,10 @@ public class MutableLogEvent implements LogEvent, ReusableMessage, ParameterVisi
this.endOfBatch = event.isEndOfBatch();
this.includeLocation = event.isIncludeLocation();
this.nanoTime = event.getNanoTime();
+
+ this.traceId = event.getTraceId();
+ this.spanId = event.getSpanId();
+ this.traceFlags = event.getTraceFlags();
setMessage(event.getMessage());
}
@@ -157,6 +166,9 @@ public class MutableLogEvent implements LogEvent, ReusableMessage, ParameterVisi
}
contextStack = null;
+ traceId = null;
+ spanId = null;
+ traceFlags = null;
// ThreadName should not be cleared: this field is set in the ReusableLogEventFactory
// where this instance is kept in a ThreadLocal, so it usually does not change.
// threadName = null; // no need to clear threadName
@@ -359,6 +371,10 @@ public class MutableLogEvent implements LogEvent, ReusableMessage, ParameterVisi
instant.initFrom(clock);
}
nanoTime = nanoClock.nanoTime();
+ final TraceContextProvider provider = TraceContextProviderService.getActiveProvider();
+ this.traceId = provider.getTraceId();
+ this.spanId = provider.getSpanId();
+ this.traceFlags = provider.getTraceFlags();
}
@Override
@@ -485,6 +501,33 @@ public class MutableLogEvent implements LogEvent, ReusableMessage, ParameterVisi
this.nanoTime = nanoTime;
}
+ @Override
+ public String getTraceId() {
+ return traceId;
+ }
+
+ public void setTraceId(final String traceId) {
+ this.traceId = traceId;
+ }
+
+ @Override
+ public String getSpanId() {
+ return spanId;
+ }
+
+ public void setSpanId(final String spanId) {
+ this.spanId = spanId;
+ }
+
+ @Override
+ public String getTraceFlags() {
+ return traceFlags;
+ }
+
+ public void setTraceFlags(final String traceFlags) {
+ this.traceFlags = traceFlags;
+ }
+
/**
* Creates a LogEventProxy that can be serialized.
* @return a LogEventProxy.
@@ -534,6 +577,8 @@ public class MutableLogEvent implements LogEvent, ReusableMessage, ParameterVisi
.setThreadPriority(threadPriority) //
.setThrown(getThrown()) // may deserialize from thrownProxy
.setInstant(instant) //
- ;
+ .setTraceId(traceId)
+ .setSpanId(spanId)
+ .setTraceFlags(traceFlags);
}
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/package-info.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/package-info.java
index 666e8325ed..2d4bdcd199 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/package-info.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/package-info.java
@@ -18,7 +18,7 @@
* Log4j 2 private implementation classes.
*/
@Export
-@Version("2.24.1")
+@Version("2.25.0")
package org.apache.logging.log4j.core.impl;
import org.osgi.annotation.bundle.Export;
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/package-info.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/package-info.java
index c09868a666..45bc926c52 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/package-info.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/package-info.java
@@ -18,7 +18,7 @@
* Implementation of Log4j 2.
*/
@Export
-@Version("2.25.3")
+@Version("2.26.0")
package org.apache.logging.log4j.core;
import org.osgi.annotation.bundle.Export;
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/TraceContextProviderService.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/TraceContextProviderService.java
new file mode 100644
index 0000000000..3440e5e4a9
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/TraceContextProviderService.java
@@ -0,0 +1,72 @@
+/*
+ * 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.core.util;
+
+import java.util.Iterator;
+import java.util.ServiceLoader;
+import org.apache.logging.log4j.spi.TraceContextProvider;
+import org.apache.logging.log4j.status.StatusLogger;
+
+/**
+ * Service registry designed to discover and cache the active {@link TraceContextProvider}.
+ */
+public final class TraceContextProviderService {
+
+ private static final TraceContextProvider ACTIVE_PROVIDER;
+
+ static {
+ TraceContextProvider found = null;
+ try {
+ final ServiceLoader<TraceContextProvider> loader =
+ ServiceLoader.load(TraceContextProvider.class, TraceContextProviderService.class.getClassLoader());
+ final Iterator<TraceContextProvider> iterator = loader.iterator();
+ if (iterator.hasNext()) {
+ found = iterator.next();
+ StatusLogger.getLogger()
+ .info("Using TraceContextProvider: {}", found.getClass().getName());
+ }
+ } catch (final Throwable t) {
+ StatusLogger.getLogger().warn("Error loading TraceContextProvider service", t);
+ }
+ ACTIVE_PROVIDER = found != null ? found : NoOpTraceContextProvider.INSTANCE;
+ }
+
+ public static TraceContextProvider getActiveProvider() {
+ return ACTIVE_PROVIDER;
+ }
+
+ private static final class NoOpTraceContextProvider implements TraceContextProvider {
+ static final NoOpTraceContextProvider INSTANCE = new NoOpTraceContextProvider();
+
+ @Override
+ public String getTraceId() {
+ return null;
+ }
+
+ @Override
+ public String getSpanId() {
+ return null;
+ }
+
+ @Override
+ public String getTraceFlags() {
+ return null;
+ }
+ }
+
+ private TraceContextProviderService() {}
+}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/package-info.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/package-info.java
index e4ac85f5eb..b9efa51956 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/package-info.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/package-info.java
@@ -18,7 +18,7 @@
* Log4j 2 helper classes.
*/
@Export
-@Version("2.25.3")
+@Version("2.26.0")
package org.apache.logging.log4j.core.util;
import org.osgi.annotation.bundle.Export;
diff --git a/log4j-perf-test/src/main/java/org/apache/logging/log4j/perf/jmh/AsyncTraceContextBenchmark.java b/log4j-perf-test/src/main/java/org/apache/logging/log4j/perf/jmh/AsyncTraceContextBenchmark.java
new file mode 100644
index 0000000000..6483b59e0a
--- /dev/null
+++ b/log4j-perf-test/src/main/java/org/apache/logging/log4j/perf/jmh/AsyncTraceContextBenchmark.java
@@ -0,0 +1,133 @@
+/*
+ * 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.perf.jmh;
+
+import java.util.concurrent.TimeUnit;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.ThreadContext;
+import org.apache.logging.log4j.core.async.RingBufferLogEvent;
+import org.apache.logging.log4j.core.async.RingBufferLogEventTranslator;
+import org.apache.logging.log4j.core.util.ClockFactory;
+import org.apache.logging.log4j.core.util.DummyNanoClock;
+import org.apache.logging.log4j.message.SimpleMessage;
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Fork;
+import org.openjdk.jmh.annotations.Measurement;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.Warmup;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+@BenchmarkMode(Mode.Throughput)
+@OutputTimeUnit(TimeUnit.MICROSECONDS)
+@Warmup(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS)
+@Measurement(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS)
+@Fork(1)
+@State(Scope.Benchmark)
+public class AsyncTraceContextBenchmark {
+
+ private SimpleMessage message;
+
+ @Setup
+ public void setup() {
+ message = new SimpleMessage("Test performance message");
+ }
+
+ /**
+ * Reusable thread-local state to match how Disruptor events and translators
+ * are held per-thread in production.
+ */
+ @State(Scope.Thread)
+ public static class ThreadState {
+ final RingBufferLogEvent event = new RingBufferLogEvent();
+ final RingBufferLogEventTranslator translator = new RingBufferLogEventTranslator();
+ }
+
+ @Benchmark
+ public void baseline(final ThreadState state) {
+ state.translator.setBasicValues(
+ null,
+ "Logger",
+ null,
+ "FQCN",
+ Level.INFO,
+ message,
+ null,
+ null,
+ null,
+ ClockFactory.getClock(),
+ new DummyNanoClock());
+ state.translator.translateTo(state.event, 0);
+ }
+
+ @Benchmark
+ public void threadContextTracing(final ThreadState state) {
+ ThreadContext.put("traceId", "4bf92f3577b34da6a3ce929d0e0e4736");
+ ThreadContext.put("spanId", "00f067aa0ba902b7");
+ ThreadContext.put("traceFlags", "01");
+
+ try {
+ state.translator.setBasicValues(
+ null,
+ "Logger",
+ null,
+ "FQCN",
+ Level.INFO,
+ message,
+ null,
+ ThreadContext.getImmutableStack(),
+ null,
+ ClockFactory.getClock(),
+ new DummyNanoClock());
+ state.translator.translateTo(state.event, 0);
+ } finally {
+ ThreadContext.clearMap();
+ }
+ }
+
+ @Benchmark
+ public void nativeTracing(final ThreadState state) {
+ state.translator.setBasicValues(
+ null,
+ "Logger",
+ null,
+ "FQCN",
+ Level.INFO,
+ message,
+ null,
+ null,
+ null,
+ ClockFactory.getClock(),
+ new DummyNanoClock(),
+ "4bf92f3577b34da6a3ce929d0e0e4736",
+ "00f067aa0ba902b7",
+ "01");
+ state.translator.translateTo(state.event, 0);
+ }
+
+ public static void main(final String[] args) throws Exception {
+ new Runner(new OptionsBuilder()
+ .include(AsyncTraceContextBenchmark.class.getSimpleName())
+ .build())
+ .run();
+ }
+}