diff --git a/agent/agent-bootstrap/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/InstrumenterBuilder.java b/agent/agent-bootstrap/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/InstrumenterBuilder.java deleted file mode 100644 index 2d73619de53..00000000000 --- a/agent/agent-bootstrap/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/InstrumenterBuilder.java +++ /dev/null @@ -1,483 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// Includes work from: -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.instrumentation.api.instrumenter; - -import static java.util.Objects.requireNonNull; -import static java.util.logging.Level.WARNING; - -import com.google.errorprone.annotations.CanIgnoreReturnValue; -import com.microsoft.applicationinsights.agent.bootstrap.preagg.AiContextCustomizerHolder; -import io.opentelemetry.api.OpenTelemetry; -import io.opentelemetry.api.metrics.Meter; -import io.opentelemetry.api.metrics.MeterBuilder; -import io.opentelemetry.api.trace.SpanKind; -import io.opentelemetry.api.trace.StatusCode; -import io.opentelemetry.api.trace.Tracer; -import io.opentelemetry.api.trace.TracerBuilder; -import io.opentelemetry.context.Context; -import io.opentelemetry.context.propagation.TextMapGetter; -import io.opentelemetry.context.propagation.TextMapSetter; -import io.opentelemetry.instrumentation.api.internal.ConfigPropertiesUtil; -import io.opentelemetry.instrumentation.api.internal.EmbeddedInstrumentationProperties; -import io.opentelemetry.instrumentation.api.internal.InstrumenterBuilderAccess; -import io.opentelemetry.instrumentation.api.internal.InstrumenterUtil; -import io.opentelemetry.instrumentation.api.internal.InternalInstrumenterCustomizer; -import io.opentelemetry.instrumentation.api.internal.InternalInstrumenterCustomizerProvider; -import io.opentelemetry.instrumentation.api.internal.InternalInstrumenterCustomizerUtil; -import io.opentelemetry.instrumentation.api.internal.SchemaUrlProvider; -import io.opentelemetry.instrumentation.api.internal.SpanKey; -import io.opentelemetry.instrumentation.api.internal.SpanKeyProvider; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import java.util.function.Function; -import java.util.logging.Logger; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import javax.annotation.Nullable; - -// copied from OpenTelemetry Instrumentation 2.19.0 - -/** - * A builder of an {@link Instrumenter}. - * - *

