Skip to content
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

package cloud resource in javaagent - but keep them disabled by default #10754

2 changes: 2 additions & 0 deletions .github/renovate.json5
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
"packageRules": [
{
"matchPackageNames": [
"io.opentelemetry.contrib:opentelemetry-aws-resources",
zeitlinger marked this conversation as resolved.
Show resolved Hide resolved
"io.opentelemetry.contrib:opentelemetry-aws-xray-propagator",
"io.opentelemetry.contrib:opentelemetry-gcp-resources",
"io.opentelemetry.proto:opentelemetry-proto",
"io.opentelemetry.semconv:opentelemetry-semconv"
],
Expand Down
5 changes: 4 additions & 1 deletion dependencyManagement/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ rootProject.extra["versions"] = dependencyVersions

// this line is managed by .github/scripts/update-sdk-version.sh
val otelSdkVersion = "1.36.0"
val otelContribVersion = "1.33.0-alpha"
val otelSdkAlphaVersion = otelSdkVersion.replaceFirst("(-SNAPSHOT)?$".toRegex(), "-alpha$1")

// Need both BOM and groovy jars
Expand Down Expand Up @@ -96,7 +97,9 @@ val DEPENDENCIES = listOf(
"commons-logging:commons-logging:1.3.0",
"commons-validator:commons-validator:1.8.0",
"io.netty:netty:3.10.6.Final",
"io.opentelemetry.contrib:opentelemetry-aws-xray-propagator:1.33.0-alpha",
"io.opentelemetry.contrib:opentelemetry-aws-resources:${otelContribVersion}",
"io.opentelemetry.contrib:opentelemetry-aws-xray-propagator:${otelContribVersion}",
"io.opentelemetry.contrib:opentelemetry-gcp-resources:${otelContribVersion}",
"io.opentelemetry.proto:opentelemetry-proto:1.1.0-alpha",
"io.opentelemetry:opentelemetry-extension-annotations:1.18.0", // deprecated, no longer part of bom
"org.assertj:assertj-core:3.25.3",
Expand Down
3 changes: 3 additions & 0 deletions javaagent-tooling/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ dependencies {

implementation("io.opentelemetry.contrib:opentelemetry-aws-xray-propagator")

implementation("io.opentelemetry.contrib:opentelemetry-aws-resources")
implementation("io.opentelemetry.contrib:opentelemetry-gcp-resources")

api("net.bytebuddy:byte-buddy-dep")
implementation("org.ow2.asm:asm-tree")
implementation("org.ow2.asm:asm-util")
Expand Down
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.javaagent.tooling.config;

import com.google.auto.service.AutoService;
import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizer;
import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nullable;

@AutoService(AutoConfigurationCustomizerProvider.class)
public class ResourceProviderPropertiesCustomizer implements AutoConfigurationCustomizerProvider {

private static final Map<String, String> DISABLED_BY_DEFAULT_RESOURCE_PROVIDERS = new HashMap<>();

static {
DISABLED_BY_DEFAULT_RESOURCE_PROVIDERS.put(
"io.opentelemetry.contrib.aws.resource.BeanstalkResourceProvider", "aws");
DISABLED_BY_DEFAULT_RESOURCE_PROVIDERS.put(
"io.opentelemetry.contrib.aws.resource.Ec2ResourceProvider", "aws");
DISABLED_BY_DEFAULT_RESOURCE_PROVIDERS.put(
"io.opentelemetry.contrib.aws.resource.EcsResourceProvider", "aws");
DISABLED_BY_DEFAULT_RESOURCE_PROVIDERS.put(
"io.opentelemetry.contrib.aws.resource.EksResourceProvider", "aws");
DISABLED_BY_DEFAULT_RESOURCE_PROVIDERS.put(
"io.opentelemetry.contrib.aws.resource.LambdaResourceProvider", "aws");
DISABLED_BY_DEFAULT_RESOURCE_PROVIDERS.put(
"io.opentelemetry.contrib.gcp.resource.GCPResourceProvider", "gcp");
// for testing
DISABLED_BY_DEFAULT_RESOURCE_PROVIDERS.put(
"io.opentelemetry.javaagent.tooling.config.ResourceProviderPropertiesCustomizerTest$Provider",
"test");
}

static final String DISABLED_KEY = "otel.java.disabled.resource.providers";
static final String ENABLED_KEY = "otel.java.enabled.resource.providers";

@Override
public void customize(AutoConfigurationCustomizer autoConfigurationCustomizer) {
autoConfigurationCustomizer.addPropertiesCustomizer(this::customize);
}

// VisibleForTesting
Map<String, String> customize(ConfigProperties config) {
Set<String> enabledProviders = new HashSet<>(config.getList(ENABLED_KEY));

List<String> enabled = new ArrayList<>();
List<String> disabled = new ArrayList<>();

for (Map.Entry<String, String> providerEntry :
DISABLED_BY_DEFAULT_RESOURCE_PROVIDERS.entrySet()) {
String providerName = providerEntry.getKey();
String providerGroup = providerEntry.getValue();
Boolean explictEnabled =
config.getBoolean(String.format("otel.resource.providers.%s.enabled", providerGroup));

if (isEnabled(providerName, enabledProviders, explictEnabled)) {
enabled.add(providerName);
} else {
disabled.add(providerName);
}
}

if (!enabledProviders.isEmpty()) {
// users has requested specific providers to be enabled only
enabled.addAll(enabledProviders);
return Collections.singletonMap(ENABLED_KEY, String.join(",", enabled));
}

if (disabled.isEmpty()) {
// all providers that are disabled by default are enabled, no need to set any properties
return Collections.emptyMap();
}

disabled.addAll(config.getList(DISABLED_KEY));
return Collections.singletonMap(DISABLED_KEY, String.join(",", disabled));
}

private static boolean isEnabled(
String className, Set<String> enabledProviders, @Nullable Boolean explicitEnabled) {
if (explicitEnabled != null) {
return explicitEnabled;
}
return !enabledProviders.isEmpty() && enabledProviders.contains(className);
}

@Override
public int order() {
// make sure it runs AFTER all the user-provided customizers
return Integer.MAX_VALUE;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.tooling.config;

import static org.assertj.core.api.Assertions.assertThat;

import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
import io.opentelemetry.sdk.autoconfigure.SdkAutoconfigureAccess;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider;
import io.opentelemetry.sdk.resources.Resource;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;
import javax.annotation.Nullable;
import org.assertj.core.util.Strings;
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.TestFactory;

public class ResourceProviderPropertiesCustomizerTest {

public static final class Provider implements ResourceProvider {
@Override
public Resource createResource(ConfigProperties config) {
return Resource.create(Attributes.of(AttributeKey.stringKey("key"), "value"));
}
}

private static class EnabledTestCase {
private final String name;
private final boolean result;
private final Set<String> enabledProviders;
private final Set<String> disabledProviders;
private final Boolean explicitEnabled;

private EnabledTestCase(
String name,
boolean result,
Set<String> enabledProviders,
Set<String> disabledProviders,
@Nullable Boolean explicitEnabled) {
this.name = name;
this.result = result;
this.enabledProviders = enabledProviders;
this.disabledProviders = disabledProviders;
this.explicitEnabled = explicitEnabled;
}
}

@SuppressWarnings("BooleanParameter")
@TestFactory
Stream<DynamicTest> enabledTestCases() {
String className =
"io.opentelemetry.javaagent.tooling.config.ResourceProviderPropertiesCustomizerTest$Provider";
return Stream.of(
new EnabledTestCase(
"explicitEnabled", true, Collections.emptySet(), Collections.emptySet(), true),
new EnabledTestCase(
"explicitEnabledFalse",
false,
Collections.emptySet(),
Collections.emptySet(),
false),
new EnabledTestCase(
"enabledProvidersEmpty",
false,
Collections.emptySet(),
Collections.emptySet(),
null),
new EnabledTestCase(
"enabledProvidersContains",
true,
Collections.singleton(className),
Collections.emptySet(),
null),
new EnabledTestCase(
"enabledProvidersNotContains",
false,
Collections.singleton("otherClassName"),
Collections.emptySet(),
null),
new EnabledTestCase(
"disabledProvidersContains",
false,
Collections.emptySet(),
Collections.singleton(className),
null),
new EnabledTestCase(
"disabledProvidersNotContains",
false,
Collections.emptySet(),
Collections.singleton("otherClassName"),
null),
new EnabledTestCase(
"defaultEnabledFalse", false, Collections.emptySet(), Collections.emptySet(), null))
.map(
tc ->
DynamicTest.dynamicTest(
tc.name,
() -> {
Map<String, String> props = new HashMap<>();
props.put(
ResourceProviderPropertiesCustomizer.ENABLED_KEY,
Strings.join(tc.enabledProviders).with(","));
props.put(
ResourceProviderPropertiesCustomizer.DISABLED_KEY,
Strings.join(tc.disabledProviders).with(","));

if (tc.explicitEnabled != null) {
props.put(
"otel.resource.providers.test.enabled",
Boolean.toString(tc.explicitEnabled));
}

Attributes attributes =
SdkAutoconfigureAccess.getResourceAttributes(
AutoConfiguredOpenTelemetrySdk.builder()
.addPropertiesSupplier(() -> props)
.build());

if (tc.result) {
assertThat(attributes.get(AttributeKey.stringKey("key")))
.isEqualTo("value");
} else {
assertThat(attributes.get(AttributeKey.stringKey("key"))).isNull();
}
}));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
io.opentelemetry.javaagent.tooling.config.ResourceProviderPropertiesCustomizerTest$Provider
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.ServiceLoader;
import org.junit.jupiter.api.Test;

public class ResourceProviderTest {

@Test
void resourceProviderOrder() throws Exception {
boolean containerProviderFound = false;
boolean awsProviderFound = false;
// verify that aws resource provider is found after the regular container provider
// provider that is found later can overrider values from previous providers
Class<?> resourceProviderClass =
Class.forName(
"io.opentelemetry.sdk.autoconfigure.spi.ResourceProvider",
false,
IntegrationTestUtils.getAgentClassLoader());
for (Object resourceProvider :
ServiceLoader.load(resourceProviderClass, IntegrationTestUtils.getAgentClassLoader())) {
Class<?> clazz = resourceProvider.getClass();
if (clazz
.getName()
.equals("io.opentelemetry.instrumentation.resources.ContainerResourceProvider")) {
containerProviderFound = true;
assertFalse(awsProviderFound);
} else if (clazz.getName().startsWith("io.opentelemetry.contrib.aws.resource.")) {
awsProviderFound = true;
assertTrue(containerProviderFound);
}
}
assertTrue(containerProviderFound);
assertTrue(awsProviderFound);
}
}
Loading
Loading