From 6cff4f53c00a61f53e76a55e0ee41391fdf50f78 Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Fri, 8 Nov 2024 12:42:33 +0200 Subject: [PATCH 1/6] Log4j2: add option to fill code attributes --- .../log4j-appender-2.17/javaagent/README.md | 15 ++-- .../javaagent/build.gradle.kts | 3 +- .../v2_17/Log4jAppenderInstrumentation.java | 7 +- .../log4j/appender/v2_17/Log4jHelper.java | 15 +++- .../log4j/appender/v2_17/Log4j2Test.java | 63 ++++++++++------ .../appender/v2_17/Slf4jToLog4jTest.java | 37 ++++++---- .../log4j-appender-2.17/library/README.md | 3 + .../appender/v2_17/LogEventToReplay.java | 6 +- .../appender/v2_17/OpenTelemetryAppender.java | 25 ++++++- .../v2_17/internal/LogEventMapper.java | 31 +++++++- .../AbstractOpenTelemetryAppenderTest.java | 72 +++++++++++-------- .../LogReplayOpenTelemetryAppenderTest.java | 27 +++++-- .../v2_17/internal/LogEventMapperTest.java | 15 ++-- .../library/src/test/resources/log4j2.xml | 2 +- 14 files changed, 227 insertions(+), 94 deletions(-) diff --git a/instrumentation/log4j/log4j-appender-2.17/javaagent/README.md b/instrumentation/log4j/log4j-appender-2.17/javaagent/README.md index a78c4d9c395e..e3bf213d9498 100644 --- a/instrumentation/log4j/log4j-appender-2.17/javaagent/README.md +++ b/instrumentation/log4j/log4j-appender-2.17/javaagent/README.md @@ -1,8 +1,11 @@ # Settings for the Log4j Appender instrumentation -| System property | Type | Default | Description | -|-----------------------------------------------------------------------------------| ------- | ------- |-----------------------------------------------------------------------------------------------------------------------| -| `otel.instrumentation.log4j-appender.experimental-log-attributes` | Boolean | `false` | Enable the capture of experimental log attributes `thread.name` and `thread.id`. | -| `otel.instrumentation.log4j-appender.experimental.capture-map-message-attributes` | Boolean | `false` | Enable the capture of `MapMessage` attributes. | -| `otel.instrumentation.log4j-appender.experimental.capture-marker-attribute` | Boolean | `false` | Enable the capture of Log4j markers as attributes. | -| `otel.instrumentation.log4j-appender.experimental.capture-mdc-attributes` | String | | Comma separated list of context data attributes to capture. Use the wildcard character `*` to capture all attributes. | +| System property | Type | Default | Description | +|-----------------------------------------------------------------------------------|---------|---------|-----------------------------------------------------------------------------------------------------------------------------------------------| +| `otel.instrumentation.log4j-appender.experimental-log-attributes` | Boolean | `false` | Enable the capture of experimental log attributes `thread.name` and `thread.id`. | +| `otel.instrumentation.log4j-appender.experimental.capture-code-attributes` | Boolean | `false` | Enable the capture of [source code attributes]. Note that capturing source code attributes at logging sites might add a performance overhead. | +| `otel.instrumentation.log4j-appender.experimental.capture-map-message-attributes` | Boolean | `false` | Enable the capture of `MapMessage` attributes. | +| `otel.instrumentation.log4j-appender.experimental.capture-marker-attribute` | Boolean | `false` | Enable the capture of Log4j markers as attributes. | +| `otel.instrumentation.log4j-appender.experimental.capture-mdc-attributes` | String | | Comma separated list of context data attributes to capture. Use the wildcard character `*` to capture all attributes. | + +[source code attributes]: https://github.com/open-telemetry/semantic-conventions/blob/main/docs/general/attributes.md#source-code-attributes diff --git a/instrumentation/log4j/log4j-appender-2.17/javaagent/build.gradle.kts b/instrumentation/log4j/log4j-appender-2.17/javaagent/build.gradle.kts index 2594f5da0463..db40212d3504 100644 --- a/instrumentation/log4j/log4j-appender-2.17/javaagent/build.gradle.kts +++ b/instrumentation/log4j/log4j-appender-2.17/javaagent/build.gradle.kts @@ -56,9 +56,10 @@ tasks { tasks.withType().configureEach { // TODO run tests both with and without experimental log attributes + jvmArgs("-Dotel.instrumentation.log4j-appender.experimental-log-attributes=true") + jvmArgs("-Dotel.instrumentation.log4j-appender.experimental.capture-code-attributes=true") jvmArgs("-Dotel.instrumentation.log4j-appender.experimental.capture-map-message-attributes=true") jvmArgs("-Dotel.instrumentation.log4j-appender.experimental.capture-mdc-attributes=*") - jvmArgs("-Dotel.instrumentation.log4j-appender.experimental-log-attributes=true") jvmArgs("-Dotel.instrumentation.log4j-appender.experimental.capture-marker-attribute=true") } diff --git a/instrumentation/log4j/log4j-appender-2.17/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/log4j/appender/v2_17/Log4jAppenderInstrumentation.java b/instrumentation/log4j/log4j-appender-2.17/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/log4j/appender/v2_17/Log4jAppenderInstrumentation.java index 9e89793aef38..4c026b86cd9a 100644 --- a/instrumentation/log4j/log4j-appender-2.17/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/log4j/appender/v2_17/Log4jAppenderInstrumentation.java +++ b/instrumentation/log4j/log4j-appender-2.17/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/log4j/appender/v2_17/Log4jAppenderInstrumentation.java @@ -73,6 +73,8 @@ public static void methodEnter( @Advice.This Logger logger, @Advice.Argument(0) Level level, @Advice.Argument(1) Marker marker, + @Advice.Argument(2) String loggerClassName, + @Advice.Argument(3) StackTraceElement location, @Advice.Argument(4) Message message, @Advice.Argument(5) Throwable t, @Advice.Local("otelCallDepth") CallDepth callDepth) { @@ -80,7 +82,7 @@ public static void methodEnter( // logging framework delegates to another callDepth = CallDepth.forClass(LoggerProvider.class); if (callDepth.getAndIncrement() == 0) { - Log4jHelper.capture(logger, level, marker, message, t); + Log4jHelper.capture(logger, loggerClassName, location, level, marker, message, t); } } @@ -96,6 +98,7 @@ public static class LogMessageAdvice { @Advice.OnMethodEnter(suppress = Throwable.class) public static void methodEnter( @Advice.This Logger logger, + @Advice.Argument(0) String loggerClassName, @Advice.Argument(1) Level level, @Advice.Argument(2) Marker marker, @Advice.Argument(3) Message message, @@ -105,7 +108,7 @@ public static void methodEnter( // logging framework delegates to another callDepth = CallDepth.forClass(LoggerProvider.class); if (callDepth.getAndIncrement() == 0) { - Log4jHelper.capture(logger, level, marker, message, t); + Log4jHelper.capture(logger, loggerClassName, null, level, marker, message, t); } } diff --git a/instrumentation/log4j/log4j-appender-2.17/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/log4j/appender/v2_17/Log4jHelper.java b/instrumentation/log4j/log4j-appender-2.17/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/log4j/appender/v2_17/Log4jHelper.java index 9ab4d41abf55..e27ef29af20e 100644 --- a/instrumentation/log4j/log4j-appender-2.17/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/log4j/appender/v2_17/Log4jHelper.java +++ b/instrumentation/log4j/log4j-appender-2.17/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/log4j/appender/v2_17/Log4jHelper.java @@ -24,6 +24,7 @@ import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.message.Message; +import org.apache.logging.log4j.util.StackLocator; public final class Log4jHelper { @@ -36,6 +37,9 @@ public final class Log4jHelper { captureExperimentalAttributes = config.getBoolean("otel.instrumentation.log4j-appender.experimental-log-attributes", false); + boolean captureCodeAttributes = + config.getBoolean( + "otel.instrumentation.log4j-appender.experimental.capture-code-attributes", false); boolean captureMapMessageAttributes = config.getBoolean( "otel.instrumentation.log4j-appender.experimental.capture-map-message-attributes", @@ -51,13 +55,20 @@ public final class Log4jHelper { new LogEventMapper<>( ContextDataAccessorImpl.INSTANCE, captureExperimentalAttributes, + captureCodeAttributes, captureMapMessageAttributes, captureMarkerAttribute, captureContextDataAttributes); } public static void capture( - Logger logger, Level level, Marker marker, Message message, Throwable throwable) { + Logger logger, + String loggerClassName, + StackTraceElement location, + Level level, + Marker marker, + Message message, + Throwable throwable) { String instrumentationName = logger.getName(); if (instrumentationName == null || instrumentationName.isEmpty()) { instrumentationName = "ROOT"; @@ -86,6 +97,8 @@ public static void capture( contextData, threadName, threadId, + () -> + location != null ? location : StackLocator.getInstance().calcLocation(loggerClassName), Context.current()); builder.setTimestamp(Instant.now()); builder.emit(); diff --git a/instrumentation/log4j/log4j-appender-2.17/javaagent/src/test/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/Log4j2Test.java b/instrumentation/log4j/log4j-appender-2.17/javaagent/src/test/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/Log4j2Test.java index 4825a990633e..0ea83e6e95c8 100644 --- a/instrumentation/log4j/log4j-appender-2.17/javaagent/src/test/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/Log4j2Test.java +++ b/instrumentation/log4j/log4j-appender-2.17/javaagent/src/test/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/Log4j2Test.java @@ -11,6 +11,12 @@ import static io.opentelemetry.semconv.ExceptionAttributes.EXCEPTION_MESSAGE; import static io.opentelemetry.semconv.ExceptionAttributes.EXCEPTION_STACKTRACE; import static io.opentelemetry.semconv.ExceptionAttributes.EXCEPTION_TYPE; +import static io.opentelemetry.semconv.incubating.CodeIncubatingAttributes.CODE_FILEPATH; +import static io.opentelemetry.semconv.incubating.CodeIncubatingAttributes.CODE_FUNCTION; +import static io.opentelemetry.semconv.incubating.CodeIncubatingAttributes.CODE_LINENO; +import static io.opentelemetry.semconv.incubating.CodeIncubatingAttributes.CODE_NAMESPACE; +import static io.opentelemetry.semconv.incubating.ThreadIncubatingAttributes.THREAD_ID; +import static io.opentelemetry.semconv.incubating.ThreadIncubatingAttributes.THREAD_NAME; import static java.util.concurrent.TimeUnit.MILLISECONDS; import io.opentelemetry.api.common.AttributeKey; @@ -22,7 +28,6 @@ import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.logs.data.LogRecordData; import io.opentelemetry.sdk.testing.assertj.AttributeAssertion; -import io.opentelemetry.semconv.incubating.ThreadIncubatingAttributes; import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; @@ -35,6 +40,7 @@ import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.message.StringMapMessage; import org.apache.logging.log4j.message.StructuredDataMessage; +import org.assertj.core.api.AbstractLongAssert; import org.assertj.core.api.AssertAccess; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; @@ -112,11 +118,12 @@ private static void test( List attributeAsserts = new ArrayList<>( Arrays.asList( - equalTo( - ThreadIncubatingAttributes.THREAD_NAME, - Thread.currentThread().getName()), - equalTo( - ThreadIncubatingAttributes.THREAD_ID, Thread.currentThread().getId()))); + equalTo(THREAD_NAME, Thread.currentThread().getName()), + equalTo(THREAD_ID, Thread.currentThread().getId()), + equalTo(CODE_NAMESPACE, Log4j2Test.class.getName()), + equalTo(CODE_FUNCTION, "performLogging"), + satisfies(CODE_LINENO, AbstractLongAssert::isPositive), + equalTo(CODE_FILEPATH, "Log4j2Test.java"))); if (logException) { attributeAsserts.addAll( Arrays.asList( @@ -158,9 +165,12 @@ void testContextData() { .hasAttributesSatisfyingExactly( equalTo(AttributeKey.stringKey("key1"), "val1"), equalTo(AttributeKey.stringKey("key2"), "val2"), - equalTo( - ThreadIncubatingAttributes.THREAD_NAME, Thread.currentThread().getName()), - equalTo(ThreadIncubatingAttributes.THREAD_ID, Thread.currentThread().getId()))); + equalTo(THREAD_NAME, Thread.currentThread().getName()), + equalTo(THREAD_ID, Thread.currentThread().getId()), + equalTo(CODE_NAMESPACE, Log4j2Test.class.getName()), + equalTo(CODE_FUNCTION, "testContextData"), + satisfies(CODE_LINENO, AbstractLongAssert::isPositive), + equalTo(CODE_FILEPATH, "Log4j2Test.java"))); } @Test @@ -180,9 +190,12 @@ void testStringMapMessage() { .hasAttributesSatisfyingExactly( equalTo(AttributeKey.stringKey("log4j.map_message.key1"), "val1"), equalTo(AttributeKey.stringKey("log4j.map_message.key2"), "val2"), - equalTo( - ThreadIncubatingAttributes.THREAD_NAME, Thread.currentThread().getName()), - equalTo(ThreadIncubatingAttributes.THREAD_ID, Thread.currentThread().getId()))); + equalTo(THREAD_NAME, Thread.currentThread().getName()), + equalTo(THREAD_ID, Thread.currentThread().getId()), + equalTo(CODE_NAMESPACE, Log4j2Test.class.getName()), + equalTo(CODE_FUNCTION, "testStringMapMessage"), + satisfies(CODE_LINENO, AbstractLongAssert::isPositive), + equalTo(CODE_FILEPATH, "Log4j2Test.java"))); } @Test @@ -201,9 +214,12 @@ void testStringMapMessageWithSpecialAttribute() { .hasSeverityText("INFO") .hasAttributesSatisfyingExactly( equalTo(AttributeKey.stringKey("log4j.map_message.key1"), "val1"), - equalTo( - ThreadIncubatingAttributes.THREAD_NAME, Thread.currentThread().getName()), - equalTo(ThreadIncubatingAttributes.THREAD_ID, Thread.currentThread().getId()))); + equalTo(THREAD_NAME, Thread.currentThread().getName()), + equalTo(THREAD_ID, Thread.currentThread().getId()), + equalTo(CODE_NAMESPACE, Log4j2Test.class.getName()), + equalTo(CODE_FUNCTION, "testStringMapMessageWithSpecialAttribute"), + satisfies(CODE_LINENO, AbstractLongAssert::isPositive), + equalTo(CODE_FILEPATH, "Log4j2Test.java"))); } @Test @@ -223,9 +239,12 @@ void testStructuredDataMapMessage() { .hasAttributesSatisfyingExactly( equalTo(AttributeKey.stringKey("log4j.map_message.key1"), "val1"), equalTo(AttributeKey.stringKey("log4j.map_message.key2"), "val2"), - equalTo( - ThreadIncubatingAttributes.THREAD_NAME, Thread.currentThread().getName()), - equalTo(ThreadIncubatingAttributes.THREAD_ID, Thread.currentThread().getId()))); + equalTo(THREAD_NAME, Thread.currentThread().getName()), + equalTo(THREAD_ID, Thread.currentThread().getId()), + equalTo(CODE_NAMESPACE, Log4j2Test.class.getName()), + equalTo(CODE_FUNCTION, "testStructuredDataMapMessage"), + satisfies(CODE_LINENO, AbstractLongAssert::isPositive), + equalTo(CODE_FILEPATH, "Log4j2Test.java"))); } @Test @@ -238,8 +257,12 @@ public void testMarker() { testing.waitAndAssertLogRecords( logRecord -> logRecord.hasAttributesSatisfyingExactly( - equalTo(ThreadIncubatingAttributes.THREAD_NAME, Thread.currentThread().getName()), - equalTo(ThreadIncubatingAttributes.THREAD_ID, Thread.currentThread().getId()), + equalTo(THREAD_NAME, Thread.currentThread().getName()), + equalTo(THREAD_ID, Thread.currentThread().getId()), + equalTo(CODE_NAMESPACE, Log4j2Test.class.getName()), + equalTo(CODE_FUNCTION, "testMarker"), + satisfies(CODE_LINENO, AbstractLongAssert::isPositive), + equalTo(CODE_FILEPATH, "Log4j2Test.java"), equalTo(AttributeKey.stringKey("log4j.marker"), markerName))); } diff --git a/instrumentation/log4j/log4j-appender-2.17/javaagent/src/test/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/Slf4jToLog4jTest.java b/instrumentation/log4j/log4j-appender-2.17/javaagent/src/test/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/Slf4jToLog4jTest.java index ce6249fe4ed6..c1f5d1b93298 100644 --- a/instrumentation/log4j/log4j-appender-2.17/javaagent/src/test/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/Slf4jToLog4jTest.java +++ b/instrumentation/log4j/log4j-appender-2.17/javaagent/src/test/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/Slf4jToLog4jTest.java @@ -11,6 +11,12 @@ import static io.opentelemetry.semconv.ExceptionAttributes.EXCEPTION_MESSAGE; import static io.opentelemetry.semconv.ExceptionAttributes.EXCEPTION_STACKTRACE; import static io.opentelemetry.semconv.ExceptionAttributes.EXCEPTION_TYPE; +import static io.opentelemetry.semconv.incubating.CodeIncubatingAttributes.CODE_FILEPATH; +import static io.opentelemetry.semconv.incubating.CodeIncubatingAttributes.CODE_FUNCTION; +import static io.opentelemetry.semconv.incubating.CodeIncubatingAttributes.CODE_LINENO; +import static io.opentelemetry.semconv.incubating.CodeIncubatingAttributes.CODE_NAMESPACE; +import static io.opentelemetry.semconv.incubating.ThreadIncubatingAttributes.THREAD_ID; +import static io.opentelemetry.semconv.incubating.ThreadIncubatingAttributes.THREAD_NAME; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.logs.Severity; @@ -19,11 +25,11 @@ import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.testing.assertj.AttributeAssertion; -import io.opentelemetry.semconv.incubating.ThreadIncubatingAttributes; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.stream.Stream; +import org.assertj.core.api.AbstractLongAssert; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import org.junit.jupiter.params.ParameterizedTest; @@ -103,11 +109,12 @@ private static void test( List attributeAsserts = new ArrayList<>( Arrays.asList( - equalTo( - ThreadIncubatingAttributes.THREAD_NAME, - Thread.currentThread().getName()), - equalTo( - ThreadIncubatingAttributes.THREAD_ID, Thread.currentThread().getId()))); + equalTo(THREAD_NAME, Thread.currentThread().getName()), + equalTo(THREAD_ID, Thread.currentThread().getId()), + equalTo(CODE_NAMESPACE, Slf4jToLog4jTest.class.getName()), + equalTo(CODE_FUNCTION, "performLogging"), + satisfies(CODE_LINENO, AbstractLongAssert::isPositive), + equalTo(CODE_FILEPATH, "Slf4jToLog4jTest.java"))); if (logException) { attributeAsserts.addAll( Arrays.asList( @@ -145,14 +152,16 @@ void testMdc() { .hasAttributesSatisfyingExactly( equalTo(AttributeKey.stringKey("key1"), "val1"), equalTo(AttributeKey.stringKey("key2"), "val2"), - equalTo( - ThreadIncubatingAttributes.THREAD_NAME, Thread.currentThread().getName()), - equalTo(ThreadIncubatingAttributes.THREAD_ID, Thread.currentThread().getId()))); + equalTo(THREAD_NAME, Thread.currentThread().getName()), + equalTo(THREAD_ID, Thread.currentThread().getId()), + equalTo(CODE_NAMESPACE, Slf4jToLog4jTest.class.getName()), + equalTo(CODE_FUNCTION, "testMdc"), + satisfies(CODE_LINENO, AbstractLongAssert::isPositive), + equalTo(CODE_FILEPATH, "Slf4jToLog4jTest.java"))); } @Test public void testMarker() { - String markerName = "aMarker"; Marker marker = MarkerFactory.getMarker(markerName); @@ -161,8 +170,12 @@ public void testMarker() { testing.waitAndAssertLogRecords( logRecord -> logRecord.hasAttributesSatisfyingExactly( - equalTo(ThreadIncubatingAttributes.THREAD_NAME, Thread.currentThread().getName()), - equalTo(ThreadIncubatingAttributes.THREAD_ID, Thread.currentThread().getId()), + equalTo(THREAD_NAME, Thread.currentThread().getName()), + equalTo(THREAD_ID, Thread.currentThread().getId()), + equalTo(CODE_NAMESPACE, Slf4jToLog4jTest.class.getName()), + equalTo(CODE_FUNCTION, "testMarker"), + satisfies(CODE_LINENO, AbstractLongAssert::isPositive), + equalTo(CODE_FILEPATH, "Slf4jToLog4jTest.java"), equalTo(AttributeKey.stringKey("log4j.marker"), markerName))); } diff --git a/instrumentation/log4j/log4j-appender-2.17/library/README.md b/instrumentation/log4j/log4j-appender-2.17/library/README.md index 4a3d14441a44..9d4a7be38e1f 100644 --- a/instrumentation/log4j/log4j-appender-2.17/library/README.md +++ b/instrumentation/log4j/log4j-appender-2.17/library/README.md @@ -95,7 +95,10 @@ The available settings are: | XML Attribute | Type | Default | Description | |------------------------------------|---------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `captureExperimentalAttributes` | Boolean | `false` | Enable the capture of experimental log attributes `thread.name` and `thread.id`. | +| `captureCodeAttributes` | Boolean | `false` | Enable the capture of [source code attributes]. Note that capturing source code attributes at logging sites might add a performance overhead. | | `captureMapMessageAttributes` | Boolean | `false` | Enable the capture of `MapMessage` attributes. | | `captureMarkerAttribute` | Boolean | `false` | Enable the capture of Log4j markers as attributes. | | `captureContextDataAttributes` | String | | Comma separated list of context data attributes to capture. Use the wildcard character `*` to capture all attributes. | | `numLogsCapturedBeforeOtelInstall` | Integer | 1000 | Log telemetry is emitted after the initialization of the OpenTelemetry Log4j appender with an OpenTelemetry object. This setting allows you to modify the size of the cache used to replay the first logs. | + +[source code attributes]: https://github.com/open-telemetry/semantic-conventions/blob/main/docs/general/attributes.md#source-code-attributes diff --git a/instrumentation/log4j/log4j-appender-2.17/library/src/main/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/LogEventToReplay.java b/instrumentation/log4j/log4j-appender-2.17/library/src/main/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/LogEventToReplay.java index e765d42e80f1..a165d0edab93 100644 --- a/instrumentation/log4j/log4j-appender-2.17/library/src/main/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/LogEventToReplay.java +++ b/instrumentation/log4j/log4j-appender-2.17/library/src/main/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/LogEventToReplay.java @@ -36,8 +36,9 @@ class LogEventToReplay implements LogEvent { private final ReadOnlyStringMap contextData; private final String threadName; private final long threadId; + private final StackTraceElement source; - LogEventToReplay(LogEvent logEvent) { + LogEventToReplay(LogEvent logEvent, boolean captureCodeAttributes) { this.loggerName = logEvent.getLoggerName(); Message messageOrigin = logEvent.getMessage(); if (messageOrigin instanceof StructuredDataMessage) { @@ -64,6 +65,7 @@ class LogEventToReplay implements LogEvent { this.contextData = new SortedArrayStringMap(logEvent.getContextData()); this.threadName = logEvent.getThreadName(); this.threadId = logEvent.getThreadId(); + this.source = captureCodeAttributes ? logEvent.getSource() : null; } @Override @@ -125,7 +127,7 @@ public Instant getInstant() { @Override public StackTraceElement getSource() { - return null; + return source; } @Override diff --git a/instrumentation/log4j/log4j-appender-2.17/library/src/main/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/OpenTelemetryAppender.java b/instrumentation/log4j/log4j-appender-2.17/library/src/main/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/OpenTelemetryAppender.java index aeeadb3e6bce..ff980b3be35a 100644 --- a/instrumentation/log4j/log4j-appender-2.17/library/src/main/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/OpenTelemetryAppender.java +++ b/instrumentation/log4j/log4j-appender-2.17/library/src/main/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/OpenTelemetryAppender.java @@ -62,10 +62,9 @@ public class OpenTelemetryAppender extends AbstractAppender { private volatile OpenTelemetry openTelemetry; private final BlockingQueue eventsToReplay; - private final AtomicBoolean replayLimitWarningLogged = new AtomicBoolean(); - private final ReadWriteLock lock = new ReentrantReadWriteLock(); + private final boolean captureCodeAttributes; /** * Installs the {@code openTelemetry} instance on any {@link OpenTelemetryAppender}s identified in @@ -98,6 +97,7 @@ public static class Builder> extends AbstractAppender.Build implements org.apache.logging.log4j.core.util.Builder { @PluginBuilderAttribute private boolean captureExperimentalAttributes; + @PluginBuilderAttribute private boolean captureCodeAttributes; @PluginBuilderAttribute private boolean captureMapMessageAttributes; @PluginBuilderAttribute private boolean captureMarkerAttribute; @PluginBuilderAttribute private String captureContextDataAttributes; @@ -116,6 +116,20 @@ public B setCaptureExperimentalAttributes(boolean captureExperimentalAttributes) return asBuilder(); } + /** + * Sets whether the code attributes (file name, class name, method name and line number) should + * be set to logs. Enabling these attributes can potentially impact performance (see + * https://logging.apache.org/log4j/2.x/manual/performance.html#layouts-location). + * + * @param captureCodeAttributes To enable or disable the code attributes (file name, class name, + * method name and line number) + */ + @CanIgnoreReturnValue + public B captureCodeAttributes(boolean captureCodeAttributes) { + this.captureCodeAttributes = captureCodeAttributes; + return asBuilder(); + } + /** Sets whether log4j {@link MapMessage} attributes should be copied to logs. */ @CanIgnoreReturnValue public B setCaptureMapMessageAttributes(boolean captureMapMessageAttributes) { @@ -170,6 +184,7 @@ public OpenTelemetryAppender build() { isIgnoreExceptions(), getPropertyArray(), captureExperimentalAttributes, + captureCodeAttributes, captureMapMessageAttributes, captureMarkerAttribute, captureContextDataAttributes, @@ -185,6 +200,7 @@ private OpenTelemetryAppender( boolean ignoreExceptions, Property[] properties, boolean captureExperimentalAttributes, + boolean captureCodeAttributes, boolean captureMapMessageAttributes, boolean captureMarkerAttribute, String captureContextDataAttributes, @@ -196,10 +212,12 @@ private OpenTelemetryAppender( new LogEventMapper<>( ContextDataAccessorImpl.INSTANCE, captureExperimentalAttributes, + captureCodeAttributes, captureMapMessageAttributes, captureMarkerAttribute, splitAndFilterBlanksAndNulls(captureContextDataAttributes)); this.openTelemetry = openTelemetry; + this.captureCodeAttributes = captureCodeAttributes; if (numLogsCapturedBeforeOtelInstall != 0) { this.eventsToReplay = new ArrayBlockingQueue<>(numLogsCapturedBeforeOtelInstall); } else { @@ -257,7 +275,7 @@ public void append(LogEvent event) { return; } - LogEventToReplay logEventToReplay = new LogEventToReplay(event); + LogEventToReplay logEventToReplay = new LogEventToReplay(event, captureCodeAttributes); if (!eventsToReplay.offer(logEventToReplay) && !replayLimitWarningLogged.getAndSet(true)) { String message = @@ -309,6 +327,7 @@ private void emit(OpenTelemetry openTelemetry, LogEvent event) { contextData, event.getThreadName(), event.getThreadId(), + event::getSource, context); Instant timestamp = event.getInstant(); diff --git a/instrumentation/log4j/log4j-appender-2.17/library/src/main/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/internal/LogEventMapper.java b/instrumentation/log4j/log4j-appender-2.17/library/src/main/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/internal/LogEventMapper.java index 1116de609bf7..e26958f5215b 100644 --- a/instrumentation/log4j/log4j-appender-2.17/library/src/main/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/internal/LogEventMapper.java +++ b/instrumentation/log4j/log4j-appender-2.17/library/src/main/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/internal/LogEventMapper.java @@ -16,6 +16,7 @@ import java.io.PrintWriter; import java.io.StringWriter; import java.util.List; +import java.util.function.Supplier; import javax.annotation.Nullable; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Marker; @@ -29,6 +30,12 @@ */ public final class LogEventMapper { + // copied from CodeIncubatingAttributes + private static final AttributeKey CODE_FILEPATH = AttributeKey.stringKey("code.filepath"); + private static final AttributeKey CODE_FUNCTION = AttributeKey.stringKey("code.function"); + private static final AttributeKey CODE_LINENO = AttributeKey.longKey("code.lineno"); + private static final AttributeKey CODE_NAMESPACE = + AttributeKey.stringKey("code.namespace"); // copied from ThreadIncubatingAttributes private static final AttributeKey THREAD_ID = AttributeKey.longKey("thread.id"); private static final AttributeKey THREAD_NAME = AttributeKey.stringKey("thread.name"); @@ -45,6 +52,7 @@ public final class LogEventMapper { private final ContextDataAccessor contextDataAccessor; private final boolean captureExperimentalAttributes; + private final boolean captureCodeAttributes; private final boolean captureMapMessageAttributes; private final boolean captureMarkerAttribute; private final List captureContextDataAttributes; @@ -53,11 +61,13 @@ public final class LogEventMapper { public LogEventMapper( ContextDataAccessor contextDataAccessor, boolean captureExperimentalAttributes, + boolean captureCodeAttributes, boolean captureMapMessageAttributes, boolean captureMarkerAttribute, List captureContextDataAttributes) { this.contextDataAccessor = contextDataAccessor; + this.captureCodeAttributes = captureCodeAttributes; this.captureExperimentalAttributes = captureExperimentalAttributes; this.captureMapMessageAttributes = captureMapMessageAttributes; this.captureMarkerAttribute = captureMarkerAttribute; @@ -71,13 +81,11 @@ public LogEventMapper( * *
    *
  • Fully qualified class name - {@link LogEvent#getLoggerFqcn()} - *
  • Thread name - {@link LogEvent#getThreadName()} - *
  • Thread id - {@link LogEvent#getThreadId()} *
  • Thread priority - {@link LogEvent#getThreadPriority()} - *
  • Marker - {@link LogEvent#getMarker()} *
  • Nested diagnostic context - {@link LogEvent#getContextStack()} *
*/ + @SuppressWarnings("TooManyParameters") public void mapLogEvent( LogRecordBuilder builder, Message message, @@ -87,6 +95,7 @@ public void mapLogEvent( T contextData, String threadName, long threadId, + Supplier sourceSupplier, Context context) { AttributesBuilder attributes = Attributes.builder(); @@ -116,6 +125,22 @@ public void mapLogEvent( attributes.put(THREAD_ID, threadId); } + if (captureCodeAttributes) { + StackTraceElement source = sourceSupplier.get(); + if (source != null) { + String fileName = source.getFileName(); + if (fileName != null) { + attributes.put(CODE_FILEPATH, fileName); + } + attributes.put(CODE_NAMESPACE, source.getClassName()); + attributes.put(CODE_FUNCTION, source.getMethodName()); + int lineNumber = source.getLineNumber(); + if (lineNumber > 0) { + attributes.put(CODE_LINENO, lineNumber); + } + } + } + builder.setAllAttributes(attributes.build()); builder.setContext(context); } diff --git a/instrumentation/log4j/log4j-appender-2.17/library/src/test/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/AbstractOpenTelemetryAppenderTest.java b/instrumentation/log4j/log4j-appender-2.17/library/src/test/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/AbstractOpenTelemetryAppenderTest.java index 74983abdede5..1ccc688489d8 100644 --- a/instrumentation/log4j/log4j-appender-2.17/library/src/test/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/AbstractOpenTelemetryAppenderTest.java +++ b/instrumentation/log4j/log4j-appender-2.17/library/src/test/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/AbstractOpenTelemetryAppenderTest.java @@ -12,6 +12,12 @@ import static io.opentelemetry.semconv.ExceptionAttributes.EXCEPTION_MESSAGE; import static io.opentelemetry.semconv.ExceptionAttributes.EXCEPTION_STACKTRACE; import static io.opentelemetry.semconv.ExceptionAttributes.EXCEPTION_TYPE; +import static io.opentelemetry.semconv.incubating.CodeIncubatingAttributes.CODE_FILEPATH; +import static io.opentelemetry.semconv.incubating.CodeIncubatingAttributes.CODE_FUNCTION; +import static io.opentelemetry.semconv.incubating.CodeIncubatingAttributes.CODE_LINENO; +import static io.opentelemetry.semconv.incubating.CodeIncubatingAttributes.CODE_NAMESPACE; +import static io.opentelemetry.semconv.incubating.ThreadIncubatingAttributes.THREAD_ID; +import static io.opentelemetry.semconv.incubating.ThreadIncubatingAttributes.THREAD_NAME; import static java.util.concurrent.TimeUnit.MILLISECONDS; import io.opentelemetry.api.logs.Severity; @@ -20,7 +26,6 @@ import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.logs.data.LogRecordData; import io.opentelemetry.sdk.resources.Resource; -import io.opentelemetry.semconv.incubating.ThreadIncubatingAttributes; import java.time.Instant; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -31,6 +36,7 @@ import org.apache.logging.log4j.message.FormattedMessage; import org.apache.logging.log4j.message.StringMapMessage; import org.apache.logging.log4j.message.StructuredDataMessage; +import org.assertj.core.api.AbstractLongAssert; import org.assertj.core.api.AssertAccess; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; @@ -96,11 +102,12 @@ void logNoSpan() { .hasInstrumentationScope(instrumentationScopeInfo) .hasBody("log message 1") .hasAttributesSatisfyingExactly( - equalTo( - ThreadIncubatingAttributes.THREAD_NAME, - Thread.currentThread().getName()), - equalTo( - ThreadIncubatingAttributes.THREAD_ID, Thread.currentThread().getId()))); + equalTo(THREAD_NAME, Thread.currentThread().getName()), + equalTo(THREAD_ID, Thread.currentThread().getId()), + equalTo(CODE_NAMESPACE, AbstractOpenTelemetryAppenderTest.class.getName()), + equalTo(CODE_FUNCTION, "logNoSpan"), + satisfies(CODE_LINENO, AbstractLongAssert::isPositive), + equalTo(CODE_FILEPATH, "AbstractOpenTelemetryAppenderTest.java"))); } @Test @@ -130,9 +137,12 @@ void logWithExtras() { .hasSeverity(Severity.INFO) .hasSeverityText("INFO") .hasAttributesSatisfyingExactly( - equalTo( - ThreadIncubatingAttributes.THREAD_NAME, Thread.currentThread().getName()), - equalTo(ThreadIncubatingAttributes.THREAD_ID, Thread.currentThread().getId()), + equalTo(THREAD_NAME, Thread.currentThread().getName()), + equalTo(THREAD_ID, Thread.currentThread().getId()), + equalTo(CODE_NAMESPACE, AbstractOpenTelemetryAppenderTest.class.getName()), + equalTo(CODE_FUNCTION, "logWithExtras"), + satisfies(CODE_LINENO, AbstractLongAssert::isPositive), + equalTo(CODE_FILEPATH, "AbstractOpenTelemetryAppenderTest.java"), equalTo(EXCEPTION_TYPE, IllegalStateException.class.getName()), equalTo(EXCEPTION_MESSAGE, "Error!"), satisfies(EXCEPTION_STACKTRACE, v -> v.contains("logWithExtras"))); @@ -164,11 +174,12 @@ void logContextData() { .hasInstrumentationScope(instrumentationScopeInfo) .hasBody("log message 1") .hasAttributesSatisfyingExactly( - equalTo( - ThreadIncubatingAttributes.THREAD_NAME, - Thread.currentThread().getName()), - equalTo( - ThreadIncubatingAttributes.THREAD_ID, Thread.currentThread().getId()), + equalTo(THREAD_NAME, Thread.currentThread().getName()), + equalTo(THREAD_ID, Thread.currentThread().getId()), + equalTo(CODE_NAMESPACE, AbstractOpenTelemetryAppenderTest.class.getName()), + equalTo(CODE_FUNCTION, "logContextData"), + satisfies(CODE_LINENO, AbstractLongAssert::isPositive), + equalTo(CODE_FILEPATH, "AbstractOpenTelemetryAppenderTest.java"), equalTo(stringKey("key1"), "val1"), equalTo(stringKey("key2"), "val2"))); } @@ -189,11 +200,12 @@ void logStringMapMessage() { .hasResource(resource) .hasInstrumentationScope(instrumentationScopeInfo) .hasAttributesSatisfyingExactly( - equalTo( - ThreadIncubatingAttributes.THREAD_NAME, - Thread.currentThread().getName()), - equalTo( - ThreadIncubatingAttributes.THREAD_ID, Thread.currentThread().getId()), + equalTo(THREAD_NAME, Thread.currentThread().getName()), + equalTo(THREAD_ID, Thread.currentThread().getId()), + equalTo(CODE_NAMESPACE, AbstractOpenTelemetryAppenderTest.class.getName()), + equalTo(CODE_FUNCTION, "logStringMapMessage"), + satisfies(CODE_LINENO, AbstractLongAssert::isPositive), + equalTo(CODE_FILEPATH, "AbstractOpenTelemetryAppenderTest.java"), equalTo(stringKey("log4j.map_message.key1"), "val1"), equalTo(stringKey("log4j.map_message.key2"), "val2"))); } @@ -215,11 +227,12 @@ void logStringMapMessageWithSpecialAttribute() { .hasInstrumentationScope(instrumentationScopeInfo) .hasBody("val2") .hasAttributesSatisfyingExactly( - equalTo( - ThreadIncubatingAttributes.THREAD_NAME, - Thread.currentThread().getName()), - equalTo( - ThreadIncubatingAttributes.THREAD_ID, Thread.currentThread().getId()), + equalTo(THREAD_NAME, Thread.currentThread().getName()), + equalTo(THREAD_ID, Thread.currentThread().getId()), + equalTo(CODE_NAMESPACE, AbstractOpenTelemetryAppenderTest.class.getName()), + equalTo(CODE_FUNCTION, "logStringMapMessageWithSpecialAttribute"), + satisfies(CODE_LINENO, AbstractLongAssert::isPositive), + equalTo(CODE_FILEPATH, "AbstractOpenTelemetryAppenderTest.java"), equalTo(stringKey("log4j.map_message.key1"), "val1"))); } @@ -255,11 +268,12 @@ void logStructuredDataMessage() { .hasInstrumentationScope(instrumentationScopeInfo) .hasBody("a message") .hasAttributesSatisfyingExactly( - equalTo( - ThreadIncubatingAttributes.THREAD_NAME, - Thread.currentThread().getName()), - equalTo( - ThreadIncubatingAttributes.THREAD_ID, Thread.currentThread().getId()), + equalTo(THREAD_NAME, Thread.currentThread().getName()), + equalTo(THREAD_ID, Thread.currentThread().getId()), + equalTo(CODE_NAMESPACE, AbstractOpenTelemetryAppenderTest.class.getName()), + equalTo(CODE_FUNCTION, "logStructuredDataMessage"), + satisfies(CODE_LINENO, AbstractLongAssert::isPositive), + equalTo(CODE_FILEPATH, "AbstractOpenTelemetryAppenderTest.java"), equalTo(stringKey("log4j.map_message.key1"), "val1"), equalTo(stringKey("log4j.map_message.key2"), "val2"))); } diff --git a/instrumentation/log4j/log4j-appender-2.17/library/src/test/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/LogReplayOpenTelemetryAppenderTest.java b/instrumentation/log4j/log4j-appender-2.17/library/src/test/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/LogReplayOpenTelemetryAppenderTest.java index fde9d06511d3..f8e46c95f1dd 100644 --- a/instrumentation/log4j/log4j-appender-2.17/library/src/test/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/LogReplayOpenTelemetryAppenderTest.java +++ b/instrumentation/log4j/log4j-appender-2.17/library/src/test/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/LogReplayOpenTelemetryAppenderTest.java @@ -7,12 +7,19 @@ import static io.opentelemetry.api.common.AttributeKey.stringKey; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo; +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies; +import static io.opentelemetry.semconv.incubating.CodeIncubatingAttributes.CODE_FILEPATH; +import static io.opentelemetry.semconv.incubating.CodeIncubatingAttributes.CODE_FUNCTION; +import static io.opentelemetry.semconv.incubating.CodeIncubatingAttributes.CODE_LINENO; +import static io.opentelemetry.semconv.incubating.CodeIncubatingAttributes.CODE_NAMESPACE; +import static io.opentelemetry.semconv.incubating.ThreadIncubatingAttributes.THREAD_ID; +import static io.opentelemetry.semconv.incubating.ThreadIncubatingAttributes.THREAD_NAME; import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; import io.opentelemetry.instrumentation.testing.junit.LibraryInstrumentationExtension; -import io.opentelemetry.semconv.incubating.ThreadIncubatingAttributes; import org.apache.logging.log4j.message.StringMapMessage; import org.apache.logging.log4j.message.StructuredDataMessage; +import org.assertj.core.api.AbstractLongAssert; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.BeforeEach; @@ -95,9 +102,12 @@ void twoLogsStringMapMessage() { .hasResource(resource) .hasInstrumentationScope(instrumentationScopeInfo) .hasAttributesSatisfyingExactly( - equalTo( - ThreadIncubatingAttributes.THREAD_NAME, Thread.currentThread().getName()), - equalTo(ThreadIncubatingAttributes.THREAD_ID, Thread.currentThread().getId()), + equalTo(THREAD_NAME, Thread.currentThread().getName()), + equalTo(THREAD_ID, Thread.currentThread().getId()), + equalTo(CODE_NAMESPACE, LogReplayOpenTelemetryAppenderTest.class.getName()), + equalTo(CODE_FUNCTION, "twoLogsStringMapMessage"), + satisfies(CODE_LINENO, AbstractLongAssert::isPositive), + equalTo(CODE_FILEPATH, "LogReplayOpenTelemetryAppenderTest.java"), equalTo(stringKey("log4j.map_message.key1"), "val1"), equalTo(stringKey("log4j.map_message.key2"), "val2"))); } @@ -128,9 +138,12 @@ void twoLogsStructuredDataMessage() { .hasInstrumentationScope(instrumentationScopeInfo) .hasBody("a message") .hasAttributesSatisfyingExactly( - equalTo( - ThreadIncubatingAttributes.THREAD_NAME, Thread.currentThread().getName()), - equalTo(ThreadIncubatingAttributes.THREAD_ID, Thread.currentThread().getId()), + equalTo(THREAD_NAME, Thread.currentThread().getName()), + equalTo(THREAD_ID, Thread.currentThread().getId()), + equalTo(CODE_NAMESPACE, LogReplayOpenTelemetryAppenderTest.class.getName()), + equalTo(CODE_FUNCTION, "twoLogsStructuredDataMessage"), + satisfies(CODE_LINENO, AbstractLongAssert::isPositive), + equalTo(CODE_FILEPATH, "LogReplayOpenTelemetryAppenderTest.java"), equalTo(stringKey("log4j.map_message.key1"), "val1"), equalTo(stringKey("log4j.map_message.key2"), "val2"))); } diff --git a/instrumentation/log4j/log4j-appender-2.17/library/src/test/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/internal/LogEventMapperTest.java b/instrumentation/log4j/log4j-appender-2.17/library/src/test/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/internal/LogEventMapperTest.java index 535e2c857e35..ce374ff97b9b 100644 --- a/instrumentation/log4j/log4j-appender-2.17/library/src/test/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/internal/LogEventMapperTest.java +++ b/instrumentation/log4j/log4j-appender-2.17/library/src/test/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/internal/LogEventMapperTest.java @@ -31,7 +31,8 @@ class LogEventMapperTest { void testDefault() { // given LogEventMapper> mapper = - new LogEventMapper<>(ContextDataAccessorImpl.INSTANCE, false, false, false, emptyList()); + new LogEventMapper<>( + ContextDataAccessorImpl.INSTANCE, false, false, false, false, emptyList()); Map contextData = new HashMap<>(); contextData.put("key1", "value1"); contextData.put("key2", "value2"); @@ -49,7 +50,7 @@ void testSome() { // given LogEventMapper> mapper = new LogEventMapper<>( - ContextDataAccessorImpl.INSTANCE, false, false, false, singletonList("key2")); + ContextDataAccessorImpl.INSTANCE, false, false, false, false, singletonList("key2")); Map contextData = new HashMap<>(); contextData.put("key1", "value1"); contextData.put("key2", "value2"); @@ -67,7 +68,7 @@ void testAll() { // given LogEventMapper> mapper = new LogEventMapper<>( - ContextDataAccessorImpl.INSTANCE, false, false, false, singletonList("*")); + ContextDataAccessorImpl.INSTANCE, false, false, false, false, singletonList("*")); Map contextData = new HashMap<>(); contextData.put("key1", "value1"); contextData.put("key2", "value2"); @@ -86,7 +87,7 @@ void testCaptureMapMessageDisabled() { // given LogEventMapper> mapper = new LogEventMapper<>( - ContextDataAccessorImpl.INSTANCE, false, false, false, singletonList("*")); + ContextDataAccessorImpl.INSTANCE, false, false, false, false, singletonList("*")); StringMapMessage message = new StringMapMessage(); message.put("key1", "value1"); @@ -108,7 +109,7 @@ void testCaptureMapMessageWithSpecialAttribute() { // given LogEventMapper> mapper = new LogEventMapper<>( - ContextDataAccessorImpl.INSTANCE, false, true, false, singletonList("*")); + ContextDataAccessorImpl.INSTANCE, false, false, true, false, singletonList("*")); StringMapMessage message = new StringMapMessage(); message.put("key1", "value1"); @@ -130,7 +131,7 @@ void testCaptureMapMessageWithoutSpecialAttribute() { // given LogEventMapper> mapper = new LogEventMapper<>( - ContextDataAccessorImpl.INSTANCE, false, true, false, singletonList("*")); + ContextDataAccessorImpl.INSTANCE, false, false, true, false, singletonList("*")); StringMapMessage message = new StringMapMessage(); message.put("key1", "value1"); @@ -155,7 +156,7 @@ void testCaptureStructuredDataMessage() { // given LogEventMapper> mapper = new LogEventMapper<>( - ContextDataAccessorImpl.INSTANCE, false, true, false, singletonList("*")); + ContextDataAccessorImpl.INSTANCE, false, false, true, false, singletonList("*")); StructuredDataMessage message = new StructuredDataMessage("an id", "a message", "a type"); message.put("key1", "value1"); diff --git a/instrumentation/log4j/log4j-appender-2.17/library/src/test/resources/log4j2.xml b/instrumentation/log4j/log4j-appender-2.17/library/src/test/resources/log4j2.xml index 39c79fc1c7fd..1953d256c0b7 100644 --- a/instrumentation/log4j/log4j-appender-2.17/library/src/test/resources/log4j2.xml +++ b/instrumentation/log4j/log4j-appender-2.17/library/src/test/resources/log4j2.xml @@ -6,7 +6,7 @@ pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} traceId: %X{trace_id} spanId: %X{span_id} flags: %X{trace_flags} - %msg%n"/> - + From d67cae279c393a0e4cda207bf3a13f44fa86aec9 Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Fri, 8 Nov 2024 13:43:17 +0200 Subject: [PATCH 2/6] use reflection --- .../javaagent/build.gradle.kts | 2 +- .../log4j/appender/v2_17/Log4jHelper.java | 49 +++++++++++++++++-- 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/instrumentation/log4j/log4j-appender-2.17/javaagent/build.gradle.kts b/instrumentation/log4j/log4j-appender-2.17/javaagent/build.gradle.kts index db40212d3504..15fee0051d3f 100644 --- a/instrumentation/log4j/log4j-appender-2.17/javaagent/build.gradle.kts +++ b/instrumentation/log4j/log4j-appender-2.17/javaagent/build.gradle.kts @@ -14,7 +14,7 @@ muzzle { val testLatestDeps = findProperty("testLatestDeps") as Boolean dependencies { - library("org.apache.logging.log4j:log4j-core:2.17.0") + library("org.apache.logging.log4j:log4j-core:2.0") compileOnly(project(":javaagent-bootstrap")) diff --git a/instrumentation/log4j/log4j-appender-2.17/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/log4j/appender/v2_17/Log4jHelper.java b/instrumentation/log4j/log4j-appender-2.17/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/log4j/appender/v2_17/Log4jHelper.java index e27ef29af20e..8bfef80a91f3 100644 --- a/instrumentation/log4j/log4j-appender-2.17/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/log4j/appender/v2_17/Log4jHelper.java +++ b/instrumentation/log4j/log4j-appender-2.17/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/log4j/appender/v2_17/Log4jHelper.java @@ -14,6 +14,9 @@ import io.opentelemetry.instrumentation.log4j.appender.v2_17.internal.ContextDataAccessor; import io.opentelemetry.instrumentation.log4j.appender.v2_17.internal.LogEventMapper; import io.opentelemetry.javaagent.bootstrap.internal.AgentInstrumentationConfig; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; import java.time.Instant; import java.util.List; import java.util.Map; @@ -24,13 +27,12 @@ import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.ThreadContext; import org.apache.logging.log4j.message.Message; -import org.apache.logging.log4j.util.StackLocator; public final class Log4jHelper { private static final LogEventMapper> mapper; - private static final boolean captureExperimentalAttributes; + private static final MethodHandle stackTraceMethodHandle = getStackTraceMethodHandle(); static { InstrumentationConfig config = AgentInstrumentationConfig.get(); @@ -98,12 +100,53 @@ public static void capture( threadName, threadId, () -> - location != null ? location : StackLocator.getInstance().calcLocation(loggerClassName), + location != null ? location : getLocation(loggerClassName), Context.current()); builder.setTimestamp(Instant.now()); builder.emit(); } + private static StackTraceElement getLocation(String loggerClassName) { + if (stackTraceMethodHandle == null) { + return null; + } + + try { + return (StackTraceElement) stackTraceMethodHandle.invoke(loggerClassName); + } catch (Throwable exception) { + return null; + } + } + + private static MethodHandle getStackTraceMethodHandle() { + // since 2.9.0 + Class stackTraceClass = null; + try { + stackTraceClass = Class.forName("org.apache.logging.log4j.util.StackLocatorUtil"); + } catch (ClassNotFoundException exception) { + // ignore + } + if (stackTraceClass == null) { + try { + stackTraceClass = Class.forName("org.apache.logging.log4j.core.impl.Log4jLogEvent"); + } catch (ClassNotFoundException exception) { + // ignore + } + } + if (stackTraceClass == null) { + return null; + } + try { + return MethodHandles.lookup() + .findStatic( + stackTraceClass, + "calcLocation", + MethodType.methodType(StackTraceElement.class, String.class)); + } catch (Exception exception) { + return null; + } + } + private enum ContextDataAccessorImpl implements ContextDataAccessor> { INSTANCE; From 44c25eb28c1b3f8b72c6013a9a53fea3fc2d9a46 Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Fri, 8 Nov 2024 13:44:10 +0200 Subject: [PATCH 3/6] spotless --- .../instrumentation/log4j/appender/v2_17/Log4jHelper.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/instrumentation/log4j/log4j-appender-2.17/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/log4j/appender/v2_17/Log4jHelper.java b/instrumentation/log4j/log4j-appender-2.17/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/log4j/appender/v2_17/Log4jHelper.java index 8bfef80a91f3..b06d61de517b 100644 --- a/instrumentation/log4j/log4j-appender-2.17/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/log4j/appender/v2_17/Log4jHelper.java +++ b/instrumentation/log4j/log4j-appender-2.17/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/log4j/appender/v2_17/Log4jHelper.java @@ -99,8 +99,7 @@ public static void capture( contextData, threadName, threadId, - () -> - location != null ? location : getLocation(loggerClassName), + () -> location != null ? location : getLocation(loggerClassName), Context.current()); builder.setTimestamp(Instant.now()); builder.emit(); From a880293e8837d125a5be793e9abe10cf0bcf9b9b Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Fri, 8 Nov 2024 16:50:17 +0200 Subject: [PATCH 4/6] fix async test --- .../AbstractOpenTelemetryAppenderTest.java | 108 ++++++++++-------- .../LogReplayOpenTelemetryAppenderTest.java | 41 +++---- 2 files changed, 81 insertions(+), 68 deletions(-) diff --git a/instrumentation/log4j/log4j-appender-2.17/library/src/test/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/AbstractOpenTelemetryAppenderTest.java b/instrumentation/log4j/log4j-appender-2.17/library/src/test/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/AbstractOpenTelemetryAppenderTest.java index 1ccc688489d8..2d14a07c7cfe 100644 --- a/instrumentation/log4j/log4j-appender-2.17/library/src/test/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/AbstractOpenTelemetryAppenderTest.java +++ b/instrumentation/log4j/log4j-appender-2.17/library/src/test/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/AbstractOpenTelemetryAppenderTest.java @@ -26,7 +26,11 @@ import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.logs.data.LogRecordData; import io.opentelemetry.sdk.resources.Resource; +import io.opentelemetry.sdk.testing.assertj.AttributeAssertion; import java.time.Instant; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Marker; @@ -102,12 +106,10 @@ void logNoSpan() { .hasInstrumentationScope(instrumentationScopeInfo) .hasBody("log message 1") .hasAttributesSatisfyingExactly( - equalTo(THREAD_NAME, Thread.currentThread().getName()), - equalTo(THREAD_ID, Thread.currentThread().getId()), - equalTo(CODE_NAMESPACE, AbstractOpenTelemetryAppenderTest.class.getName()), - equalTo(CODE_FUNCTION, "logNoSpan"), - satisfies(CODE_LINENO, AbstractLongAssert::isPositive), - equalTo(CODE_FILEPATH, "AbstractOpenTelemetryAppenderTest.java"))); + addLocationAttributes( + "logNoSpan", + equalTo(THREAD_NAME, Thread.currentThread().getName()), + equalTo(THREAD_ID, Thread.currentThread().getId())))); } @Test @@ -137,15 +139,13 @@ void logWithExtras() { .hasSeverity(Severity.INFO) .hasSeverityText("INFO") .hasAttributesSatisfyingExactly( - equalTo(THREAD_NAME, Thread.currentThread().getName()), - equalTo(THREAD_ID, Thread.currentThread().getId()), - equalTo(CODE_NAMESPACE, AbstractOpenTelemetryAppenderTest.class.getName()), - equalTo(CODE_FUNCTION, "logWithExtras"), - satisfies(CODE_LINENO, AbstractLongAssert::isPositive), - equalTo(CODE_FILEPATH, "AbstractOpenTelemetryAppenderTest.java"), - equalTo(EXCEPTION_TYPE, IllegalStateException.class.getName()), - equalTo(EXCEPTION_MESSAGE, "Error!"), - satisfies(EXCEPTION_STACKTRACE, v -> v.contains("logWithExtras"))); + addLocationAttributes( + "logWithExtras", + equalTo(THREAD_NAME, Thread.currentThread().getName()), + equalTo(THREAD_ID, Thread.currentThread().getId()), + equalTo(EXCEPTION_TYPE, IllegalStateException.class.getName()), + equalTo(EXCEPTION_MESSAGE, "Error!"), + satisfies(EXCEPTION_STACKTRACE, v -> v.contains("logWithExtras")))); LogRecordData logRecordData = AssertAccess.getActual(logRecord); assertThat(logRecordData.getTimestampEpochNanos()) @@ -174,14 +174,12 @@ void logContextData() { .hasInstrumentationScope(instrumentationScopeInfo) .hasBody("log message 1") .hasAttributesSatisfyingExactly( - equalTo(THREAD_NAME, Thread.currentThread().getName()), - equalTo(THREAD_ID, Thread.currentThread().getId()), - equalTo(CODE_NAMESPACE, AbstractOpenTelemetryAppenderTest.class.getName()), - equalTo(CODE_FUNCTION, "logContextData"), - satisfies(CODE_LINENO, AbstractLongAssert::isPositive), - equalTo(CODE_FILEPATH, "AbstractOpenTelemetryAppenderTest.java"), - equalTo(stringKey("key1"), "val1"), - equalTo(stringKey("key2"), "val2"))); + addLocationAttributes( + "logContextData", + equalTo(THREAD_NAME, Thread.currentThread().getName()), + equalTo(THREAD_ID, Thread.currentThread().getId()), + equalTo(stringKey("key1"), "val1"), + equalTo(stringKey("key2"), "val2")))); } @Test @@ -200,14 +198,12 @@ void logStringMapMessage() { .hasResource(resource) .hasInstrumentationScope(instrumentationScopeInfo) .hasAttributesSatisfyingExactly( - equalTo(THREAD_NAME, Thread.currentThread().getName()), - equalTo(THREAD_ID, Thread.currentThread().getId()), - equalTo(CODE_NAMESPACE, AbstractOpenTelemetryAppenderTest.class.getName()), - equalTo(CODE_FUNCTION, "logStringMapMessage"), - satisfies(CODE_LINENO, AbstractLongAssert::isPositive), - equalTo(CODE_FILEPATH, "AbstractOpenTelemetryAppenderTest.java"), - equalTo(stringKey("log4j.map_message.key1"), "val1"), - equalTo(stringKey("log4j.map_message.key2"), "val2"))); + addLocationAttributes( + "logStringMapMessage", + equalTo(THREAD_NAME, Thread.currentThread().getName()), + equalTo(THREAD_ID, Thread.currentThread().getId()), + equalTo(stringKey("log4j.map_message.key1"), "val1"), + equalTo(stringKey("log4j.map_message.key2"), "val2")))); } @Test @@ -227,13 +223,11 @@ void logStringMapMessageWithSpecialAttribute() { .hasInstrumentationScope(instrumentationScopeInfo) .hasBody("val2") .hasAttributesSatisfyingExactly( - equalTo(THREAD_NAME, Thread.currentThread().getName()), - equalTo(THREAD_ID, Thread.currentThread().getId()), - equalTo(CODE_NAMESPACE, AbstractOpenTelemetryAppenderTest.class.getName()), - equalTo(CODE_FUNCTION, "logStringMapMessageWithSpecialAttribute"), - satisfies(CODE_LINENO, AbstractLongAssert::isPositive), - equalTo(CODE_FILEPATH, "AbstractOpenTelemetryAppenderTest.java"), - equalTo(stringKey("log4j.map_message.key1"), "val1"))); + addLocationAttributes( + "logStringMapMessageWithSpecialAttribute", + equalTo(THREAD_NAME, Thread.currentThread().getName()), + equalTo(THREAD_ID, Thread.currentThread().getId()), + equalTo(stringKey("log4j.map_message.key1"), "val1")))); } @Test @@ -268,13 +262,35 @@ void logStructuredDataMessage() { .hasInstrumentationScope(instrumentationScopeInfo) .hasBody("a message") .hasAttributesSatisfyingExactly( - equalTo(THREAD_NAME, Thread.currentThread().getName()), - equalTo(THREAD_ID, Thread.currentThread().getId()), - equalTo(CODE_NAMESPACE, AbstractOpenTelemetryAppenderTest.class.getName()), - equalTo(CODE_FUNCTION, "logStructuredDataMessage"), - satisfies(CODE_LINENO, AbstractLongAssert::isPositive), - equalTo(CODE_FILEPATH, "AbstractOpenTelemetryAppenderTest.java"), - equalTo(stringKey("log4j.map_message.key1"), "val1"), - equalTo(stringKey("log4j.map_message.key2"), "val2"))); + addLocationAttributes( + "logStructuredDataMessage", + equalTo(THREAD_NAME, Thread.currentThread().getName()), + equalTo(THREAD_ID, Thread.currentThread().getId()), + equalTo(stringKey("log4j.map_message.key1"), "val1"), + equalTo(stringKey("log4j.map_message.key2"), "val2")))); + } + + private static List addLocationAttributes( + String methodName, AttributeAssertion... assertions) { + return addLocationAttributes(AbstractOpenTelemetryAppenderTest.class, methodName, assertions); + } + + protected static List addLocationAttributes( + Class testClass, String methodName, AttributeAssertion... assertions) { + String selector = System.getProperty("Log4j2.contextSelector"); + boolean async = selector != null && selector.endsWith("AsyncLoggerContextSelector"); + if (async) { + // code attributes as not added by default when async logger is used + return Arrays.asList(assertions); + } + + List result = new ArrayList<>(Arrays.asList(assertions)); + result.addAll( + Arrays.asList( + equalTo(CODE_NAMESPACE, testClass.getName()), + equalTo(CODE_FUNCTION, methodName), + satisfies(CODE_LINENO, AbstractLongAssert::isPositive), + equalTo(CODE_FILEPATH, testClass.getSimpleName() + ".java"))); + return result; } } diff --git a/instrumentation/log4j/log4j-appender-2.17/library/src/test/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/LogReplayOpenTelemetryAppenderTest.java b/instrumentation/log4j/log4j-appender-2.17/library/src/test/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/LogReplayOpenTelemetryAppenderTest.java index f8e46c95f1dd..aeccb412fcd9 100644 --- a/instrumentation/log4j/log4j-appender-2.17/library/src/test/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/LogReplayOpenTelemetryAppenderTest.java +++ b/instrumentation/log4j/log4j-appender-2.17/library/src/test/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/LogReplayOpenTelemetryAppenderTest.java @@ -7,19 +7,15 @@ import static io.opentelemetry.api.common.AttributeKey.stringKey; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo; -import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies; -import static io.opentelemetry.semconv.incubating.CodeIncubatingAttributes.CODE_FILEPATH; -import static io.opentelemetry.semconv.incubating.CodeIncubatingAttributes.CODE_FUNCTION; -import static io.opentelemetry.semconv.incubating.CodeIncubatingAttributes.CODE_LINENO; -import static io.opentelemetry.semconv.incubating.CodeIncubatingAttributes.CODE_NAMESPACE; import static io.opentelemetry.semconv.incubating.ThreadIncubatingAttributes.THREAD_ID; import static io.opentelemetry.semconv.incubating.ThreadIncubatingAttributes.THREAD_NAME; import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; import io.opentelemetry.instrumentation.testing.junit.LibraryInstrumentationExtension; +import io.opentelemetry.sdk.testing.assertj.AttributeAssertion; +import java.util.List; import org.apache.logging.log4j.message.StringMapMessage; import org.apache.logging.log4j.message.StructuredDataMessage; -import org.assertj.core.api.AbstractLongAssert; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.BeforeEach; @@ -102,14 +98,12 @@ void twoLogsStringMapMessage() { .hasResource(resource) .hasInstrumentationScope(instrumentationScopeInfo) .hasAttributesSatisfyingExactly( - equalTo(THREAD_NAME, Thread.currentThread().getName()), - equalTo(THREAD_ID, Thread.currentThread().getId()), - equalTo(CODE_NAMESPACE, LogReplayOpenTelemetryAppenderTest.class.getName()), - equalTo(CODE_FUNCTION, "twoLogsStringMapMessage"), - satisfies(CODE_LINENO, AbstractLongAssert::isPositive), - equalTo(CODE_FILEPATH, "LogReplayOpenTelemetryAppenderTest.java"), - equalTo(stringKey("log4j.map_message.key1"), "val1"), - equalTo(stringKey("log4j.map_message.key2"), "val2"))); + addLocationAttributes( + "twoLogsStringMapMessage", + equalTo(THREAD_NAME, Thread.currentThread().getName()), + equalTo(THREAD_ID, Thread.currentThread().getId()), + equalTo(stringKey("log4j.map_message.key1"), "val1"), + equalTo(stringKey("log4j.map_message.key2"), "val2")))); } @Test @@ -138,13 +132,16 @@ void twoLogsStructuredDataMessage() { .hasInstrumentationScope(instrumentationScopeInfo) .hasBody("a message") .hasAttributesSatisfyingExactly( - equalTo(THREAD_NAME, Thread.currentThread().getName()), - equalTo(THREAD_ID, Thread.currentThread().getId()), - equalTo(CODE_NAMESPACE, LogReplayOpenTelemetryAppenderTest.class.getName()), - equalTo(CODE_FUNCTION, "twoLogsStructuredDataMessage"), - satisfies(CODE_LINENO, AbstractLongAssert::isPositive), - equalTo(CODE_FILEPATH, "LogReplayOpenTelemetryAppenderTest.java"), - equalTo(stringKey("log4j.map_message.key1"), "val1"), - equalTo(stringKey("log4j.map_message.key2"), "val2"))); + addLocationAttributes( + "twoLogsStructuredDataMessage", + equalTo(THREAD_NAME, Thread.currentThread().getName()), + equalTo(THREAD_ID, Thread.currentThread().getId()), + equalTo(stringKey("log4j.map_message.key1"), "val1"), + equalTo(stringKey("log4j.map_message.key2"), "val2")))); + } + + private static List addLocationAttributes( + String methodName, AttributeAssertion... assertions) { + return addLocationAttributes(LogReplayOpenTelemetryAppenderTest.class, methodName, assertions); } } From 3eca7a1abf78efa079cb8464c254553b27c5b651 Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Fri, 8 Nov 2024 20:05:56 +0200 Subject: [PATCH 5/6] address review comment --- .../instrumentation/log4j/appender/v2_17/Log4jHelper.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/instrumentation/log4j/log4j-appender-2.17/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/log4j/appender/v2_17/Log4jHelper.java b/instrumentation/log4j/log4j-appender-2.17/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/log4j/appender/v2_17/Log4jHelper.java index b06d61de517b..6fc308cc1dd9 100644 --- a/instrumentation/log4j/log4j-appender-2.17/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/log4j/appender/v2_17/Log4jHelper.java +++ b/instrumentation/log4j/log4j-appender-2.17/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/log4j/appender/v2_17/Log4jHelper.java @@ -118,15 +118,16 @@ private static StackTraceElement getLocation(String loggerClassName) { } private static MethodHandle getStackTraceMethodHandle() { - // since 2.9.0 Class stackTraceClass = null; try { + // since 2.9.0 stackTraceClass = Class.forName("org.apache.logging.log4j.util.StackLocatorUtil"); } catch (ClassNotFoundException exception) { // ignore } if (stackTraceClass == null) { try { + // before 2.9.0 stackTraceClass = Class.forName("org.apache.logging.log4j.core.impl.Log4jLogEvent"); } catch (ClassNotFoundException exception) { // ignore From 99f1f827a09aa5e15407746df09bbf247df605bf Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Sun, 10 Nov 2024 09:51:00 +0200 Subject: [PATCH 6/6] fix latest dep test --- .../log4j/log4j-appender-2.17/library/build.gradle.kts | 1 + .../appender/v2_17/AbstractOpenTelemetryAppenderTest.java | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/instrumentation/log4j/log4j-appender-2.17/library/build.gradle.kts b/instrumentation/log4j/log4j-appender-2.17/library/build.gradle.kts index a0d41b8f78fd..4c80b3a5f2da 100644 --- a/instrumentation/log4j/log4j-appender-2.17/library/build.gradle.kts +++ b/instrumentation/log4j/log4j-appender-2.17/library/build.gradle.kts @@ -18,6 +18,7 @@ dependencies { tasks { withType().configureEach { + systemProperty("testLatestDeps", findProperty("testLatestDeps") as Boolean) jvmArgs("-Dotel.instrumentation.common.experimental.controller-telemetry.enabled=true") } diff --git a/instrumentation/log4j/log4j-appender-2.17/library/src/test/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/AbstractOpenTelemetryAppenderTest.java b/instrumentation/log4j/log4j-appender-2.17/library/src/test/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/AbstractOpenTelemetryAppenderTest.java index 2d14a07c7cfe..c7be6426f3cb 100644 --- a/instrumentation/log4j/log4j-appender-2.17/library/src/test/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/AbstractOpenTelemetryAppenderTest.java +++ b/instrumentation/log4j/log4j-appender-2.17/library/src/test/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/AbstractOpenTelemetryAppenderTest.java @@ -279,8 +279,8 @@ protected static List addLocationAttributes( Class testClass, String methodName, AttributeAssertion... assertions) { String selector = System.getProperty("Log4j2.contextSelector"); boolean async = selector != null && selector.endsWith("AsyncLoggerContextSelector"); - if (async) { - // code attributes as not added by default when async logger is used + if (async && !Boolean.getBoolean("testLatestDeps")) { + // source info is not available by default when async logger is used in non latest dep tests return Arrays.asList(assertions); }