Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
86c9dc6
add system properties bridge
zeitlinger Nov 17, 2025
1538cf5
add system properties bridge
zeitlinger Nov 17, 2025
b68ada4
add tests
zeitlinger Nov 17, 2025
c9e630c
add list
zeitlinger Nov 18, 2025
ca0249b
refactor
zeitlinger Nov 18, 2025
e8238c8
refactor
zeitlinger Nov 18, 2025
1b6a955
string
zeitlinger Nov 18, 2025
6d1472d
string
zeitlinger Nov 18, 2025
15ff6ca
string
zeitlinger Nov 18, 2025
2da5774
string
zeitlinger Nov 18, 2025
8414a8d
string
zeitlinger Nov 18, 2025
75f1a1b
string
zeitlinger Nov 18, 2025
a3aae6f
string
zeitlinger Nov 18, 2025
2a5bedb
string
zeitlinger Nov 18, 2025
22df64b
javadoc
zeitlinger Nov 18, 2025
8b028e4
add contract
zeitlinger Nov 18, 2025
949d443
add contract
zeitlinger Nov 18, 2025
2856550
remove contract
zeitlinger Nov 18, 2025
fea44fa
remove contract
zeitlinger Nov 18, 2025
29b691e
inline method to avoid class not found exception for DeclarativeConfi…
zeitlinger Nov 18, 2025
bf79af8
pr review
zeitlinger Nov 25, 2025
b3148b2
use optional instead of providing default for boolean
zeitlinger Nov 25, 2025
77e228e
use optional instead of providing default for int
zeitlinger Nov 25, 2025
516fce8
use optional instead of providing default for list
zeitlinger Nov 25, 2025
6e47652
use optional instead of providing default for string
zeitlinger Nov 25, 2025
42a2495
fix
zeitlinger Nov 25, 2025
68d05e2
fix
zeitlinger Nov 25, 2025
013caa9
fix
zeitlinger Nov 25, 2025
70fa129
split pr
zeitlinger Nov 27, 2025
6564d1d
split pr
zeitlinger Nov 27, 2025
3bc5bbe
fix
zeitlinger Nov 27, 2025
75fefac
fix
zeitlinger Nov 27, 2025
a1867eb
pr review
zeitlinger Dec 3, 2025
6bba135
revert aws test
zeitlinger Dec 3, 2025
4a104d4
use "/development" instead of "experimental" in declarative config
zeitlinger Dec 3, 2025
265f236
use "/development" instead of "experimental" in declarative config
zeitlinger Dec 3, 2025
0bf6460
fix
zeitlinger Dec 3, 2025
1a292e2
docs
zeitlinger Dec 3, 2025
23932b3
avoid double bridge
zeitlinger Dec 4, 2025
5221a18
normalize system props before lookup to avoid ambiguity of "experimen…
zeitlinger Dec 4, 2025
aa2ebcb
normalize system props before lookup to avoid ambiguity of "experimen…
zeitlinger Dec 4, 2025
6abc03f
normalize system props before lookup to avoid ambiguity of "experimen…
zeitlinger Dec 5, 2025
91d25fc
normalize system props before lookup to avoid ambiguity of "experimen…
zeitlinger Dec 5, 2025
36494c5
rename js snippet property
zeitlinger Dec 5, 2025
8eaf7d6
normalize system props before lookup to avoid ambiguity of "experimen…
zeitlinger Dec 5, 2025
031ab24
add changelog
zeitlinger Dec 7, 2025
86456ca
format
zeitlinger Dec 7, 2025
edcda71
remove param that is always false
zeitlinger Dec 11, 2025
7ed8b6e
remove performance optimization
zeitlinger Dec 11, 2025
6e5fbb6
remove performance optimization
zeitlinger Dec 11, 2025
16cc3a7
avoid lambda in early phase
zeitlinger Dec 11, 2025
3c4a069
deprecated fallback
trask Dec 11, 2025
3982f88
cleanup
zeitlinger Dec 12, 2025
61da982
fix experimental in the middle
zeitlinger Dec 12, 2025
3b7e81b
add SystemPropertiesDeclarativeConfigProperties
zeitlinger Dec 12, 2025
42ab6c0
add SystemPropertiesDeclarativeConfigProperties
zeitlinger Dec 12, 2025
0e1343f
add SystemPropertiesDeclarativeConfigProperties
zeitlinger Dec 12, 2025
4ec6980
add to InstrumentationConfig
zeitlinger Dec 12, 2025
157507a
add to InstrumentationConfig
zeitlinger Dec 12, 2025
1138e43
add to InstrumentationConfig
zeitlinger Dec 12, 2025
3f65273
use InstrumentationConfigUtil
zeitlinger Dec 12, 2025
b8b562a
cleanup
zeitlinger Dec 12, 2025
7799b48
simplify
zeitlinger Dec 12, 2025
0264b54
fix
zeitlinger Dec 12, 2025
9164797
fix
zeitlinger Dec 12, 2025
30f1943
cleanup
zeitlinger Dec 12, 2025
2d2ed1a
use bridge
zeitlinger Dec 12, 2025
c2a048a
use bridge
zeitlinger Dec 12, 2025
22d71fc
use bridge
zeitlinger Dec 12, 2025
176e09b
fix
zeitlinger Dec 12, 2025
11d523d
fix
zeitlinger Dec 12, 2025
2507ce4
fix
zeitlinger Dec 12, 2025
a50c5e8
docs
zeitlinger Dec 12, 2025
e3b2711
fix
zeitlinger Dec 13, 2025
17e0ada
avoid inheritance
zeitlinger Dec 13, 2025
c6b5ea3
avoid inheritance
zeitlinger Dec 13, 2025
d4eb195
avoid inheritance
zeitlinger Dec 13, 2025
ece1b21
simplify logic to determine bridged config provider
zeitlinger Dec 13, 2025
a9fd3e2
api
zeitlinger Dec 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@

