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 50c0a2999c9e..1187c775ff3c 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,7 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS; import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Value; import io.opentelemetry.api.logs.Severity; import io.opentelemetry.api.trace.SpanContext; import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension; @@ -173,7 +174,7 @@ void testStringMapMessage() { testing.waitAndAssertLogRecords( logRecord -> logRecord - .hasBody("") + .hasBody((Value) null) .hasInstrumentationScope(InstrumentationScopeInfo.builder("abc").build()) .hasSeverity(Severity.INFO) .hasSeverityText("INFO") diff --git a/instrumentation/opentelemetry-api/opentelemetry-api-1.27/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_27/ApplicationOpenTelemetry127.java b/instrumentation/opentelemetry-api/opentelemetry-api-1.27/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_27/ApplicationOpenTelemetry127.java index 148e3e7d9000..51d4d1f49c55 100644 --- a/instrumentation/opentelemetry-api/opentelemetry-api-1.27/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_27/ApplicationOpenTelemetry127.java +++ b/instrumentation/opentelemetry-api/opentelemetry-api-1.27/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_27/ApplicationOpenTelemetry127.java @@ -14,6 +14,8 @@ import io.opentelemetry.javaagent.instrumentation.opentelemetryapi.v1_10.metrics.ApplicationMeterFactory; import io.opentelemetry.javaagent.instrumentation.opentelemetryapi.v1_10.metrics.ApplicationMeterProvider; import io.opentelemetry.javaagent.instrumentation.opentelemetryapi.v1_15.metrics.ApplicationMeterFactory115; +import io.opentelemetry.javaagent.instrumentation.opentelemetryapi.v1_27.logs.ApplicationLoggerFactory; +import io.opentelemetry.javaagent.instrumentation.opentelemetryapi.v1_27.logs.ApplicationLoggerFactory127; import io.opentelemetry.javaagent.instrumentation.opentelemetryapi.v1_27.logs.ApplicationLoggerProvider; import io.opentelemetry.javaagent.instrumentation.opentelemetryapi.v1_4.trace.ApplicationTracerProvider14; import java.lang.reflect.InvocationTargetException; @@ -39,7 +41,8 @@ private ApplicationOpenTelemetry127() { new ApplicationContextPropagators(agentOpenTelemetry.getPropagators()); applicationMeterProvider = new ApplicationMeterProvider(getMeterFactory(), agentOpenTelemetry.getMeterProvider()); - applicationLoggerProvider = new ApplicationLoggerProvider(agentOpenTelemetry.getLogsBridge()); + applicationLoggerProvider = + new ApplicationLoggerProvider(getLoggerFactory(), agentOpenTelemetry.getLogsBridge()); } @Override @@ -105,9 +108,29 @@ private static ApplicationMeterFactory getMeterFactory() { } private static ApplicationMeterFactory getMeterFactory(String className) { + return getFactory(className, ApplicationMeterFactory.class); + } + + private static ApplicationLoggerFactory getLoggerFactory() { + // this class is defined in opentelemetry-api-1.42 + ApplicationLoggerFactory loggerFactory = + getLoggerFactory( + "io.opentelemetry.javaagent.instrumentation.opentelemetryapi.v1_42.logs.ApplicationLoggerFactory142"); + if (loggerFactory == null) { + loggerFactory = new ApplicationLoggerFactory127(); + } + + return loggerFactory; + } + + private static ApplicationLoggerFactory getLoggerFactory(String className) { + return getFactory(className, ApplicationLoggerFactory.class); + } + + private static T getFactory(String className, Class factoryClass) { try { Class clazz = Class.forName(className); - return (ApplicationMeterFactory) clazz.getConstructor().newInstance(); + return factoryClass.cast(clazz.getConstructor().newInstance()); } catch (ClassNotFoundException | NoSuchMethodException | InstantiationException diff --git a/instrumentation/opentelemetry-api/opentelemetry-api-1.27/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_27/logs/ApplicationLogRecordBuilder.java b/instrumentation/opentelemetry-api/opentelemetry-api-1.27/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_27/logs/ApplicationLogRecordBuilder.java index 1060663c7d9f..006927fdc605 100644 --- a/instrumentation/opentelemetry-api/opentelemetry-api-1.27/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_27/logs/ApplicationLogRecordBuilder.java +++ b/instrumentation/opentelemetry-api/opentelemetry-api-1.27/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_27/logs/ApplicationLogRecordBuilder.java @@ -15,11 +15,12 @@ import java.time.Instant; import java.util.concurrent.TimeUnit; -class ApplicationLogRecordBuilder implements LogRecordBuilder { +public class ApplicationLogRecordBuilder implements LogRecordBuilder { private final io.opentelemetry.api.logs.LogRecordBuilder agentLogRecordBuilder; - ApplicationLogRecordBuilder(io.opentelemetry.api.logs.LogRecordBuilder agentLogRecordBuilder) { + protected ApplicationLogRecordBuilder( + io.opentelemetry.api.logs.LogRecordBuilder agentLogRecordBuilder) { this.agentLogRecordBuilder = agentLogRecordBuilder; } diff --git a/instrumentation/opentelemetry-api/opentelemetry-api-1.27/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_27/logs/ApplicationLogger.java b/instrumentation/opentelemetry-api/opentelemetry-api-1.27/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_27/logs/ApplicationLogger.java index 7bfe4898ff0f..d05568f2545e 100644 --- a/instrumentation/opentelemetry-api/opentelemetry-api-1.27/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_27/logs/ApplicationLogger.java +++ b/instrumentation/opentelemetry-api/opentelemetry-api-1.27/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_27/logs/ApplicationLogger.java @@ -8,11 +8,11 @@ import application.io.opentelemetry.api.logs.LogRecordBuilder; import application.io.opentelemetry.api.logs.Logger; -class ApplicationLogger implements Logger { +public class ApplicationLogger implements Logger { private final io.opentelemetry.api.logs.Logger agentLogger; - ApplicationLogger(io.opentelemetry.api.logs.Logger agentLogger) { + protected ApplicationLogger(io.opentelemetry.api.logs.Logger agentLogger) { this.agentLogger = agentLogger; } diff --git a/instrumentation/opentelemetry-api/opentelemetry-api-1.27/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_27/logs/ApplicationLoggerBuilder.java b/instrumentation/opentelemetry-api/opentelemetry-api-1.27/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_27/logs/ApplicationLoggerBuilder.java index 995697f2aa4a..1636b4d96560 100644 --- a/instrumentation/opentelemetry-api/opentelemetry-api-1.27/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_27/logs/ApplicationLoggerBuilder.java +++ b/instrumentation/opentelemetry-api/opentelemetry-api-1.27/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_27/logs/ApplicationLoggerBuilder.java @@ -11,9 +11,13 @@ final class ApplicationLoggerBuilder implements LoggerBuilder { + private final ApplicationLoggerFactory loggerFactory; private final io.opentelemetry.api.logs.LoggerBuilder agentBuilder; - ApplicationLoggerBuilder(io.opentelemetry.api.logs.LoggerBuilder agentBuilder) { + ApplicationLoggerBuilder( + ApplicationLoggerFactory loggerFactory, + io.opentelemetry.api.logs.LoggerBuilder agentBuilder) { + this.loggerFactory = loggerFactory; this.agentBuilder = agentBuilder; } @@ -33,6 +37,6 @@ public LoggerBuilder setInstrumentationVersion(String version) { @Override public Logger build() { - return new ApplicationLogger(agentBuilder.build()); + return loggerFactory.newLogger(agentBuilder.build()); } } diff --git a/instrumentation/opentelemetry-api/opentelemetry-api-1.27/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_27/logs/ApplicationLoggerFactory.java b/instrumentation/opentelemetry-api/opentelemetry-api-1.27/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_27/logs/ApplicationLoggerFactory.java new file mode 100644 index 000000000000..b66ee7e5722f --- /dev/null +++ b/instrumentation/opentelemetry-api/opentelemetry-api-1.27/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_27/logs/ApplicationLoggerFactory.java @@ -0,0 +1,11 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.opentelemetryapi.v1_27.logs; + +public interface ApplicationLoggerFactory { + + ApplicationLogger newLogger(io.opentelemetry.api.logs.Logger agentLogger); +} diff --git a/instrumentation/opentelemetry-api/opentelemetry-api-1.27/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_27/logs/ApplicationLoggerFactory127.java b/instrumentation/opentelemetry-api/opentelemetry-api-1.27/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_27/logs/ApplicationLoggerFactory127.java new file mode 100644 index 000000000000..386852755959 --- /dev/null +++ b/instrumentation/opentelemetry-api/opentelemetry-api-1.27/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_27/logs/ApplicationLoggerFactory127.java @@ -0,0 +1,16 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.opentelemetryapi.v1_27.logs; + +import io.opentelemetry.api.logs.Logger; + +public class ApplicationLoggerFactory127 implements ApplicationLoggerFactory { + + @Override + public ApplicationLogger newLogger(Logger agentLogger) { + return new ApplicationLogger(agentLogger); + } +} diff --git a/instrumentation/opentelemetry-api/opentelemetry-api-1.27/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_27/logs/ApplicationLoggerProvider.java b/instrumentation/opentelemetry-api/opentelemetry-api-1.27/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_27/logs/ApplicationLoggerProvider.java index 192f53efbc95..875bf75daaa8 100644 --- a/instrumentation/opentelemetry-api/opentelemetry-api-1.27/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_27/logs/ApplicationLoggerProvider.java +++ b/instrumentation/opentelemetry-api/opentelemetry-api-1.27/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_27/logs/ApplicationLoggerProvider.java @@ -12,14 +12,19 @@ @SuppressWarnings("UnnecessarilyFullyQualified") public class ApplicationLoggerProvider implements LoggerProvider { + private final ApplicationLoggerFactory loggerFactory; private final io.opentelemetry.api.logs.LoggerProvider agentLoggerProvider; - public ApplicationLoggerProvider(io.opentelemetry.api.logs.LoggerProvider agentLoggerProvider) { + public ApplicationLoggerProvider( + ApplicationLoggerFactory loggerFactory, + io.opentelemetry.api.logs.LoggerProvider agentLoggerProvider) { + this.loggerFactory = loggerFactory; this.agentLoggerProvider = agentLoggerProvider; } @Override public LoggerBuilder loggerBuilder(String instrumentationName) { - return new ApplicationLoggerBuilder(agentLoggerProvider.loggerBuilder(instrumentationName)); + return new ApplicationLoggerBuilder( + loggerFactory, agentLoggerProvider.loggerBuilder(instrumentationName)); } } diff --git a/instrumentation/opentelemetry-api/opentelemetry-api-1.42/javaagent/build.gradle.kts b/instrumentation/opentelemetry-api/opentelemetry-api-1.42/javaagent/build.gradle.kts new file mode 100644 index 000000000000..1d96e7a2e605 --- /dev/null +++ b/instrumentation/opentelemetry-api/opentelemetry-api-1.42/javaagent/build.gradle.kts @@ -0,0 +1,26 @@ +plugins { + id("otel.javaagent-instrumentation") +} + +dependencies { + compileOnly(project(":opentelemetry-api-shaded-for-instrumenting", configuration = "v1_42")) + compileOnly("io.opentelemetry:opentelemetry-api-incubator") + + implementation(project(":instrumentation:opentelemetry-api:opentelemetry-api-1.0:javaagent")) + implementation(project(":instrumentation:opentelemetry-api:opentelemetry-api-1.4:javaagent")) + implementation(project(":instrumentation:opentelemetry-api:opentelemetry-api-1.10:javaagent")) + implementation(project(":instrumentation:opentelemetry-api:opentelemetry-api-1.15:javaagent")) + implementation(project(":instrumentation:opentelemetry-api:opentelemetry-api-1.27:javaagent")) + implementation(project(":instrumentation:opentelemetry-api:opentelemetry-api-1.31:javaagent")) + implementation(project(":instrumentation:opentelemetry-api:opentelemetry-api-1.32:javaagent")) + implementation(project(":instrumentation:opentelemetry-api:opentelemetry-api-1.37:javaagent")) + implementation(project(":instrumentation:opentelemetry-api:opentelemetry-api-1.38:javaagent")) +} + +configurations.configureEach { + if (name.endsWith("testRuntimeClasspath", true) || name.endsWith("testCompileClasspath", true)) { + resolutionStrategy { + force("io.opentelemetry:opentelemetry-api:1.42.0") + } + } +} diff --git a/instrumentation/opentelemetry-api/opentelemetry-api-1.42/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_42/OpenTelemetryApiInstrumentationModule.java b/instrumentation/opentelemetry-api/opentelemetry-api-1.42/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_42/OpenTelemetryApiInstrumentationModule.java new file mode 100644 index 000000000000..bd9fd79a8542 --- /dev/null +++ b/instrumentation/opentelemetry-api/opentelemetry-api-1.42/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_42/OpenTelemetryApiInstrumentationModule.java @@ -0,0 +1,32 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.opentelemetryapi.v1_42; + +import static java.util.Collections.singletonList; + +import com.google.auto.service.AutoService; +import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule; +import java.util.List; + +@AutoService(InstrumentationModule.class) +public class OpenTelemetryApiInstrumentationModule extends InstrumentationModule + implements ExperimentalInstrumentationModule { + public OpenTelemetryApiInstrumentationModule() { + super("opentelemetry-api", "opentelemetry-api-1.42"); + } + + @Override + public List typeInstrumentations() { + return singletonList(new OpenTelemetryInstrumentation()); + } + + @Override + public String getModuleGroup() { + return "opentelemetry-api-bridge"; + } +} diff --git a/instrumentation/opentelemetry-api/opentelemetry-api-1.42/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_42/OpenTelemetryInstrumentation.java b/instrumentation/opentelemetry-api/opentelemetry-api-1.42/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_42/OpenTelemetryInstrumentation.java new file mode 100644 index 000000000000..da6c1901f92d --- /dev/null +++ b/instrumentation/opentelemetry-api/opentelemetry-api-1.42/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_42/OpenTelemetryInstrumentation.java @@ -0,0 +1,40 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.opentelemetryapi.v1_42; + +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.none; + +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer; +import io.opentelemetry.javaagent.instrumentation.opentelemetryapi.v1_42.logs.ApplicationLoggerFactory142; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +public class OpenTelemetryInstrumentation implements TypeInstrumentation { + + @Override + public ElementMatcher typeMatcher() { + return named("application.io.opentelemetry.api.GlobalOpenTelemetry"); + } + + @Override + public void transform(TypeTransformer transformer) { + transformer.applyAdviceToMethod( + none(), OpenTelemetryInstrumentation.class.getName() + "$InitAdvice"); + } + + @SuppressWarnings({"ReturnValueIgnored", "unused"}) + public static class InitAdvice { + @Advice.OnMethodEnter + public static void init() { + // the sole purpose of this advice is to ensure that ApplicationLoggerFactory142 is recognized + // as helper class and injected into class loader + ApplicationLoggerFactory142.class.getName(); + } + } +} diff --git a/instrumentation/opentelemetry-api/opentelemetry-api-1.42/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_42/logs/ApplicationLogRecordBuilder142.java b/instrumentation/opentelemetry-api/opentelemetry-api-1.42/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_42/logs/ApplicationLogRecordBuilder142.java new file mode 100644 index 000000000000..57735e01f41f --- /dev/null +++ b/instrumentation/opentelemetry-api/opentelemetry-api-1.42/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_42/logs/ApplicationLogRecordBuilder142.java @@ -0,0 +1,74 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.opentelemetryapi.v1_42.logs; + +import application.io.opentelemetry.api.common.KeyValue; +import application.io.opentelemetry.api.common.Value; +import application.io.opentelemetry.api.logs.LogRecordBuilder; +import io.opentelemetry.javaagent.instrumentation.opentelemetryapi.v1_27.logs.ApplicationLogRecordBuilder; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + +class ApplicationLogRecordBuilder142 extends ApplicationLogRecordBuilder + implements LogRecordBuilder { + + private final io.opentelemetry.api.logs.LogRecordBuilder agentLogRecordBuilder; + + ApplicationLogRecordBuilder142(io.opentelemetry.api.logs.LogRecordBuilder agentLogRecordBuilder) { + super(agentLogRecordBuilder); + this.agentLogRecordBuilder = agentLogRecordBuilder; + } + + @Override + public LogRecordBuilder setBody(Value body) { + agentLogRecordBuilder.setBody(convertValue(body)); + return this; + } + + @SuppressWarnings("unchecked") + private static io.opentelemetry.api.common.Value convertValue(Value value) { + if (value == null) { + return null; + } + + switch (value.getType()) { + case STRING: + return io.opentelemetry.api.common.Value.of((String) value.getValue()); + case BOOLEAN: + return io.opentelemetry.api.common.Value.of((Boolean) value.getValue()); + case LONG: + return io.opentelemetry.api.common.Value.of((Long) value.getValue()); + case DOUBLE: + return io.opentelemetry.api.common.Value.of((Double) value.getValue()); + case ARRAY: + List> values = (List>) value.getValue(); + List> convertedValues = new ArrayList<>(); + for (Value source : values) { + convertedValues.add(convertValue(source)); + } + return io.opentelemetry.api.common.Value.of(convertedValues); + case KEY_VALUE_LIST: + List keyValueList = (List) value.getValue(); + io.opentelemetry.api.common.KeyValue[] convertedKeyValueList = + new io.opentelemetry.api.common.KeyValue[keyValueList.size()]; + int i = 0; + for (KeyValue source : keyValueList) { + convertedKeyValueList[i++] = + io.opentelemetry.api.common.KeyValue.of( + source.getKey(), convertValue(source.getValue())); + } + return io.opentelemetry.api.common.Value.of(convertedKeyValueList); + case BYTES: + ByteBuffer byteBuffer = (ByteBuffer) value.getValue(); + byte[] bytes = new byte[byteBuffer.remaining()]; + byteBuffer.get(bytes); + break; + } + + throw new IllegalStateException("Unhandled value type: " + value.getType()); + } +} diff --git a/instrumentation/opentelemetry-api/opentelemetry-api-1.42/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_42/logs/ApplicationLogger142.java b/instrumentation/opentelemetry-api/opentelemetry-api-1.42/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_42/logs/ApplicationLogger142.java new file mode 100644 index 000000000000..e702b600217b --- /dev/null +++ b/instrumentation/opentelemetry-api/opentelemetry-api-1.42/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_42/logs/ApplicationLogger142.java @@ -0,0 +1,24 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.opentelemetryapi.v1_42.logs; + +import application.io.opentelemetry.api.logs.LogRecordBuilder; +import io.opentelemetry.javaagent.instrumentation.opentelemetryapi.v1_27.logs.ApplicationLogger; + +class ApplicationLogger142 extends ApplicationLogger { + + private final io.opentelemetry.api.logs.Logger agentLogger; + + ApplicationLogger142(io.opentelemetry.api.logs.Logger agentLogger) { + super(agentLogger); + this.agentLogger = agentLogger; + } + + @Override + public LogRecordBuilder logRecordBuilder() { + return new ApplicationLogRecordBuilder142(agentLogger.logRecordBuilder()); + } +} diff --git a/instrumentation/opentelemetry-api/opentelemetry-api-1.42/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_42/logs/ApplicationLoggerFactory142.java b/instrumentation/opentelemetry-api/opentelemetry-api-1.42/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_42/logs/ApplicationLoggerFactory142.java new file mode 100644 index 000000000000..4353833b8a42 --- /dev/null +++ b/instrumentation/opentelemetry-api/opentelemetry-api-1.42/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_42/logs/ApplicationLoggerFactory142.java @@ -0,0 +1,18 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.opentelemetryapi.v1_42.logs; + +import io.opentelemetry.api.logs.Logger; +import io.opentelemetry.javaagent.instrumentation.opentelemetryapi.v1_27.logs.ApplicationLogger; +import io.opentelemetry.javaagent.instrumentation.opentelemetryapi.v1_27.logs.ApplicationLoggerFactory; + +public class ApplicationLoggerFactory142 implements ApplicationLoggerFactory { + + @Override + public ApplicationLogger newLogger(Logger agentLogger) { + return new ApplicationLogger142(agentLogger); + } +} diff --git a/instrumentation/opentelemetry-api/opentelemetry-api-1.42/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_42/LoggerTest.java b/instrumentation/opentelemetry-api/opentelemetry-api-1.42/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_42/LoggerTest.java new file mode 100644 index 000000000000..912a2f85054a --- /dev/null +++ b/instrumentation/opentelemetry-api/opentelemetry-api-1.42/javaagent/src/test/java/io/opentelemetry/javaagent/instrumentation/opentelemetryapi/v1_42/LoggerTest.java @@ -0,0 +1,142 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.instrumentation.opentelemetryapi.v1_42; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; + +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.common.KeyValue; +import io.opentelemetry.api.common.Value; +import io.opentelemetry.api.common.ValueType; +import io.opentelemetry.api.logs.Logger; +import io.opentelemetry.api.logs.Severity; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanContext; +import io.opentelemetry.api.trace.TraceFlags; +import io.opentelemetry.api.trace.TraceState; +import io.opentelemetry.context.Context; +import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension; +import io.opentelemetry.sdk.trace.IdGenerator; +import java.time.Instant; +import java.util.concurrent.TimeUnit; +import java.util.stream.Stream; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInfo; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class LoggerTest { + + @RegisterExtension + static final AgentInstrumentationExtension testing = AgentInstrumentationExtension.create(); + + private String instrumentationName; + private Logger logger; + + @BeforeEach + void setupLogger(TestInfo test) { + instrumentationName = "test-" + test.getDisplayName(); + logger = + GlobalOpenTelemetry.get() + .getLogsBridge() + .loggerBuilder(instrumentationName) + .setInstrumentationVersion("1.2.3") + .setSchemaUrl("http://schema.org") + .build(); + } + + @Test + void logRecordBuilder() { + SpanContext spanContext = + SpanContext.create( + IdGenerator.random().generateTraceId(), + IdGenerator.random().generateSpanId(), + TraceFlags.getDefault(), + TraceState.getDefault()); + + logger + .logRecordBuilder() + .setTimestamp(1, TimeUnit.SECONDS) + .setTimestamp(Instant.now()) + .setContext(Context.current().with(Span.wrap(spanContext))) + .setSeverity(Severity.DEBUG) + .setSeverityText("debug") + .setBody("body") + .setAttribute(AttributeKey.stringKey("key"), "value") + .setAllAttributes(Attributes.builder().put("key", "value").build()) + .emit(); + + await() + .untilAsserted( + () -> + assertThat(testing.logRecords()) + .satisfiesExactly( + logRecordData -> { + assertThat(logRecordData.getInstrumentationScopeInfo().getName()) + .isEqualTo(instrumentationName); + assertThat(logRecordData.getInstrumentationScopeInfo().getVersion()) + .isEqualTo("1.2.3"); + assertThat(logRecordData.getTimestampEpochNanos()).isGreaterThan(0); + assertThat(logRecordData.getSpanContext()).isEqualTo(spanContext); + assertThat(logRecordData.getSeverity()).isEqualTo(Severity.DEBUG); + assertThat(logRecordData.getSeverityText()).isEqualTo("debug"); + assertThat(logRecordData.getBodyValue().getType()) + .isEqualTo(ValueType.STRING); + assertThat(logRecordData.getBodyValue().getValue()).isEqualTo("body"); + assertThat(logRecordData.getAttributes()) + .isEqualTo(Attributes.builder().put("key", "value").build()); + })); + } + + private static Stream bodyValues() { + return Stream.of( + Arguments.of(Value.of("hello")), + Arguments.of(Value.of(42)), + Arguments.of(Value.of(42.42)), + Arguments.of(Value.of(true)), + Arguments.of(Value.of(new byte[] {4, 2})), + Arguments.of(Value.of(Value.of("hello"), Value.of(42))), + Arguments.of(Value.of(KeyValue.of("key", Value.of(42))))); + } + + @ParameterizedTest + @MethodSource("bodyValues") + void logBodyValue() { + Value value = Value.of(42); + logger.logRecordBuilder().setBody(value).emit(); + + await() + .untilAsserted( + () -> + assertThat(testing.logRecords()) + .satisfiesExactly( + logRecordData -> { + assertThat(logRecordData.getBodyValue().getType()) + .isEqualTo(value.getType()); + assertThat(logRecordData.getBodyValue().getValue()) + .isEqualTo(value.getValue()); + })); + } + + @Test + void logNullBody() { + Value value = null; + logger.logRecordBuilder().setBody(value).emit(); + + await() + .untilAsserted( + () -> + assertThat(testing.logRecords()) + .satisfiesExactly( + logRecordData -> assertThat(logRecordData.getBodyValue()).isNull())); + } +} diff --git a/opentelemetry-api-shaded-for-instrumenting/build.gradle.kts b/opentelemetry-api-shaded-for-instrumenting/build.gradle.kts index 1f188a09a255..a3849d97fb1d 100644 --- a/opentelemetry-api-shaded-for-instrumenting/build.gradle.kts +++ b/opentelemetry-api-shaded-for-instrumenting/build.gradle.kts @@ -58,6 +58,13 @@ val v1_38Deps by configurations.creating { exclude("io.opentelemetry", "opentelemetry-bom") exclude("io.opentelemetry", "opentelemetry-bom-alpha") } +val v1_42Deps by configurations.creating { + isCanBeResolved = true + isCanBeConsumed = false + // exclude the bom added by dependencyManagement + exclude("io.opentelemetry", "opentelemetry-bom") + exclude("io.opentelemetry", "opentelemetry-bom-alpha") +} // configuration for publishing the shadowed artifact val v1_10 by configurations.creating { isCanBeConsumed = true @@ -87,6 +94,10 @@ val v1_38 by configurations.creating { isCanBeConsumed = true isCanBeResolved = false } +val v1_42 by configurations.creating { + isCanBeConsumed = true + isCanBeResolved = false +} dependencies { latestDeps("io.opentelemetry:opentelemetry-api") @@ -143,6 +154,11 @@ dependencies { strictly("1.38.0-alpha") } } + v1_42Deps("io.opentelemetry:$it") { + version { + strictly("1.42.0-alpha") + } + } } } @@ -186,6 +202,10 @@ tasks { configurations = listOf(v1_38Deps) archiveClassifier.set("v1_38") } + val v1_42Shadow by registering(ShadowJar::class) { + configurations = listOf(v1_42Deps) + archiveClassifier.set("v1_42") + } artifacts { add(v1_10.name, v1_10Shadow) @@ -195,5 +215,6 @@ tasks { add(v1_32.name, v1_32Shadow) add(v1_37.name, v1_37Shadow) add(v1_38.name, v1_38Shadow) + add(v1_42.name, v1_42Shadow) } } diff --git a/settings.gradle.kts b/settings.gradle.kts index c4c5435d6055..5882499605b1 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -457,6 +457,7 @@ include(":instrumentation:opentelemetry-api:opentelemetry-api-1.31:javaagent") include(":instrumentation:opentelemetry-api:opentelemetry-api-1.32:javaagent") include(":instrumentation:opentelemetry-api:opentelemetry-api-1.37:javaagent") include(":instrumentation:opentelemetry-api:opentelemetry-api-1.38:javaagent") +include(":instrumentation:opentelemetry-api:opentelemetry-api-1.42:javaagent") include(":instrumentation:opentelemetry-extension-annotations-1.0:javaagent") include(":instrumentation:opentelemetry-extension-kotlin-1.0:javaagent") include(":instrumentation:opentelemetry-instrumentation-annotations-1.16:javaagent") diff --git a/testing-common/src/main/java/io/opentelemetry/javaagent/testing/common/AgentTestingExporterAccess.java b/testing-common/src/main/java/io/opentelemetry/javaagent/testing/common/AgentTestingExporterAccess.java index 41b6b6fb9ec3..7bc9e8e61d97 100644 --- a/testing-common/src/main/java/io/opentelemetry/javaagent/testing/common/AgentTestingExporterAccess.java +++ b/testing-common/src/main/java/io/opentelemetry/javaagent/testing/common/AgentTestingExporterAccess.java @@ -15,6 +15,7 @@ import com.google.protobuf.InvalidProtocolBufferException; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.common.AttributesBuilder; +import io.opentelemetry.api.common.Value; import io.opentelemetry.api.logs.Severity; import io.opentelemetry.api.trace.SpanContext; import io.opentelemetry.api.trace.SpanKind; @@ -29,6 +30,7 @@ import io.opentelemetry.proto.common.v1.ArrayValue; import io.opentelemetry.proto.common.v1.InstrumentationScope; import io.opentelemetry.proto.common.v1.KeyValue; +import io.opentelemetry.proto.common.v1.KeyValueList; import io.opentelemetry.proto.logs.v1.LogRecord; import io.opentelemetry.proto.logs.v1.ResourceLogs; import io.opentelemetry.proto.logs.v1.ScopeLogs; @@ -91,6 +93,9 @@ public final class AgentTestingExporterAccess { private static final MethodHandle getLogExportRequests; private static final MethodHandle reset; private static final MethodHandle forceFlushCalled; + // opentelemetry-api-1.27:javaagent tests use an older version of opentelemetry-api where Value + // class is missing + private static final boolean canUseValue = classAvailable("io.opentelemetry.api.common.Value"); static { try { @@ -126,6 +131,15 @@ public final class AgentTestingExporterAccess { } } + private static boolean classAvailable(String className) { + try { + Class.forName(className); + return true; + } catch (ClassNotFoundException e) { + return false; + } + } + public static void reset() { try { reset.invokeExact(); @@ -402,21 +416,62 @@ private static LogRecordData createLogData( LogRecord logRecord, io.opentelemetry.sdk.resources.Resource resource, InstrumentationScopeInfo instrumentationScopeInfo) { - return TestLogRecordData.builder() - .setResource(resource) - .setInstrumentationScopeInfo(instrumentationScopeInfo) - .setTimestamp(logRecord.getTimeUnixNano(), TimeUnit.NANOSECONDS) - .setSpanContext( - SpanContext.create( - bytesToHex(logRecord.getTraceId().toByteArray()), - bytesToHex(logRecord.getSpanId().toByteArray()), - TraceFlags.getDefault(), - TraceState.getDefault())) - .setSeverity(fromProto(logRecord.getSeverityNumber())) - .setSeverityText(logRecord.getSeverityText()) - .setBody(logRecord.getBody().getStringValue()) - .setAttributes(fromProto(logRecord.getAttributesList())) - .build(); + TestLogRecordData.Builder builder = + TestLogRecordData.builder() + .setResource(resource) + .setInstrumentationScopeInfo(instrumentationScopeInfo) + .setTimestamp(logRecord.getTimeUnixNano(), TimeUnit.NANOSECONDS) + .setSpanContext( + SpanContext.create( + bytesToHex(logRecord.getTraceId().toByteArray()), + bytesToHex(logRecord.getSpanId().toByteArray()), + TraceFlags.getDefault(), + TraceState.getDefault())) + .setSeverity(fromProto(logRecord.getSeverityNumber())) + .setSeverityText(logRecord.getSeverityText()) + .setAttributes(fromProto(logRecord.getAttributesList())); + if (canUseValue) { + builder.setBodyValue(getBodyValue(logRecord.getBody())); + } else { + builder.setBody(logRecord.getBody().getStringValue()); + } + return builder.build(); + } + + private static Value getBodyValue(AnyValue value) { + switch (value.getValueCase()) { + case STRING_VALUE: + return Value.of(value.getStringValue()); + case BOOL_VALUE: + return Value.of(value.getBoolValue()); + case INT_VALUE: + return Value.of(value.getIntValue()); + case DOUBLE_VALUE: + return Value.of(value.getDoubleValue()); + case ARRAY_VALUE: + ArrayValue array = value.getArrayValue(); + List> convertedValues = new ArrayList<>(); + for (int i = 0; i < array.getValuesCount(); i++) { + convertedValues.add(getBodyValue(array.getValues(i))); + } + return Value.of(convertedValues); + case KVLIST_VALUE: + KeyValueList keyValueList = value.getKvlistValue(); + io.opentelemetry.api.common.KeyValue[] convertedKeyValueList = + new io.opentelemetry.api.common.KeyValue[keyValueList.getValuesCount()]; + for (int i = 0; i < keyValueList.getValuesCount(); i++) { + KeyValue keyValue = keyValueList.getValues(i); + convertedKeyValueList[i] = + io.opentelemetry.api.common.KeyValue.of( + keyValue.getKey(), getBodyValue(keyValue.getValue())); + } + return Value.of(convertedKeyValueList); + case BYTES_VALUE: + return Value.of(value.getBytesValue().toByteArray()); + case VALUE_NOT_SET: + return null; + } + throw new IllegalStateException("Unexpected attribute: " + value.getValueCase()); } private static boolean isDouble(List points) {