diff --git a/instrumentation/jboss-logmanager/README.md b/instrumentation/jboss-logmanager/README.md index 1cedd4d8aac7..e303c2648b8c 100644 --- a/instrumentation/jboss-logmanager/README.md +++ b/instrumentation/jboss-logmanager/README.md @@ -1,6 +1,7 @@ # Settings for the JBoss Log Manager instrumentation -| System property | Type | Default | Description | -|-----------------------------------------------------------------------------|---------|---------|--------------------------------------------------------------------------------------------------------------| -| `otel.instrumentation.jboss-logmanager.experimental-log-attributes` | Boolean | `false` | Enable the capture of experimental log attributes `thread.name` and `thread.id`. | -| `otel.instrumentation.jboss-logmanager.experimental.capture-mdc-attributes` | String | | Comma separated list of MDC attributes to capture. Use the wildcard character `*` to capture all attributes. | +| System property | Type | Default | Description | +|-----------------------------------------------------------------------------|---------|---------|------------------------------------------------------------------------------------------------------------------------------------| +| `otel.instrumentation.jboss-logmanager.experimental-log-attributes` | Boolean | `false` | Enable the capture of experimental log attributes `thread.name` and `thread.id`. | +| `otel.instrumentation.jboss-logmanager.experimental.capture-mdc-attributes` | String | | Comma separated list of MDC attributes to capture. Use the wildcard character `*` to capture all attributes. | +| `otel.instrumentation.jboss-logmanager.experimental.capture-event-name` | Boolean | `false` | Enable moving the `event.name` attribute (captured by one of the other mechanisms of capturing attributes) to the log event name. | diff --git a/instrumentation/jboss-logmanager/jboss-logmanager-appender-1.1/javaagent/build.gradle.kts b/instrumentation/jboss-logmanager/jboss-logmanager-appender-1.1/javaagent/build.gradle.kts index 99b421c73921..be600b3b52b4 100644 --- a/instrumentation/jboss-logmanager/jboss-logmanager-appender-1.1/javaagent/build.gradle.kts +++ b/instrumentation/jboss-logmanager/jboss-logmanager-appender-1.1/javaagent/build.gradle.kts @@ -33,6 +33,7 @@ if (latestDepTest) { tasks.withType().configureEach { // TODO run tests both with and without experimental log attributes jvmArgs("-Dotel.instrumentation.jboss-logmanager.experimental.capture-mdc-attributes=*") + jvmArgs("-Dotel.instrumentation.jboss-logmanager.experimental.capture-event-name=true") jvmArgs("-Dotel.instrumentation.jboss-logmanager.experimental-log-attributes=true") jvmArgs("-Dotel.instrumentation.java-util-logging.experimental-log-attributes=true") } diff --git a/instrumentation/jboss-logmanager/jboss-logmanager-appender-1.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jbosslogmanager/appender/v1_1/LoggingEventMapper.java b/instrumentation/jboss-logmanager/jboss-logmanager-appender-1.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jbosslogmanager/appender/v1_1/LoggingEventMapper.java index 344c831605ac..c9df4e328c04 100644 --- a/instrumentation/jboss-logmanager/jboss-logmanager-appender-1.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jbosslogmanager/appender/v1_1/LoggingEventMapper.java +++ b/instrumentation/jboss-logmanager/jboss-logmanager-appender-1.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jbosslogmanager/appender/v1_1/LoggingEventMapper.java @@ -10,8 +10,6 @@ import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.common.AttributeKey; -import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.api.common.AttributesBuilder; import io.opentelemetry.api.incubator.logs.ExtendedLogRecordBuilder; import io.opentelemetry.api.logs.LogRecordBuilder; import io.opentelemetry.api.logs.Severity; @@ -32,6 +30,9 @@ public final class LoggingEventMapper { private static final Cache> mdcAttributeKeys = Cache.bounded(100); + // copied from EventIncubatingAttributes + private static final AttributeKey EVENT_NAME = AttributeKey.stringKey("event.name"); + private final List captureMdcAttributes; private static final boolean captureExperimentalAttributes = @@ -41,6 +42,11 @@ public final class LoggingEventMapper { // cached as an optimization private final boolean captureAllMdcAttributes; + private final boolean captureEventName = + AgentInstrumentationConfig.get() + .getBoolean( + "otel.instrumentation.jboss-logmanager.experimental.capture-event-name", false); + private LoggingEventMapper() { this.captureMdcAttributes = AgentInstrumentationConfig.get() @@ -75,38 +81,33 @@ public void capture(Logger logger, ExtLogRecord record) { builder.setSeverityText(level.toString()); } - AttributesBuilder attributes = Attributes.builder(); - Throwable throwable = record.getThrown(); if (throwable != null) { // this cast is safe within java agent instrumentation ((ExtendedLogRecordBuilder) builder).setException(throwable); } - captureMdcAttributes(attributes); + captureMdcAttributes(builder); if (captureExperimentalAttributes) { Thread currentThread = Thread.currentThread(); - attributes.put(ThreadIncubatingAttributes.THREAD_NAME, currentThread.getName()); - attributes.put(ThreadIncubatingAttributes.THREAD_ID, currentThread.getId()); + builder.setAttribute(ThreadIncubatingAttributes.THREAD_NAME, currentThread.getName()); + builder.setAttribute(ThreadIncubatingAttributes.THREAD_ID, currentThread.getId()); } - builder.setAllAttributes(attributes.build()); - builder.setContext(Context.current()); builder.setTimestamp(record.getMillis(), MILLISECONDS); builder.emit(); } - private void captureMdcAttributes(AttributesBuilder attributes) { + private void captureMdcAttributes(LogRecordBuilder builder) { Map context = MDC.copy(); if (captureAllMdcAttributes) { if (context != null) { for (Map.Entry entry : context.entrySet()) { - attributes.put( - getMdcAttributeKey(String.valueOf(entry.getKey())), String.valueOf(entry.getValue())); + setAttributeOrEventName(builder, getMdcAttributeKey(entry.getKey()), entry.getValue()); } } return; @@ -114,9 +115,7 @@ private void captureMdcAttributes(AttributesBuilder attributes) { for (String key : captureMdcAttributes) { Object value = context.get(key); - if (value != null) { - attributes.put(key, value.toString()); - } + setAttributeOrEventName(builder, getMdcAttributeKey(key), value); } } @@ -124,6 +123,17 @@ public static AttributeKey getMdcAttributeKey(String key) { return mdcAttributeKeys.computeIfAbsent(key, AttributeKey::stringKey); } + private void setAttributeOrEventName( + LogRecordBuilder builder, AttributeKey key, Object value) { + if (value != null) { + if (captureEventName && key.equals(EVENT_NAME)) { + builder.setEventName(value.toString()); + } else { + builder.setAttribute(key, value.toString()); + } + } + } + private static Severity levelToSeverity(java.util.logging.Level level) { int levelInt = level.intValue(); if (levelInt >= Level.FATAL.intValue()) { diff --git a/instrumentation/jboss-logmanager/jboss-logmanager-appender-1.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/jbosslogmanager/appender/v1_1/JbossLogmanagerTest.java b/instrumentation/jboss-logmanager/jboss-logmanager-appender-1.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/jbosslogmanager/appender/v1_1/JbossLogmanagerTest.java index 97d886c020a5..bbf8ff2ac4bb 100644 --- a/instrumentation/jboss-logmanager/jboss-logmanager-appender-1.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/jbosslogmanager/appender/v1_1/JbossLogmanagerTest.java +++ b/instrumentation/jboss-logmanager/jboss-logmanager-appender-1.1/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/jbosslogmanager/appender/v1_1/JbossLogmanagerTest.java @@ -202,11 +202,13 @@ private static void performLogging( void testMdc() { MDC.put("key1", "val1"); MDC.put("key2", "val2"); + MDC.put("event.name", "MyEventName"); try { logger.info("xyz"); } finally { MDC.remove("key1"); MDC.remove("key2"); + MDC.remove("event.name"); } testing.waitAndAssertLogRecords( @@ -216,6 +218,7 @@ void testMdc() { .hasInstrumentationScope(InstrumentationScopeInfo.builder("abc").build()) .hasSeverity(Severity.INFO) .hasSeverityText("INFO") + .hasEventName("MyEventName") .hasAttributesSatisfyingExactly( equalTo(AttributeKey.stringKey("key1"), "val1"), equalTo(AttributeKey.stringKey("key2"), "val2"), diff --git a/instrumentation/log4j/log4j-appender-1.2/javaagent/README.md b/instrumentation/log4j/log4j-appender-1.2/javaagent/README.md index 24751c2aa966..8b8abb4deb7d 100644 --- a/instrumentation/log4j/log4j-appender-1.2/javaagent/README.md +++ b/instrumentation/log4j/log4j-appender-1.2/javaagent/README.md @@ -5,5 +5,6 @@ | `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-mdc-attributes` | String | | Comma separated list of context data attributes to capture. Use the wildcard character `*` to capture all attributes. | +| `otel.instrumentation.log4j-appender.experimental.capture-event-name` | Boolean | `false` | Enable moving the `event.name` attribute (captured by one of the other mechanisms of capturing attributes) to the log event name. | [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-1.2/javaagent/build.gradle.kts b/instrumentation/log4j/log4j-appender-1.2/javaagent/build.gradle.kts index f31453561e78..f126e1d06caa 100644 --- a/instrumentation/log4j/log4j-appender-1.2/javaagent/build.gradle.kts +++ b/instrumentation/log4j/log4j-appender-1.2/javaagent/build.gradle.kts @@ -35,7 +35,7 @@ tasks.withType().configureEach { // TODO run tests both with and without experimental log attributes jvmArgs("-Dotel.instrumentation.log4j-appender.experimental.capture-mdc-attributes=*") jvmArgs("-Dotel.instrumentation.log4j-appender.experimental.capture-code-attributes=true") - jvmArgs("-Dotel.instrumentation.log4j-appender.experimental-log-attributes=true") + jvmArgs("-Dotel.instrumentation.log4j-appender.experimental.capture-event-name=true") jvmArgs("-Dotel.instrumentation.log4j-appender.experimental-log-attributes=true") jvmArgs("-Dotel.instrumentation.common.experimental.controller-telemetry.enabled=true") } diff --git a/instrumentation/log4j/log4j-appender-1.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/log4j/appender/v1_2/LogEventMapper.java b/instrumentation/log4j/log4j-appender-1.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/log4j/appender/v1_2/LogEventMapper.java index 1f6966503fde..22c28ad19fbb 100644 --- a/instrumentation/log4j/log4j-appender-1.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/log4j/appender/v1_2/LogEventMapper.java +++ b/instrumentation/log4j/log4j-appender-1.2/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/log4j/appender/v1_2/LogEventMapper.java @@ -9,8 +9,6 @@ import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.common.AttributeKey; -import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.api.common.AttributesBuilder; import io.opentelemetry.api.incubator.logs.ExtendedLogRecordBuilder; import io.opentelemetry.api.logs.LogRecordBuilder; import io.opentelemetry.api.logs.Severity; @@ -44,6 +42,8 @@ public final class LogEventMapper { private static final AttributeKey CODE_LINENO = AttributeKey.longKey("code.lineno"); private static final AttributeKey CODE_NAMESPACE = AttributeKey.stringKey("code.namespace"); + // copied from EventIncubatingAttributes + private static final AttributeKey EVENT_NAME = AttributeKey.stringKey("event.name"); // copied from org.apache.log4j.Level because it was only introduced in 1.2.12 private static final int TRACE_INT = 5000; @@ -56,6 +56,10 @@ public final class LogEventMapper { // cached as an optimization private final boolean captureAllMdcAttributes; + private final boolean captureEventName = + AgentInstrumentationConfig.get() + .getBoolean("otel.instrumentation.log4j-appender.experimental.capture-event-name", false); + private LogEventMapper() { List captureMdcAttributes = AgentInstrumentationConfig.get() @@ -98,27 +102,25 @@ public void capture( builder.setSeverityText(level.toString()); } - AttributesBuilder attributes = Attributes.builder(); - // throwable if (throwable != null) { if (builder instanceof ExtendedLogRecordBuilder) { ((ExtendedLogRecordBuilder) builder).setException(throwable); } else { - attributes.put(ExceptionAttributes.EXCEPTION_TYPE, throwable.getClass().getName()); - attributes.put(ExceptionAttributes.EXCEPTION_MESSAGE, throwable.getMessage()); + builder.setAttribute(ExceptionAttributes.EXCEPTION_TYPE, throwable.getClass().getName()); + builder.setAttribute(ExceptionAttributes.EXCEPTION_MESSAGE, throwable.getMessage()); StringWriter writer = new StringWriter(); throwable.printStackTrace(new PrintWriter(writer)); - attributes.put(ExceptionAttributes.EXCEPTION_STACKTRACE, writer.toString()); + builder.setAttribute(ExceptionAttributes.EXCEPTION_STACKTRACE, writer.toString()); } } - captureMdcAttributes(attributes); + captureMdcAttributes(builder); if (captureExperimentalAttributes) { Thread currentThread = Thread.currentThread(); - attributes.put(ThreadIncubatingAttributes.THREAD_NAME, currentThread.getName()); - attributes.put(ThreadIncubatingAttributes.THREAD_ID, currentThread.getId()); + builder.setAttribute(ThreadIncubatingAttributes.THREAD_NAME, currentThread.getName()); + builder.setAttribute(ThreadIncubatingAttributes.THREAD_ID, currentThread.getId()); } if (captureCodeAttributes) { @@ -126,21 +128,21 @@ public void capture( String fileName = locationInfo.getFileName(); if (fileName != null) { if (SemconvStability.isEmitStableCodeSemconv()) { - attributes.put(CodeAttributes.CODE_FILE_PATH, fileName); + builder.setAttribute(CodeAttributes.CODE_FILE_PATH, fileName); } if (SemconvStability.isEmitOldCodeSemconv()) { - attributes.put(CODE_FILEPATH, fileName); + builder.setAttribute(CODE_FILEPATH, fileName); } } if (SemconvStability.isEmitStableCodeSemconv()) { - attributes.put( + builder.setAttribute( CodeAttributes.CODE_FUNCTION_NAME, locationInfo.getClassName() + "." + locationInfo.getMethodName()); } if (SemconvStability.isEmitOldCodeSemconv()) { - attributes.put(CODE_NAMESPACE, locationInfo.getClassName()); - attributes.put(CODE_FUNCTION, locationInfo.getMethodName()); + builder.setAttribute(CODE_NAMESPACE, locationInfo.getClassName()); + builder.setAttribute(CODE_FUNCTION, locationInfo.getMethodName()); } String lineNumber = locationInfo.getLineNumber(); @@ -154,16 +156,14 @@ public void capture( } if (codeLineNo >= 0) { if (SemconvStability.isEmitStableCodeSemconv()) { - attributes.put(CodeAttributes.CODE_LINE_NUMBER, codeLineNo); + builder.setAttribute(CodeAttributes.CODE_LINE_NUMBER, (long) codeLineNo); } if (SemconvStability.isEmitOldCodeSemconv()) { - attributes.put(CODE_LINENO, codeLineNo); + builder.setAttribute(CODE_LINENO, (long) codeLineNo); } } } - builder.setAllAttributes(attributes.build()); - // span context builder.setContext(Context.current()); @@ -171,15 +171,15 @@ public void capture( builder.emit(); } - private void captureMdcAttributes(AttributesBuilder attributes) { + private void captureMdcAttributes(LogRecordBuilder builder) { Hashtable context = MDC.getContext(); if (captureAllMdcAttributes) { if (context != null) { for (Map.Entry entry : context.entrySet()) { - attributes.put( - getMdcAttributeKey(String.valueOf(entry.getKey())), String.valueOf(entry.getValue())); + setAttributeOrEventName( + builder, getMdcAttributeKey(String.valueOf(entry.getKey())), entry.getValue()); } } return; @@ -187,9 +187,7 @@ private void captureMdcAttributes(AttributesBuilder attributes) { for (Map.Entry> entry : captureMdcAttributes.entrySet()) { Object value = context.get(entry.getKey()); - if (value != null) { - attributes.put(entry.getValue(), value.toString()); - } + setAttributeOrEventName(builder, entry.getValue(), value); } } @@ -197,6 +195,17 @@ private static AttributeKey getMdcAttributeKey(String key) { return mdcAttributeKeys.computeIfAbsent(key, AttributeKey::stringKey); } + private void setAttributeOrEventName( + LogRecordBuilder builder, AttributeKey key, Object value) { + if (value != null) { + if (captureEventName && key.equals(EVENT_NAME)) { + builder.setEventName(value.toString()); + } else { + builder.setAttribute(key, value.toString()); + } + } + } + private static Severity levelToSeverity(Priority level) { int lev = level.toInt(); if (lev <= TRACE_INT) { diff --git a/instrumentation/log4j/log4j-appender-1.2/javaagent/src/test/java/io/opentelemetry/instrumentation/log4j/appender/v1_2/Log4j1Test.java b/instrumentation/log4j/log4j-appender-1.2/javaagent/src/test/java/io/opentelemetry/instrumentation/log4j/appender/v1_2/Log4j1Test.java index b43d402e3c24..6f088c19d62a 100644 --- a/instrumentation/log4j/log4j-appender-1.2/javaagent/src/test/java/io/opentelemetry/instrumentation/log4j/appender/v1_2/Log4j1Test.java +++ b/instrumentation/log4j/log4j-appender-1.2/javaagent/src/test/java/io/opentelemetry/instrumentation/log4j/appender/v1_2/Log4j1Test.java @@ -176,11 +176,13 @@ private static void test( void testMdc() { MDC.put("key1", "val1"); MDC.put("key2", "val2"); + MDC.put("event.name", "MyEventName"); try { logger.info("xyz"); } finally { MDC.remove("key1"); MDC.remove("key2"); + MDC.remove("event.name"); } List assertions = @@ -195,6 +197,7 @@ void testMdc() { logRecord -> logRecord .hasBody("xyz") + .hasEventName("MyEventName") .hasInstrumentationScope(InstrumentationScopeInfo.builder("abc").build()) .hasSeverity(Severity.INFO) .hasSeverityText("INFO") diff --git a/instrumentation/log4j/log4j-appender-2.17/javaagent/README.md b/instrumentation/log4j/log4j-appender-2.17/javaagent/README.md index e3bf213d9498..eb3d5b3771d7 100644 --- a/instrumentation/log4j/log4j-appender-2.17/javaagent/README.md +++ b/instrumentation/log4j/log4j-appender-2.17/javaagent/README.md @@ -7,5 +7,6 @@ | `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. | +| `otel.instrumentation.log4j-appender.experimental.capture-event-name` | Boolean | `false` | Enable moving the `event.name` attribute (captured by one of the other mechanisms of capturing attributes) to the log event name. | [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/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 6fc308cc1dd9..ee35aaa184a4 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 @@ -52,6 +52,9 @@ public final class Log4jHelper { List captureContextDataAttributes = config.getList( "otel.instrumentation.log4j-appender.experimental.capture-mdc-attributes", emptyList()); + boolean captureEventName = + config.getBoolean( + "otel.instrumentation.log4j-appender.experimental.capture-event-name", false); mapper = new LogEventMapper<>( @@ -60,7 +63,8 @@ public final class Log4jHelper { captureCodeAttributes, captureMapMessageAttributes, captureMarkerAttribute, - captureContextDataAttributes); + captureContextDataAttributes, + captureEventName); } public static void capture( diff --git a/instrumentation/log4j/log4j-appender-2.17/library/README.md b/instrumentation/log4j/log4j-appender-2.17/library/README.md index 07bd37bba715..c51475b5b116 100644 --- a/instrumentation/log4j/log4j-appender-2.17/library/README.md +++ b/instrumentation/log4j/log4j-appender-2.17/library/README.md @@ -99,6 +99,7 @@ The available settings are: | `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. | +| `captureEventName` | Boolean | `false` | Enable moving the `event.name` attribute (captured by one of the other mechanisms of capturing attributes) to the log event name. | | `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/OpenTelemetryAppender.java b/instrumentation/log4j/log4j-appender-2.17/library/src/main/java/io/opentelemetry/instrumentation/log4j/appender/v2_17/OpenTelemetryAppender.java index ff980b3be35a..85eb7821ee92 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 @@ -101,6 +101,7 @@ public static class Builder> extends AbstractAppender.Build @PluginBuilderAttribute private boolean captureMapMessageAttributes; @PluginBuilderAttribute private boolean captureMarkerAttribute; @PluginBuilderAttribute private String captureContextDataAttributes; + @PluginBuilderAttribute private boolean captureEventName; @PluginBuilderAttribute private int numLogsCapturedBeforeOtelInstall; @Nullable private OpenTelemetry openTelemetry; @@ -155,6 +156,24 @@ public B setCaptureContextDataAttributes(String captureContextDataAttributes) { return asBuilder(); } + /** + * Sets whether the value of the {@code event.name} attribute is used as the log event name. + * + *

