Skip to content

Commit 23c0b22

Browse files
committed
Add Java agentless feature flag source
1 parent ce75656 commit 23c0b22

9 files changed

Lines changed: 102 additions & 65 deletions

File tree

dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Agent.java

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
import java.net.URL;
7373
import java.security.CodeSource;
7474
import java.util.EnumSet;
75+
import java.util.Locale;
7576
import java.util.concurrent.TimeUnit;
7677
import java.util.concurrent.atomic.AtomicBoolean;
7778
import java.util.regex.PatternSyntaxException;
@@ -135,7 +136,7 @@ private enum AgentFeature {
135136
APP_LOGS_COLLECTION(GeneralConfig.APP_LOGS_COLLECTION_ENABLED, false),
136137
LLMOBS(LlmObsConfig.LLMOBS_ENABLED, false),
137138
LLMOBS_AGENTLESS(LlmObsConfig.LLMOBS_AGENTLESS_ENABLED, false),
138-
FEATURE_FLAGGING(FeatureFlaggingConfig.FLAGGING_PROVIDER_ENABLED, false);
139+
FEATURE_FLAGGING(FeatureFlaggingConfig.FEATURE_FLAGS_ENABLED, false);
139140

140141
private final String configKey;
141142
private final String systemProp;
@@ -282,9 +283,7 @@ public static void start(
282283
agentlessLogSubmissionEnabled = isFeatureEnabled(AgentFeature.AGENTLESS_LOG_SUBMISSION);
283284
appLogsCollectionEnabled = isFeatureEnabled(AgentFeature.APP_LOGS_COLLECTION);
284285
llmObsEnabled = isFeatureEnabled(AgentFeature.LLMOBS);
285-
featureFlaggingEnabled =
286-
isFeatureEnabled(AgentFeature.FEATURE_FLAGGING)
287-
|| isFeatureFlaggingCdnConfigurationSourceConfigured();
286+
featureFlaggingEnabled = isFeatureFlaggingEnabled();
288287

289288
// setup writers when llmobs is enabled to accomodate apm and llmobs
290289
if (llmObsEnabled) {
@@ -1633,10 +1632,36 @@ private static boolean isFeatureEnabled(AgentFeature feature) {
16331632
}
16341633
}
16351634

1636-
private static boolean isFeatureFlaggingCdnConfigurationSourceConfigured() {
1635+
private static boolean isFeatureFlaggingEnabled() {
1636+
final String enabled = getConfiguredValue(FeatureFlaggingConfig.FEATURE_FLAGS_ENABLED);
1637+
if ("false".equalsIgnoreCase(enabled) || "0".equals(enabled)) {
1638+
return false;
1639+
}
1640+
if ("true".equalsIgnoreCase(enabled) || "1".equals(enabled)) {
1641+
return true;
1642+
}
1643+
1644+
final String oldEnabled = getConfiguredValue(FeatureFlaggingConfig.FLAGGING_PROVIDER_ENABLED);
1645+
if ("false".equalsIgnoreCase(oldEnabled) || "0".equals(oldEnabled)) {
1646+
return false;
1647+
}
1648+
if ("true".equalsIgnoreCase(oldEnabled) || "1".equals(oldEnabled)) {
1649+
return true;
1650+
}
1651+
1652+
return isFeatureFlaggingConfigurationSourceAutoEnabled();
1653+
}
1654+
1655+
private static boolean isFeatureFlaggingConfigurationSourceAutoEnabled() {
16371656
final String configurationSource =
1638-
getConfiguredValue(FeatureFlaggingConfig.FLAGGING_CONFIGURATION_SOURCE);
1639-
return configurationSource != null && "cdn".equalsIgnoreCase(configurationSource.trim());
1657+
getConfiguredValue(FeatureFlaggingConfig.FEATURE_FLAGS_CONFIGURATION_SOURCE);
1658+
if (configurationSource == null) {
1659+
return true;
1660+
}
1661+
final String normalized = configurationSource.trim().toLowerCase(Locale.ROOT);
1662+
return "agentless".equals(normalized)
1663+
|| "remote_config".equals(normalized)
1664+
|| "offline".equals(normalized);
16401665
}
16411666

16421667
private static String getConfiguredValue(final String configKey) {

dd-trace-api/src/main/java/datadog/trace/api/ConfigDefaults.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public final class ConfigDefaults {
4949
static final boolean DEFAULT_INJECT_DATADOG_ATTRIBUTE = true;
5050
static final String DEFAULT_SITE = "datadoghq.com";
5151

52-
public static final String DEFAULT_FLAGGING_CONFIGURATION_SOURCE = "cdn";
52+
public static final String DEFAULT_FLAGGING_CONFIGURATION_SOURCE = "agentless";
5353
public static final double DEFAULT_FLAGGING_CONFIGURATION_SOURCE_POLL_INTERVAL_SECONDS = 30.0D;
5454
public static final double DEFAULT_FLAGGING_CONFIGURATION_SOURCE_REQUEST_TIMEOUT_SECONDS = 2.0D;
5555

dd-trace-api/src/main/java/datadog/trace/api/config/FeatureFlaggingConfig.java

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,19 @@
22

33
public class FeatureFlaggingConfig {
44

5+
public static final String FEATURE_FLAGS_ENABLED = "feature.flags.enabled";
56
public static final String FLAGGING_PROVIDER_ENABLED = "experimental.flagging.provider.enabled";
67

7-
public static final String FLAGGING_CONFIGURATION_SOURCE = "flagging.configuration.source";
8-
public static final String FLAGGING_CONFIGURATION_SOURCE_BASE_URL =
9-
"flagging.configuration.source.base.url";
10-
public static final String FLAGGING_CONFIGURATION_SOURCE_POLL_INTERVAL_SECONDS =
11-
"flagging.configuration.source.poll.interval.seconds";
12-
public static final String FLAGGING_CONFIGURATION_SOURCE_REQUEST_TIMEOUT_SECONDS =
13-
"flagging.configuration.source.request.timeout.seconds";
14-
public static final String FLAGGING_CONFIGURATION_SOURCE_EXTRA_HEADERS =
15-
"flagging.configuration.source.extra.headers";
8+
public static final String FEATURE_FLAGS_CONFIGURATION_SOURCE =
9+
"feature.flags.configuration.source";
10+
public static final String FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_BASE_URL =
11+
"feature.flags.configuration.source.agentless.base.url";
12+
public static final String FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_POLL_INTERVAL_SECONDS =
13+
"feature.flags.configuration.source.agentless.poll.interval.seconds";
14+
public static final String FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_REQUEST_TIMEOUT_SECONDS =
15+
"feature.flags.configuration.source.agentless.request.timeout.seconds";
16+
public static final String FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_EXTRA_HEADERS =
17+
"feature.flags.configuration.source.agentless.extra.headers";
1618

1719
private FeatureFlaggingConfig() {}
1820
}

internal-api/src/main/java/datadog/trace/api/Config.java

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -364,11 +364,11 @@
364364
import static datadog.trace.api.config.DebuggerConfig.THIRD_PARTY_EXCLUDES;
365365
import static datadog.trace.api.config.DebuggerConfig.THIRD_PARTY_INCLUDES;
366366
import static datadog.trace.api.config.DebuggerConfig.THIRD_PARTY_SHADING_IDENTIFIERS;
367-
import static datadog.trace.api.config.FeatureFlaggingConfig.FLAGGING_CONFIGURATION_SOURCE;
368-
import static datadog.trace.api.config.FeatureFlaggingConfig.FLAGGING_CONFIGURATION_SOURCE_BASE_URL;
369-
import static datadog.trace.api.config.FeatureFlaggingConfig.FLAGGING_CONFIGURATION_SOURCE_EXTRA_HEADERS;
370-
import static datadog.trace.api.config.FeatureFlaggingConfig.FLAGGING_CONFIGURATION_SOURCE_POLL_INTERVAL_SECONDS;
371-
import static datadog.trace.api.config.FeatureFlaggingConfig.FLAGGING_CONFIGURATION_SOURCE_REQUEST_TIMEOUT_SECONDS;
367+
import static datadog.trace.api.config.FeatureFlaggingConfig.FEATURE_FLAGS_CONFIGURATION_SOURCE;
368+
import static datadog.trace.api.config.FeatureFlaggingConfig.FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_BASE_URL;
369+
import static datadog.trace.api.config.FeatureFlaggingConfig.FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_EXTRA_HEADERS;
370+
import static datadog.trace.api.config.FeatureFlaggingConfig.FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_POLL_INTERVAL_SECONDS;
371+
import static datadog.trace.api.config.FeatureFlaggingConfig.FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_REQUEST_TIMEOUT_SECONDS;
372372
import static datadog.trace.api.config.GeneralConfig.AGENTLESS_LOG_SUBMISSION_LEVEL;
373373
import static datadog.trace.api.config.GeneralConfig.AGENTLESS_LOG_SUBMISSION_QUEUE_SIZE;
374374
import static datadog.trace.api.config.GeneralConfig.AGENTLESS_LOG_SUBMISSION_URL;
@@ -2852,19 +2852,20 @@ PROFILING_DATADOG_PROFILER_ENABLED, isDatadogProfilerSafeInCurrentEnvironment())
28522852
flaggingConfigurationSource =
28532853
normalizeFlaggingConfigurationSource(
28542854
configProvider.getString(
2855-
FLAGGING_CONFIGURATION_SOURCE, DEFAULT_FLAGGING_CONFIGURATION_SOURCE));
2855+
FEATURE_FLAGS_CONFIGURATION_SOURCE, DEFAULT_FLAGGING_CONFIGURATION_SOURCE));
28562856
flaggingConfigurationSourceBaseUrl =
2857-
configProvider.getStringNotEmpty(FLAGGING_CONFIGURATION_SOURCE_BASE_URL, null);
2857+
configProvider.getStringNotEmpty(
2858+
FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_BASE_URL, null);
28582859
flaggingConfigurationSourcePollIntervalSeconds =
28592860
configProvider.getDouble(
2860-
FLAGGING_CONFIGURATION_SOURCE_POLL_INTERVAL_SECONDS,
2861+
FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_POLL_INTERVAL_SECONDS,
28612862
DEFAULT_FLAGGING_CONFIGURATION_SOURCE_POLL_INTERVAL_SECONDS);
28622863
flaggingConfigurationSourceRequestTimeoutSeconds =
28632864
configProvider.getDouble(
2864-
FLAGGING_CONFIGURATION_SOURCE_REQUEST_TIMEOUT_SECONDS,
2865+
FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_REQUEST_TIMEOUT_SECONDS,
28652866
DEFAULT_FLAGGING_CONFIGURATION_SOURCE_REQUEST_TIMEOUT_SECONDS);
28662867
flaggingConfigurationSourceExtraHeaders =
2867-
configProvider.getMergedMap(FLAGGING_CONFIGURATION_SOURCE_EXTRA_HEADERS, '=');
2868+
configProvider.getMergedMap(FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_EXTRA_HEADERS, '=');
28682869

28692870
dynamicInstrumentationEnabled =
28702871
configProvider.getBoolean(

metadata/supported-configurations.json

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1497,62 +1497,70 @@
14971497
"aliases": []
14981498
}
14991499
],
1500-
"DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED": [
1501-
{
1502-
"version": "A",
1503-
"type": "boolean",
1504-
"default": "false",
1505-
"aliases": []
1506-
}
1507-
],
1508-
"DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED": [
1509-
{
1510-
"version": "B",
1511-
"type": "boolean",
1512-
"default": "true",
1513-
"aliases": []
1514-
}
1515-
],
1516-
"DD_FLAGGING_CONFIGURATION_SOURCE": [
1500+
"DD_FEATURE_FLAGS_CONFIGURATION_SOURCE": [
15171501
{
15181502
"version": "A",
15191503
"type": "string",
1520-
"default": "cdn",
1504+
"default": "agentless",
15211505
"aliases": []
15221506
}
15231507
],
1524-
"DD_FLAGGING_CONFIGURATION_SOURCE_BASE_URL": [
1508+
"DD_FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_BASE_URL": [
15251509
{
15261510
"version": "A",
15271511
"type": "string",
15281512
"default": null,
15291513
"aliases": []
15301514
}
15311515
],
1532-
"DD_FLAGGING_CONFIGURATION_SOURCE_EXTRA_HEADERS": [
1516+
"DD_FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_EXTRA_HEADERS": [
15331517
{
15341518
"version": "A",
15351519
"type": "map",
15361520
"default": null,
15371521
"aliases": []
15381522
}
15391523
],
1540-
"DD_FLAGGING_CONFIGURATION_SOURCE_POLL_INTERVAL_SECONDS": [
1524+
"DD_FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_POLL_INTERVAL_SECONDS": [
15411525
{
15421526
"version": "A",
15431527
"type": "decimal",
15441528
"default": "30",
15451529
"aliases": []
15461530
}
15471531
],
1548-
"DD_FLAGGING_CONFIGURATION_SOURCE_REQUEST_TIMEOUT_SECONDS": [
1532+
"DD_FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_REQUEST_TIMEOUT_SECONDS": [
15491533
{
15501534
"version": "A",
15511535
"type": "decimal",
15521536
"default": "2",
15531537
"aliases": []
15541538
}
15551539
],
1540+
"DD_FEATURE_FLAGS_ENABLED": [
1541+
{
1542+
"version": "A",
1543+
"type": "boolean",
1544+
"default": "true",
1545+
"aliases": ["DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED"]
1546+
}
1547+
],
1548+
"DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED": [
1549+
{
1550+
"version": "A",
1551+
"type": "boolean",
1552+
"default": "false",
1553+
"aliases": []
1554+
}
1555+
],
1556+
"DD_EXPERIMENTAL_PROPAGATE_PROCESS_TAGS_ENABLED": [
1557+
{
1558+
"version": "B",
1559+
"type": "boolean",
1560+
"default": "true",
1561+
"aliases": []
1562+
}
1563+
],
15561564
"DD_FORCE_CLEAR_TEXT_HTTP_FOR_INTAKE_CLIENT": [
15571565
{
15581566
"version": "A",

products/feature-flagging/feature-flagging-agent/src/main/java/com/datadog/featureflag/FeatureFlaggingSystem.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
public class FeatureFlaggingSystem {
99

1010
private static final Logger LOGGER = LoggerFactory.getLogger(FeatureFlaggingSystem.class);
11-
private static final String SOURCE_CDN = "cdn";
11+
private static final String SOURCE_AGENTLESS = "agentless";
1212
private static final String SOURCE_REMOTE_CONFIG = "remote_config";
1313
private static final String SOURCE_OFFLINE = "offline";
1414

@@ -41,7 +41,7 @@ static ConfigurationSourceService createConfigurationSourceService(
4141
throw new IllegalStateException("Feature Flagging system started without RC");
4242
}
4343
return new RemoteConfigServiceImpl(sco, config);
44-
} else if (SOURCE_CDN.equals(configurationSource)) {
44+
} else if (SOURCE_AGENTLESS.equals(configurationSource)) {
4545
return new UfcHttpConfigService(config);
4646
} else if (SOURCE_OFFLINE.equals(configurationSource)) {
4747
LOGGER.debug(

products/feature-flagging/feature-flagging-agent/src/test/java/com/datadog/featureflag/FeatureFlaggingSystemTest.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package com.datadog.featureflag;
22

3-
import static datadog.trace.api.config.FeatureFlaggingConfig.FLAGGING_CONFIGURATION_SOURCE;
3+
import static datadog.trace.api.config.FeatureFlaggingConfig.FEATURE_FLAGS_CONFIGURATION_SOURCE;
44
import static datadog.trace.api.config.RemoteConfigConfig.REMOTE_CONFIGURATION_ENABLED;
55
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
66
import static org.junit.jupiter.api.Assertions.assertNull;
@@ -26,7 +26,7 @@
2626
class FeatureFlaggingSystemTest {
2727

2828
@Test
29-
@WithConfig(key = FLAGGING_CONFIGURATION_SOURCE, value = "remote_config")
29+
@WithConfig(key = FEATURE_FLAGS_CONFIGURATION_SOURCE, value = "remote_config")
3030
@WithConfig(key = REMOTE_CONFIGURATION_ENABLED, value = "true")
3131
void testFeatureFlagSystemInitialization() {
3232
ConfigurationPoller poller = mock(ConfigurationPoller.class);
@@ -53,7 +53,7 @@ void testFeatureFlagSystemInitialization() {
5353
}
5454

5555
@Test
56-
@WithConfig(key = FLAGGING_CONFIGURATION_SOURCE, value = "remote_config")
56+
@WithConfig(key = FEATURE_FLAGS_CONFIGURATION_SOURCE, value = "remote_config")
5757
@WithConfig(key = REMOTE_CONFIGURATION_ENABLED, value = "false")
5858
void testThatRemoteConfigIsRequired() {
5959
SharedCommunicationObjects sharedCommunicationObjects = mock(SharedCommunicationObjects.class);
@@ -68,17 +68,17 @@ void testThatRemoteConfigIsRequired() {
6868
}
6969

7070
@Test
71-
@WithConfig(key = FLAGGING_CONFIGURATION_SOURCE, value = "cdn")
71+
@WithConfig(key = FEATURE_FLAGS_CONFIGURATION_SOURCE, value = "agentless")
7272
@WithConfig(key = REMOTE_CONFIGURATION_ENABLED, value = "false")
73-
void cdnConfigurationSourceUsesHttpServiceWithoutRemoteConfig() {
73+
void agentlessConfigurationSourceUsesHttpServiceWithoutRemoteConfig() {
7474
assertInstanceOf(
7575
UfcHttpConfigService.class,
7676
FeatureFlaggingSystem.createConfigurationSourceService(
7777
sharedCommunicationObjects(), Config.get()));
7878
}
7979

8080
@Test
81-
@WithConfig(key = FLAGGING_CONFIGURATION_SOURCE, value = "remote_config")
81+
@WithConfig(key = FEATURE_FLAGS_CONFIGURATION_SOURCE, value = "remote_config")
8282
@WithConfig(key = REMOTE_CONFIGURATION_ENABLED, value = "true")
8383
void explicitRemoteConfigUsesRemoteConfigService() {
8484
SharedCommunicationObjects sharedCommunicationObjects = sharedCommunicationObjects();
@@ -92,7 +92,7 @@ void explicitRemoteConfigUsesRemoteConfigService() {
9292
}
9393

9494
@Test
95-
@WithConfig(key = FLAGGING_CONFIGURATION_SOURCE, value = "invalid")
95+
@WithConfig(key = FEATURE_FLAGS_CONFIGURATION_SOURCE, value = "invalid")
9696
void invalidConfigurationSourceFailsBeforeStartingNetworkSource() {
9797
assertThrows(
9898
IllegalArgumentException.class,
@@ -102,7 +102,7 @@ void invalidConfigurationSourceFailsBeforeStartingNetworkSource() {
102102
}
103103

104104
@Test
105-
@WithConfig(key = FLAGGING_CONFIGURATION_SOURCE, value = "offline")
105+
@WithConfig(key = FEATURE_FLAGS_CONFIGURATION_SOURCE, value = "offline")
106106
void offlineConfigurationSourceDoesNotStartNetworkSource() {
107107
assertNull(
108108
FeatureFlaggingSystem.createConfigurationSourceService(

products/feature-flagging/feature-flagging-api/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,5 +85,5 @@ OTEL_EXPORTER_OTLP_PROTOCOL=grpc
8585
## Requirements
8686

8787
- Java 11+
88-
- Datadog Agent with Remote Configuration enabled
89-
- `DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED=true`
88+
- Feature Flags provider enabled with `DD_FEATURE_FLAGS_ENABLED=true`, or left unset
89+
for the default `agentless` configuration source.

products/feature-flagging/feature-flagging-lib/src/test/java/com/datadog/featureflag/UfcHttpConfigServiceTest.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,19 +49,20 @@ void cleanup() {
4949

5050
@Test
5151
void appendsMockConfigPathWhenConfiguredUrlIsRoot() {
52-
final Config config = config("http://mock-cdn:8092", "datadoghq.com", "");
52+
final Config config = config("http://mock-backend:8092", "datadoghq.com", "");
5353

5454
assertEquals(
55-
"http://mock-cdn:8092/mock/ufc/config", UfcHttpConfigService.endpoint(config).toString());
55+
"http://mock-backend:8092/mock/ufc/config",
56+
UfcHttpConfigService.endpoint(config).toString());
5657
}
5758

5859
@Test
5960
void preservesConfiguredFullEndpointUrl() {
6061
final Config config =
61-
config("http://mock-cdn:8092/mock/ufc/config?fixture=valid", "datadoghq.com", "");
62+
config("http://mock-backend:8092/mock/ufc/config?fixture=valid", "datadoghq.com", "");
6263

6364
assertEquals(
64-
"http://mock-cdn:8092/mock/ufc/config?fixture=valid",
65+
"http://mock-backend:8092/mock/ufc/config?fixture=valid",
6566
UfcHttpConfigService.endpoint(config).toString());
6667
}
6768

0 commit comments

Comments
 (0)