-
Notifications
You must be signed in to change notification settings - Fork 163
declarative config: add declaravite config bridge, gcp auth, span stacktrace #2020
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
Draft
zeitlinger
wants to merge
41
commits into
open-telemetry:main
Choose a base branch
from
zeitlinger:gcp-auth
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
41 commits
Select commit
Hold shift + click to select a range
51cd517
gcp auth
zeitlinger 4a6bda9
./gradlew spotlessApply
otelbot[bot] d6f03ab
copy declarative config bridge from instrumentation
zeitlinger 1dee070
support config bridge
zeitlinger a2c30d7
support config bridge
zeitlinger 7564023
copy declarative config bridge from instrumentation
zeitlinger 858d71f
format
zeitlinger 3296368
cleanup
zeitlinger b268964
cleanup
zeitlinger 6054d35
fix test
zeitlinger 3c15bff
fix
zeitlinger a5fe6a2
add property translation for inferred spans
zeitlinger 7c48794
inferred spans
zeitlinger 2854093
inferred spans
zeitlinger 0eb9b1e
inferred spans
zeitlinger 1c22094
baggage processor
zeitlinger d2279bc
format
zeitlinger 63d7c8c
format
zeitlinger 402d305
stack trace span processor
zeitlinger e5355f5
stack trace span processor
zeitlinger c6d9eee
fix
zeitlinger 67adb3b
fix
zeitlinger 6daffa5
fix
zeitlinger 434fb80
make temp dir more reliable
zeitlinger 9bc8664
make temp dir more reliable
zeitlinger d7d4915
revert inferred spans (flaky)
zeitlinger 25c42bf
baggage is in a separate PR
zeitlinger 1aa789c
use unified bridge
zeitlinger 7bf95df
add experimental- suffix, add test
zeitlinger 06cb016
add experimental- suffix, add test
zeitlinger fedec51
update bridge to match agent
zeitlinger 93b93e1
update bridge to match agent
zeitlinger cdbe87b
Revert "update bridge to match agent"
zeitlinger e18a052
update bridge to match agent
zeitlinger 933fb80
Update gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/…
zeitlinger df08db5
Update gcp-auth-extension/src/main/java/io/opentelemetry/contrib/gcp/…
zeitlinger bbc3bfb
pr review
zeitlinger 187b278
pr review
zeitlinger c5c8e86
pr review
zeitlinger 682fc65
update config bridge from agent
zeitlinger f895a1e
./gradlew spotlessApply
otelbot[bot] 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
plugins { | ||
id("otel.java-conventions") | ||
id("otel.publish-conventions") | ||
} | ||
|
||
description = "OpenTelemetry extension that provides a bridge for declarative configuration." | ||
otelJava.moduleName.set("io.opentelemetry.contrib.sdk.declarative.config.bridge") | ||
|
||
dependencies { | ||
// We use `compileOnly` dependency because during runtime all necessary classes are provided by | ||
// javaagent itself. | ||
compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure") | ||
compileOnly("io.opentelemetry:opentelemetry-sdk-extension-incubator") | ||
|
||
testImplementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure") | ||
testImplementation("io.opentelemetry:opentelemetry-sdk-extension-incubator") | ||
testImplementation("org.mockito:mockito-inline") | ||
} |
23 changes: 23 additions & 0 deletions
23
...bridge/src/main/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtil.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,23 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.contrib.sdk.autoconfigure; | ||
|
||
public final class ConfigPropertiesUtil { | ||
private ConfigPropertiesUtil() {} | ||
|
||
public static String propertyYamlPath(String propertyName) { | ||
return yamlPath(propertyName); | ||
} | ||
|
||
static String yamlPath(String property) { | ||
String[] segments = DeclarativeConfigPropertiesBridge.getSegments(property); | ||
if (segments.length == 0) { | ||
throw new IllegalArgumentException("Invalid property: " + property); | ||
} | ||
|
||
return "'instrumentation/development' / 'java' / '" + String.join("' / '", segments) + "'"; | ||
} | ||
} |
188 changes: 188 additions & 0 deletions
188
...in/java/io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridge.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,188 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.contrib.sdk.autoconfigure; | ||
|
||
import static io.opentelemetry.api.incubator.config.DeclarativeConfigProperties.empty; | ||
|
||
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; | ||
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; | ||
import java.time.Duration; | ||
import java.util.Collections; | ||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Objects; | ||
import java.util.function.BiFunction; | ||
import javax.annotation.Nullable; | ||
|
||
/** | ||
* A {@link ConfigProperties} which resolves properties based on {@link | ||
* DeclarativeConfigProperties}. | ||
* | ||
* <p>Only properties starting with "otel.instrumentation." are resolved. Others return null (or | ||
* default value if provided). | ||
* | ||
* <p>To resolve: | ||
* | ||
* <ul> | ||
* <li>"otel.instrumentation" refers to the ".instrumentation.java" node | ||
* <li>The portion of the property after "otel.instrumentation." is split into segments based on | ||
* ".". | ||
* <li>For each N-1 segment, we walk down the tree to find the relevant leaf {@link | ||
* DeclarativeConfigProperties}. | ||
* <li>We extract the property from the resolved {@link DeclarativeConfigProperties} using the | ||
* last segment as the property key. | ||
* </ul> | ||
* | ||
* <p>For example, given the following YAML, asking for {@code | ||
* ConfigProperties#getString("otel.instrumentation.common.string_key")} yields "value": | ||
* | ||
* <pre> | ||
* instrumentation: | ||
* java: | ||
* common: | ||
* string_key: value | ||
* </pre> | ||
*/ | ||
final class DeclarativeConfigPropertiesBridge implements ConfigProperties { | ||
|
||
private static final String OTEL_INSTRUMENTATION_PREFIX = "otel.instrumentation."; | ||
|
||
private final DeclarativeConfigProperties baseNode; | ||
|
||
// lookup order matters - we choose the first match | ||
private final Map<String, String> mappings; | ||
private final Map<String, Object> overrideValues; | ||
|
||
DeclarativeConfigPropertiesBridge( | ||
DeclarativeConfigProperties baseNode, | ||
Map<String, String> mappings, | ||
Map<String, Object> overrideValues) { | ||
this.baseNode = Objects.requireNonNull(baseNode); | ||
this.mappings = mappings; | ||
this.overrideValues = overrideValues; | ||
} | ||
|
||
@Nullable | ||
@Override | ||
public String getString(String propertyName) { | ||
return getPropertyValue(propertyName, String.class, DeclarativeConfigProperties::getString); | ||
} | ||
|
||
@Nullable | ||
@Override | ||
public Boolean getBoolean(String propertyName) { | ||
return getPropertyValue(propertyName, Boolean.class, DeclarativeConfigProperties::getBoolean); | ||
} | ||
|
||
@Nullable | ||
@Override | ||
public Integer getInt(String propertyName) { | ||
return getPropertyValue(propertyName, Integer.class, DeclarativeConfigProperties::getInt); | ||
} | ||
|
||
@Nullable | ||
@Override | ||
public Long getLong(String propertyName) { | ||
return getPropertyValue(propertyName, Long.class, DeclarativeConfigProperties::getLong); | ||
} | ||
|
||
@Nullable | ||
@Override | ||
public Double getDouble(String propertyName) { | ||
return getPropertyValue(propertyName, Double.class, DeclarativeConfigProperties::getDouble); | ||
} | ||
|
||
@Nullable | ||
@Override | ||
public Duration getDuration(String propertyName) { | ||
Long millis = getPropertyValue(propertyName, Long.class, DeclarativeConfigProperties::getLong); | ||
if (millis == null) { | ||
return null; | ||
} | ||
return Duration.ofMillis(millis); | ||
} | ||
|
||
@SuppressWarnings("unchecked") | ||
@Override | ||
public List<String> getList(String propertyName) { | ||
List<String> propertyValue = | ||
getPropertyValue( | ||
propertyName, | ||
List.class, | ||
(properties, lastPart) -> properties.getScalarList(lastPart, String.class)); | ||
return propertyValue == null ? Collections.emptyList() : propertyValue; | ||
} | ||
|
||
@SuppressWarnings("unchecked") | ||
@Override | ||
public Map<String, String> getMap(String propertyName) { | ||
DeclarativeConfigProperties propertyValue = | ||
getPropertyValue( | ||
propertyName, | ||
DeclarativeConfigProperties.class, | ||
DeclarativeConfigProperties::getStructured); | ||
if (propertyValue == null) { | ||
return Collections.emptyMap(); | ||
} | ||
Map<String, String> result = new HashMap<>(); | ||
propertyValue | ||
.getPropertyKeys() | ||
.forEach( | ||
key -> { | ||
String value = propertyValue.getString(key); | ||
if (value == null) { | ||
return; | ||
} | ||
result.put(key, value); | ||
}); | ||
return Collections.unmodifiableMap(result); | ||
} | ||
|
||
@Nullable | ||
private <T> T getPropertyValue( | ||
String property, | ||
Class<T> clazz, | ||
BiFunction<DeclarativeConfigProperties, String, T> extractor) { | ||
T override = clazz.cast(overrideValues.get(property)); | ||
if (override != null) { | ||
return override; | ||
} | ||
|
||
String[] segments = getSegments(translateProperty(property)); | ||
if (segments.length == 0) { | ||
return null; | ||
} | ||
|
||
// Extract the value by walking to the N-1 entry | ||
DeclarativeConfigProperties target = baseNode; | ||
if (segments.length > 1) { | ||
for (int i = 0; i < segments.length - 1; i++) { | ||
target = target.getStructured(segments[i], empty()); | ||
} | ||
} | ||
String lastPart = segments[segments.length - 1]; | ||
|
||
return extractor.apply(target, lastPart); | ||
} | ||
|
||
static String[] getSegments(String property) { | ||
if (property.startsWith(OTEL_INSTRUMENTATION_PREFIX)) { | ||
property = property.substring(OTEL_INSTRUMENTATION_PREFIX.length()); | ||
} | ||
// Split the remainder of the property on "." | ||
return property.replace('-', '_').split("\\."); | ||
} | ||
|
||
private String translateProperty(String property) { | ||
for (Map.Entry<String, String> entry : mappings.entrySet()) { | ||
if (property.startsWith(entry.getKey())) { | ||
return entry.getValue() + property.substring(entry.getKey().length()); | ||
} | ||
} | ||
return property; | ||
} | ||
} |
102 changes: 102 additions & 0 deletions
102
.../io/opentelemetry/contrib/sdk/autoconfigure/DeclarativeConfigPropertiesBridgeBuilder.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,102 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.contrib.sdk.autoconfigure; | ||
|
||
import static io.opentelemetry.api.incubator.config.DeclarativeConfigProperties.empty; | ||
|
||
import com.google.errorprone.annotations.CanIgnoreReturnValue; | ||
import io.opentelemetry.api.incubator.config.ConfigProvider; | ||
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; | ||
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; | ||
import io.opentelemetry.sdk.autoconfigure.internal.AutoConfigureUtil; | ||
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; | ||
import java.util.HashMap; | ||
import java.util.LinkedHashMap; | ||
import java.util.Map; | ||
import javax.annotation.Nullable; | ||
|
||
/** | ||
* A builder for {@link DeclarativeConfigPropertiesBridge} that allows adding translations and fixed | ||
* values for properties. | ||
*/ | ||
public class DeclarativeConfigPropertiesBridgeBuilder { | ||
/** | ||
* order is important here, so we use LinkedHashMap - see {@link #addMapping(String, String)} for | ||
* more details | ||
*/ | ||
private final Map<String, String> mappings = new LinkedHashMap<>(); | ||
|
||
private final Map<String, Object> overrideValues = new HashMap<>(); | ||
|
||
public DeclarativeConfigPropertiesBridgeBuilder() {} | ||
|
||
/** | ||
* Adds a mapping from a property prefix to a YAML path. | ||
* | ||
* <p>For example, if the property prefix is "otel.javaagent" and the YAML path is "agent", then | ||
* any property starting with "otel.javaagent." will be resolved against the "agent" node in the | ||
* instrumentation/java section of the YAML configuration. | ||
* | ||
* @param propertyPrefix the prefix of the property to translate | ||
* @param yamlPath the YAML path to resolve the property against | ||
*/ | ||
@CanIgnoreReturnValue | ||
public DeclarativeConfigPropertiesBridgeBuilder addMapping( | ||
String propertyPrefix, String yamlPath) { | ||
mappings.put(propertyPrefix, yamlPath); | ||
return this; | ||
} | ||
|
||
/** | ||
* Adds a fixed override value for a property. | ||
* | ||
* @param propertyName the name of the property to override | ||
* @param value the value to return when the property is requested | ||
*/ | ||
@CanIgnoreReturnValue | ||
public DeclarativeConfigPropertiesBridgeBuilder addOverride(String propertyName, Object value) { | ||
overrideValues.put(propertyName, value); | ||
return this; | ||
} | ||
|
||
/** Build {@link ConfigProperties} from the {@code autoConfiguredOpenTelemetrySdk}. */ | ||
public ConfigProperties build(AutoConfiguredOpenTelemetrySdk autoConfiguredOpenTelemetrySdk) { | ||
ConfigProperties sdkConfigProperties = | ||
AutoConfigureUtil.getConfig(autoConfiguredOpenTelemetrySdk); | ||
if (sdkConfigProperties != null) { | ||
return sdkConfigProperties; | ||
} | ||
ConfigProvider configProvider = | ||
AutoConfigureUtil.getConfigProvider(autoConfiguredOpenTelemetrySdk); | ||
if (configProvider != null) { | ||
return buildFromInstrumentationConfig(configProvider.getInstrumentationConfig()); | ||
} | ||
// Should never happen | ||
throw new IllegalStateException( | ||
"AutoConfiguredOpenTelemetrySdk does not have ConfigProperties or DeclarativeConfigProperties. This is likely a programming error in opentelemetry-java"); | ||
} | ||
|
||
/** | ||
* Build {@link ConfigProperties} from the {@link DeclarativeConfigProperties} provided by the | ||
* instrumentation configuration. | ||
* | ||
* <p>If the provided {@code instrumentationConfig} is null, an empty {@link | ||
* DeclarativeConfigProperties} will be used. | ||
* | ||
* @param instrumentationConfig the instrumentation configuration to build from | ||
* @return a new instance of {@link ConfigProperties} | ||
*/ | ||
public ConfigProperties buildFromInstrumentationConfig( | ||
@Nullable DeclarativeConfigProperties instrumentationConfig) { | ||
// leave the name "build" for a future method that builds from a DeclarativeConfigProperties | ||
// instance that doesn't come from the top-level instrumentation config | ||
if (instrumentationConfig == null) { | ||
instrumentationConfig = DeclarativeConfigProperties.empty(); | ||
} | ||
return new DeclarativeConfigPropertiesBridge( | ||
instrumentationConfig.getStructured("java", empty()), mappings, overrideValues); | ||
} | ||
} |
19 changes: 19 additions & 0 deletions
19
...ge/src/test/java/io/opentelemetry/contrib/sdk/autoconfigure/ConfigPropertiesUtilTest.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,19 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.contrib.sdk.autoconfigure; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
|
||
import org.junit.jupiter.api.Test; | ||
|
||
class ConfigPropertiesUtilTest { | ||
@Test | ||
void propertyYamlPath() { | ||
assertThat(ConfigPropertiesUtil.propertyYamlPath("google.otel.auth.target.signals")) | ||
.isEqualTo( | ||
"'instrumentation/development' / 'java' / 'google' / 'otel' / 'auth' / 'target' / 'signals'"); | ||
} | ||
} |
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the bridge is also part of open-telemetry/opentelemetry-java-instrumentation#14184 - once it's reviewed there it will be updated here
but that can also be done after this PR is merged