-
Notifications
You must be signed in to change notification settings - Fork 1k
Support extensions for attributesExtractors, contextCustomizers, operationListeners and spanNameExtractor #13917
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
trask
merged 23 commits into
open-telemetry:main
from
steverao:support-custom-extention
Aug 14, 2025
Merged
Changes from 14 commits
Commits
Show all changes
23 commits
Select commit
Hold shift + click to select a range
7b4c56d
Support extensions for attributesExtractors, contextCustomizers and o…
steverao 8ba2bf0
Fix failing test
steverao 84b1c70
Merge branch 'main' into support-custom-extention
steverao 5531d16
Fix failing CI
steverao 35da705
Add necessary description of classes
steverao 30182a3
Address review comments
steverao 6972f96
Address review comments
steverao 59662da
Moved API to internal directory
steverao 798ba56
Moved API to internal directory
steverao 611aa90
Moved API to internal directory
steverao 891822a
Fix CI failing
steverao 7ed6e43
Add support for spanNameExtractor
steverao da46f57
Support extensions for spanNameExtractor
steverao 7109962
Optimize codes
steverao 159e53d
Refactor extension to be consistent with existence.
steverao e7d8de3
Move customizer api to incubator module (#9)
laurit fb9d6c6
Optimize codes
steverao 5c0489c
Add example
steverao f11181d
Removed unexpected part in example
steverao 47bf9da
Fix formatting in DemoInstrumenterCustomizerProvider
steverao 49a2e90
Address review comments
steverao 26e1675
Add missing imports in InstrumenterCustomizer
steverao 5ca4e61
Update README to clarify customization conditions based on instrument…
steverao File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
98 changes: 98 additions & 0 deletions
98
...rc/main/java/io/opentelemetry/instrumentation/api/internal/InstrumentationCustomizer.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,98 @@ | ||
| /* | ||
| * Copyright The OpenTelemetry Authors | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
|
|
||
| package io.opentelemetry.instrumentation.api.internal; | ||
|
|
||
| import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; | ||
| import io.opentelemetry.instrumentation.api.instrumenter.ContextCustomizer; | ||
| import io.opentelemetry.instrumentation.api.instrumenter.OperationMetrics; | ||
| import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; | ||
| import java.util.List; | ||
| import java.util.function.Predicate; | ||
| import javax.annotation.Nullable; | ||
|
|
||
| /** | ||
| * A service provider interface (SPI) for providing customizations for instrumentation, including | ||
| * operation metrics, attributes extraction, and context customization. | ||
| * | ||
| * <p>This allows external modules or plugins to contribute custom logic for specific instrumented | ||
| * libraries, without modifying core instrumentation code. This class is internal and is hence not | ||
| * for public use. Its APIs are unstable and can change at any time. | ||
| */ | ||
| public interface InstrumentationCustomizer { | ||
|
|
||
| /** | ||
| * Returns a predicate that determines whether this customizer supports a given instrumentation | ||
| * name. | ||
| * | ||
| * <p>The customizer will only be applied if the current instrumentation name matches the | ||
| * predicate. For example, the predicate might match names like "io.opentelemetry.netty-3.8" or | ||
| * "io.opentelemetry.apache-httpclient-4.3". | ||
| * | ||
| * @return a predicate for supported instrumentation names | ||
| */ | ||
| Predicate<String> instrumentationNamePredicate(); | ||
|
|
||
| /** | ||
| * Returns a new instance of an {@link OperationMetrics} that will record metrics for the | ||
| * instrumented operation. | ||
| * | ||
| * @return an operation metrics instance, or null if not applicable | ||
| */ | ||
| default OperationMetrics getOperationMetrics() { | ||
| return null; | ||
| } | ||
|
|
||
| /** | ||
| * Returns a new instance of an {@link AttributesExtractor} that will extract attributes from | ||
| * requests and responses during the instrumentation process. | ||
| * | ||
| * @param <REQUEST> the type of request object used by the instrumented library | ||
| * @param <RESPONSE> the type of response object used by the instrumented library | ||
| * @return an attributes extractor instance, or null if not applicable | ||
| */ | ||
| default <REQUEST, RESPONSE> AttributesExtractor<REQUEST, RESPONSE> getAttributesExtractor() { | ||
| return null; | ||
| } | ||
|
|
||
| /** | ||
| * Returns a list of {@link AttributesExtractor}s that will extract attributes from requests and | ||
| * responses during the instrumentation process. | ||
| * | ||
| * <p>This allows providing multiple extractors for a single instrumentation. The default | ||
| * implementation returns {@code null} for backward compatibility. | ||
| * | ||
| * @param <REQUEST> the type of request object used by the instrumented library | ||
| * @param <RESPONSE> the type of response object used by the instrumented library | ||
| * @return a list of attributes extractors, or null if not applicable | ||
| */ | ||
| @Nullable | ||
| default <REQUEST, RESPONSE> | ||
| List<AttributesExtractor<REQUEST, RESPONSE>> getAttributesExtractors() { | ||
| return null; | ||
| } | ||
|
|
||
| /** | ||
| * Returns a new instance of a {@link ContextCustomizer} that will customize the tracing context | ||
| * during request processing. | ||
| * | ||
| * @param <REQUEST> the type of request object used by the instrumented library | ||
| * @return a context customizer instance, or null if not applicable | ||
| */ | ||
| default <REQUEST> ContextCustomizer<REQUEST> getContextCustomizer() { | ||
| return null; | ||
| } | ||
|
|
||
| /** | ||
| * Returns a new instance of a {@link SpanNameExtractor} that will customize the span name during | ||
| * request processing. | ||
| * | ||
| * @param <REQUEST> the type of request object used by the instrumented library | ||
| * @return a customized {@link SpanNameExtractor}, or null if not applicable | ||
| */ | ||
| default <REQUEST> SpanNameExtractor<REQUEST> getSpanNameExtractor() { | ||
| return null; | ||
| } | ||
| } | ||
41 changes: 41 additions & 0 deletions
41
...on-api/src/main/java/io/opentelemetry/instrumentation/api/internal/ServiceLoaderUtil.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| /* | ||
| * Copyright The OpenTelemetry Authors | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
|
|
||
| package io.opentelemetry.instrumentation.api.internal; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
| import java.util.ServiceLoader; | ||
| import java.util.function.Function; | ||
|
|
||
| /** | ||
| * This class is internal and is hence not for public use. Its APIs are unstable and can change at | ||
| * any time. | ||
| */ | ||
| public final class ServiceLoaderUtil { | ||
|
|
||
| private static Function<Class<?>, List<?>> loaderFunction = | ||
steverao marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| clazz -> { | ||
| List<Object> instances = new ArrayList<>(); | ||
| ServiceLoader<?> serviceLoader = ServiceLoader.load(clazz); | ||
| for (Object instance : serviceLoader) { | ||
| instances.add(instance); | ||
| } | ||
| return instances; | ||
| }; | ||
|
|
||
| private ServiceLoaderUtil() { | ||
| // Utility class, no instantiation | ||
| } | ||
|
|
||
| @SuppressWarnings("unchecked") | ||
| public static <T> List<T> load(Class<T> clazz) { | ||
| return (List<T>) loaderFunction.apply(clazz); | ||
| } | ||
|
|
||
| public static void setLoaderFunction(Function<Class<?>, List<?>> customLoaderFunction) { | ||
| loaderFunction = customLoaderFunction; | ||
| } | ||
| } | ||
110 changes: 110 additions & 0 deletions
110
...est/java/io/opentelemetry/instrumentation/api/internal/InstrumentationCustomizerTest.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,110 @@ | ||
| /* | ||
| * Copyright The OpenTelemetry Authors | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
|
|
||
| package io.opentelemetry.instrumentation.api.internal; | ||
|
|
||
| import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; | ||
|
|
||
| import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; | ||
| import io.opentelemetry.instrumentation.api.instrumenter.ContextCustomizer; | ||
| import io.opentelemetry.instrumentation.api.instrumenter.OperationMetrics; | ||
| import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; | ||
| import java.util.Collections; | ||
| import java.util.List; | ||
| import java.util.function.Predicate; | ||
| import org.junit.jupiter.api.BeforeEach; | ||
| import org.junit.jupiter.api.Test; | ||
| import org.junit.jupiter.api.extension.ExtendWith; | ||
| import org.mockito.Mock; | ||
| import org.mockito.junit.jupiter.MockitoExtension; | ||
|
|
||
| @ExtendWith(MockitoExtension.class) | ||
| class InstrumentationCustomizerTest { | ||
|
|
||
| @Mock private OperationMetrics operationMetrics; | ||
| @Mock private AttributesExtractor<Object, Object> attributesExtractor; | ||
| @Mock private ContextCustomizer<Object> contextCustomizer; | ||
| @Mock private SpanNameExtractor<Object> spanNameExtractor; | ||
|
|
||
| private InstrumentationCustomizer customizer; | ||
|
|
||
| @BeforeEach | ||
| @SuppressWarnings("unchecked") | ||
| void setUp() { | ||
| customizer = | ||
| new InstrumentationCustomizer() { | ||
|
|
||
| @Override | ||
| public Predicate<String> instrumentationNamePredicate() { | ||
| return name -> name.startsWith("test.instrumentation"); | ||
| } | ||
|
|
||
| @Override | ||
| public OperationMetrics getOperationMetrics() { | ||
| return operationMetrics; | ||
| } | ||
|
|
||
| @Override | ||
| public <REQUEST, RESPONSE> | ||
| AttributesExtractor<REQUEST, RESPONSE> getAttributesExtractor() { | ||
| return (AttributesExtractor<REQUEST, RESPONSE>) attributesExtractor; | ||
| } | ||
|
|
||
| @Override | ||
| public <REQUEST, RESPONSE> | ||
| List<AttributesExtractor<REQUEST, RESPONSE>> getAttributesExtractors() { | ||
| return Collections.singletonList( | ||
| (AttributesExtractor<REQUEST, RESPONSE>) attributesExtractor); | ||
| } | ||
|
|
||
| @Override | ||
| public <REQUEST> ContextCustomizer<REQUEST> getContextCustomizer() { | ||
| return (ContextCustomizer<REQUEST>) contextCustomizer; | ||
| } | ||
|
|
||
| @Override | ||
| public <REQUEST> SpanNameExtractor<REQUEST> getSpanNameExtractor() { | ||
| return (SpanNameExtractor<REQUEST>) spanNameExtractor; | ||
| } | ||
| }; | ||
| } | ||
|
|
||
| @Test | ||
| void testInstrumentationNamePredicate() { | ||
| assertThat(customizer.instrumentationNamePredicate().test("test.instrumentation.example")) | ||
| .isTrue(); | ||
| assertThat(customizer.instrumentationNamePredicate().test("other.instrumentation.example")) | ||
| .isFalse(); | ||
| } | ||
|
|
||
| @Test | ||
| void testGetOperationMetrics() { | ||
| OperationMetrics metrics = customizer.getOperationMetrics(); | ||
| assertThat(metrics).isSameAs(operationMetrics); | ||
| } | ||
|
|
||
| @Test | ||
| void testGetAttributesExtractor() { | ||
| AttributesExtractor<Object, Object> extractor = customizer.getAttributesExtractor(); | ||
| assertThat(extractor).isSameAs(attributesExtractor); | ||
| } | ||
|
|
||
| @Test | ||
| void testGetAttributesExtractors() { | ||
| List<AttributesExtractor<Object, Object>> extractors = customizer.getAttributesExtractors(); | ||
| assertThat(extractors).containsExactly(attributesExtractor); | ||
| } | ||
|
|
||
| @Test | ||
| void testGetContextCustomizer() { | ||
| assertThat(customizer.getContextCustomizer()).isSameAs(contextCustomizer); | ||
| } | ||
|
|
||
| @Test | ||
| void testGetSpanNameExtractor() { | ||
| SpanNameExtractor<Object> extractor = customizer.getSpanNameExtractor(); | ||
| assertThat(extractor).isSameAs(spanNameExtractor); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.