diff --git a/instrumentation/logback/logback-appender-1.0/library/src/logstashStructuredArgsTest/java/io/opentelemetry/instrumentation/logback/appender/v1_0/LogstashStructuredArgsTest.java b/instrumentation/logback/logback-appender-1.0/library/src/logstashStructuredArgsTest/java/io/opentelemetry/instrumentation/logback/appender/v1_0/LogstashStructuredArgsTest.java index 89359af9f722..5722afe9de44 100644 --- a/instrumentation/logback/logback-appender-1.0/library/src/logstashStructuredArgsTest/java/io/opentelemetry/instrumentation/logback/appender/v1_0/LogstashStructuredArgsTest.java +++ b/instrumentation/logback/logback-appender-1.0/library/src/logstashStructuredArgsTest/java/io/opentelemetry/instrumentation/logback/appender/v1_0/LogstashStructuredArgsTest.java @@ -9,6 +9,8 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.instrumentation.testing.junit.LibraryInstrumentationExtension; +import java.util.HashMap; +import java.util.Map; import net.logstash.logback.argument.StructuredArguments; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -90,4 +92,17 @@ void structuredArgumentsWithTypedValues() { equalTo(AttributeKey.longKey("timestamp"), timestamp), equalTo(AttributeKey.booleanKey("session_active"), true))); } + + @Test + void logWithStructuredArgument() { + Map eventData = new HashMap<>(); + eventData.put("foo", "bar"); + logger.info("message: {}", StructuredArguments.entries(eventData)); + + testing.waitAndAssertLogRecords( + logRecord -> + logRecord + .hasBody("message: {foo=bar}") + .hasAttributesSatisfying(equalTo(AttributeKey.stringKey("foo"), "bar"))); + } } diff --git a/instrumentation/logback/logback-appender-1.0/library/src/main/java/io/opentelemetry/instrumentation/logback/appender/v1_0/internal/LoggingEventMapper.java b/instrumentation/logback/logback-appender-1.0/library/src/main/java/io/opentelemetry/instrumentation/logback/appender/v1_0/internal/LoggingEventMapper.java index fbb74ff559ca..a35c72a075ab 100644 --- a/instrumentation/logback/logback-appender-1.0/library/src/main/java/io/opentelemetry/instrumentation/logback/appender/v1_0/internal/LoggingEventMapper.java +++ b/instrumentation/logback/logback-appender-1.0/library/src/main/java/io/opentelemetry/instrumentation/logback/appender/v1_0/internal/LoggingEventMapper.java @@ -640,7 +640,7 @@ private static boolean supportsLogstashStructuredArguments() { private void captureLogstashStructuredArguments(LogRecordBuilder builder, Object[] arguments) { for (Object argument : arguments) { if (isLogstashStructuredArgument(argument)) { - captureLogstashStructuredArgument(builder, argument); + captureLogstashMarker(builder, argument); } } } @@ -649,15 +649,8 @@ private void captureLogstashStructuredArguments(LogRecordBuilder builder, Object private static boolean isLogstashStructuredArgument(Object argument) { // StructuredArguments implement the marker interface, so we can check for it // without importing the class directly (which may not be available at runtime) - return argument instanceof SingleFieldAppendingMarker; - } - - @NoMuzzle - private void captureLogstashStructuredArgument(LogRecordBuilder builder, Object argument) { - // StructuredArguments created by v() or keyValue() extend SingleFieldAppendingMarker - // which has getFieldName() and provides field value via reflection - SingleFieldAppendingMarker marker = (SingleFieldAppendingMarker) argument; - captureLogstashMarker(builder, marker); + return argument instanceof SingleFieldAppendingMarker + || argument instanceof MapEntriesAppendingMarker; } private interface FieldReader {