Span kind for method instrumentation / Declarative configuration tooling (#14014)
Co-authored-by: Lauri Tulmin <ltulmin@splunk.com> Co-authored-by: otelbot <197425009+otelbot@users.noreply.github.com>
This commit is contained in:
parent
7689228d47
commit
4251217436
|
|
@ -13,7 +13,7 @@ group = "io.opentelemetry.instrumentation"
|
|||
dependencies {
|
||||
api("io.opentelemetry.semconv:opentelemetry-semconv")
|
||||
api(project(":instrumentation-api"))
|
||||
implementation("io.opentelemetry:opentelemetry-api-incubator")
|
||||
api("io.opentelemetry:opentelemetry-api-incubator")
|
||||
|
||||
compileOnly("com.google.auto.value:auto-value-annotations")
|
||||
annotationProcessor("com.google.auto.value:auto-value")
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ package io.opentelemetry.instrumentation.api.incubator.config.internal;
|
|||
|
||||
import static java.util.Collections.emptyList;
|
||||
|
||||
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
|
@ -107,4 +108,18 @@ public interface InstrumentationConfig {
|
|||
* {@code key=value,anotherKey=anotherValue}. The returned map is unmodifiable.
|
||||
*/
|
||||
Map<String, String> getMap(String name, Map<String, String> defaultValue);
|
||||
|
||||
/**
|
||||
* Returns a {@link DeclarativeConfigProperties} for the given instrumentation name, or {@code
|
||||
* null} if no declarative configuration is available for that instrumentation.
|
||||
*
|
||||
* <p>Declarative configuration is used to configure instrumentation properties in a declarative
|
||||
* way, such as through YAML or JSON files.
|
||||
*
|
||||
* @param instrumentationName the name of the instrumentation
|
||||
* @return the declarative configuration properties for the given instrumentation name, or {@code
|
||||
* null} if not available
|
||||
*/
|
||||
@Nullable
|
||||
DeclarativeConfigProperties getDeclarativeConfig(String instrumentationName);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,8 +13,30 @@ dependencies {
|
|||
compileOnly(project(":instrumentation-annotations-support"))
|
||||
}
|
||||
|
||||
tasks.withType<Test>().configureEach {
|
||||
tasks.test {
|
||||
jvmArgs(
|
||||
"-Dotel.instrumentation.methods.include=io.opentelemetry.javaagent.instrumentation.methods.MethodTest\$ConfigTracedCallable[call];io.opentelemetry.javaagent.instrumentation.methods.MethodTest\$ConfigTracedCompletableFuture[getResult];javax.naming.directory.InitialDirContext[search]"
|
||||
)
|
||||
}
|
||||
|
||||
testing {
|
||||
suites {
|
||||
val declarativeConfigTest by registering(JvmTestSuite::class) {
|
||||
targets {
|
||||
all {
|
||||
testTask.configure {
|
||||
jvmArgs(
|
||||
"-Dotel.experimental.config.file=$projectDir/src/declarativeConfigTest/resources/declarative-config.yaml"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks {
|
||||
check {
|
||||
dependsOn(testing.suites)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.methods;
|
||||
|
||||
import static io.opentelemetry.instrumentation.testing.junit.code.SemconvCodeStabilityUtil.codeFunctionAssertions;
|
||||
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
|
||||
|
||||
import io.opentelemetry.api.trace.SpanKind;
|
||||
import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension;
|
||||
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
|
||||
import java.util.concurrent.Callable;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
@SuppressWarnings("deprecation") // using deprecated semconv
|
||||
class MethodTest {
|
||||
|
||||
@RegisterExtension
|
||||
static final InstrumentationExtension testing = AgentInstrumentationExtension.create();
|
||||
|
||||
@SuppressWarnings("deprecation") // using deprecated semconv
|
||||
@Test
|
||||
void methodTraced() {
|
||||
assertThat(new ConfigTracedCallable().call()).isEqualTo("Hello!");
|
||||
testing.waitAndAssertTraces(
|
||||
trace ->
|
||||
trace.hasSpansSatisfyingExactly(
|
||||
span ->
|
||||
span.hasName("ConfigTracedCallable.call")
|
||||
.hasKind(SpanKind.SERVER)
|
||||
.hasAttributesSatisfyingExactly(
|
||||
codeFunctionAssertions(ConfigTracedCallable.class, "call"))));
|
||||
}
|
||||
|
||||
static class ConfigTracedCallable implements Callable<String> {
|
||||
|
||||
@Override
|
||||
public String call() {
|
||||
return "Hello!";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
file_format: "0.4"
|
||||
tracer_provider:
|
||||
processors:
|
||||
- simple:
|
||||
exporter:
|
||||
test:
|
||||
- simple:
|
||||
exporter:
|
||||
console:
|
||||
|
||||
logger_provider:
|
||||
processors:
|
||||
- simple:
|
||||
exporter:
|
||||
test:
|
||||
|
||||
meter_provider:
|
||||
readers:
|
||||
- periodic:
|
||||
# Set really long interval. We'll call forceFlush when we need the metrics
|
||||
# instead of collecting them periodically.
|
||||
interval: 1000000
|
||||
exporter:
|
||||
test:
|
||||
|
||||
instrumentation/development:
|
||||
java:
|
||||
methods:
|
||||
include:
|
||||
- class: io.opentelemetry.javaagent.instrumentation.methods.MethodTest$ConfigTracedCallable
|
||||
methods:
|
||||
- name: call
|
||||
span_kind: SERVER
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.methods;
|
||||
|
||||
import io.opentelemetry.api.trace.SpanKind;
|
||||
import io.opentelemetry.instrumentation.api.incubator.semconv.util.ClassAndMethod;
|
||||
|
||||
public class MethodAndType {
|
||||
private final ClassAndMethod classAndMethod;
|
||||
private final SpanKind spanKind;
|
||||
|
||||
private MethodAndType(ClassAndMethod classAndMethod, SpanKind spanKind) {
|
||||
this.classAndMethod = classAndMethod;
|
||||
this.spanKind = spanKind;
|
||||
}
|
||||
|
||||
public static MethodAndType create(ClassAndMethod classAndMethod, SpanKind spanKind) {
|
||||
return new MethodAndType(classAndMethod, spanKind);
|
||||
}
|
||||
|
||||
public ClassAndMethod getClassAndMethod() {
|
||||
return classAndMethod;
|
||||
}
|
||||
|
||||
public SpanKind getSpanKind() {
|
||||
return spanKind;
|
||||
}
|
||||
}
|
||||
|
|
@ -10,33 +10,41 @@ import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.
|
|||
import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasSuperType;
|
||||
import static io.opentelemetry.javaagent.instrumentation.methods.MethodSingletons.getBootstrapLoader;
|
||||
import static io.opentelemetry.javaagent.instrumentation.methods.MethodSingletons.instrumenter;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.any;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.namedOneOf;
|
||||
import static net.bytebuddy.matcher.ElementMatchers.none;
|
||||
|
||||
import io.opentelemetry.api.trace.SpanKind;
|
||||
import io.opentelemetry.context.Context;
|
||||
import io.opentelemetry.context.Scope;
|
||||
import io.opentelemetry.instrumentation.api.annotation.support.async.AsyncOperationEndSupport;
|
||||
import io.opentelemetry.instrumentation.api.incubator.semconv.util.ClassAndMethod;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
|
||||
import java.util.Set;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
import net.bytebuddy.description.enumeration.EnumerationDescription;
|
||||
import net.bytebuddy.description.type.TypeDescription;
|
||||
import net.bytebuddy.implementation.bytecode.assign.Assigner;
|
||||
import net.bytebuddy.matcher.ElementMatcher;
|
||||
|
||||
public class MethodInstrumentation implements TypeInstrumentation {
|
||||
private final String className;
|
||||
private final Set<String> methodNames;
|
||||
private final Map<SpanKind, Collection<String>> methodNames;
|
||||
|
||||
public MethodInstrumentation(String className, Set<String> methodNames) {
|
||||
public MethodInstrumentation(String className, Map<SpanKind, Collection<String>> methodNames) {
|
||||
this.className = className;
|
||||
this.methodNames = methodNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElementMatcher<ClassLoader> classLoaderOptimization() {
|
||||
if (className == null) {
|
||||
return any();
|
||||
}
|
||||
ElementMatcher<ClassLoader> delegate = hasClassesNamed(className);
|
||||
return target -> {
|
||||
// hasClassesNamed does not support null class loader, so we provide a custom loader that
|
||||
|
|
@ -50,37 +58,51 @@ public class MethodInstrumentation implements TypeInstrumentation {
|
|||
|
||||
@Override
|
||||
public ElementMatcher<TypeDescription> typeMatcher() {
|
||||
return hasSuperType(named(className));
|
||||
return className == null ? none() : hasSuperType(named(className));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transform(TypeTransformer transformer) {
|
||||
transformer.applyAdviceToMethod(
|
||||
namedOneOf(methodNames.toArray(new String[0])).and(isMethod()),
|
||||
mapping ->
|
||||
mapping.bind(
|
||||
MethodReturnType.class,
|
||||
(instrumentedType, instrumentedMethod, assigner, argumentHandler, sort) ->
|
||||
Advice.OffsetMapping.Target.ForStackManipulation.of(
|
||||
instrumentedMethod.getReturnType().asErasure())),
|
||||
MethodInstrumentation.class.getName() + "$MethodAdvice");
|
||||
for (Map.Entry<SpanKind, Collection<String>> entry : methodNames.entrySet()) {
|
||||
SpanKind spanKind = entry.getKey();
|
||||
Collection<String> names = entry.getValue();
|
||||
transformer.applyAdviceToMethod(
|
||||
namedOneOf(names.toArray(new String[0])).and(isMethod()),
|
||||
mapping ->
|
||||
mapping
|
||||
.bind(
|
||||
MethodReturnType.class,
|
||||
(instrumentedType, instrumentedMethod, assigner, argumentHandler, sort) ->
|
||||
Advice.OffsetMapping.Target.ForStackManipulation.of(
|
||||
instrumentedMethod.getReturnType().asErasure()))
|
||||
.bind(
|
||||
MethodSpanKind.class,
|
||||
new EnumerationDescription.ForLoadedEnumeration(spanKind)),
|
||||
MethodInstrumentation.class.getName() + "$MethodAdvice");
|
||||
}
|
||||
}
|
||||
|
||||
// custom annotation that represents the return type of the method
|
||||
@interface MethodReturnType {}
|
||||
|
||||
// custom annotation that represents the SpanKind of the method
|
||||
@interface MethodSpanKind {}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static class MethodAdvice {
|
||||
|
||||
@Advice.OnMethodEnter(suppress = Throwable.class)
|
||||
public static void onEnter(
|
||||
@MethodSpanKind SpanKind spanKind,
|
||||
@Advice.Origin("#t") Class<?> declaringClass,
|
||||
@Advice.Origin("#m") String methodName,
|
||||
@Advice.Local("otelMethod") ClassAndMethod classAndMethod,
|
||||
@Advice.Local("otelMethod") MethodAndType classAndMethod,
|
||||
@Advice.Local("otelContext") Context context,
|
||||
@Advice.Local("otelScope") Scope scope) {
|
||||
Context parentContext = currentContext();
|
||||
classAndMethod = ClassAndMethod.create(declaringClass, methodName);
|
||||
classAndMethod =
|
||||
MethodAndType.create(ClassAndMethod.create(declaringClass, methodName), spanKind);
|
||||
|
||||
if (!instrumenter().shouldStart(parentContext, classAndMethod)) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -92,7 +114,7 @@ public class MethodInstrumentation implements TypeInstrumentation {
|
|||
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
|
||||
public static void stopSpan(
|
||||
@MethodReturnType Class<?> methodReturnType,
|
||||
@Advice.Local("otelMethod") ClassAndMethod classAndMethod,
|
||||
@Advice.Local("otelMethod") MethodAndType classAndMethod,
|
||||
@Advice.Local("otelContext") Context context,
|
||||
@Advice.Local("otelScope") Scope scope,
|
||||
@Advice.Return(typing = Assigner.Typing.DYNAMIC, readOnly = false) Object returnValue,
|
||||
|
|
|
|||
|
|
@ -6,13 +6,16 @@
|
|||
package io.opentelemetry.javaagent.instrumentation.methods;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
import static java.util.Collections.singletonList;
|
||||
import static java.util.Collections.singletonMap;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
|
||||
import io.opentelemetry.api.trace.SpanKind;
|
||||
import io.opentelemetry.javaagent.bootstrap.internal.AgentInstrumentationConfig;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||
import io.opentelemetry.javaagent.tooling.config.MethodsConfigurationParser;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
|
@ -27,27 +30,35 @@ public class MethodInstrumentationModule extends InstrumentationModule {
|
|||
|
||||
public MethodInstrumentationModule() {
|
||||
super("methods");
|
||||
typeInstrumentations = createInstrumentations();
|
||||
}
|
||||
|
||||
private static List<TypeInstrumentation> createInstrumentations() {
|
||||
DeclarativeConfigProperties methods =
|
||||
AgentInstrumentationConfig.get().getDeclarativeConfig("methods");
|
||||
List<TypeInstrumentation> list =
|
||||
methods != null ? MethodsConfig.parseDeclarativeConfig(methods) : parseConfigProperties();
|
||||
// ensure that there is at least one instrumentation so that muzzle reference collection could
|
||||
// work
|
||||
if (list.isEmpty()) {
|
||||
return singletonList(
|
||||
new MethodInstrumentation(null, singletonMap(SpanKind.INTERNAL, emptyList())));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private static List<TypeInstrumentation> parseConfigProperties() {
|
||||
Map<String, Set<String>> classMethodsToTrace =
|
||||
MethodsConfigurationParser.parse(
|
||||
AgentInstrumentationConfig.get().getString(TRACE_METHODS_CONFIG));
|
||||
|
||||
typeInstrumentations =
|
||||
classMethodsToTrace.entrySet().stream()
|
||||
.filter(e -> !e.getValue().isEmpty())
|
||||
.map(e -> new MethodInstrumentation(e.getKey(), e.getValue()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
// the default configuration has empty "otel.instrumentation.methods.include", and so doesn't
|
||||
// generate any TypeInstrumentation for muzzle to analyze
|
||||
@Override
|
||||
public List<String> getAdditionalHelperClassNames() {
|
||||
return typeInstrumentations.isEmpty()
|
||||
? emptyList()
|
||||
: Arrays.asList(
|
||||
"io.opentelemetry.javaagent.instrumentation.methods.MethodSingletons",
|
||||
"io.opentelemetry.javaagent.instrumentation.methods.MethodSingletons$BootstrapLoader");
|
||||
return classMethodsToTrace.entrySet().stream()
|
||||
.filter(e -> !e.getValue().isEmpty())
|
||||
.map(
|
||||
e ->
|
||||
new MethodInstrumentation(
|
||||
e.getKey(), singletonMap(SpanKind.INTERNAL, e.getValue())))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -9,30 +9,41 @@ import io.opentelemetry.api.GlobalOpenTelemetry;
|
|||
import io.opentelemetry.instrumentation.api.incubator.semconv.code.CodeAttributesExtractor;
|
||||
import io.opentelemetry.instrumentation.api.incubator.semconv.code.CodeAttributesGetter;
|
||||
import io.opentelemetry.instrumentation.api.incubator.semconv.code.CodeSpanNameExtractor;
|
||||
import io.opentelemetry.instrumentation.api.incubator.semconv.util.ClassAndMethod;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
|
||||
import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public final class MethodSingletons {
|
||||
private static final String INSTRUMENTATION_NAME = "io.opentelemetry.methods";
|
||||
|
||||
private static final Instrumenter<ClassAndMethod, Void> INSTRUMENTER;
|
||||
private static final Instrumenter<MethodAndType, Void> INSTRUMENTER;
|
||||
private static final ClassLoader bootstrapLoader = new BootstrapLoader();
|
||||
|
||||
static {
|
||||
CodeAttributesGetter<ClassAndMethod> codeAttributesGetter =
|
||||
ClassAndMethod.codeAttributesGetter();
|
||||
CodeAttributesGetter<MethodAndType> codeAttributesGetter =
|
||||
new CodeAttributesGetter<MethodAndType>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public Class<?> getCodeClass(MethodAndType methodAndType) {
|
||||
return methodAndType.getClassAndMethod().declaringClass();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getMethodName(MethodAndType methodAndType) {
|
||||
return methodAndType.getClassAndMethod().methodName();
|
||||
}
|
||||
};
|
||||
|
||||
INSTRUMENTER =
|
||||
Instrumenter.<ClassAndMethod, Void>builder(
|
||||
Instrumenter.<MethodAndType, Void>builder(
|
||||
GlobalOpenTelemetry.get(),
|
||||
INSTRUMENTATION_NAME,
|
||||
CodeSpanNameExtractor.create(codeAttributesGetter))
|
||||
.addAttributesExtractor(CodeAttributesExtractor.create(codeAttributesGetter))
|
||||
.buildInstrumenter(SpanKindExtractor.alwaysInternal());
|
||||
.buildInstrumenter(MethodAndType::getSpanKind);
|
||||
}
|
||||
|
||||
public static Instrumenter<ClassAndMethod, Void> instrumenter() {
|
||||
public static Instrumenter<MethodAndType, Void> instrumenter() {
|
||||
return INSTRUMENTER;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.instrumentation.methods;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
|
||||
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
|
||||
import io.opentelemetry.api.trace.SpanKind;
|
||||
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class MethodsConfig {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(MethodsConfig.class.getName());
|
||||
|
||||
private MethodsConfig() {}
|
||||
|
||||
static List<TypeInstrumentation> parseDeclarativeConfig(DeclarativeConfigProperties methods) {
|
||||
return methods.getStructuredList("include", emptyList()).stream()
|
||||
.flatMap(MethodsConfig::parseMethodInstrumentation)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static Stream<MethodInstrumentation> parseMethodInstrumentation(
|
||||
DeclarativeConfigProperties config) {
|
||||
String clazz = config.getString("class");
|
||||
if (isNullOrEmpty(clazz)) {
|
||||
logger.log(Level.WARNING, "Invalid methods configuration - class name missing: {0}", config);
|
||||
return Stream.empty();
|
||||
}
|
||||
|
||||
Map<SpanKind, Collection<String>> methodNames = new EnumMap<>(SpanKind.class);
|
||||
for (DeclarativeConfigProperties method : config.getStructuredList("methods", emptyList())) {
|
||||
String methodName = method.getString("name");
|
||||
if (isNullOrEmpty(methodName)) {
|
||||
logger.log(
|
||||
Level.WARNING, "Invalid methods configuration - method name missing: {0}", method);
|
||||
continue;
|
||||
}
|
||||
String spanKind = method.getString("span_kind", "INTERNAL");
|
||||
try {
|
||||
methodNames
|
||||
.computeIfAbsent(
|
||||
SpanKind.valueOf(spanKind.toUpperCase(Locale.ROOT)), unused -> new ArrayList<>())
|
||||
.add(methodName);
|
||||
} catch (IllegalArgumentException e) {
|
||||
logger.log(
|
||||
Level.WARNING,
|
||||
"Invalid methods configuration - unknown span_kind: {0} for method: {1}",
|
||||
new Object[] {spanKind, methodName});
|
||||
}
|
||||
}
|
||||
|
||||
if (methodNames.isEmpty()) {
|
||||
logger.log(Level.WARNING, "Invalid methods configuration - no methods defined: {0}", config);
|
||||
return Stream.empty();
|
||||
}
|
||||
|
||||
return Stream.of(new MethodInstrumentation(clazz, methodNames));
|
||||
}
|
||||
|
||||
private static boolean isNullOrEmpty(String s) {
|
||||
return s == null || s.isEmpty();
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
package io.opentelemetry.instrumentation.spring.autoconfigure.internal.properties;
|
||||
|
||||
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
|
||||
import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig;
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
|
||||
|
|
@ -108,4 +109,11 @@ public final class ConfigPropertiesBridge implements InstrumentationConfig {
|
|||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public DeclarativeConfigProperties getDeclarativeConfig(String instrumentationName) {
|
||||
// create a spring boot bridge for DeclarativeConfigProperties
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ dependencies {
|
|||
api("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi")
|
||||
api("net.bytebuddy:byte-buddy-dep")
|
||||
|
||||
implementation("io.opentelemetry:opentelemetry-api-incubator")
|
||||
implementation(project(":instrumentation-api"))
|
||||
implementation(project(":instrumentation-api-incubator"))
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
package io.opentelemetry.javaagent.bootstrap.internal;
|
||||
|
||||
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
|
||||
import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig;
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
|
|
@ -58,4 +59,10 @@ final class EmptyInstrumentationConfig implements InstrumentationConfig {
|
|||
public Map<String, String> getMap(String name, Map<String, String> defaultValue) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public DeclarativeConfigProperties getDeclarativeConfig(String instrumentationName) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ dependencies {
|
|||
implementation(project(":sdk-autoconfigure-support"))
|
||||
|
||||
implementation("io.opentelemetry:opentelemetry-api")
|
||||
testImplementation("io.opentelemetry:opentelemetry-api-incubator")
|
||||
implementation("io.opentelemetry:opentelemetry-sdk")
|
||||
implementation("io.opentelemetry:opentelemetry-extension-kotlin")
|
||||
implementation("io.opentelemetry:opentelemetry-extension-trace-propagators")
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ import io.opentelemetry.javaagent.tooling.muzzle.AgentTooling;
|
|||
import io.opentelemetry.javaagent.tooling.util.Trie;
|
||||
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
|
||||
import io.opentelemetry.sdk.autoconfigure.SdkAutoconfigureAccess;
|
||||
import io.opentelemetry.sdk.autoconfigure.internal.AutoConfigureUtil;
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
|
||||
import java.lang.instrument.ClassFileTransformer;
|
||||
import java.lang.instrument.Instrumentation;
|
||||
|
|
@ -166,7 +167,9 @@ public class AgentInstaller {
|
|||
installOpenTelemetrySdk(extensionClassLoader);
|
||||
|
||||
ConfigProperties sdkConfig = AgentListener.resolveConfigProperties(autoConfiguredSdk);
|
||||
AgentInstrumentationConfig.internalInitializeConfig(new ConfigPropertiesBridge(sdkConfig));
|
||||
AgentInstrumentationConfig.internalInitializeConfig(
|
||||
new ConfigPropertiesBridge(
|
||||
sdkConfig, AutoConfigureUtil.getConfigProvider(autoConfiguredSdk)));
|
||||
copyNecessaryConfigToSystemProperties(sdkConfig);
|
||||
|
||||
setBootstrapPackages(sdkConfig, extensionClassLoader);
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@
|
|||
|
||||
package io.opentelemetry.javaagent.tooling.config;
|
||||
|
||||
import io.opentelemetry.api.incubator.config.ConfigProvider;
|
||||
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
|
||||
import io.opentelemetry.api.incubator.config.InstrumentationConfigUtil;
|
||||
import io.opentelemetry.instrumentation.api.incubator.config.internal.InstrumentationConfig;
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
|
||||
|
|
@ -16,9 +19,12 @@ import javax.annotation.Nullable;
|
|||
public final class ConfigPropertiesBridge implements InstrumentationConfig {
|
||||
|
||||
private final ConfigProperties configProperties;
|
||||
@Nullable private final ConfigProvider configProvider;
|
||||
|
||||
public ConfigPropertiesBridge(ConfigProperties configProperties) {
|
||||
public ConfigPropertiesBridge(
|
||||
ConfigProperties configProperties, @Nullable ConfigProvider configProvider) {
|
||||
this.configProperties = configProperties;
|
||||
this.configProvider = configProvider;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
|
@ -102,4 +108,12 @@ public final class ConfigPropertiesBridge implements InstrumentationConfig {
|
|||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public DeclarativeConfigProperties getDeclarativeConfig(String instrumentationName) {
|
||||
return configProvider != null
|
||||
? InstrumentationConfigUtil.javaInstrumentationConfig(configProvider, instrumentationName)
|
||||
: null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@ dependencies {
|
|||
api("org.junit.jupiter:junit-jupiter-params")
|
||||
|
||||
api("io.opentelemetry:opentelemetry-api")
|
||||
compileOnly("io.opentelemetry:opentelemetry-api-incubator")
|
||||
api("io.opentelemetry:opentelemetry-sdk")
|
||||
api("io.opentelemetry:opentelemetry-sdk-testing")
|
||||
api("io.opentelemetry.semconv:opentelemetry-semconv-incubating")
|
||||
|
|
@ -69,6 +68,7 @@ dependencies {
|
|||
implementation("org.slf4j:jul-to-slf4j")
|
||||
implementation("io.opentelemetry:opentelemetry-exporter-logging")
|
||||
implementation("io.opentelemetry.contrib:opentelemetry-baggage-processor")
|
||||
implementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi")
|
||||
api(project(":instrumentation-api-incubator"))
|
||||
|
||||
annotationProcessor("com.google.auto.service:auto-service")
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import static java.util.Arrays.asList;
|
|||
import io.opentelemetry.api.GlobalOpenTelemetry;
|
||||
import io.opentelemetry.api.OpenTelemetry;
|
||||
import io.opentelemetry.api.baggage.propagation.W3CBaggagePropagator;
|
||||
import io.opentelemetry.api.incubator.config.GlobalConfigProvider;
|
||||
import io.opentelemetry.api.logs.LoggerProvider;
|
||||
import io.opentelemetry.api.metrics.MeterProvider;
|
||||
import io.opentelemetry.api.trace.TracerBuilder;
|
||||
|
|
@ -21,6 +22,9 @@ import io.opentelemetry.context.propagation.TextMapPropagator;
|
|||
import io.opentelemetry.contrib.baggage.processor.BaggageSpanProcessor;
|
||||
import io.opentelemetry.exporter.logging.LoggingSpanExporter;
|
||||
import io.opentelemetry.instrumentation.testing.internal.MetaDataCollector;
|
||||
import io.opentelemetry.instrumentation.testing.provider.TestLogRecordExporterComponentProvider;
|
||||
import io.opentelemetry.instrumentation.testing.provider.TestMetricExporterComponentProvider;
|
||||
import io.opentelemetry.instrumentation.testing.provider.TestSpanExporterComponentProvider;
|
||||
import io.opentelemetry.sdk.OpenTelemetrySdk;
|
||||
import io.opentelemetry.sdk.common.CompletableResultCode;
|
||||
import io.opentelemetry.sdk.logs.SdkLoggerProvider;
|
||||
|
|
@ -63,10 +67,14 @@ public final class LibraryTestRunner extends InstrumentationTestRunner {
|
|||
|
||||
static {
|
||||
GlobalOpenTelemetry.resetForTest();
|
||||
GlobalConfigProvider.resetForTest();
|
||||
|
||||
testSpanExporter = InMemorySpanExporter.create();
|
||||
testMetricExporter = InMemoryMetricExporter.create(AggregationTemporality.DELTA);
|
||||
testLogRecordExporter = InMemoryLogRecordExporter.create();
|
||||
TestSpanExporterComponentProvider.setSpanExporter(testSpanExporter);
|
||||
TestMetricExporterComponentProvider.setMetricExporter(testMetricExporter);
|
||||
TestLogRecordExporterComponentProvider.setLogRecordExporter(testLogRecordExporter);
|
||||
|
||||
metricReader =
|
||||
PeriodicMetricReader.builder(testMetricExporter)
|
||||
|
|
@ -116,6 +124,7 @@ public final class LibraryTestRunner extends InstrumentationTestRunner {
|
|||
public void beforeTestClass() {
|
||||
// just in case: if there was any test that modified the global instance, reset it
|
||||
GlobalOpenTelemetry.resetForTest();
|
||||
GlobalConfigProvider.resetForTest();
|
||||
GlobalOpenTelemetry.set(openTelemetrySdk);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -95,6 +95,7 @@ public abstract class InstrumentationExtension
|
|||
}
|
||||
|
||||
@SafeVarargs
|
||||
@SuppressWarnings("varargs")
|
||||
public final void waitAndAssertMetrics(
|
||||
String instrumentationName, Consumer<MetricAssert>... assertions) {
|
||||
testRunner.waitAndAssertMetrics(instrumentationName, assertions);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.testing.provider;
|
||||
|
||||
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
|
||||
import io.opentelemetry.sdk.logs.export.LogRecordExporter;
|
||||
import java.util.Objects;
|
||||
|
||||
public class TestLogRecordExporterComponentProvider
|
||||
implements ComponentProvider<LogRecordExporter> {
|
||||
|
||||
private static LogRecordExporter logRecordExporter;
|
||||
|
||||
@Override
|
||||
public Class<LogRecordExporter> getType() {
|
||||
return LogRecordExporter.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "test";
|
||||
}
|
||||
|
||||
@Override
|
||||
public LogRecordExporter create(DeclarativeConfigProperties config) {
|
||||
return Objects.requireNonNull(logRecordExporter, "logRecordExporter must not be null");
|
||||
}
|
||||
|
||||
public static void setLogRecordExporter(LogRecordExporter logRecordExporter) {
|
||||
TestLogRecordExporterComponentProvider.logRecordExporter = logRecordExporter;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.testing.provider;
|
||||
|
||||
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
|
||||
import io.opentelemetry.sdk.metrics.export.MetricExporter;
|
||||
import java.util.Objects;
|
||||
|
||||
public class TestMetricExporterComponentProvider implements ComponentProvider<MetricExporter> {
|
||||
|
||||
private static MetricExporter metricExporter;
|
||||
|
||||
@Override
|
||||
public Class<MetricExporter> getType() {
|
||||
return MetricExporter.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "test";
|
||||
}
|
||||
|
||||
@Override
|
||||
public MetricExporter create(DeclarativeConfigProperties config) {
|
||||
return Objects.requireNonNull(metricExporter, "metricExporter must not be null");
|
||||
}
|
||||
|
||||
public static void setMetricExporter(MetricExporter metricExporter) {
|
||||
TestMetricExporterComponentProvider.metricExporter = metricExporter;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.instrumentation.testing.provider;
|
||||
|
||||
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
|
||||
import io.opentelemetry.sdk.trace.export.SpanExporter;
|
||||
import java.util.Objects;
|
||||
|
||||
public class TestSpanExporterComponentProvider implements ComponentProvider<SpanExporter> {
|
||||
|
||||
private static SpanExporter spanExporter;
|
||||
|
||||
@Override
|
||||
public Class<SpanExporter> getType() {
|
||||
return SpanExporter.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "test";
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpanExporter create(DeclarativeConfigProperties config) {
|
||||
return Objects.requireNonNull(spanExporter, "spanExporter must not be null");
|
||||
}
|
||||
|
||||
public static void setSpanExporter(SpanExporter spanExporter) {
|
||||
TestSpanExporterComponentProvider.spanExporter = spanExporter;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
io.opentelemetry.instrumentation.testing.provider.TestSpanExporterComponentProvider
|
||||
io.opentelemetry.instrumentation.testing.provider.TestMetricExporterComponentProvider
|
||||
io.opentelemetry.instrumentation.testing.provider.TestLogRecordExporterComponentProvider
|
||||
|
||||
|
|
@ -17,5 +17,6 @@ dependencies {
|
|||
compileOnly(project(":javaagent-tooling"))
|
||||
|
||||
implementation("io.opentelemetry:opentelemetry-exporter-otlp-common")
|
||||
compileOnly("io.opentelemetry:opentelemetry-api-incubator")
|
||||
compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@
|
|||
|
||||
package io.opentelemetry.javaagent.testing.exporter;
|
||||
|
||||
import io.opentelemetry.javaagent.testing.provider.TestLogRecordExporterComponentProvider;
|
||||
import io.opentelemetry.javaagent.testing.provider.TestMetricExporterComponentProvider;
|
||||
import io.opentelemetry.javaagent.testing.provider.TestSpanExporterComponentProvider;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
|
@ -14,6 +17,12 @@ public final class AgentTestingExporterFactory {
|
|||
static final OtlpInMemoryMetricExporter metricExporter = new OtlpInMemoryMetricExporter();
|
||||
static final OtlpInMemoryLogRecordExporter logExporter = new OtlpInMemoryLogRecordExporter();
|
||||
|
||||
static {
|
||||
TestSpanExporterComponentProvider.setSpanExporter(spanExporter);
|
||||
TestMetricExporterComponentProvider.setMetricExporter(metricExporter);
|
||||
TestLogRecordExporterComponentProvider.setLogRecordExporter(logExporter);
|
||||
}
|
||||
|
||||
public static List<byte[]> getSpanExportRequests() {
|
||||
return spanExporter.getCollectedExportRequests();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.testing.provider;
|
||||
|
||||
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
|
||||
import io.opentelemetry.sdk.logs.export.LogRecordExporter;
|
||||
import java.util.Objects;
|
||||
|
||||
public class TestLogRecordExporterComponentProvider
|
||||
implements ComponentProvider<LogRecordExporter> {
|
||||
|
||||
private static LogRecordExporter logRecordExporter;
|
||||
|
||||
@Override
|
||||
public Class<LogRecordExporter> getType() {
|
||||
return LogRecordExporter.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "test";
|
||||
}
|
||||
|
||||
@Override
|
||||
public LogRecordExporter create(DeclarativeConfigProperties config) {
|
||||
return Objects.requireNonNull(logRecordExporter, "logRecordExporter must not be null");
|
||||
}
|
||||
|
||||
public static void setLogRecordExporter(LogRecordExporter logRecordExporter) {
|
||||
TestLogRecordExporterComponentProvider.logRecordExporter = logRecordExporter;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.testing.provider;
|
||||
|
||||
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
|
||||
import io.opentelemetry.sdk.metrics.export.MetricExporter;
|
||||
import java.util.Objects;
|
||||
|
||||
public class TestMetricExporterComponentProvider implements ComponentProvider<MetricExporter> {
|
||||
|
||||
private static MetricExporter metricExporter;
|
||||
|
||||
@Override
|
||||
public Class<MetricExporter> getType() {
|
||||
return MetricExporter.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "test";
|
||||
}
|
||||
|
||||
@Override
|
||||
public MetricExporter create(DeclarativeConfigProperties config) {
|
||||
return Objects.requireNonNull(metricExporter, "metricExporter must not be null");
|
||||
}
|
||||
|
||||
public static void setMetricExporter(MetricExporter metricExporter) {
|
||||
TestMetricExporterComponentProvider.metricExporter = metricExporter;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.javaagent.testing.provider;
|
||||
|
||||
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
|
||||
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
|
||||
import io.opentelemetry.sdk.trace.export.SpanExporter;
|
||||
import java.util.Objects;
|
||||
|
||||
public class TestSpanExporterComponentProvider implements ComponentProvider<SpanExporter> {
|
||||
|
||||
private static SpanExporter spanExporter;
|
||||
|
||||
@Override
|
||||
public Class<SpanExporter> getType() {
|
||||
return SpanExporter.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "test";
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpanExporter create(DeclarativeConfigProperties config) {
|
||||
return Objects.requireNonNull(spanExporter, "spanExporter must not be null");
|
||||
}
|
||||
|
||||
public static void setSpanExporter(SpanExporter spanExporter) {
|
||||
TestSpanExporterComponentProvider.spanExporter = spanExporter;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
io.opentelemetry.javaagent.testing.provider.TestSpanExporterComponentProvider
|
||||
io.opentelemetry.javaagent.testing.provider.TestMetricExporterComponentProvider
|
||||
io.opentelemetry.javaagent.testing.provider.TestLogRecordExporterComponentProvider
|
||||
|
||||
Loading…
Reference in New Issue