### ⚠️ Breaking Changes

- Rename `otel.experimental.javascript-snippet` to
`otel.instrumentation.servlet.experimental.javascript-snippet` to follow naming conventions
([#15339](https://github.com/open-telemetry/opentelemetry-java-instrumentation/pull/15339))

### ⚠️ Breaking Changes

- ActiveMQ Classic JMX metrics: rename attributes and metrics to align
with semantic conventions (see PR description for specifics)
([#14996](https://github.com/open-telemetry/opentelemetry-java-instrumentation/pull/14996))
Expand Down
1 change: 1 addition & 0 deletions declarative-config-bridge/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ group = "io.opentelemetry.instrumentation"

dependencies {
compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure")
implementation(project(":instrumentation-api"))
implementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi")
implementation("io.opentelemetry:opentelemetry-api-incubator")

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.instrumentation.config.bridge;

import io.opentelemetry.api.incubator.config.ConfigProvider;
import io.opentelemetry.instrumentation.api.internal.BridgedConfigProvider;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;

public final class ConfigPropertiesDeclarativeConfigProperties {

private ConfigPropertiesDeclarativeConfigProperties() {}

public static ConfigProvider create(ConfigProperties configProperties) {
return new BridgedConfigProvider(configProperties::getString);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.instrumentation.config.bridge;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import io.opentelemetry.api.incubator.config.ConfigProvider;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import org.junit.jupiter.api.Test;

class ConfigPropertiesDeclarativeConfigPropertiesTest {

@Test
void shouldBridgeConfigProperties() {
ConfigProperties configProperties = mock(ConfigProperties.class);
when(configProperties.getString("otel.instrumentation.foo.bar")).thenReturn("baz");
when(configProperties.getString("otel.instrumentation.experimental.foo.bar")).thenReturn("qux");

ConfigProvider configProvider =
ConfigPropertiesDeclarativeConfigProperties.create(configProperties);
DeclarativeConfigProperties properties = configProvider.getInstrumentationConfig();

assertThat(properties.getStructured("java").getStructured("foo").getString("bar"))
.isEqualTo("baz");
assertThat(properties.getStructured("java").getStructured("foo/development").getString("bar"))
.isEqualTo("qux");
}
}
6 changes: 3 additions & 3 deletions docs/advanced-configuration-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ This feature is designed for integrating client-side monitoring.
We plan to integrate OpenTelemetry's own client-side monitoring solution by default once it's available
(see the [browser instrumentation proposal](https://github.com/open-telemetry/community/blob/main/projects/browser-phase-1.md)).

| System property | Environment variable | Purpose |
|--------------------------------------|--------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| otel.experimental.javascript-snippet | OTEL_EXPERIMENTAL_JAVASCRIPT_SNIPPET | Experimental setting to inject a JavaScript snippet into HTML responses after the opening `<head>` tag. The value should be a complete JavaScript snippet including `<script>` tags if needed, e.g. `-Dotel.experimental.javascript-snippet="<script>console.log('Hello world!');</script>"` |
| System property | Environment variable | Purpose |
|----------------------------------------------------------------|----------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `otel.instrumentation.servlet.experimental.javascript-snippet` | `OTEL_INSTRUMENTATION_SERVLET_EXPERIMENTAL_JAVASCRIPT_SNIPPET` | Experimental setting to inject a JavaScript snippet into HTML responses after the opening `<head>` tag. The value should be a complete JavaScript snippet including `<script>` tags if needed, e.g. `-Dotel.instrumentation.servlet.experimental.javascript-snippet="<script>console.log('Hello world!');</script>"` |

**Important notes:**

Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
Comparing source compatibility of opentelemetry-instrumentation-api-2.24.0-SNAPSHOT.jar against opentelemetry-instrumentation-api-2.23.0.jar
No changes.
*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder (not serializable)
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
GENERIC TEMPLATES: === REQUEST:java.lang.Object, === RESPONSE:java.lang.Object
+++ NEW METHOD: PUBLIC(+) STATIC(+) boolean isDeclarativeConfig(io.opentelemetry.api.OpenTelemetry)
Original file line number Diff line number Diff line change
Expand Up @@ -175,9 +175,8 @@ private static <T> T getFromConfigProviderOrFallback(
ValueProvider<T> getFromConfigProvider,
T defaultValue,
Supplier<T> fallback) {
ConfigProvider configProvider = config.getConfigProvider();
if (configProvider != null) {
T value = getFromConfigProvider.get(configProvider);
if (config.isDeclarative()) {
T value = getFromConfigProvider.get(config.getConfigProvider());
return value != null ? value : defaultValue;
}
// fallback doesn't return null, so we can safely call it
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@

package io.opentelemetry.instrumentation.api.incubator.config.internal;

import static io.opentelemetry.api.incubator.config.DeclarativeConfigProperties.empty;
import static java.util.Collections.emptyList;

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.internal.BridgedConfigProvider;
import java.time.Duration;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -111,29 +114,34 @@ default List<String> getList(String name) {
Map<String, String> getMap(String name, Map<String, String> defaultValue);

/** Returns {@code true} if declarative configuration is used in this configuration. */
boolean isDeclarative();
default boolean isDeclarative() {
return !(getConfigProvider() instanceof BridgedConfigProvider);
}

/**
* Returns a {@link DeclarativeConfigProperties} for the given node name, which is usually an
* instrumentation name
*
* <p>Call {@link #isDeclarative()} first to check if declarative configuration is used.
* instrumentation name. If declarative configuration is not used, a bridge to ConfigProperties is
*
* <p>Declarative configuration is used to configure instrumentation properties in a declarative
* way, such as through YAML or JSON files.
*
* @param node the name of the instrumentation (e.g. "log4j"), the vendor name (e.g. "google"), or
* "common" for common Java settings that don't apply to other languages.
* @return the declarative configuration properties for the given node name
* @throws IllegalStateException if {@link #isDeclarative()} returns {@code false}
*/
DeclarativeConfigProperties getDeclarativeConfig(String node);
default DeclarativeConfigProperties getDeclarativeConfig(String node) {
DeclarativeConfigProperties config =
InstrumentationConfigUtil.javaInstrumentationConfig(getConfigProvider(), node);
if (config == null) {
// there is no declarative config for this node
return empty();
}
return config;
}

/**
* Returns the {@link ConfigProvider} if declarative configuration is used.
*
* @return the {@link ConfigProvider} or {@code null} if no provider is available
* Returns the {@link ConfigProvider}, which is a bridge to ConfigProperties if declarative
* configuration is not used
*/
@Nullable
ConfigProvider getConfigProvider();
}
1 change: 1 addition & 0 deletions instrumentation-api/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ dependencies {
testImplementation("io.opentelemetry.javaagent:opentelemetry-testing-common")
testImplementation("io.opentelemetry:opentelemetry-sdk-testing")
testImplementation("io.opentelemetry:opentelemetry-exporter-common")
testImplementation("io.opentelemetry:opentelemetry-sdk-extension-incubator")
testImplementation("org.junit-pioneer:junit-pioneer")

jmhImplementation(project(":instrumentation-api-incubator"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@
import static java.util.logging.Level.WARNING;

import com.google.errorprone.annotations.CanIgnoreReturnValue;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.incubator.ExtendedOpenTelemetry;
import io.opentelemetry.api.incubator.config.InstrumentationConfigUtil;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.api.metrics.MeterBuilder;
import io.opentelemetry.api.trace.SpanKind;
Expand All @@ -20,6 +23,7 @@
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.ConfigProviderUtil;
import io.opentelemetry.instrumentation.api.internal.EmbeddedInstrumentationProperties;
import io.opentelemetry.instrumentation.api.internal.Experimental;
import io.opentelemetry.instrumentation.api.internal.InstrumenterBuilderAccess;
Expand Down Expand Up @@ -48,11 +52,7 @@
public final class InstrumenterBuilder<REQUEST, RESPONSE> {

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"));
private static final boolean supportsDeclarativeConfig = supportsDeclarativeConfig();

final OpenTelemetry openTelemetry;
final String instrumentationName;
Expand All @@ -76,6 +76,20 @@ public final class InstrumenterBuilder<REQUEST, RESPONSE> {
boolean propagateOperationListenersToOnEnd = false;
boolean enabled = true;

private static boolean supportsDeclarativeConfig() {
try {
Class.forName("io.opentelemetry.api.incubator.ExtendedOpenTelemetry");
return true;
} catch (ClassNotFoundException e) {
// The incubator module is not available.
// This only happens in OpenTelemetry API instrumentation tests, where an older version of
// OpenTelemetry API is used that does not have ExtendedOpenTelemetry.
// Having the incubator module without ExtendedOpenTelemetry class should still return false
// for those tests to avoid a ClassNotFoundException.
return false;
}
}

static {
Experimental.internalAddOperationListenerAttributesExtractor(
(builder, operationListenerAttributesExtractor) ->
Expand Down Expand Up @@ -373,8 +387,19 @@ private String getSchemaUrl() {
}

SpanSuppressor buildSpanSuppressor() {
// otel.instrumentation.experimental.* doesn't fit the usual pattern of configuration properties
// for instrumentations, so we need to handle both declarative and non-declarative configs here
String value =
isDeclarativeConfig(openTelemetry)
? InstrumentationConfigUtil.getOrNull(
ConfigProviderUtil.getConfigProvider(GlobalOpenTelemetry.get()),
config -> config.getString("span_suppression_strategy/development"),
"java",
"common")
: ConfigPropertiesUtil.getString(
"otel.instrumentation.experimental.span-suppression-strategy");
return new SpanSuppressors.ByContextKey(
spanSuppressionStrategy.create(getSpanKeysFromAttributesExtractors()));
SpanSuppressionStrategy.fromConfig(value).create(getSpanKeysFromAttributesExtractors()));
}

private Set<SpanKey> getSpanKeysFromAttributesExtractors() {
Expand Down Expand Up @@ -454,6 +479,11 @@ public void setSpanStatusExtractorCustomizer(
}
}

/** Returns true if the given OpenTelemetry instance supports Declarative Config. */
public static boolean isDeclarativeConfig(OpenTelemetry openTelemetry) {
return supportsDeclarativeConfig && openTelemetry instanceof ExtendedOpenTelemetry;
}

private interface InstrumenterConstructor<RQ, RS> {
Instrumenter<RQ, RS> create(InstrumenterBuilder<RQ, RS> builder);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.instrumentation.api.internal;

import io.opentelemetry.api.incubator.config.ConfigProvider;
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
import io.opentelemetry.common.ComponentLoader;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import javax.annotation.Nullable;

/**
* This class is internal and is hence not for public use. Its APIs are unstable and can change at
* any time.
*/
public final class BridgedConfigProvider implements ConfigProvider {

private final Function<String, String> propertySource;

public BridgedConfigProvider(Function<String, String> propertySource) {
this.propertySource = propertySource;
}

@Nullable
@Override
public DeclarativeConfigProperties getInstrumentationConfig() {
return createEmptyDeclarativeConfigProperties(
java -> {
if (java.equals("java")) {
return createEmptyDeclarativeConfigProperties(
name -> new BridgedDeclarativeConfigProperties(name, null, propertySource));
}
throw new UnsupportedOperationException();
});
}

private static DeclarativeConfigProperties createEmptyDeclarativeConfigProperties(
Function<String, DeclarativeConfigProperties> getStructuredFunc) {
return EmptyDeclarativeConfigPropertiesFactory.create(getStructuredFunc);
}

private static final class EmptyDeclarativeConfigPropertiesFactory {
private EmptyDeclarativeConfigPropertiesFactory() {}

static DeclarativeConfigProperties create(
Function<String, DeclarativeConfigProperties> getStructuredFunc) {
return new InnerDeclarativeConfigProperties(getStructuredFunc);
}
}

private static final class InnerDeclarativeConfigProperties
implements DeclarativeConfigProperties {
private final Function<String, DeclarativeConfigProperties> getStructuredFunc;

InnerDeclarativeConfigProperties(
Function<String, DeclarativeConfigProperties> getStructuredFunc) {
this.getStructuredFunc = getStructuredFunc;
}

@Nullable
@Override
public String getString(String name) {
throw new UnsupportedOperationException();
}

@Nullable
@Override
public Boolean getBoolean(String name) {
throw new UnsupportedOperationException();
}

@Nullable
@Override
public Integer getInt(String name) {
throw new UnsupportedOperationException();
}

@Nullable
@Override
public Long getLong(String name) {
throw new UnsupportedOperationException();
}

@Nullable
@Override
public Double getDouble(String name) {
throw new UnsupportedOperationException();
}

@Nullable
@Override
public <T> List<T> getScalarList(String name, Class<T> scalarType) {
throw new UnsupportedOperationException();
}

@Nullable
@Override
public DeclarativeConfigProperties getStructured(String name) {
return getStructuredFunc.apply(name);
}

@Nullable
@Override
public List<DeclarativeConfigProperties> getStructuredList(String name) {
throw new UnsupportedOperationException();
}

@Override
public Set<String> getPropertyKeys() {
throw new UnsupportedOperationException();
}

@Override
public ComponentLoader getComponentLoader() {
throw new UnsupportedOperationException();
}
}
}
Loading
Loading