Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
import java.net.URL;
import java.security.CodeSource;
import java.util.EnumSet;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.PatternSyntaxException;
Expand Down Expand Up @@ -135,7 +136,7 @@ private enum AgentFeature {
APP_LOGS_COLLECTION(GeneralConfig.APP_LOGS_COLLECTION_ENABLED, false),
LLMOBS(LlmObsConfig.LLMOBS_ENABLED, false),
LLMOBS_AGENTLESS(LlmObsConfig.LLMOBS_AGENTLESS_ENABLED, false),
FEATURE_FLAGGING(FeatureFlaggingConfig.FLAGGING_PROVIDER_ENABLED, false);
FEATURE_FLAGGING(FeatureFlaggingConfig.FEATURE_FLAGS_ENABLED, false);

private final String configKey;
private final String systemProp;
Expand Down Expand Up @@ -282,7 +283,7 @@ public static void start(
agentlessLogSubmissionEnabled = isFeatureEnabled(AgentFeature.AGENTLESS_LOG_SUBMISSION);
appLogsCollectionEnabled = isFeatureEnabled(AgentFeature.APP_LOGS_COLLECTION);
llmObsEnabled = isFeatureEnabled(AgentFeature.LLMOBS);
featureFlaggingEnabled = isFeatureEnabled(AgentFeature.FEATURE_FLAGGING);
featureFlaggingEnabled = isFeatureFlaggingEnabled();

// setup writers when llmobs is enabled to accomodate apm and llmobs
if (llmObsEnabled) {
Expand Down Expand Up @@ -1631,6 +1632,53 @@ private static boolean isFeatureEnabled(AgentFeature feature) {
}
}

private static boolean isFeatureFlaggingEnabled() {
final String enabled = getConfiguredValue(FeatureFlaggingConfig.FEATURE_FLAGS_ENABLED);
if ("false".equalsIgnoreCase(enabled) || "0".equals(enabled)) {
return false;
}
if ("true".equalsIgnoreCase(enabled) || "1".equals(enabled)) {
return true;
}

final String oldEnabled = getConfiguredValue(FeatureFlaggingConfig.FLAGGING_PROVIDER_ENABLED);
if ("false".equalsIgnoreCase(oldEnabled) || "0".equals(oldEnabled)) {
return false;
}
if ("true".equalsIgnoreCase(oldEnabled) || "1".equals(oldEnabled)) {
return true;
}

return isFeatureFlaggingConfigurationSourceAutoEnabled();
}

private static boolean isFeatureFlaggingConfigurationSourceAutoEnabled() {
final String configurationSource =
getConfiguredValue(FeatureFlaggingConfig.FEATURE_FLAGS_CONFIGURATION_SOURCE);
if (configurationSource == null) {
return true;
}
final String normalized = configurationSource.trim().toLowerCase(Locale.ROOT);
return "agentless".equals(normalized)
|| "remote_config".equals(normalized)
|| "offline".equals(normalized);
}

private static String getConfiguredValue(final String configKey) {
final String systemProp = propertyNameToSystemPropertyName(configKey);
String settingValue = getNullIfEmpty(SystemProperties.get(systemProp));
if (settingValue == null) {
settingValue = getNullIfEmpty(getStableConfig(FLEET, configKey));
}
if (settingValue == null) {
settingValue = getNullIfEmpty(ddGetEnv(systemProp));
}
if (settingValue == null) {
settingValue = getNullIfEmpty(getStableConfig(LOCAL, configKey));
}
return settingValue;
}

/**
* @see datadog.trace.api.ProductActivation#fromString(String)
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ public final class ConfigDefaults {
static final boolean DEFAULT_INJECT_DATADOG_ATTRIBUTE = true;
static final String DEFAULT_SITE = "datadoghq.com";

public static final String DEFAULT_FEATURE_FLAGGING_CONFIGURATION_SOURCE = "agentless";
public static final double DEFAULT_FEATURE_FLAGGING_CONFIGURATION_SOURCE_POLL_INTERVAL_SECONDS =
30.0D;
public static final double DEFAULT_FEATURE_FLAGGING_CONFIGURATION_SOURCE_REQUEST_TIMEOUT_SECONDS =
2.0D;

static final boolean DEFAULT_CODE_ORIGIN_FOR_SPANS_INTERFACE_SUPPORT = false;
static final int DEFAULT_CODE_ORIGIN_MAX_USER_FRAMES = 8;
static final boolean DEFAULT_TRACE_ENABLED = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,19 @@

public class FeatureFlaggingConfig {

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

public static final String FEATURE_FLAGS_CONFIGURATION_SOURCE =
"feature.flags.configuration.source";
public static final String FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_BASE_URL =
"feature.flags.configuration.source.agentless.base.url";
public static final String FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_POLL_INTERVAL_SECONDS =
"feature.flags.configuration.source.agentless.poll.interval.seconds";
public static final String FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_REQUEST_TIMEOUT_SECONDS =
"feature.flags.configuration.source.agentless.request.timeout.seconds";
public static final String FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_EXTRA_HEADERS =
"feature.flags.configuration.source.agentless.extra.headers";

private FeatureFlaggingConfig() {}
}
71 changes: 71 additions & 0 deletions internal-api/src/main/java/datadog/trace/api/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -361,6 +364,11 @@
import static datadog.trace.api.config.DebuggerConfig.THIRD_PARTY_EXCLUDES;
import static datadog.trace.api.config.DebuggerConfig.THIRD_PARTY_INCLUDES;
import static datadog.trace.api.config.DebuggerConfig.THIRD_PARTY_SHADING_IDENTIFIERS;
import static datadog.trace.api.config.FeatureFlaggingConfig.FEATURE_FLAGS_CONFIGURATION_SOURCE;
import static datadog.trace.api.config.FeatureFlaggingConfig.FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_BASE_URL;
import static datadog.trace.api.config.FeatureFlaggingConfig.FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_EXTRA_HEADERS;
import static datadog.trace.api.config.FeatureFlaggingConfig.FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_POLL_INTERVAL_SECONDS;
import static datadog.trace.api.config.FeatureFlaggingConfig.FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_REQUEST_TIMEOUT_SECONDS;
import static datadog.trace.api.config.GeneralConfig.AGENTLESS_LOG_SUBMISSION_LEVEL;
import static datadog.trace.api.config.GeneralConfig.AGENTLESS_LOG_SUBMISSION_QUEUE_SIZE;
import static datadog.trace.api.config.GeneralConfig.AGENTLESS_LOG_SUBMISSION_URL;
Expand Down Expand Up @@ -1213,6 +1221,12 @@ public static String getHostName() {

private final int remoteConfigMaxExtraServices;

private final String featureFlaggingConfigurationSource;
private final String featureFlaggingConfigurationSourceBaseUrl;
private final double featureFlaggingConfigurationSourcePollIntervalSeconds;
private final double featureFlaggingConfigurationSourceRequestTimeoutSeconds;
private final Map<String, String> featureFlaggingConfigurationSourceExtraHeaders;

private final boolean dbmInjectSqlBaseHash;
private final String dbmPropagationMode;
private final boolean dbmTracePreparedStatements;
Expand Down Expand Up @@ -2835,6 +2849,25 @@ 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));
featureFlaggingConfigurationSourceBaseUrl =
configProvider.getStringNotEmpty(
FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_BASE_URL, null);
featureFlaggingConfigurationSourcePollIntervalSeconds =
configProvider.getDouble(
FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_POLL_INTERVAL_SECONDS,
DEFAULT_FEATURE_FLAGGING_CONFIGURATION_SOURCE_POLL_INTERVAL_SECONDS);
featureFlaggingConfigurationSourceRequestTimeoutSeconds =
configProvider.getDouble(
FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_REQUEST_TIMEOUT_SECONDS,
DEFAULT_FEATURE_FLAGGING_CONFIGURATION_SOURCE_REQUEST_TIMEOUT_SECONDS);
featureFlaggingConfigurationSourceExtraHeaders =
configProvider.getMergedMap(
FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_EXTRA_HEADERS, '=');

dynamicInstrumentationEnabled =
configProvider.getBoolean(
DYNAMIC_INSTRUMENTATION_ENABLED, DEFAULT_DYNAMIC_INSTRUMENTATION_ENABLED);
Expand Down Expand Up @@ -3747,6 +3780,14 @@ public boolean isInferredProxyPropagationEnabled() {
return traceInferredProxyEnabled;
}

private static String normalizeFeatureFlaggingConfigurationSource(final String source) {
if (source == null) {
return DEFAULT_FEATURE_FLAGGING_CONFIGURATION_SOURCE;
}
final String normalized = source.trim().toLowerCase(Locale.ROOT);
return normalized.isEmpty() ? DEFAULT_FEATURE_FLAGGING_CONFIGURATION_SOURCE : normalized;
}

public boolean isBaggageExtract() {
return tracePropagationStylesToExtract.contains(TracePropagationStyle.BAGGAGE);
}
Expand Down Expand Up @@ -4654,6 +4695,26 @@ public int getRemoteConfigMaxExtraServices() {
return remoteConfigMaxExtraServices;
}

public String getFeatureFlaggingConfigurationSource() {
return featureFlaggingConfigurationSource;
}

public String getFeatureFlaggingConfigurationSourceBaseUrl() {
return featureFlaggingConfigurationSourceBaseUrl;
}

public double getFeatureFlaggingConfigurationSourcePollIntervalSeconds() {
return featureFlaggingConfigurationSourcePollIntervalSeconds;
}

public double getFeatureFlaggingConfigurationSourceRequestTimeoutSeconds() {
return featureFlaggingConfigurationSourceRequestTimeoutSeconds;
}

public Map<String, String> getFeatureFlaggingConfigurationSourceExtraHeaders() {
return featureFlaggingConfigurationSourceExtraHeaders;
}

public boolean isDynamicInstrumentationEnabled() {
return dynamicInstrumentationEnabled;
}
Expand Down Expand Up @@ -6486,6 +6547,16 @@ public String toString() {
+ remoteConfigMaxPayloadSize
+ ", remoteConfigIntegrityCheckEnabled="
+ remoteConfigIntegrityCheckEnabled
+ ", featureFlaggingConfigurationSource="
+ featureFlaggingConfigurationSource
+ ", featureFlaggingConfigurationSourceBaseUrl="
+ featureFlaggingConfigurationSourceBaseUrl
+ ", featureFlaggingConfigurationSourcePollIntervalSeconds="
+ featureFlaggingConfigurationSourcePollIntervalSeconds
+ ", featureFlaggingConfigurationSourceRequestTimeoutSeconds="
+ featureFlaggingConfigurationSourceRequestTimeoutSeconds
+ ", featureFlaggingConfigurationSourceExtraHeaderNames="
+ featureFlaggingConfigurationSourceExtraHeaders.keySet()
+ ", debuggerEnabled="
+ dynamicInstrumentationEnabled
+ ", debuggerUploadTimeout="
Expand Down
48 changes: 48 additions & 0 deletions metadata/supported-configurations.json
Original file line number Diff line number Diff line change
Expand Up @@ -1497,6 +1497,54 @@
"aliases": []
}
],
"DD_FEATURE_FLAGS_CONFIGURATION_SOURCE": [
{
"version": "A",
"type": "string",
"default": "agentless",
"aliases": []
}
],
"DD_FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_BASE_URL": [
{
"version": "A",
"type": "string",
"default": null,
"aliases": []
}
],
"DD_FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_EXTRA_HEADERS": [
{
"version": "A",
"type": "map",
"default": null,
"aliases": []
}
],
"DD_FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_POLL_INTERVAL_SECONDS": [
{
"version": "A",
"type": "decimal",
"default": "30",
"aliases": []
}
],
"DD_FEATURE_FLAGS_CONFIGURATION_SOURCE_AGENTLESS_REQUEST_TIMEOUT_SECONDS": [
{
"version": "A",
"type": "decimal",
"default": "2",
"aliases": []
}
],
"DD_FEATURE_FLAGS_ENABLED": [
{
"version": "A",
"type": "boolean",
"default": "true",
"aliases": ["DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED"]
}
],
"DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED": [
{
"version": "A",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,50 @@ public class FeatureFlaggingSystem {

private static final Logger LOGGER = LoggerFactory.getLogger(FeatureFlaggingSystem.class);

private static volatile RemoteConfigService CONFIG_SERVICE;
private static volatile ConfigurationSourceService CONFIG_SERVICE;
private static volatile ExposureWriter EXPOSURE_WRITER;

private FeatureFlaggingSystem() {}

public static void start(final SharedCommunicationObjects sco) {
LOGGER.debug("Feature Flagging system starting");
final Config config = Config.get();
CONFIG_SERVICE = createConfigurationSourceService(sco, config);

if (!config.isRemoteConfigEnabled()) {
throw new IllegalStateException("Feature Flagging system started without RC");
if (CONFIG_SERVICE != null) {
CONFIG_SERVICE.init();
}
CONFIG_SERVICE = new RemoteConfigServiceImpl(sco, config);
CONFIG_SERVICE.init();

EXPOSURE_WRITER = new ExposureWriterImpl(sco, config);
EXPOSURE_WRITER.init();

LOGGER.debug("Feature Flagging system started");
}

static ConfigurationSourceService createConfigurationSourceService(
final SharedCommunicationObjects sco, final Config config) {
final ConfigurationSource configurationSource =
ConfigurationSource.from(config.getFeatureFlaggingConfigurationSource());

switch (configurationSource) {
case REMOTE_CONFIG:
if (!config.isRemoteConfigEnabled()) {
throw new IllegalStateException("Feature Flagging system started without RC");
}
return new RemoteConfigServiceImpl(sco, config);
case AGENTLESS:
return new UfcHttpConfigService(config);
case OFFLINE:
LOGGER.debug(
"Feature Flagging offline configuration source selected; no config service started");
return null;
default:
throw new IllegalArgumentException(
"Unsupported Feature Flagging configuration source: "
+ config.getFeatureFlaggingConfigurationSource());
}
}

public static void stop() {
if (EXPOSURE_WRITER != null) {
EXPOSURE_WRITER.close();
Expand All @@ -41,4 +64,26 @@ public static void stop() {
}
LOGGER.debug("Feature Flagging system stopped");
}

private enum ConfigurationSource {
AGENTLESS("agentless"),
REMOTE_CONFIG("remote_config"),
OFFLINE("offline");

private final String value;

ConfigurationSource(final String value) {
this.value = value;
}

private static ConfigurationSource from(final String value) {
for (final ConfigurationSource source : values()) {
if (source.value.equals(value)) {
return source;
}
}
throw new IllegalArgumentException(
"Unsupported Feature Flagging configuration source: " + value);
}
}
}
Loading
Loading