-
Notifications
You must be signed in to change notification settings - Fork 344
Add agentless Feature Flagging configuration source #11892
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
base: master
Are you sure you want to change the base?
Changes from all commits
b8bbd26
4baefdb
d378350
f9e70e6
17a02ad
0f02a2a
5057539
7aa2181
ffbf970
3b9b97c
eaaea27
76917d6
2cee183
ebc28ca
0984370
c146f09
488b477
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| package datadog.trace.bootstrap; | ||
|
|
||
| import static org.junit.jupiter.api.Assertions.assertEquals; | ||
|
|
||
| import java.util.concurrent.atomic.AtomicInteger; | ||
| import org.junit.jupiter.api.BeforeEach; | ||
| import org.junit.jupiter.api.Test; | ||
|
|
||
| class AgentFeatureFlaggingLifecycleTest { | ||
|
|
||
| @BeforeEach | ||
| void reset() { | ||
| FakeFeatureFlaggingSystem.stopCalls.set(0); | ||
| } | ||
|
|
||
| @Test | ||
| void shutdownInvokesFeatureFlaggingSystemStopThroughAgentClassLoader() { | ||
| final ClassLoader classLoader = | ||
| new ClassLoader(null) { | ||
| @Override | ||
| public Class<?> loadClass(final String name) throws ClassNotFoundException { | ||
| if ("com.datadog.featureflag.FeatureFlaggingSystem".equals(name)) { | ||
| return FakeFeatureFlaggingSystem.class; | ||
| } | ||
| return super.loadClass(name); | ||
| } | ||
| }; | ||
|
|
||
| Agent.shutdownFeatureFlagging(classLoader); | ||
|
|
||
| assertEquals(1, FakeFeatureFlaggingSystem.stopCalls.get()); | ||
| } | ||
|
|
||
| @Test | ||
| void shutdownIsNoopBeforeAgentClassLoaderExists() { | ||
| Agent.shutdownFeatureFlagging(null); | ||
|
|
||
| assertEquals(0, FakeFeatureFlaggingSystem.stopCalls.get()); | ||
| } | ||
|
|
||
| public static final class FakeFeatureFlaggingSystem { | ||
| private static final AtomicInteger stopCalls = new AtomicInteger(); | ||
|
|
||
| public static void stop() { | ||
| stopCalls.incrementAndGet(); | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -86,6 +86,9 @@ | |
| import static datadog.trace.api.ConfigDefaults.DEFAULT_ELASTICSEARCH_BODY_ENABLED; | ||
| import static datadog.trace.api.ConfigDefaults.DEFAULT_ELASTICSEARCH_PARAMS_ENABLED; | ||
| import static datadog.trace.api.ConfigDefaults.DEFAULT_EXPERIMENTATAL_JEE_SPLIT_BY_DEPLOYMENT; | ||
| import static datadog.trace.api.ConfigDefaults.DEFAULT_FEATURE_FLAGGING_CONFIGURATION_SOURCE; | ||
| import static datadog.trace.api.ConfigDefaults.DEFAULT_FEATURE_FLAGGING_CONFIGURATION_SOURCE_POLL_INTERVAL_SECONDS; | ||
| import static datadog.trace.api.ConfigDefaults.DEFAULT_FEATURE_FLAGGING_CONFIGURATION_SOURCE_REQUEST_TIMEOUT_SECONDS; | ||
| import static datadog.trace.api.ConfigDefaults.DEFAULT_GRPC_CLIENT_ERROR_STATUSES; | ||
| import static datadog.trace.api.ConfigDefaults.DEFAULT_GRPC_SERVER_ERROR_STATUSES; | ||
| import static datadog.trace.api.ConfigDefaults.DEFAULT_HEALTH_METRICS_ENABLED; | ||
|
|
@@ -723,6 +726,10 @@ | |
| import static datadog.trace.api.config.TracerConfig.WRITER_BAGGAGE_INJECT; | ||
| import static datadog.trace.api.config.TracerConfig.WRITER_LINKS_INJECT; | ||
| import static datadog.trace.api.config.TracerConfig.WRITER_TYPE; | ||
| import static datadog.trace.api.featureflag.config.FeatureFlaggingConfig.FEATURE_FLAGS_CONFIGURATION_SOURCE; | ||
| import static datadog.trace.api.featureflag.config.FeatureFlaggingConfig.FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_BASE_URL; | ||
| import static datadog.trace.api.featureflag.config.FeatureFlaggingConfig.FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_POLL_INTERVAL_SECONDS; | ||
| import static datadog.trace.api.featureflag.config.FeatureFlaggingConfig.FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_REQUEST_TIMEOUT_SECONDS; | ||
| import static datadog.trace.api.telemetry.LogCollector.SEND_TELEMETRY; | ||
| import static datadog.trace.bootstrap.instrumentation.api.WriterConstants.OTLP_WRITER_TYPE; | ||
| import static datadog.trace.util.CollectionUtils.tryMakeImmutableList; | ||
|
|
@@ -1214,6 +1221,11 @@ public static String getHostName() { | |
|
|
||
| private final int remoteConfigMaxExtraServices; | ||
|
|
||
| private final String featureFlaggingConfigurationSource; | ||
| private final String featureFlaggingConfigurationSourceAgentlessBaseUrl; | ||
| private final int featureFlaggingConfigurationSourcePollIntervalSeconds; | ||
| private final int featureFlaggingConfigurationSourceRequestTimeoutSeconds; | ||
|
|
||
| private final boolean dbmInjectSqlBaseHash; | ||
| private final String dbmPropagationMode; | ||
| private final boolean dbmTracePreparedStatements; | ||
|
|
@@ -2839,6 +2851,40 @@ PROFILING_DATADOG_PROFILER_ENABLED, isDatadogProfilerSafeInCurrentEnvironment()) | |
| configProvider.getInteger( | ||
| REMOTE_CONFIG_MAX_EXTRA_SERVICES, DEFAULT_REMOTE_CONFIG_MAX_EXTRA_SERVICES); | ||
|
|
||
| featureFlaggingConfigurationSource = | ||
| normalizeFeatureFlaggingConfigurationSource( | ||
| configProvider.getString( | ||
| FEATURE_FLAGS_CONFIGURATION_SOURCE, DEFAULT_FEATURE_FLAGGING_CONFIGURATION_SOURCE)); | ||
| featureFlaggingConfigurationSourceAgentlessBaseUrl = | ||
| configProvider.getStringNotEmpty( | ||
| FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_BASE_URL, null); | ||
| int configuredFeatureFlaggingPollIntervalSeconds = | ||
| configProvider.getInteger( | ||
| FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_POLL_INTERVAL_SECONDS, | ||
| DEFAULT_FEATURE_FLAGGING_CONFIGURATION_SOURCE_POLL_INTERVAL_SECONDS); | ||
| if (configuredFeatureFlaggingPollIntervalSeconds <= 0) { | ||
| log.warn( | ||
| "Invalid Feature Flagging agentless poll interval: {}. The value must be positive", | ||
| configuredFeatureFlaggingPollIntervalSeconds); | ||
| configuredFeatureFlaggingPollIntervalSeconds = | ||
| DEFAULT_FEATURE_FLAGGING_CONFIGURATION_SOURCE_POLL_INTERVAL_SECONDS; | ||
| } | ||
| featureFlaggingConfigurationSourcePollIntervalSeconds = | ||
| configuredFeatureFlaggingPollIntervalSeconds; | ||
| int configuredFeatureFlaggingRequestTimeoutSeconds = | ||
| configProvider.getInteger( | ||
| FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_REQUEST_TIMEOUT_SECONDS, | ||
| DEFAULT_FEATURE_FLAGGING_CONFIGURATION_SOURCE_REQUEST_TIMEOUT_SECONDS); | ||
| if (configuredFeatureFlaggingRequestTimeoutSeconds <= 0) { | ||
| log.warn( | ||
| "Invalid Feature Flagging agentless request timeout: {}. The value must be positive", | ||
| configuredFeatureFlaggingRequestTimeoutSeconds); | ||
| configuredFeatureFlaggingRequestTimeoutSeconds = | ||
| DEFAULT_FEATURE_FLAGGING_CONFIGURATION_SOURCE_REQUEST_TIMEOUT_SECONDS; | ||
| } | ||
| featureFlaggingConfigurationSourceRequestTimeoutSeconds = | ||
| configuredFeatureFlaggingRequestTimeoutSeconds; | ||
|
|
||
| dynamicInstrumentationEnabled = | ||
| configProvider.getBoolean( | ||
| DYNAMIC_INSTRUMENTATION_ENABLED, DEFAULT_DYNAMIC_INSTRUMENTATION_ENABLED); | ||
|
|
@@ -3751,6 +3797,28 @@ public boolean isInferredProxyPropagationEnabled() { | |
| return traceInferredProxyEnabled; | ||
| } | ||
|
|
||
| private static String normalizeFeatureFlaggingConfigurationSource(final String source) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IIUC if a typo / invalid value is set as config source, the Feature Flagging subsystem would not start and just log an IllegalArgumentException: https://github.com/DataDog/dd-trace-java/pull/11892/changes#diff-a2718be99f97d918aebd130483af618925dd3121c802f00eed3fe9c3af712dfeR122. Instead we should probably catch invalid values here immediately and fall-back to the default |
||
| if (source == null) { | ||
| return DEFAULT_FEATURE_FLAGGING_CONFIGURATION_SOURCE; | ||
| } | ||
| final String normalized = source.trim().toLowerCase(Locale.ROOT); | ||
| if (normalized.isEmpty()) { | ||
| return DEFAULT_FEATURE_FLAGGING_CONFIGURATION_SOURCE; | ||
| } | ||
| switch (normalized) { | ||
| case "agentless": | ||
| case "remote_config": | ||
| case "offline": | ||
| return normalized; | ||
| default: | ||
| log.warn( | ||
| "Unsupported Feature Flagging configuration source: {}. Defaulting to {}", | ||
| source, | ||
| DEFAULT_FEATURE_FLAGGING_CONFIGURATION_SOURCE); | ||
| return DEFAULT_FEATURE_FLAGGING_CONFIGURATION_SOURCE; | ||
| } | ||
| } | ||
|
|
||
| public boolean isBaggageExtract() { | ||
| return tracePropagationStylesToExtract.contains(TracePropagationStyle.BAGGAGE); | ||
| } | ||
|
|
@@ -4668,6 +4736,22 @@ public int getRemoteConfigMaxExtraServices() { | |
| return remoteConfigMaxExtraServices; | ||
| } | ||
|
|
||
| public String getFeatureFlaggingConfigurationSource() { | ||
| return featureFlaggingConfigurationSource; | ||
| } | ||
|
|
||
| public String getFeatureFlaggingConfigurationSourceAgentlessBaseUrl() { | ||
| return featureFlaggingConfigurationSourceAgentlessBaseUrl; | ||
| } | ||
|
|
||
| public int getFeatureFlaggingConfigurationSourcePollIntervalSeconds() { | ||
| return featureFlaggingConfigurationSourcePollIntervalSeconds; | ||
| } | ||
|
|
||
| public int getFeatureFlaggingConfigurationSourceRequestTimeoutSeconds() { | ||
| return featureFlaggingConfigurationSourceRequestTimeoutSeconds; | ||
| } | ||
|
|
||
| public boolean isDynamicInstrumentationEnabled() { | ||
| return dynamicInstrumentationEnabled; | ||
| } | ||
|
|
@@ -6500,6 +6584,14 @@ public String toString() { | |
| + remoteConfigMaxPayloadSize | ||
| + ", remoteConfigIntegrityCheckEnabled=" | ||
| + remoteConfigIntegrityCheckEnabled | ||
| + ", featureFlaggingConfigurationSource=" | ||
| + featureFlaggingConfigurationSource | ||
| + ", featureFlaggingConfigurationSourceAgentlessBaseUrl=" | ||
| + featureFlaggingConfigurationSourceAgentlessBaseUrl | ||
| + ", featureFlaggingConfigurationSourcePollIntervalSeconds=" | ||
| + featureFlaggingConfigurationSourcePollIntervalSeconds | ||
| + ", featureFlaggingConfigurationSourceRequestTimeoutSeconds=" | ||
| + featureFlaggingConfigurationSourceRequestTimeoutSeconds | ||
| + ", debuggerEnabled=" | ||
| + dynamicInstrumentationEnabled | ||
| + ", debuggerUploadTimeout=" | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.