The {@code event.name} attribute is captured via any other mechanism supported by this + * appender, such as when {@code captureContextDataAttributes} includes {@code event.name}. + * + *

When {@code captureEventName} is true, then the value of the {@code event.name} attribute + * will be used as the log event name, and {@code event.name} attribute will be removed. + * + * @param captureEventName to enable or disable capturing the {@code event.name} attribute as + * the log event name + */ + @CanIgnoreReturnValue + public B setCaptureEventName(boolean captureEventName) { + this.captureEventName = captureEventName; + return asBuilder(); + } + /** * Log telemetry is emitted after the initialization of the OpenTelemetry Logback appender with * an {@link OpenTelemetry} object. This setting allows you to modify the size of the cache used @@ -188,6 +207,7 @@ public OpenTelemetryAppender build() { captureMapMessageAttributes, captureMarkerAttribute, captureContextDataAttributes, + captureEventName, numLogsCapturedBeforeOtelInstall, openTelemetry); } @@ -204,6 +224,7 @@ private OpenTelemetryAppender( boolean captureMapMessageAttributes, boolean captureMarkerAttribute, String captureContextDataAttributes, + boolean captureEventName, int numLogsCapturedBeforeOtelInstall, OpenTelemetry openTelemetry) { @@ -215,7 +236,8 @@ private OpenTelemetryAppender( captureCodeAttributes, captureMapMessageAttributes, captureMarkerAttribute, - splitAndFilterBlanksAndNulls(captureContextDataAttributes)); + splitAndFilterBlanksAndNulls(captureContextDataAttributes), + captureEventName); this.openTelemetry = openTelemetry; this.captureCodeAttributes = captureCodeAttributes; if (numLogsCapturedBeforeOtelInstall != 0) { 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 36ec63fcd186..6663107e1074 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 @@ -6,8 +6,6 @@ package io.opentelemetry.instrumentation.log4j.appender.v2_17.internal; import io.opentelemetry.api.common.AttributeKey; -import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.api.common.AttributesBuilder; import io.opentelemetry.api.incubator.logs.ExtendedLogRecordBuilder; import io.opentelemetry.api.logs.LogRecordBuilder; import io.opentelemetry.api.logs.Severity; @@ -42,6 +40,8 @@ public final class LogEventMapper { // copied from ThreadIncubatingAttributes private static final AttributeKey THREAD_ID = AttributeKey.longKey("thread.id"); private static final AttributeKey THREAD_NAME = AttributeKey.stringKey("thread.name"); + // copied from EventIncubatingAttributes + private static final AttributeKey EVENT_NAME = AttributeKey.stringKey("event.name"); private static final String SPECIAL_MAP_MESSAGE_ATTRIBUTE = "message"; @@ -60,6 +60,7 @@ public final class LogEventMapper { private final boolean captureMarkerAttribute; private final List captureContextDataAttributes; private final boolean captureAllContextDataAttributes; + private final boolean captureEventName; public LogEventMapper( ContextDataAccessor contextDataAccessor, @@ -67,7 +68,8 @@ public LogEventMapper( boolean captureCodeAttributes, boolean captureMapMessageAttributes, boolean captureMarkerAttribute, - List captureContextDataAttributes) { + List captureContextDataAttributes, + boolean captureEventName) { this.contextDataAccessor = contextDataAccessor; this.captureCodeAttributes = captureCodeAttributes; @@ -77,6 +79,7 @@ public LogEventMapper( this.captureContextDataAttributes = captureContextDataAttributes; this.captureAllContextDataAttributes = captureContextDataAttributes.size() == 1 && captureContextDataAttributes.get(0).equals("*"); + this.captureEventName = captureEventName; } /** @@ -101,14 +104,12 @@ public void mapLogEvent( Supplier sourceSupplier, Context context) { - AttributesBuilder attributes = Attributes.builder(); - - captureMessage(builder, attributes, message); + captureMessage(builder, message); if (captureMarkerAttribute) { if (marker != null) { String markerName = marker.getName(); - attributes.put(LOG_MARKER, markerName); + builder.setAttribute(LOG_MARKER, markerName); } } @@ -118,14 +119,14 @@ public void mapLogEvent( } if (throwable != null) { - setThrowable(builder, attributes, throwable); + setThrowable(builder, throwable); } - captureContextDataAttributes(attributes, contextData); + captureContextDataAttributes(builder, contextData); if (captureExperimentalAttributes) { - attributes.put(THREAD_NAME, threadName); - attributes.put(THREAD_ID, threadId); + builder.setAttribute(THREAD_NAME, threadName); + builder.setAttribute(THREAD_ID, threadId); } if (captureCodeAttributes) { @@ -134,40 +135,39 @@ public void mapLogEvent( String fileName = source.getFileName(); if (fileName != null) { if (SemconvStability.isEmitStableCodeSemconv()) { - attributes.put(CodeAttributes.CODE_FILE_PATH, fileName); + builder.setAttribute(CodeAttributes.CODE_FILE_PATH, fileName); } if (SemconvStability.isEmitOldCodeSemconv()) { - attributes.put(CODE_FILEPATH, fileName); + builder.setAttribute(CODE_FILEPATH, fileName); } } if (SemconvStability.isEmitStableCodeSemconv()) { - attributes.put( + builder.setAttribute( CodeAttributes.CODE_FUNCTION_NAME, source.getClassName() + "." + source.getMethodName()); } if (SemconvStability.isEmitOldCodeSemconv()) { - attributes.put(CODE_NAMESPACE, source.getClassName()); - attributes.put(CODE_FUNCTION, source.getMethodName()); + builder.setAttribute(CODE_NAMESPACE, source.getClassName()); + builder.setAttribute(CODE_FUNCTION, source.getMethodName()); } int lineNumber = source.getLineNumber(); if (lineNumber > 0) { if (SemconvStability.isEmitStableCodeSemconv()) { - attributes.put(CodeAttributes.CODE_LINE_NUMBER, lineNumber); + builder.setAttribute(CodeAttributes.CODE_LINE_NUMBER, (long) lineNumber); } if (SemconvStability.isEmitOldCodeSemconv()) { - attributes.put(CODE_LINENO, lineNumber); + builder.setAttribute(CODE_LINENO, (long) lineNumber); } } } } - builder.setAllAttributes(attributes.build()); builder.setContext(context); } // visible for testing - void captureMessage(LogRecordBuilder builder, AttributesBuilder attributes, Message message) { + void captureMessage(LogRecordBuilder builder, Message message) { if (message == null) { return; } @@ -197,30 +197,35 @@ void captureMessage(LogRecordBuilder builder, AttributesBuilder attributes, Mess if (value != null && (!checkSpecialMapMessageAttribute || !key.equals(SPECIAL_MAP_MESSAGE_ATTRIBUTE))) { - attributes.put(getMapMessageAttributeKey(key), value.toString()); + builder.setAttribute(getMapMessageAttributeKey(key), value.toString()); } }); } } // visible for testing - void captureContextDataAttributes(AttributesBuilder attributes, T contextData) { + void captureContextDataAttributes(LogRecordBuilder builder, T contextData) { if (captureAllContextDataAttributes) { contextDataAccessor.forEach( contextData, - (key, value) -> { - if (value != null) { - attributes.put(getContextDataAttributeKey(key), value); - } - }); + (key, value) -> setAttributeOrEventName(builder, getContextDataAttributeKey(key), value)); return; } for (String key : captureContextDataAttributes) { String value = contextDataAccessor.getValue(contextData, key); - if (value != null) { - attributes.put(getContextDataAttributeKey(key), value); + setAttributeOrEventName(builder, getContextDataAttributeKey(key), value); + } + } + + private void setAttributeOrEventName( + LogRecordBuilder builder, AttributeKey key, Object value) { + if (value != null) { + if (captureEventName && key.equals(EVENT_NAME)) { + builder.setEventName(value.toString()); + } else { + builder.setAttribute(key, value.toString()); } } } @@ -234,16 +239,15 @@ public static AttributeKey getMapMessageAttributeKey(String key) { key, k -> AttributeKey.stringKey("log4j.map_message." + k)); } - private static void setThrowable( - LogRecordBuilder builder, AttributesBuilder attributes, Throwable throwable) { + private static void setThrowable(LogRecordBuilder builder, Throwable throwable) { if (builder instanceof ExtendedLogRecordBuilder) { ((ExtendedLogRecordBuilder) builder).setException(throwable); } else { - attributes.put(ExceptionAttributes.EXCEPTION_TYPE, throwable.getClass().getName()); - attributes.put(ExceptionAttributes.EXCEPTION_MESSAGE, throwable.getMessage()); + builder.setAttribute(ExceptionAttributes.EXCEPTION_TYPE, throwable.getClass().getName()); + builder.setAttribute(ExceptionAttributes.EXCEPTION_MESSAGE, throwable.getMessage()); StringWriter writer = new StringWriter(); throwable.printStackTrace(new PrintWriter(writer)); - attributes.put(ExceptionAttributes.EXCEPTION_STACKTRACE, writer.toString()); + builder.setAttribute(ExceptionAttributes.EXCEPTION_STACKTRACE, writer.toString()); } } 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 9b51bf835faa..872f5dedc0f2 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 @@ -155,6 +155,7 @@ void logWithExtras() { void logContextData() { ThreadContext.put("key1", "val1"); ThreadContext.put("key2", "val2"); + ThreadContext.put("event.name", "MyEventName"); try { logger.info("log message 1"); } finally { @@ -170,6 +171,7 @@ void logContextData() { .hasResource(resource) .hasInstrumentationScope(instrumentationScopeInfo) .hasBody("log message 1") + .hasEventName("MyEventName") .hasAttributesSatisfyingExactly( addLocationAttributes( "logContextData", 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 ce374ff97b9b..4309848cf2a0 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 @@ -5,17 +5,16 @@ package io.opentelemetry.instrumentation.log4j.appender.v2_17.internal; -import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; -import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.attributeEntry; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; +import static org.mockito.Mockito.verifyNoMoreInteractions; -import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.api.common.AttributesBuilder; +import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.logs.LogRecordBuilder; import java.util.HashMap; import java.util.Map; @@ -32,17 +31,17 @@ void testDefault() { // given LogEventMapper> mapper = new LogEventMapper<>( - ContextDataAccessorImpl.INSTANCE, false, false, false, false, emptyList()); + ContextDataAccessorImpl.INSTANCE, false, false, false, false, emptyList(), false); Map contextData = new HashMap<>(); contextData.put("key1", "value1"); contextData.put("key2", "value2"); - AttributesBuilder attributes = Attributes.builder(); + LogRecordBuilder builder = mock(LogRecordBuilder.class); // when - mapper.captureContextDataAttributes(attributes, contextData); + mapper.captureContextDataAttributes(builder, contextData); // then - assertThat(attributes.build()).isEmpty(); + verifyNoInteractions(builder); } @Test @@ -50,17 +49,24 @@ void testSome() { // given LogEventMapper> mapper = new LogEventMapper<>( - ContextDataAccessorImpl.INSTANCE, false, false, false, false, singletonList("key2")); + ContextDataAccessorImpl.INSTANCE, + false, + false, + false, + false, + singletonList("key2"), + false); Map contextData = new HashMap<>(); contextData.put("key1", "value1"); contextData.put("key2", "value2"); - AttributesBuilder attributes = Attributes.builder(); + LogRecordBuilder builder = mock(LogRecordBuilder.class); // when - mapper.captureContextDataAttributes(attributes, contextData); + mapper.captureContextDataAttributes(builder, contextData); // then - assertThat(attributes.build()).containsOnly(attributeEntry("key2", "value2")); + verify(builder).setAttribute(AttributeKey.stringKey("key2"), "value2"); + verifyNoMoreInteractions(builder); } @Test @@ -68,18 +74,25 @@ void testAll() { // given LogEventMapper> mapper = new LogEventMapper<>( - ContextDataAccessorImpl.INSTANCE, false, false, false, false, singletonList("*")); + ContextDataAccessorImpl.INSTANCE, + false, + false, + false, + false, + singletonList("*"), + false); Map contextData = new HashMap<>(); contextData.put("key1", "value1"); contextData.put("key2", "value2"); - AttributesBuilder attributes = Attributes.builder(); + LogRecordBuilder builder = mock(LogRecordBuilder.class); // when - mapper.captureContextDataAttributes(attributes, contextData); + mapper.captureContextDataAttributes(builder, contextData); // then - assertThat(attributes.build()) - .containsOnly(attributeEntry("key1", "value1"), attributeEntry("key2", "value2")); + verify(builder).setAttribute(AttributeKey.stringKey("key1"), "value1"); + verify(builder).setAttribute(AttributeKey.stringKey("key2"), "value2"); + verifyNoMoreInteractions(builder); } @Test @@ -87,21 +100,26 @@ void testCaptureMapMessageDisabled() { // given LogEventMapper> mapper = new LogEventMapper<>( - ContextDataAccessorImpl.INSTANCE, false, false, false, false, singletonList("*")); + ContextDataAccessorImpl.INSTANCE, + false, + false, + false, + false, + singletonList("*"), + false); StringMapMessage message = new StringMapMessage(); message.put("key1", "value1"); message.put("message", "value2"); - LogRecordBuilder logRecordBuilder = mock(LogRecordBuilder.class); - AttributesBuilder attributes = Attributes.builder(); + LogRecordBuilder builder = mock(LogRecordBuilder.class); // when - mapper.captureMessage(logRecordBuilder, attributes, message); + mapper.captureMessage(builder, message); // then - verify(logRecordBuilder).setBody("value2"); - assertThat(attributes.build()).isEmpty(); + verify(builder).setBody("value2"); + verifyNoMoreInteractions(builder); } @Test @@ -109,21 +127,21 @@ void testCaptureMapMessageWithSpecialAttribute() { // given LogEventMapper> mapper = new LogEventMapper<>( - ContextDataAccessorImpl.INSTANCE, false, false, true, false, singletonList("*")); + ContextDataAccessorImpl.INSTANCE, false, false, true, false, singletonList("*"), false); StringMapMessage message = new StringMapMessage(); message.put("key1", "value1"); message.put("message", "value2"); - LogRecordBuilder logRecordBuilder = mock(LogRecordBuilder.class); - AttributesBuilder attributes = Attributes.builder(); + LogRecordBuilder builder = mock(LogRecordBuilder.class); // when - mapper.captureMessage(logRecordBuilder, attributes, message); + mapper.captureMessage(builder, message); // then - verify(logRecordBuilder).setBody("value2"); - assertThat(attributes.build()).containsOnly(attributeEntry("log4j.map_message.key1", "value1")); + verify(builder).setBody("value2"); + verify(builder).setAttribute(AttributeKey.stringKey("log4j.map_message.key1"), "value1"); + verifyNoMoreInteractions(builder); } @Test @@ -131,24 +149,22 @@ void testCaptureMapMessageWithoutSpecialAttribute() { // given LogEventMapper> mapper = new LogEventMapper<>( - ContextDataAccessorImpl.INSTANCE, false, false, true, false, singletonList("*")); + ContextDataAccessorImpl.INSTANCE, false, false, true, false, singletonList("*"), false); StringMapMessage message = new StringMapMessage(); message.put("key1", "value1"); message.put("key2", "value2"); - LogRecordBuilder logRecordBuilder = mock(LogRecordBuilder.class); - AttributesBuilder attributes = Attributes.builder(); + LogRecordBuilder builder = mock(LogRecordBuilder.class); // when - mapper.captureMessage(logRecordBuilder, attributes, message); + mapper.captureMessage(builder, message); // then - verify(logRecordBuilder, never()).setBody(anyString()); - assertThat(attributes.build()) - .containsOnly( - attributeEntry("log4j.map_message.key1", "value1"), - attributeEntry("log4j.map_message.key2", "value2")); + verify(builder, never()).setBody(anyString()); + verify(builder).setAttribute(AttributeKey.stringKey("log4j.map_message.key1"), "value1"); + verify(builder).setAttribute(AttributeKey.stringKey("log4j.map_message.key2"), "value2"); + verifyNoMoreInteractions(builder); } @Test @@ -156,24 +172,22 @@ void testCaptureStructuredDataMessage() { // given LogEventMapper> mapper = new LogEventMapper<>( - ContextDataAccessorImpl.INSTANCE, false, false, true, false, singletonList("*")); + ContextDataAccessorImpl.INSTANCE, false, false, true, false, singletonList("*"), false); StructuredDataMessage message = new StructuredDataMessage("an id", "a message", "a type"); message.put("key1", "value1"); message.put("message", "value2"); - LogRecordBuilder logRecordBuilder = mock(LogRecordBuilder.class); - AttributesBuilder attributes = Attributes.builder(); + LogRecordBuilder builder = mock(LogRecordBuilder.class); // when - mapper.captureMessage(logRecordBuilder, attributes, message); + mapper.captureMessage(builder, message); // then - verify(logRecordBuilder).setBody("a message"); - assertThat(attributes.build()) - .containsOnly( - attributeEntry("log4j.map_message.key1", "value1"), - attributeEntry("log4j.map_message.message", "value2")); + verify(builder).setBody("a message"); + verify(builder).setAttribute(AttributeKey.stringKey("log4j.map_message.key1"), "value1"); + verify(builder).setAttribute(AttributeKey.stringKey("log4j.map_message.message"), "value2"); + verifyNoMoreInteractions(builder); } private enum ContextDataAccessorImpl implements ContextDataAccessor> { 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 1953d256c0b7..ceb9351c5e81 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"/> - + diff --git a/instrumentation/logback/logback-appender-1.0/javaagent/README.md b/instrumentation/logback/logback-appender-1.0/javaagent/README.md index 581211cddb91..e83844e560db 100644 --- a/instrumentation/logback/logback-appender-1.0/javaagent/README.md +++ b/instrumentation/logback/logback-appender-1.0/javaagent/README.md @@ -10,5 +10,6 @@ | `otel.instrumentation.logback-appender.experimental.capture-arguments` | Boolean | `false` | Enable the capture of Logback logger arguments. | | `otel.instrumentation.logback-appender.experimental.capture-logstash-attributes` | Boolean | `false` | Enable the capture of Logstash attributes, supported are those added to logs via `Markers.append()`, `Markers.appendEntries()`, `Markers.appendArray()` and `Markers.appendRaw()` methods. | | `otel.instrumentation.logback-appender.experimental.capture-mdc-attributes` | String | | Comma separated list of MDC attributes to capture. Use the wildcard character `*` to capture all attributes. | +| `otel.instrumentation.logback-appender.experimental.capture-event-name` | Boolean | `false` | Enable moving the `event.name` attribute (captured by one of the other mechanisms of capturing attributes) to the log event name. | [source code attributes]: https://github.com/open-telemetry/semantic-conventions/blob/main/docs/general/attributes.md#source-code-attributes diff --git a/instrumentation/logback/logback-appender-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/logback/appender/v1_0/LogbackSingletons.java b/instrumentation/logback/logback-appender-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/logback/appender/v1_0/LogbackSingletons.java index 76a99383ec1b..7a5df143cf4e 100644 --- a/instrumentation/logback/logback-appender-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/logback/appender/v1_0/LogbackSingletons.java +++ b/instrumentation/logback/logback-appender-1.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/logback/appender/v1_0/LogbackSingletons.java @@ -47,6 +47,9 @@ public final class LogbackSingletons { config.getList( "otel.instrumentation.logback-appender.experimental.capture-mdc-attributes", emptyList()); + boolean captureEventName = + config.getBoolean( + "otel.instrumentation.logback-appender.experimental.capture-event-name", false); mapper = LoggingEventMapper.builder() @@ -58,6 +61,7 @@ public final class LogbackSingletons { .setCaptureLoggerContext(captureLoggerContext) .setCaptureArguments(captureArguments) .setCaptureLogstashAttributes(captureLogstashAttributes) + .setCaptureEventName(captureEventName) .build(); } diff --git a/instrumentation/logback/logback-appender-1.0/library/README.md b/instrumentation/logback/logback-appender-1.0/library/README.md index fe98849e6747..6de16a108ce5 100644 --- a/instrumentation/logback/logback-appender-1.0/library/README.md +++ b/instrumentation/logback/logback-appender-1.0/library/README.md @@ -103,6 +103,7 @@ The available settings are: | `captureArguments` | Boolean | `false` | Enable the capture of Logback logger arguments. | | `captureLogstashAttributes` | Boolean | `false` | Enable the capture of Logstash attributes, supported are those added to logs via `Markers.append()`, `Markers.appendEntries()`, `Markers.appendArray()` and `Markers.appendRaw()` methods. | | `captureMdcAttributes` | String | | Comma separated list of MDC attributes to capture. Use the wildcard character `*` to capture all attributes. | +| `captureEventName` | Boolean | `false` | Enable moving the `event.name` attribute (captured by one of the other mechanisms of capturing attributes) to the log event name. | | `numLogsCapturedBeforeOtelInstall` | Integer | 1000 | Log telemetry is emitted after the initialization of the OpenTelemetry Logback appender with an OpenTelemetry object. This setting allows you to modify the size of the cache used to replay the first logs. thread.id attribute is not captured. | diff --git a/instrumentation/logback/logback-appender-1.0/library/src/main/java/io/opentelemetry/instrumentation/logback/appender/v1_0/OpenTelemetryAppender.java b/instrumentation/logback/logback-appender-1.0/library/src/main/java/io/opentelemetry/instrumentation/logback/appender/v1_0/OpenTelemetryAppender.java index ede0a1ebe010..19dc01bf398a 100644 --- a/instrumentation/logback/logback-appender-1.0/library/src/main/java/io/opentelemetry/instrumentation/logback/appender/v1_0/OpenTelemetryAppender.java +++ b/instrumentation/logback/logback-appender-1.0/library/src/main/java/io/opentelemetry/instrumentation/logback/appender/v1_0/OpenTelemetryAppender.java @@ -38,6 +38,7 @@ public class OpenTelemetryAppender extends UnsynchronizedAppenderBase captureMdcAttributes = emptyList(); + private boolean captureEventName = false; private volatile OpenTelemetry openTelemetry; private LoggingEventMapper mapper; @@ -88,6 +89,7 @@ public void start() { .setCaptureLoggerContext(captureLoggerContext) .setCaptureArguments(captureArguments) .setCaptureLogstashAttributes(captureLogstashAttributes) + .setCaptureEventName(captureEventName) .build(); eventsToReplay = new ArrayBlockingQueue<>(numLogsCapturedBeforeOtelInstall); super.start(); @@ -200,6 +202,22 @@ public void setCaptureMdcAttributes(String attributes) { } } + /** + * Sets whether the value of the {@code event.name} attribute is used as the log event name. + * + *

The {@code event.name} attribute is captured via any other mechanism supported by this + * appender, such as when {@code captureKeyValuePairAttributes} is true. + * + *

When {@code captureEventName} is true, then the value of the {@code event.name} attribute + * will be used as the log event name, and {@code event.name} attribute will be removed. + * + * @param captureEventName to enable or disable capturing the {@code event.name} attribute as the + * log event name + */ + public void setCaptureEventName(boolean captureEventName) { + this.captureEventName = captureEventName; + } + /** * Log telemetry is emitted after the initialization of the OpenTelemetry Logback appender with an * {@link OpenTelemetry} object. This setting allows you to modify the size of the cache used to 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 0819c73a93d1..fe385550d305 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 @@ -15,8 +15,6 @@ import ch.qos.logback.classic.spi.ThrowableProxy; import com.google.errorprone.annotations.CanIgnoreReturnValue; import io.opentelemetry.api.common.AttributeKey; -import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.api.common.AttributesBuilder; import io.opentelemetry.api.incubator.logs.ExtendedLogRecordBuilder; import io.opentelemetry.api.logs.LogRecordBuilder; import io.opentelemetry.api.logs.LoggerProvider; @@ -33,6 +31,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -60,12 +59,13 @@ public final class LoggingEventMapper { // copied from ThreadIncubatingAttributes private static final AttributeKey THREAD_ID = AttributeKey.longKey("thread.id"); private static final AttributeKey THREAD_NAME = AttributeKey.stringKey("thread.name"); + // copied from EventIncubatingAttributes + private static final AttributeKey EVENT_NAME = AttributeKey.stringKey("event.name"); private static final boolean supportsInstant = supportsInstant(); private static final boolean supportsKeyValuePairs = supportsKeyValuePairs(); private static final boolean supportsMultipleMarkers = supportsMultipleMarkers(); private static final boolean supportsLogstashMarkers = supportsLogstashMarkers(); - private static final Cache> mdcAttributeKeys = Cache.bounded(100); private static final Cache> attributeKeys = Cache.bounded(100); private static final AttributeKey> LOG_MARKER = @@ -84,6 +84,7 @@ public final class LoggingEventMapper { private final boolean captureLoggerContext; private final boolean captureArguments; private final boolean captureLogstashAttributes; + private final boolean captureEventName; private LoggingEventMapper(Builder builder) { this.captureExperimentalAttributes = builder.captureExperimentalAttributes; @@ -96,6 +97,7 @@ private LoggingEventMapper(Builder builder) { this.captureLogstashAttributes = builder.captureLogstashAttributes; this.captureAllMdcAttributes = builder.captureMdcAttributes.size() == 1 && builder.captureMdcAttributes.get(0).equals("*"); + this.captureEventName = builder.captureEventName; } public static Builder builder() { @@ -137,8 +139,6 @@ private void mapLoggingEvent( builder.setSeverityText(level.levelStr); } - AttributesBuilder attributes = Attributes.builder(); - // throwable Object throwableProxy = loggingEvent.getThrowableProxy(); Throwable throwable = null; @@ -148,15 +148,15 @@ private void mapLoggingEvent( throwable = ((ThrowableProxy) throwableProxy).getThrowable(); } if (throwable != null) { - setThrowable(builder, attributes, throwable); + setThrowable(builder, throwable); } - captureMdcAttributes(attributes, loggingEvent.getMDCPropertyMap()); + captureMdcAttributes(builder, loggingEvent.getMDCPropertyMap()); if (captureExperimentalAttributes) { - attributes.put(THREAD_NAME, loggingEvent.getThreadName()); + builder.setAttribute(THREAD_NAME, loggingEvent.getThreadName()); if (threadId != -1) { - attributes.put(THREAD_ID, threadId); + builder.setAttribute(THREAD_ID, threadId); } } @@ -169,23 +169,23 @@ private void mapLoggingEvent( if (SemconvStability.isEmitOldCodeSemconv()) { if (fileName != null) { - attributes.put(CODE_FILEPATH, fileName); + builder.setAttribute(CODE_FILEPATH, fileName); } - attributes.put(CODE_NAMESPACE, firstStackElement.getClassName()); - attributes.put(CODE_FUNCTION, firstStackElement.getMethodName()); + builder.setAttribute(CODE_NAMESPACE, firstStackElement.getClassName()); + builder.setAttribute(CODE_FUNCTION, firstStackElement.getMethodName()); if (lineNumber > 0) { - attributes.put(CODE_LINENO, lineNumber); + builder.setAttribute(CODE_LINENO, (long) lineNumber); } } if (SemconvStability.isEmitStableCodeSemconv()) { if (fileName != null) { - attributes.put(CODE_FILE_PATH, fileName); + builder.setAttribute(CODE_FILE_PATH, fileName); } - attributes.put( + builder.setAttribute( CODE_FUNCTION_NAME, firstStackElement.getClassName() + "." + firstStackElement.getMethodName()); if (lineNumber > 0) { - attributes.put(CODE_LINE_NUMBER, lineNumber); + builder.setAttribute(CODE_LINE_NUMBER, (long) lineNumber); } } } @@ -193,29 +193,26 @@ private void mapLoggingEvent( if (captureMarkerAttribute) { boolean skipLogstashMarkers = supportsLogstashMarkers && captureLogstashAttributes; - captureMarkerAttribute(attributes, loggingEvent, skipLogstashMarkers); + captureMarkerAttribute(builder, loggingEvent, skipLogstashMarkers); } if (supportsKeyValuePairs && captureKeyValuePairAttributes) { - captureKeyValuePairAttributes(attributes, loggingEvent); + captureKeyValuePairAttributes(builder, loggingEvent); } if (captureLoggerContext) { - captureLoggerContext(attributes, loggingEvent.getLoggerContextVO().getPropertyMap()); + captureLoggerContext(builder, loggingEvent.getLoggerContextVO().getPropertyMap()); } if (captureArguments && loggingEvent.getArgumentArray() != null && loggingEvent.getArgumentArray().length > 0) { - captureArguments(attributes, loggingEvent.getMessage(), loggingEvent.getArgumentArray()); + captureArguments(builder, loggingEvent.getMessage(), loggingEvent.getArgumentArray()); } if (supportsLogstashMarkers && captureLogstashAttributes) { - captureLogstashAttributes(attributes, loggingEvent); + captureLogstashAttributes(builder, loggingEvent); } - - builder.setAllAttributes(attributes.build()); - // span context builder.setContext(Context.current()); } @@ -243,43 +240,36 @@ private static void setTimestampFromInstant( } // visible for testing - void captureMdcAttributes(AttributesBuilder attributes, Map mdcProperties) { + void captureMdcAttributes(LogRecordBuilder builder, Map mdcProperties) { if (captureAllMdcAttributes) { for (Map.Entry entry : mdcProperties.entrySet()) { - attributes.put(getMdcAttributeKey(entry.getKey()), entry.getValue()); + setAttributeOrEventName(builder, getAttributeKey(entry.getKey()), entry.getValue()); } return; } for (String key : captureMdcAttributes) { String value = mdcProperties.get(key); - if (value != null) { - attributes.put(getMdcAttributeKey(key), value); - } + setAttributeOrEventName(builder, getAttributeKey(key), value); } } - void captureArguments(AttributesBuilder attributes, String message, Object[] arguments) { - attributes.put(LOG_BODY_TEMPLATE, message); - attributes.put( + void captureArguments(LogRecordBuilder builder, String message, Object[] arguments) { + builder.setAttribute(LOG_BODY_TEMPLATE, message); + builder.setAttribute( LOG_BODY_PARAMETERS, Arrays.stream(arguments).map(String::valueOf).collect(Collectors.toList())); } - public static AttributeKey getMdcAttributeKey(String key) { - return mdcAttributeKeys.computeIfAbsent(key, AttributeKey::stringKey); - } - - private static void setThrowable( - LogRecordBuilder builder, AttributesBuilder attributes, Throwable throwable) { + private static void setThrowable(LogRecordBuilder builder, Throwable throwable) { if (builder instanceof ExtendedLogRecordBuilder) { ((ExtendedLogRecordBuilder) builder).setException(throwable); } else { - attributes.put(ExceptionAttributes.EXCEPTION_TYPE, throwable.getClass().getName()); - attributes.put(ExceptionAttributes.EXCEPTION_MESSAGE, throwable.getMessage()); + builder.setAttribute(ExceptionAttributes.EXCEPTION_TYPE, throwable.getClass().getName()); + builder.setAttribute(ExceptionAttributes.EXCEPTION_MESSAGE, throwable.getMessage()); StringWriter writer = new StringWriter(); throwable.printStackTrace(new PrintWriter(writer)); - attributes.put(ExceptionAttributes.EXCEPTION_STACKTRACE, writer.toString()); + builder.setAttribute(ExceptionAttributes.EXCEPTION_STACKTRACE, writer.toString()); } } @@ -303,35 +293,35 @@ private static Severity levelToSeverity(Level level) { } @NoMuzzle - private static void captureKeyValuePairAttributes( - AttributesBuilder attributes, ILoggingEvent loggingEvent) { + private void captureKeyValuePairAttributes(LogRecordBuilder builder, ILoggingEvent loggingEvent) { List keyValuePairs = loggingEvent.getKeyValuePairs(); if (keyValuePairs != null) { for (KeyValuePair keyValuePair : keyValuePairs) { - captureAttribute(attributes, keyValuePair.key, keyValuePair.value); + captureAttribute(builder, this.captureEventName, keyValuePair.key, keyValuePair.value); } } } // visible for testing - static void captureAttribute(AttributesBuilder attributes, Object key, Object value) { + static void captureAttribute( + LogRecordBuilder builder, boolean captureEventName, Object key, Object value) { // empty values are not serialized if (key != null && value != null) { String keyStr = key.toString(); // preserve type for boolean and numeric values, everything else is converted to String if (value instanceof Boolean) { - attributes.put(keyStr, (Boolean) value); + builder.setAttribute(keyStr, (Boolean) value); } else if (value instanceof Byte || value instanceof Integer || value instanceof Long || value instanceof Short) { - attributes.put(keyStr, ((Number) value).longValue()); + builder.setAttribute(keyStr, ((Number) value).longValue()); } else if (value instanceof Double || value instanceof Float) { - attributes.put(keyStr, ((Number) value).doubleValue()); + builder.setAttribute(keyStr, ((Number) value).doubleValue()); } else if (value.getClass().isArray()) { if (value instanceof boolean[] || value instanceof Boolean[]) { captureArrayValueAttribute( - attributes, AttributeKey.booleanArrayKey(keyStr), value, o -> (Boolean) o); + builder, AttributeKey.booleanArrayKey(keyStr), value, o -> (Boolean) o); } else if (value instanceof byte[] || value instanceof Byte[] || value instanceof int[] @@ -341,34 +331,47 @@ static void captureAttribute(AttributesBuilder attributes, Object key, Object va || value instanceof short[] || value instanceof Short[]) { captureArrayValueAttribute( - attributes, AttributeKey.longArrayKey(keyStr), value, o -> ((Number) o).longValue()); + builder, AttributeKey.longArrayKey(keyStr), value, o -> ((Number) o).longValue()); } else if (value instanceof float[] || value instanceof Float[] || value instanceof double[] || value instanceof Double[]) { captureArrayValueAttribute( - attributes, - AttributeKey.doubleArrayKey(keyStr), - value, - o -> ((Number) o).doubleValue()); + builder, AttributeKey.doubleArrayKey(keyStr), value, o -> ((Number) o).doubleValue()); } else { captureArrayValueAttribute( - attributes, AttributeKey.stringArrayKey(keyStr), value, String::valueOf); + builder, AttributeKey.stringArrayKey(keyStr), value, String::valueOf); } } else if (value instanceof Collection) { captureArrayValueAttribute( - attributes, + builder, AttributeKey.stringArrayKey(keyStr), ((Collection) value).toArray(), String::valueOf); } else { - attributes.put(getAttributeKey(keyStr), String.valueOf(value)); + setAttributeOrEventName(builder, captureEventName, getAttributeKey(keyStr), value); + } + } + } + + private void setAttributeOrEventName( + LogRecordBuilder builder, AttributeKey key, Object value) { + setAttributeOrEventName(builder, this.captureEventName, key, value); + } + + private static void setAttributeOrEventName( + LogRecordBuilder builder, boolean captureEventName, AttributeKey key, Object value) { + if (value != null) { + if (captureEventName && key.equals(EVENT_NAME)) { + builder.setEventName(value.toString()); + } else { + builder.setAttribute(key, value.toString()); } } } private static void captureArrayValueAttribute( - AttributesBuilder attributes, + LogRecordBuilder builder, AttributeKey> key, Object array, Function extractor) { @@ -382,14 +385,14 @@ private static void captureArrayValueAttribute( } // empty lists are not serialized if (!list.isEmpty()) { - attributes.put(key, list); + builder.setAttribute(key, list); } } - private static void captureLoggerContext( - AttributesBuilder attributes, Map loggerContextProperties) { + private void captureLoggerContext( + LogRecordBuilder builder, Map loggerContextProperties) { for (Map.Entry entry : loggerContextProperties.entrySet()) { - attributes.put(getAttributeKey(entry.getKey()), entry.getValue()); + setAttributeOrEventName(builder, getAttributeKey(entry.getKey()), entry.getValue()); } } @@ -413,26 +416,26 @@ private static boolean supportsKeyValuePairs() { } private static void captureMarkerAttribute( - AttributesBuilder attributes, ILoggingEvent loggingEvent, boolean skipLogstashMarkers) { + LogRecordBuilder builder, ILoggingEvent loggingEvent, boolean skipLogstashMarkers) { if (supportsMultipleMarkers && hasMultipleMarkers(loggingEvent)) { - captureMultipleMarkerAttributes(attributes, loggingEvent, skipLogstashMarkers); + captureMultipleMarkerAttributes(builder, loggingEvent, skipLogstashMarkers); } else { - captureSingleMarkerAttribute(attributes, loggingEvent, skipLogstashMarkers); + captureSingleMarkerAttribute(builder, loggingEvent, skipLogstashMarkers); } } @SuppressWarnings("deprecation") // getMarker is deprecate since 1.3.0 private static void captureSingleMarkerAttribute( - AttributesBuilder attributes, ILoggingEvent loggingEvent, boolean skipLogstashMarkers) { + LogRecordBuilder builder, ILoggingEvent loggingEvent, boolean skipLogstashMarkers) { Marker marker = loggingEvent.getMarker(); if (marker != null && (!skipLogstashMarkers || !isLogstashMarker(marker))) { - attributes.put(LOG_MARKER, marker.getName()); + builder.setAttribute(LOG_MARKER, Collections.singletonList(marker.getName())); } } @NoMuzzle private static void captureMultipleMarkerAttributes( - AttributesBuilder attributes, ILoggingEvent loggingEvent, boolean skipLogstashMarkers) { + LogRecordBuilder builder, ILoggingEvent loggingEvent, boolean skipLogstashMarkers) { List markerNames = new ArrayList<>(loggingEvent.getMarkerList().size()); for (Marker marker : loggingEvent.getMarkerList()) { if (!skipLogstashMarkers || !isLogstashMarker(marker)) { @@ -440,7 +443,7 @@ private static void captureMultipleMarkerAttributes( } } if (!markerNames.isEmpty()) { - attributes.put(LOG_MARKER, markerNames.toArray(new String[0])); + builder.setAttribute(LOG_MARKER, markerNames); } } @@ -460,12 +463,11 @@ private static boolean supportsMultipleMarkers() { return true; } - private static void captureLogstashAttributes( - AttributesBuilder attributes, ILoggingEvent loggingEvent) { + private void captureLogstashAttributes(LogRecordBuilder builder, ILoggingEvent loggingEvent) { if (supportsMultipleMarkers && hasMultipleMarkers(loggingEvent)) { - captureMultipleLogstashAttributes(attributes, loggingEvent); + captureMultipleLogstashAttributes(builder, loggingEvent); } else { - captureSingleLogstashAttribute(attributes, loggingEvent); + captureSingleLogstashAttribute(builder, loggingEvent); } } @@ -475,44 +477,43 @@ private static boolean isLogstashMarker(Marker marker) { } @SuppressWarnings("deprecation") // getMarker is deprecate since 1.3.0 - private static void captureSingleLogstashAttribute( - AttributesBuilder attributes, ILoggingEvent loggingEvent) { + private void captureSingleLogstashAttribute( + LogRecordBuilder builder, ILoggingEvent loggingEvent) { Marker marker = loggingEvent.getMarker(); if (isLogstashMarker(marker)) { - captureLogstashMarker(attributes, marker); + captureLogstashMarker(builder, marker); } } @NoMuzzle - private static void captureMultipleLogstashAttributes( - AttributesBuilder attributes, ILoggingEvent loggingEvent) { + private void captureMultipleLogstashAttributes( + LogRecordBuilder builder, ILoggingEvent loggingEvent) { for (Marker marker : loggingEvent.getMarkerList()) { if (isLogstashMarker(marker)) { - captureLogstashMarker(attributes, marker); + captureLogstashMarker(builder, marker); } } } @NoMuzzle - private static void captureLogstashMarker(AttributesBuilder attributes, Marker marker) { + private void captureLogstashMarker(LogRecordBuilder builder, Marker marker) { LogstashMarker logstashMarker = (LogstashMarker) marker; - captureLogstashMarkerAttributes(attributes, logstashMarker); + captureLogstashMarkerAttributes(builder, logstashMarker); if (logstashMarker.hasReferences()) { for (Iterator it = logstashMarker.iterator(); it.hasNext(); ) { Marker referenceMarker = it.next(); if (isLogstashMarker(referenceMarker)) { - captureLogstashMarker(attributes, referenceMarker); + captureLogstashMarker(builder, referenceMarker); } } } } - private static void captureLogstashMarkerAttributes( - AttributesBuilder attributes, Object logstashMarker) { + private void captureLogstashMarkerAttributes(LogRecordBuilder builder, Object logstashMarker) { FieldReader fieldReader = LogstashFieldReaderHolder.valueField.get(logstashMarker.getClass()); if (fieldReader != null) { - fieldReader.read(attributes, logstashMarker); + fieldReader.read(builder, logstashMarker, this.captureEventName); } } @@ -551,10 +552,10 @@ private static FieldReader createStringReader(Field field) { if (field == null) { return null; } - return (attributes, logstashMarker) -> { + return (builder, logstashMarker, captureEventName) -> { String fieldName = getSingleFieldAppendingMarkerName(logstashMarker); Object fieldValue = extractFieldValue(field, logstashMarker); - captureAttribute(attributes, fieldName, fieldValue); + captureAttribute(builder, captureEventName, fieldName, fieldValue); }; } @@ -563,14 +564,14 @@ private static FieldReader createMapReader(Field field) { if (field == null) { return null; } - return (attributes, logstashMarker) -> { + return (attributes, logstashMarker, captureEventName) -> { Object fieldValue = extractFieldValue(field, logstashMarker); if (fieldValue instanceof Map) { Map map = (Map) fieldValue; for (Map.Entry entry : map.entrySet()) { Object key = entry.getKey(); Object value = entry.getValue(); - captureAttribute(attributes, key, value); + captureAttribute(attributes, captureEventName, key, value); } } }; @@ -615,7 +616,7 @@ private static boolean supportsLogstashMarkers() { } private interface FieldReader { - void read(AttributesBuilder attributes, Object logstashMarker); + void read(LogRecordBuilder builder, Object logstashMarker, boolean captureEventName); } private static class LogstashFieldReaderHolder { @@ -642,6 +643,7 @@ public static final class Builder { private boolean captureLoggerContext; private boolean captureArguments; private boolean captureLogstashAttributes; + private boolean captureEventName; Builder() {} @@ -693,6 +695,12 @@ public Builder setCaptureLogstashAttributes(boolean captureLogstashAttributes) { return this; } + @CanIgnoreReturnValue + public Builder setCaptureEventName(boolean captureEventName) { + this.captureEventName = captureEventName; + return this; + } + public LoggingEventMapper build() { return new LoggingEventMapper(this); } diff --git a/instrumentation/logback/logback-appender-1.0/library/src/slf4j2ApiTest/java/io/opentelemetry/instrumentation/logback/appender/v1_0/Slf4j2Test.java b/instrumentation/logback/logback-appender-1.0/library/src/slf4j2ApiTest/java/io/opentelemetry/instrumentation/logback/appender/v1_0/Slf4j2Test.java index a71e8460193b..a8ae2ab74fde 100644 --- a/instrumentation/logback/logback-appender-1.0/library/src/slf4j2ApiTest/java/io/opentelemetry/instrumentation/logback/appender/v1_0/Slf4j2Test.java +++ b/instrumentation/logback/logback-appender-1.0/library/src/slf4j2ApiTest/java/io/opentelemetry/instrumentation/logback/appender/v1_0/Slf4j2Test.java @@ -54,6 +54,7 @@ void keyValue() { .addKeyValue("long key", 4L) .addKeyValue("float key", 5.0f) .addKeyValue("double key", 6.0) + .addKeyValue("event.name", "MyEventName") .log(); testing.waitAndAssertLogRecords( @@ -63,6 +64,7 @@ void keyValue() { .hasInstrumentationScope(instrumentationScopeInfo) .hasBody("log message 1") .hasTotalAttributeCount(codeAttributesLogCount() + 8) // 8 key value pairs + .hasEventName("MyEventName") .hasAttributesSatisfying( equalTo(AttributeKey.stringKey("string key"), "string value"), equalTo(AttributeKey.booleanKey("boolean key"), true), @@ -140,6 +142,7 @@ void logstash() { .atInfo() .setMessage("log message 1") .addMarker(Markers.append("field1", "value1")) + .addMarker(Markers.append("event.name", "MyEventName")) .addMarker(Markers.appendEntries(entries)) .log(); @@ -150,6 +153,7 @@ void logstash() { .hasInstrumentationScope(instrumentationScopeInfo) .hasBody("log message 1") .hasTotalAttributeCount(codeAttributesLogCount() + 3) // 3 markers + .hasEventName("MyEventName") .hasAttributesSatisfying( equalTo(AttributeKey.stringKey("field1"), "value1"), equalTo(AttributeKey.longKey("field2"), 2L), diff --git a/instrumentation/logback/logback-appender-1.0/library/src/slf4j2ApiTest/resources/logback-test.xml b/instrumentation/logback/logback-appender-1.0/library/src/slf4j2ApiTest/resources/logback-test.xml index aa3a4517bd73..60a3589281bf 100644 --- a/instrumentation/logback/logback-appender-1.0/library/src/slf4j2ApiTest/resources/logback-test.xml +++ b/instrumentation/logback/logback-appender-1.0/library/src/slf4j2ApiTest/resources/logback-test.xml @@ -17,6 +17,7 @@ true true * + true diff --git a/instrumentation/logback/logback-appender-1.0/library/src/test/java/io/opentelemetry/instrumentation/logback/appender/v1_0/AbstractOpenTelemetryAppenderTest.java b/instrumentation/logback/logback-appender-1.0/library/src/test/java/io/opentelemetry/instrumentation/logback/appender/v1_0/AbstractOpenTelemetryAppenderTest.java index ca91e1cb4744..08dbec0f075d 100644 --- a/instrumentation/logback/logback-appender-1.0/library/src/test/java/io/opentelemetry/instrumentation/logback/appender/v1_0/AbstractOpenTelemetryAppenderTest.java +++ b/instrumentation/logback/logback-appender-1.0/library/src/test/java/io/opentelemetry/instrumentation/logback/appender/v1_0/AbstractOpenTelemetryAppenderTest.java @@ -142,6 +142,7 @@ void logWithExtras() { void logContextData() { MDC.put("key1", "val1"); MDC.put("key2", "val2"); + MDC.put("event.name", "MyEventName"); try { logger.info("log message 1"); } finally { @@ -158,6 +159,7 @@ void logContextData() { .hasInstrumentationScope(instrumentationScopeInfo) .hasBody("log message 1") .hasTotalAttributeCount(2 + codeAttributesLogCount()) // code attributes + .hasEventName("MyEventName") .hasAttributesSatisfying( equalTo(AttributeKey.stringKey("key1"), "val1"), equalTo(AttributeKey.stringKey("key2"), "val2"))); diff --git a/instrumentation/logback/logback-appender-1.0/library/src/test/java/io/opentelemetry/instrumentation/logback/appender/v1_0/internal/LoggingEventMapperTest.java b/instrumentation/logback/logback-appender-1.0/library/src/test/java/io/opentelemetry/instrumentation/logback/appender/v1_0/internal/LoggingEventMapperTest.java index 2a1ec8e0d96f..072f348add64 100644 --- a/instrumentation/logback/logback-appender-1.0/library/src/test/java/io/opentelemetry/instrumentation/logback/appender/v1_0/internal/LoggingEventMapperTest.java +++ b/instrumentation/logback/logback-appender-1.0/library/src/test/java/io/opentelemetry/instrumentation/logback/appender/v1_0/internal/LoggingEventMapperTest.java @@ -5,13 +5,14 @@ package io.opentelemetry.instrumentation.logback.appender.v1_0.internal; -import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; import static java.util.Collections.singletonList; -import static org.assertj.core.api.Assertions.entry; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; +import static org.mockito.Mockito.verifyNoMoreInteractions; import io.opentelemetry.api.common.AttributeKey; -import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.api.common.AttributesBuilder; +import io.opentelemetry.api.logs.LogRecordBuilder; import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -26,13 +27,13 @@ void testDefault() { Map contextData = new HashMap<>(); contextData.put("key1", "value1"); contextData.put("key2", "value2"); - AttributesBuilder attributes = Attributes.builder(); + LogRecordBuilder builder = mock(LogRecordBuilder.class); // when - mapper.captureMdcAttributes(attributes, contextData); + mapper.captureMdcAttributes(builder, contextData); // then - assertThat(attributes.build()).isEmpty(); + verifyNoInteractions(builder); } @Test @@ -43,13 +44,14 @@ void testSome() { Map contextData = new HashMap<>(); contextData.put("key1", "value1"); contextData.put("key2", "value2"); - AttributesBuilder attributes = Attributes.builder(); + LogRecordBuilder builder = mock(LogRecordBuilder.class); // when - mapper.captureMdcAttributes(attributes, contextData); + mapper.captureMdcAttributes(builder, contextData); // then - assertThat(attributes.build()).containsOnly(entry(AttributeKey.stringKey("key2"), "value2")); + verify(builder).setAttribute(AttributeKey.stringKey("key2"), "value2"); + verifyNoMoreInteractions(builder); } @Test @@ -60,65 +62,63 @@ void testAll() { Map contextData = new HashMap<>(); contextData.put("key1", "value1"); contextData.put("key2", "value2"); - AttributesBuilder attributes = Attributes.builder(); + LogRecordBuilder builder = mock(LogRecordBuilder.class); // when - mapper.captureMdcAttributes(attributes, contextData); + mapper.captureMdcAttributes(builder, contextData); // then - assertThat(attributes.build()) - .containsOnly( - entry(AttributeKey.stringKey("key1"), "value1"), - entry(AttributeKey.stringKey("key2"), "value2")); + verify(builder).setAttribute(AttributeKey.stringKey("key1"), "value1"); + verify(builder).setAttribute(AttributeKey.stringKey("key2"), "value2"); + verifyNoMoreInteractions(builder); } @Test void testCaptureAttributeArray() { - AttributesBuilder builder = Attributes.builder(); - - LoggingEventMapper.captureAttribute(builder, "booleanArray", new boolean[] {true}); - LoggingEventMapper.captureAttribute(builder, "BooleanArray", new Boolean[] {true}); - - LoggingEventMapper.captureAttribute(builder, "byteArray", new byte[] {2}); - LoggingEventMapper.captureAttribute(builder, "ByteArray", new Byte[] {2}); - - LoggingEventMapper.captureAttribute(builder, "shortArray", new short[] {2}); - LoggingEventMapper.captureAttribute(builder, "ShortArray", new Short[] {2}); - - LoggingEventMapper.captureAttribute(builder, "intArray", new int[] {2}); - LoggingEventMapper.captureAttribute(builder, "IntegerArray", new Integer[] {2}); - - LoggingEventMapper.captureAttribute(builder, "longArray", new long[] {2}); - LoggingEventMapper.captureAttribute(builder, "LongArray", new Long[] {2L}); - - LoggingEventMapper.captureAttribute(builder, "floatArray", new float[] {2.0f}); - LoggingEventMapper.captureAttribute(builder, "FloatArray", new Float[] {2.0f}); - - LoggingEventMapper.captureAttribute(builder, "doubleArray", new double[] {2.0}); - LoggingEventMapper.captureAttribute(builder, "DoubleArray", new Double[] {2.0}); - - LoggingEventMapper.captureAttribute(builder, "ObjectArray", new Object[] {"test"}); - LoggingEventMapper.captureAttribute(builder, "List", Collections.singletonList("test")); - LoggingEventMapper.captureAttribute(builder, "Set", Collections.singleton("test")); - - assertThat(builder.build()) - .containsOnly( - entry(AttributeKey.booleanArrayKey("booleanArray"), singletonList(true)), - entry(AttributeKey.booleanArrayKey("BooleanArray"), singletonList(true)), - entry(AttributeKey.longArrayKey("byteArray"), singletonList(2L)), - entry(AttributeKey.longArrayKey("ByteArray"), singletonList(2L)), - entry(AttributeKey.longArrayKey("shortArray"), singletonList(2L)), - entry(AttributeKey.longArrayKey("ShortArray"), singletonList(2L)), - entry(AttributeKey.longArrayKey("intArray"), singletonList(2L)), - entry(AttributeKey.longArrayKey("IntegerArray"), singletonList(2L)), - entry(AttributeKey.longArrayKey("longArray"), singletonList(2L)), - entry(AttributeKey.longArrayKey("LongArray"), singletonList(2L)), - entry(AttributeKey.doubleArrayKey("floatArray"), singletonList(2.0)), - entry(AttributeKey.doubleArrayKey("FloatArray"), singletonList(2.0)), - entry(AttributeKey.doubleArrayKey("doubleArray"), singletonList(2.0)), - entry(AttributeKey.doubleArrayKey("DoubleArray"), singletonList(2.0)), - entry(AttributeKey.stringArrayKey("ObjectArray"), singletonList("test")), - entry(AttributeKey.stringArrayKey("List"), singletonList("test")), - entry(AttributeKey.stringArrayKey("Set"), singletonList("test"))); + LogRecordBuilder builder = mock(LogRecordBuilder.class); + + LoggingEventMapper.captureAttribute(builder, false, "booleanArray", new boolean[] {true}); + LoggingEventMapper.captureAttribute(builder, false, "BooleanArray", new Boolean[] {true}); + + LoggingEventMapper.captureAttribute(builder, false, "byteArray", new byte[] {2}); + LoggingEventMapper.captureAttribute(builder, false, "ByteArray", new Byte[] {2}); + + LoggingEventMapper.captureAttribute(builder, false, "shortArray", new short[] {2}); + LoggingEventMapper.captureAttribute(builder, false, "ShortArray", new Short[] {2}); + + LoggingEventMapper.captureAttribute(builder, false, "intArray", new int[] {2}); + LoggingEventMapper.captureAttribute(builder, false, "IntegerArray", new Integer[] {2}); + + LoggingEventMapper.captureAttribute(builder, false, "longArray", new long[] {2}); + LoggingEventMapper.captureAttribute(builder, false, "LongArray", new Long[] {2L}); + + LoggingEventMapper.captureAttribute(builder, false, "floatArray", new float[] {2.0f}); + LoggingEventMapper.captureAttribute(builder, false, "FloatArray", new Float[] {2.0f}); + + LoggingEventMapper.captureAttribute(builder, false, "doubleArray", new double[] {2.0}); + LoggingEventMapper.captureAttribute(builder, false, "DoubleArray", new Double[] {2.0}); + + LoggingEventMapper.captureAttribute(builder, false, "ObjectArray", new Object[] {"test"}); + LoggingEventMapper.captureAttribute(builder, false, "List", Collections.singletonList("test")); + LoggingEventMapper.captureAttribute(builder, false, "Set", Collections.singleton("test")); + + verify(builder).setAttribute(AttributeKey.booleanArrayKey("booleanArray"), singletonList(true)); + verify(builder).setAttribute(AttributeKey.booleanArrayKey("BooleanArray"), singletonList(true)); + verify(builder).setAttribute(AttributeKey.longArrayKey("byteArray"), singletonList(2L)); + verify(builder).setAttribute(AttributeKey.longArrayKey("ByteArray"), singletonList(2L)); + verify(builder).setAttribute(AttributeKey.longArrayKey("shortArray"), singletonList(2L)); + verify(builder).setAttribute(AttributeKey.longArrayKey("ShortArray"), singletonList(2L)); + verify(builder).setAttribute(AttributeKey.longArrayKey("intArray"), singletonList(2L)); + verify(builder).setAttribute(AttributeKey.longArrayKey("IntegerArray"), singletonList(2L)); + verify(builder).setAttribute(AttributeKey.longArrayKey("longArray"), singletonList(2L)); + verify(builder).setAttribute(AttributeKey.longArrayKey("LongArray"), singletonList(2L)); + verify(builder).setAttribute(AttributeKey.doubleArrayKey("floatArray"), singletonList(2.0)); + verify(builder).setAttribute(AttributeKey.doubleArrayKey("FloatArray"), singletonList(2.0)); + verify(builder).setAttribute(AttributeKey.doubleArrayKey("doubleArray"), singletonList(2.0)); + verify(builder).setAttribute(AttributeKey.doubleArrayKey("DoubleArray"), singletonList(2.0)); + verify(builder).setAttribute(AttributeKey.stringArrayKey("ObjectArray"), singletonList("test")); + verify(builder).setAttribute(AttributeKey.stringArrayKey("List"), singletonList("test")); + verify(builder).setAttribute(AttributeKey.stringArrayKey("Set"), singletonList("test")); + verifyNoMoreInteractions(builder); } } diff --git a/instrumentation/logback/logback-appender-1.0/library/src/test/resources/logback-test.xml b/instrumentation/logback/logback-appender-1.0/library/src/test/resources/logback-test.xml index 7bc078e69050..bf0d82349833 100644 --- a/instrumentation/logback/logback-appender-1.0/library/src/test/resources/logback-test.xml +++ b/instrumentation/logback/logback-appender-1.0/library/src/test/resources/logback-test.xml @@ -16,6 +16,7 @@ true * 1 + true