Instrumentation libraries should generally expose their own builder with controls that are - * appropriate for that library and delegate to this class to create the {@link Instrumenter}. - */ -@SuppressWarnings("TypeParameterNaming") -public final class InstrumenterBuilder { - - private static final Logger logger = Logger.getLogger(InstrumenterBuilder.class.getName()); - - private static final SpanSuppressionStrategy spanSuppressionStrategy = - SpanSuppressionStrategy.fromConfig( - ConfigPropertiesUtil.getString( - "otel.instrumentation.experimental.span-suppression-strategy")); - - final OpenTelemetry openTelemetry; - final String instrumentationName; - SpanNameExtractor spanNameExtractor; - - final List> spanLinksExtractors = new ArrayList<>(); - final List> attributesExtractors = - new ArrayList<>(); - final List> contextCustomizers = new ArrayList<>(); - private final List operationListeners = new ArrayList<>(); - private final List operationMetrics = new ArrayList<>(); - - @Nullable private String instrumentationVersion; - @Nullable private String schemaUrl = null; - SpanKindExtractor spanKindExtractor = SpanKindExtractor.alwaysInternal(); - SpanStatusExtractor spanStatusExtractor = - SpanStatusExtractor.getDefault(); - ErrorCauseExtractor errorCauseExtractor = ErrorCauseExtractor.getDefault(); - boolean propagateOperationListenersToOnEnd = false; - boolean enabled = true; - - InstrumenterBuilder( - OpenTelemetry openTelemetry, - String instrumentationName, - SpanNameExtractor spanNameExtractor) { - this.openTelemetry = openTelemetry; - this.instrumentationName = instrumentationName; - this.spanNameExtractor = spanNameExtractor; - this.instrumentationVersion = - EmbeddedInstrumentationProperties.findVersion(instrumentationName); - - // START APPLICATION INSIGHTS MODIFICATIONS - contextCustomizers.add(AiContextCustomizerHolder.getInstance()); - // END APPLICATION INSIGHTS MODIFICATIONS - } - - /** - * Sets the instrumentation version that will be associated with all telemetry produced by this - * {@link Instrumenter}. - * - * @param instrumentationVersion is the version of the instrumentation library, not the version of - * the instrumented library. - */ - @CanIgnoreReturnValue - public InstrumenterBuilder setInstrumentationVersion( - String instrumentationVersion) { - this.instrumentationVersion = requireNonNull(instrumentationVersion, "instrumentationVersion"); - return this; - } - - /** - * Sets the OpenTelemetry schema URL that will be associated with all telemetry produced by this - * {@link Instrumenter}. - */ - @CanIgnoreReturnValue - public InstrumenterBuilder setSchemaUrl(String schemaUrl) { - this.schemaUrl = requireNonNull(schemaUrl, "schemaUrl"); - return this; - } - - /** - * Sets the {@link SpanStatusExtractor} that will determine the {@link StatusCode} for a response. - */ - @CanIgnoreReturnValue - public InstrumenterBuilder setSpanStatusExtractor( - SpanStatusExtractor spanStatusExtractor) { - this.spanStatusExtractor = requireNonNull(spanStatusExtractor, "spanStatusExtractor"); - return this; - } - - /** - * Adds a {@link AttributesExtractor} that will extract attributes from requests and responses. - */ - @CanIgnoreReturnValue - public InstrumenterBuilder addAttributesExtractor( - AttributesExtractor attributesExtractor) { - this.attributesExtractors.add(requireNonNull(attributesExtractor, "attributesExtractor")); - return this; - } - - /** Adds {@link AttributesExtractor}s that will extract attributes from requests and responses. */ - @CanIgnoreReturnValue - public InstrumenterBuilder addAttributesExtractors( - Iterable> - attributesExtractors) { - attributesExtractors.forEach(this::addAttributesExtractor); - return this; - } - - /** Adds a {@link SpanLinksExtractor} that will extract span links from requests. */ - @CanIgnoreReturnValue - public InstrumenterBuilder addSpanLinksExtractor( - SpanLinksExtractor spanLinksExtractor) { - spanLinksExtractors.add(requireNonNull(spanLinksExtractor, "spanLinksExtractor")); - return this; - } - - /** - * Adds a {@link ContextCustomizer} that will customize the context during {@link - * Instrumenter#start(Context, Object)}. - */ - @CanIgnoreReturnValue - public InstrumenterBuilder addContextCustomizer( - ContextCustomizer contextCustomizer) { - contextCustomizers.add(requireNonNull(contextCustomizer, "contextCustomizer")); - return this; - } - - /** - * Adds a {@link OperationListener} that will be called when an instrumented operation starts and - * ends. - */ - @CanIgnoreReturnValue - public InstrumenterBuilder addOperationListener(OperationListener listener) { - operationListeners.add(requireNonNull(listener, "operationListener")); - return this; - } - - /** - * Adds a {@link OperationMetrics} that will produce a {@link OperationListener} capturing the - * requests processing metrics. - */ - @CanIgnoreReturnValue - public InstrumenterBuilder addOperationMetrics(OperationMetrics factory) { - operationMetrics.add(requireNonNull(factory, "operationMetrics")); - return this; - } - - /** - * Sets the {@link ErrorCauseExtractor} that will extract the root cause of an error thrown during - * request processing. - */ - @CanIgnoreReturnValue - public InstrumenterBuilder setErrorCauseExtractor( - ErrorCauseExtractor errorCauseExtractor) { - this.errorCauseExtractor = requireNonNull(errorCauseExtractor, "errorCauseExtractor"); - return this; - } - - /** - * Allows enabling/disabling the {@link Instrumenter} based on the {@code enabled} value passed as - * parameter. All instrumenters are enabled by default. - */ - @CanIgnoreReturnValue - public InstrumenterBuilder setEnabled(boolean enabled) { - this.enabled = enabled; - return this; - } - - /** - * Returns a new {@link Instrumenter} which will create {@linkplain SpanKind#CLIENT client} spans - * and inject context into requests with the passed {@link TextMapSetter}. - */ - public Instrumenter buildClientInstrumenter(TextMapSetter setter) { - return buildInstrumenter( - InstrumenterConstructor.propagatingToDownstream(requireNonNull(setter, "setter")), - SpanKindExtractor.alwaysClient()); - } - - /** - * Returns a new {@link Instrumenter} which will create {@linkplain SpanKind#SERVER server} spans - * and extract context from requests with the passed {@link TextMapGetter}. - */ - public Instrumenter buildServerInstrumenter(TextMapGetter getter) { - return buildInstrumenter( - InstrumenterConstructor.propagatingFromUpstream(requireNonNull(getter, "getter")), - SpanKindExtractor.alwaysServer()); - } - - /** - * Returns a new {@link Instrumenter} which will create {@linkplain SpanKind#PRODUCER producer} - * spans and inject context into requests with the passed {@link TextMapSetter}. - */ - public Instrumenter buildProducerInstrumenter(TextMapSetter setter) { - return buildInstrumenter( - InstrumenterConstructor.propagatingToDownstream(requireNonNull(setter, "setter")), - SpanKindExtractor.alwaysProducer()); - } - - /** - * Returns a new {@link Instrumenter} which will create {@linkplain SpanKind#CONSUMER consumer} - * spans and extract context from requests with the passed {@link TextMapGetter}. - */ - public Instrumenter buildConsumerInstrumenter(TextMapGetter getter) { - return buildInstrumenter( - InstrumenterConstructor.propagatingFromUpstream(requireNonNull(getter, "getter")), - SpanKindExtractor.alwaysConsumer()); - } - - /** - * Returns a new {@link Instrumenter} which will create spans with kind determined by the passed - * {@link SpanKindExtractor} and extract context from requests with the passed {@link - * TextMapGetter}. - */ - // TODO: candidate for public API - Instrumenter buildUpstreamInstrumenter( - TextMapGetter getter, SpanKindExtractor spanKindExtractor) { - return buildInstrumenter( - InstrumenterConstructor.propagatingFromUpstream(requireNonNull(getter, "getter")), - spanKindExtractor); - } - - /** - * Returns a new {@link Instrumenter} which will create spans with kind determined by the passed - * {@link SpanKindExtractor} and inject context into requests with the passed {@link - * TextMapSetter}. - */ - // TODO: candidate for public API - Instrumenter buildDownstreamInstrumenter( - TextMapSetter setter, SpanKindExtractor spanKindExtractor) { - return buildInstrumenter( - InstrumenterConstructor.propagatingToDownstream(requireNonNull(setter, "setter")), - spanKindExtractor); - } - - /** - * Returns a new {@link Instrumenter} which will create {@linkplain SpanKind#INTERNAL internal} - * spans and do no context propagation. - */ - public Instrumenter buildInstrumenter() { - return buildInstrumenter( - InstrumenterConstructor.internal(), SpanKindExtractor.alwaysInternal()); - } - - /** - * Returns a new {@link Instrumenter} which will create spans with kind determined by the passed - * {@link SpanKindExtractor} and do no context propagation. - */ - public Instrumenter buildInstrumenter( - SpanKindExtractor spanKindExtractor) { - return buildInstrumenter( - InstrumenterConstructor.internal(), requireNonNull(spanKindExtractor, "spanKindExtractor")); - } - - private Instrumenter buildInstrumenter( - InstrumenterConstructor constructor, - SpanKindExtractor spanKindExtractor) { - applyCustomizers(this); - - this.spanKindExtractor = spanKindExtractor; - return constructor.create(this); - } - - Tracer buildTracer() { - TracerBuilder tracerBuilder = - openTelemetry.getTracerProvider().tracerBuilder(instrumentationName); - if (instrumentationVersion != null) { - tracerBuilder.setInstrumentationVersion(instrumentationVersion); - } - String schemaUrl = getSchemaUrl(); - if (schemaUrl != null) { - tracerBuilder.setSchemaUrl(schemaUrl); - } - return tracerBuilder.build(); - } - - List buildOperationListeners() { - // just copy the listeners list if there are no metrics registered - if (operationMetrics.isEmpty()) { - return new ArrayList<>(operationListeners); - } - - List listeners = - new ArrayList<>(operationListeners.size() + operationMetrics.size()); - listeners.addAll(operationListeners); - - MeterBuilder meterBuilder = openTelemetry.getMeterProvider().meterBuilder(instrumentationName); - if (instrumentationVersion != null) { - meterBuilder.setInstrumentationVersion(instrumentationVersion); - } - String schemaUrl = getSchemaUrl(); - if (schemaUrl != null) { - meterBuilder.setSchemaUrl(schemaUrl); - } - Meter meter = meterBuilder.build(); - for (OperationMetrics factory : operationMetrics) { - listeners.add(factory.create(meter)); - } - - return listeners; - } - - @Nullable - private String getSchemaUrl() { - // url set explicitly overrides url computed using attributes extractors - if (schemaUrl != null) { - return schemaUrl; - } - Set computedSchemaUrls = - attributesExtractors.stream() - .filter(SchemaUrlProvider.class::isInstance) - .map(SchemaUrlProvider.class::cast) - .flatMap( - provider -> { - String url = provider.internalGetSchemaUrl(); - return url == null ? Stream.of() : Stream.of(url); - }) - .collect(Collectors.toSet()); - switch (computedSchemaUrls.size()) { - case 0: - return null; - case 1: - return computedSchemaUrls.iterator().next(); - default: - logger.log( - WARNING, - "Multiple schemaUrls were detected: {0}. The built Instrumenter will have no schemaUrl assigned.", - computedSchemaUrls); - return null; - } - } - - SpanSuppressor buildSpanSuppressor() { - return new SpanSuppressors.ByContextKey( - spanSuppressionStrategy.create(getSpanKeysFromAttributesExtractors())); - } - - private Set getSpanKeysFromAttributesExtractors() { - return attributesExtractors.stream() - .filter(SpanKeyProvider.class::isInstance) - .map(SpanKeyProvider.class::cast) - .flatMap( - provider -> { - SpanKey spanKey = provider.internalGetSpanKey(); - return spanKey == null ? Stream.of() : Stream.of(spanKey); - }) - .collect(Collectors.toSet()); - } - - private void propagateOperationListenersToOnEnd() { - propagateOperationListenersToOnEnd = true; - } - - private static void applyCustomizers( - InstrumenterBuilder builder) { - for (InternalInstrumenterCustomizerProvider provider : - InternalInstrumenterCustomizerUtil.getInstrumenterCustomizerProviders()) { - provider.customize( - new InternalInstrumenterCustomizer() { - @Override - public String getInstrumentationName() { - return builder.instrumentationName; - } - - @Override - public void addAttributesExtractor(AttributesExtractor extractor) { - builder.addAttributesExtractor(extractor); - } - - @Override - public void addAttributesExtractors( - Iterable> extractors) { - builder.addAttributesExtractors(extractors); - } - - @Override - public void addOperationMetrics(OperationMetrics operationMetrics) { - builder.addOperationMetrics(operationMetrics); - } - - @Override - public void addContextCustomizer(ContextCustomizer customizer) { - builder.addContextCustomizer(customizer); - } - - @Override - public void setSpanNameExtractor( - Function, SpanNameExtractor> - spanNameExtractorTransformer) { - builder.spanNameExtractor = - spanNameExtractorTransformer.apply(builder.spanNameExtractor); - } - }); - } - } - - private interface InstrumenterConstructor { - Instrumenter create(InstrumenterBuilder builder); - - static InstrumenterConstructor internal() { - return Instrumenter::new; - } - - static InstrumenterConstructor propagatingToDownstream( - TextMapSetter setter) { - return builder -> new PropagatingToDownstreamInstrumenter<>(builder, setter); - } - - static InstrumenterConstructor propagatingFromUpstream( - TextMapGetter getter) { - return builder -> new PropagatingFromUpstreamInstrumenter<>(builder, getter); - } - } - - static { - InstrumenterUtil.setInstrumenterBuilderAccess( - new InstrumenterBuilderAccess() { - @Override - public Instrumenter buildUpstreamInstrumenter( - InstrumenterBuilder builder, - TextMapGetter getter, - SpanKindExtractor spanKindExtractor) { - return builder.buildUpstreamInstrumenter(getter, spanKindExtractor); - } - - @Override - public Instrumenter buildDownstreamInstrumenter( - InstrumenterBuilder builder, - TextMapSetter setter, - SpanKindExtractor spanKindExtractor) { - return builder.buildDownstreamInstrumenter(setter, spanKindExtractor); - } - - @Override - public void propagateOperationListenersToOnEnd( - InstrumenterBuilder builder) { - builder.propagateOperationListenersToOnEnd(); - } - }); - } -} diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/AiInstrumenterCustomizerProvider.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/AiInstrumenterCustomizerProvider.java new file mode 100644 index 00000000000..beaf6f2600d --- /dev/null +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/init/AiInstrumenterCustomizerProvider.java @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.microsoft.applicationinsights.agent.internal.init; + +import com.google.auto.service.AutoService; +import com.microsoft.applicationinsights.agent.bootstrap.preagg.AiContextCustomizerHolder; +import io.opentelemetry.instrumentation.api.incubator.instrumenter.InstrumenterCustomizer; +import io.opentelemetry.instrumentation.api.incubator.instrumenter.InstrumenterCustomizerProvider; + +/** + * InstrumenterCustomizerProvider implementation that adds Application Insights context customizer + * to all instrumenters. This replaces the need for copying the InstrumenterBuilder class. + */ +@AutoService(InstrumenterCustomizerProvider.class) +public class AiInstrumenterCustomizerProvider implements InstrumenterCustomizerProvider { + + @Override + public void customize(InstrumenterCustomizer customizer) { + // Add the Application Insights context customizer to all instrumenters + // This was previously done by modifying the InstrumenterBuilder constructor + customizer.addContextCustomizer(AiContextCustomizerHolder.getInstance()); + } +} diff --git a/agent/agent/build.gradle.kts b/agent/agent/build.gradle.kts index bc8c5e41423..c7a9d4f147f 100644 --- a/agent/agent/build.gradle.kts +++ b/agent/agent/build.gradle.kts @@ -111,11 +111,6 @@ tasks { exclude("inst/io/prometheus/**") - // this excludes the upstream classes, but not the distro classes since the exclusion step - // takes place before the transformation step - exclude("io/opentelemetry/javaagent/shaded/instrumentation/api/instrumenter/http/TemporaryMetricsView.class") - exclude("io/opentelemetry/javaagent/shaded/instrumentation/api/instrumenter/InstrumenterBuilder.class") - dependsOn(isolateJavaagentLibs) from(isolateJavaagentLibs.get().outputs)