diff --git a/dd-java-agent/instrumentation/graal/native-image/src/main/java/datadog/trace/instrumentation/graal/nativeimage/NativeImageGeneratorRunnerInstrumentation.java b/dd-java-agent/instrumentation/graal/native-image/src/main/java/datadog/trace/instrumentation/graal/nativeimage/NativeImageGeneratorRunnerInstrumentation.java index b61ab5e7531..2ccf55418ec 100644 --- a/dd-java-agent/instrumentation/graal/native-image/src/main/java/datadog/trace/instrumentation/graal/nativeimage/NativeImageGeneratorRunnerInstrumentation.java +++ b/dd-java-agent/instrumentation/graal/native-image/src/main/java/datadog/trace/instrumentation/graal/nativeimage/NativeImageGeneratorRunnerInstrumentation.java @@ -101,6 +101,7 @@ public static void onEnter(@Advice.Argument(value = 0, readOnly = false) String[ + "datadog.trace.api.TracePropagationStyle:build_time," + "datadog.trace.api.TracePropagationBehaviorExtract:build_time," + "datadog.trace.api.telemetry.OtelEnvMetricCollectorImpl:build_time," + + "datadog.trace.api.telemetry.ConfigInversionMetricCollectorImpl:build_time," + "datadog.trace.api.profiling.ProfilingEnablement:build_time," + "datadog.trace.bootstrap.config.provider.ConfigConverter:build_time," + "datadog.trace.bootstrap.config.provider.ConfigConverter$ValueOfLookup:build_time," diff --git a/internal-api/build.gradle.kts b/internal-api/build.gradle.kts index c4f0dfd019f..c0f3f4bd2d7 100644 --- a/internal-api/build.gradle.kts +++ b/internal-api/build.gradle.kts @@ -78,7 +78,6 @@ val excludedClassesCoverage by extra( // Bootstrap API "datadog.trace.bootstrap.ActiveSubsystems", "datadog.trace.bootstrap.ContextStore.Factory", - "datadog.trace.bootstrap.config.provider.ConfigProvider.Singleton", "datadog.trace.bootstrap.instrumentation.api.java.lang.ProcessImplInstrumentationHelpers", "datadog.trace.bootstrap.instrumentation.api.Tags", "datadog.trace.bootstrap.instrumentation.api.CommonTagValues", @@ -167,7 +166,6 @@ val excludedClassesCoverage by extra( "datadog.trace.api.Config", "datadog.trace.api.Config.HostNameHolder", "datadog.trace.api.Config.RuntimeIdHolder", - "datadog.trace.api.ConfigCollector", "datadog.trace.api.DynamicConfig", "datadog.trace.api.DynamicConfig.Builder", "datadog.trace.api.DynamicConfig.Snapshot", @@ -249,9 +247,6 @@ val excludedClassesBranchCoverage by extra( "datadog.trace.api.ClassloaderConfigurationOverrides.Lazy", "datadog.trace.util.stacktrace.HotSpotStackWalker", "datadog.trace.util.stacktrace.StackWalkerFactory", - // Tested using forked process - "datadog.trace.api.env.CapturedEnvironment", - "datadog.trace.api.env.CapturedEnvironment.ProcessInfo", "datadog.trace.util.TempLocationManager", "datadog.trace.util.TempLocationManager.*", // Branches depend on RUM injector state that cannot be reliably controlled in unit tests @@ -261,8 +256,6 @@ val excludedClassesBranchCoverage by extra( val excludedClassesInstructionCoverage by extra( listOf( - "datadog.trace.bootstrap.config.provider.EnvironmentConfigSource", - "datadog.trace.bootstrap.config.provider.SystemPropertiesConfigSource", "datadog.trace.util.stacktrace.StackWalkerFactory" ) ) diff --git a/internal-api/src/main/java/datadog/trace/api/Config.java b/internal-api/src/main/java/datadog/trace/api/Config.java index aef84a8c58e..175b6cd9f23 100644 --- a/internal-api/src/main/java/datadog/trace/api/Config.java +++ b/internal-api/src/main/java/datadog/trace/api/Config.java @@ -654,6 +654,8 @@ import datadog.trace.api.profiling.ProfilingEnablement; import datadog.trace.api.rum.RumInjectorConfig; import datadog.trace.api.rum.RumInjectorConfig.PrivacyLevel; +import datadog.trace.api.telemetry.ConfigInversionMetricCollectorImpl; +import datadog.trace.api.telemetry.ConfigInversionMetricCollectorProvider; import datadog.trace.api.telemetry.OtelEnvMetricCollectorImpl; import datadog.trace.api.telemetry.OtelEnvMetricCollectorProvider; import datadog.trace.bootstrap.config.provider.CapturedEnvironmentConfigSource; @@ -1248,6 +1250,8 @@ public static String getHostName() { static { // Bind telemetry collector to config module before initializing ConfigProvider OtelEnvMetricCollectorProvider.register(OtelEnvMetricCollectorImpl.getInstance()); + ConfigInversionMetricCollectorProvider.register( + ConfigInversionMetricCollectorImpl.getInstance()); } // Read order: System Properties -> Env Variables, [-> properties file], [-> default value] diff --git a/internal-api/src/main/java/datadog/trace/api/telemetry/ConfigInversionMetricCollector.java b/internal-api/src/main/java/datadog/trace/api/telemetry/ConfigInversionMetricCollectorImpl.java similarity index 65% rename from internal-api/src/main/java/datadog/trace/api/telemetry/ConfigInversionMetricCollector.java rename to internal-api/src/main/java/datadog/trace/api/telemetry/ConfigInversionMetricCollectorImpl.java index cdd781c78d6..6a956388256 100644 --- a/internal-api/src/main/java/datadog/trace/api/telemetry/ConfigInversionMetricCollector.java +++ b/internal-api/src/main/java/datadog/trace/api/telemetry/ConfigInversionMetricCollectorImpl.java @@ -9,22 +9,25 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class ConfigInversionMetricCollector - implements MetricCollector { - private static final Logger log = LoggerFactory.getLogger(ConfigInversionMetricCollector.class); +public class ConfigInversionMetricCollectorImpl + implements MetricCollector, + ConfigInversionMetricCollector { + private static final Logger log = + LoggerFactory.getLogger(ConfigInversionMetricCollectorImpl.class); private static final String CONFIG_INVERSION_KEY_TAG = "config_name:"; private static final String CONFIG_INVERSION_METRIC_NAME = "untracked.config.detected"; private static final String NAMESPACE = "tracers"; - private static final ConfigInversionMetricCollector INSTANCE = - new ConfigInversionMetricCollector(); + private static final ConfigInversionMetricCollectorImpl INSTANCE = + new ConfigInversionMetricCollectorImpl(); - private final BlockingQueue metricsQueue; + private final BlockingQueue + metricsQueue; - private ConfigInversionMetricCollector() { + private ConfigInversionMetricCollectorImpl() { this.metricsQueue = new ArrayBlockingQueue<>(RAW_QUEUE_SIZE); } - public static ConfigInversionMetricCollector getInstance() { + public static ConfigInversionMetricCollectorImpl getInstance() { return INSTANCE; } @@ -34,7 +37,7 @@ public void setUndocumentedEnvVarMetric(String configName) { private void setMetricConfigInversionMetric(final String... tags) { if (!metricsQueue.offer( - new ConfigInversionMetricCollector.ConfigInversionMetric( + new ConfigInversionMetricCollectorImpl.ConfigInversionMetric( NAMESPACE, true, CONFIG_INVERSION_METRIC_NAME, "count", 1, tags))) { log.debug("Unable to add telemetry metric {} for {}", CONFIG_INVERSION_METRIC_NAME, tags[0]); } @@ -46,11 +49,11 @@ public void prepareMetrics() { } @Override - public Collection drain() { + public Collection drain() { if (this.metricsQueue.isEmpty()) { return Collections.emptyList(); } - List drained = + List drained = new ArrayList<>(this.metricsQueue.size()); this.metricsQueue.drainTo(drained); return drained; diff --git a/internal-api/src/test/groovy/datadog/trace/api/telemetry/ConfigInversionMetricCollectorTest.groovy b/internal-api/src/test/groovy/datadog/trace/api/telemetry/ConfigInversionMetricCollectorImplTest.groovy similarity index 74% rename from internal-api/src/test/groovy/datadog/trace/api/telemetry/ConfigInversionMetricCollectorTest.groovy rename to internal-api/src/test/groovy/datadog/trace/api/telemetry/ConfigInversionMetricCollectorImplTest.groovy index 7f63048eb27..b6a4607ac9c 100644 --- a/internal-api/src/test/groovy/datadog/trace/api/telemetry/ConfigInversionMetricCollectorTest.groovy +++ b/internal-api/src/test/groovy/datadog/trace/api/telemetry/ConfigInversionMetricCollectorImplTest.groovy @@ -2,13 +2,13 @@ package datadog.trace.api.telemetry import datadog.trace.test.util.DDSpecification -import static datadog.trace.api.telemetry.ConfigInversionMetricCollector.CONFIG_INVERSION_METRIC_NAME +import static ConfigInversionMetricCollectorImpl.CONFIG_INVERSION_METRIC_NAME -class ConfigInversionMetricCollectorTest extends DDSpecification { +class ConfigInversionMetricCollectorImplTest extends DDSpecification { def "should emit metric when unsupported env var is used"() { setup: - def collector = ConfigInversionMetricCollector.getInstance() + def collector = ConfigInversionMetricCollectorImpl.getInstance() when: ConfigInversionMetricCollectorTestHelper.checkAndEmitUnsupported("DD_UNKNOWN_FEATURE") @@ -28,7 +28,7 @@ class ConfigInversionMetricCollectorTest extends DDSpecification { def "should not emit metric when supported env var is used"() { setup: - def collector = ConfigInversionMetricCollector.getInstance() + def collector = ConfigInversionMetricCollectorImpl.getInstance() when: ConfigInversionMetricCollectorTestHelper.checkAndEmitUnsupported("DD_ENV") diff --git a/internal-api/src/test/groovy/datadog/trace/api/telemetry/ConfigInversionMetricCollectorTestHelper.java b/internal-api/src/test/groovy/datadog/trace/api/telemetry/ConfigInversionMetricCollectorTestHelper.java index 9cb70dd68b5..841ca68e26b 100644 --- a/internal-api/src/test/groovy/datadog/trace/api/telemetry/ConfigInversionMetricCollectorTestHelper.java +++ b/internal-api/src/test/groovy/datadog/trace/api/telemetry/ConfigInversionMetricCollectorTestHelper.java @@ -10,8 +10,8 @@ public class ConfigInversionMetricCollectorTestHelper { private static final Set SUPPORTED_ENV_VARS = new HashSet<>(Arrays.asList("DD_ENV", "DD_SERVICE")); - private static final ConfigInversionMetricCollector configInversionMetricCollector = - ConfigInversionMetricCollector.getInstance(); + private static final ConfigInversionMetricCollectorImpl configInversionMetricCollector = + ConfigInversionMetricCollectorImpl.getInstance(); public static void checkAndEmitUnsupported(String envVarName) { if (!SUPPORTED_ENV_VARS.contains(envVarName)) { diff --git a/telemetry/src/main/java/datadog/telemetry/metric/ConfigInversionMetricPeriodicAction.java b/telemetry/src/main/java/datadog/telemetry/metric/ConfigInversionMetricPeriodicAction.java index e7eb7dfab48..d1d526fb2e9 100644 --- a/telemetry/src/main/java/datadog/telemetry/metric/ConfigInversionMetricPeriodicAction.java +++ b/telemetry/src/main/java/datadog/telemetry/metric/ConfigInversionMetricPeriodicAction.java @@ -1,6 +1,6 @@ package datadog.telemetry.metric; -import datadog.trace.api.telemetry.ConfigInversionMetricCollector; +import datadog.trace.api.telemetry.ConfigInversionMetricCollectorImpl; import datadog.trace.api.telemetry.MetricCollector; import edu.umd.cs.findbugs.annotations.NonNull; @@ -8,6 +8,6 @@ public class ConfigInversionMetricPeriodicAction extends MetricPeriodicAction { @Override @NonNull public MetricCollector collector() { - return ConfigInversionMetricCollector.getInstance(); + return ConfigInversionMetricCollectorImpl.getInstance(); } } diff --git a/utils/config-utils/build.gradle.kts b/utils/config-utils/build.gradle.kts index bb3598f5587..e77af1d50d0 100644 --- a/utils/config-utils/build.gradle.kts +++ b/utils/config-utils/build.gradle.kts @@ -5,6 +5,48 @@ plugins { apply(from = "$rootDir/gradle/java.gradle") +val minimumBranchCoverage by extra(0.7) +val minimumInstructionCoverage by extra(0.7) + +val excludedClassesCoverage by extra( + listOf( + "datadog.trace.api.ConfigCollector", + "datadog.trace.api.env.CapturedEnvironment", + "datadog.trace.api.env.CapturedEnvironment.ProcessInfo", + // tested in internal-api + "datadog.trace.api.telemetry.OtelEnvMetricCollectorProvider", + "datadog.trace.api.telemetry.ConfigInversionMetricCollectorProvider", + "datadog.trace.bootstrap.config.provider.CapturedEnvironmentConfigSource", + "datadog.trace.bootstrap.config.provider.ConfigConverter.ValueOfLookup", + // tested in internal-api + "datadog.trace.bootstrap.config.provider.ConfigProvider", + "datadog.trace.bootstrap.config.provider.ConfigProvider.ConfigMergeResolver", + "datadog.trace.bootstrap.config.provider.ConfigProvider.ConfigValueResolver", + "datadog.trace.bootstrap.config.provider.ConfigProvider.Singleton", + "datadog.trace.bootstrap.config.provider.ConfigProvider.Source", + "datadog.trace.bootstrap.config.provider.EnvironmentConfigSource", + // tested in internal-api + "datadog.trace.bootstrap.config.provider.OtelEnvironmentConfigSource", + "datadog.trace.bootstrap.config.provider.stableconfig.Selector", + // tested in internal-api + "datadog.trace.bootstrap.config.provider.StableConfigParser", + "datadog.trace.bootstrap.config.provider.SystemPropertiesConfigSource", + ) +) + +val excludedClassesBranchCoverage by extra( + listOf( + "datadog.trace.bootstrap.config.provider.AgentArgsInjector", + "datadog.trace.util.ConfigStrings" + ) +) + +val excludedClassesInstructionCoverage by extra( + listOf( + "datadog.trace.config.inversion.GeneratedSupportedConfigurations" + ) +) + dependencies { implementation(project(":components:environment")) implementation(project(":components:yaml")) @@ -12,6 +54,7 @@ dependencies { implementation(libs.slf4j) testImplementation(project(":utils:test-utils")) + testImplementation("org.snakeyaml:snakeyaml-engine:2.9") } tasks.named("javadoc") { diff --git a/utils/config-utils/src/main/java/datadog/trace/api/telemetry/ConfigInversionMetricCollector.java b/utils/config-utils/src/main/java/datadog/trace/api/telemetry/ConfigInversionMetricCollector.java new file mode 100644 index 00000000000..e36045d7836 --- /dev/null +++ b/utils/config-utils/src/main/java/datadog/trace/api/telemetry/ConfigInversionMetricCollector.java @@ -0,0 +1,5 @@ +package datadog.trace.api.telemetry; + +public interface ConfigInversionMetricCollector { + void setUndocumentedEnvVarMetric(String configName); +} diff --git a/utils/config-utils/src/main/java/datadog/trace/api/telemetry/ConfigInversionMetricCollectorProvider.java b/utils/config-utils/src/main/java/datadog/trace/api/telemetry/ConfigInversionMetricCollectorProvider.java new file mode 100644 index 00000000000..cecc104a36f --- /dev/null +++ b/utils/config-utils/src/main/java/datadog/trace/api/telemetry/ConfigInversionMetricCollectorProvider.java @@ -0,0 +1,19 @@ +package datadog.trace.api.telemetry; + +public final class ConfigInversionMetricCollectorProvider { + private static ConfigInversionMetricCollector INSTANCE = null; + + private ConfigInversionMetricCollectorProvider() {} + + public static ConfigInversionMetricCollector get() { + if (INSTANCE == null) { + throw new IllegalStateException( + "ConfigInversionMetricCollectorService has not been registered."); + } + return INSTANCE; + } + + public static void register(ConfigInversionMetricCollector instance) { + INSTANCE = instance; + } +} diff --git a/internal-api/src/test/groovy/datadog/trace/api/ConfigSettingTest.groovy b/utils/config-utils/src/test/groovy/datadog/trace/api/ConfigSettingTest.groovy similarity index 100% rename from internal-api/src/test/groovy/datadog/trace/api/ConfigSettingTest.groovy rename to utils/config-utils/src/test/groovy/datadog/trace/api/ConfigSettingTest.groovy diff --git a/internal-api/src/test/groovy/datadog/trace/api/env/CapturedEnvironmentTest.groovy b/utils/config-utils/src/test/groovy/datadog/trace/api/env/CapturedEnvironmentTest.groovy similarity index 100% rename from internal-api/src/test/groovy/datadog/trace/api/env/CapturedEnvironmentTest.groovy rename to utils/config-utils/src/test/groovy/datadog/trace/api/env/CapturedEnvironmentTest.groovy diff --git a/internal-api/src/test/groovy/datadog/trace/bootstrap/config/provider/AgentArgsInjectorTest.groovy b/utils/config-utils/src/test/groovy/datadog/trace/bootstrap/config/provider/AgentArgsInjectorTest.groovy similarity index 100% rename from internal-api/src/test/groovy/datadog/trace/bootstrap/config/provider/AgentArgsInjectorTest.groovy rename to utils/config-utils/src/test/groovy/datadog/trace/bootstrap/config/provider/AgentArgsInjectorTest.groovy diff --git a/internal-api/src/test/groovy/datadog/trace/bootstrap/config/provider/AgentArgsParserTest.groovy b/utils/config-utils/src/test/groovy/datadog/trace/bootstrap/config/provider/AgentArgsParserTest.groovy similarity index 100% rename from internal-api/src/test/groovy/datadog/trace/bootstrap/config/provider/AgentArgsParserTest.groovy rename to utils/config-utils/src/test/groovy/datadog/trace/bootstrap/config/provider/AgentArgsParserTest.groovy diff --git a/internal-api/src/test/groovy/datadog/trace/bootstrap/config/provider/ConfigConverterTest.groovy b/utils/config-utils/src/test/groovy/datadog/trace/bootstrap/config/provider/ConfigConverterTest.groovy similarity index 100% rename from internal-api/src/test/groovy/datadog/trace/bootstrap/config/provider/ConfigConverterTest.groovy rename to utils/config-utils/src/test/groovy/datadog/trace/bootstrap/config/provider/ConfigConverterTest.groovy diff --git a/internal-api/src/test/groovy/datadog/trace/bootstrap/config/provider/PropertiesConfigSourceTest.groovy b/utils/config-utils/src/test/groovy/datadog/trace/bootstrap/config/provider/PropertiesConfigSourceTest.groovy similarity index 100% rename from internal-api/src/test/groovy/datadog/trace/bootstrap/config/provider/PropertiesConfigSourceTest.groovy rename to utils/config-utils/src/test/groovy/datadog/trace/bootstrap/config/provider/PropertiesConfigSourceTest.groovy diff --git a/internal-api/src/test/groovy/datadog/trace/bootstrap/config/provider/StableConfigMappingExceptionTest.groovy b/utils/config-utils/src/test/groovy/datadog/trace/bootstrap/config/provider/StableConfigMappingExceptionTest.groovy similarity index 100% rename from internal-api/src/test/groovy/datadog/trace/bootstrap/config/provider/StableConfigMappingExceptionTest.groovy rename to utils/config-utils/src/test/groovy/datadog/trace/bootstrap/config/provider/StableConfigMappingExceptionTest.groovy diff --git a/internal-api/src/test/groovy/datadog/trace/bootstrap/config/provider/StableConfigSourceTest.groovy b/utils/config-utils/src/test/groovy/datadog/trace/bootstrap/config/provider/StableConfigSourceTest.groovy similarity index 100% rename from internal-api/src/test/groovy/datadog/trace/bootstrap/config/provider/StableConfigSourceTest.groovy rename to utils/config-utils/src/test/groovy/datadog/trace/bootstrap/config/provider/StableConfigSourceTest.groovy