diff --git a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Agent.java b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Agent.java index b2a4b3b65ad..40aa0cd2b0d 100644 --- a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Agent.java +++ b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Agent.java @@ -32,6 +32,7 @@ import datadog.trace.api.config.UsmConfig; import datadog.trace.api.gateway.RequestContextSlot; import datadog.trace.api.gateway.SubscriptionService; +import datadog.trace.api.profiling.ProfilingEnablement; import datadog.trace.api.scopemanager.ScopeListener; import datadog.trace.bootstrap.benchmark.StaticEventLogger; import datadog.trace.bootstrap.instrumentation.api.AgentTracer; @@ -1124,6 +1125,11 @@ private static boolean isFeatureEnabled(AgentFeature feature) { // true unless it's explicitly set to "false" return !("false".equalsIgnoreCase(featureEnabled) || "0".equals(featureEnabled)); } else { + if (feature == AgentFeature.PROFILING) { + // We need this hack because profiling in SSI can receive 'auto' value in + // the enablement config + return ProfilingEnablement.of(featureEnabled).isActive(); + } // false unless it's explicitly set to "true" return Boolean.parseBoolean(featureEnabled) || "1".equals(featureEnabled); } 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 41c3fb5d51a..f128c9febe6 100644 --- a/internal-api/src/main/java/datadog/trace/api/Config.java +++ b/internal-api/src/main/java/datadog/trace/api/Config.java @@ -495,6 +495,7 @@ import datadog.trace.api.iast.IastDetectionMode; import datadog.trace.api.iast.telemetry.Verbosity; import datadog.trace.api.naming.SpanNaming; +import datadog.trace.api.profiling.ProfilingEnablement; import datadog.trace.bootstrap.config.provider.CapturedEnvironmentConfigSource; import datadog.trace.bootstrap.config.provider.ConfigProvider; import datadog.trace.bootstrap.config.provider.SystemPropertiesConfigSource; @@ -709,7 +710,7 @@ static class HostNameHolder { private final String spanSamplingRules; private final String spanSamplingRulesFile; - private final boolean profilingEnabled; + private final ProfilingEnablement profilingEnabled; private final boolean profilingAgentless; private final boolean isDatadogProfilerEnabled; @Deprecated private final String profilingUrl; @@ -1504,9 +1505,12 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins // on whether // the profiler was enabled at build time or not. // Otherwise just do the standard config lookup by key. + // An extra step is needed to properly handle the 'auto' value for profiling enablement via SSI. profilingEnabled = - configProvider.getBoolean( - ProfilingConfig.PROFILING_ENABLED, instrumenterConfig.isProfilingEnabled()); + ProfilingEnablement.of( + configProvider.getString( + ProfilingConfig.PROFILING_ENABLED, + String.valueOf(instrumenterConfig.isProfilingEnabled()))); profilingAgentless = configProvider.getBoolean(PROFILING_AGENTLESS, PROFILING_AGENTLESS_DEFAULT); isDatadogProfilerEnabled = @@ -1548,10 +1552,27 @@ PROFILING_DATADOG_PROFILER_ENABLED, isDatadogProfilerSafeInCurrentEnvironment()) } profilingTags = configProvider.getMergedMap(PROFILING_TAGS); - profilingStartDelay = + int profilingStartDelayValue = configProvider.getInteger(PROFILING_START_DELAY, PROFILING_START_DELAY_DEFAULT); - profilingStartForceFirst = + boolean profilingStartForceFirstValue = configProvider.getBoolean(PROFILING_START_FORCE_FIRST, PROFILING_START_FORCE_FIRST_DEFAULT); + if (profilingEnabled == ProfilingEnablement.AUTO) { + if (profilingStartDelayValue != PROFILING_START_DELAY_DEFAULT) { + log.info( + "Profiling start delay is set to {}s, but profiling enablement is set to auto. Using the default delay of {}s.", + profilingStartDelayValue, + PROFILING_START_DELAY_DEFAULT); + } + if (profilingStartForceFirstValue != PROFILING_START_FORCE_FIRST_DEFAULT) { + log.info( + "Profiling is requested to start immediately, but profiling enablement is set to auto. Profiling will be started with delay of {}s.", + PROFILING_START_DELAY_DEFAULT); + } + profilingStartDelayValue = PROFILING_START_DELAY_DEFAULT; + profilingStartForceFirstValue = PROFILING_START_FORCE_FIRST_DEFAULT; + } + profilingStartDelay = profilingStartDelayValue; + profilingStartForceFirst = profilingStartForceFirstValue; profilingUploadPeriod = configProvider.getInteger(PROFILING_UPLOAD_PERIOD, PROFILING_UPLOAD_PERIOD_DEFAULT); profilingTemplateOverrideFile = configProvider.getString(PROFILING_TEMPLATE_OVERRIDE_FILE); @@ -2664,14 +2685,14 @@ public String getSpanSamplingRulesFile() { public boolean isProfilingEnabled() { if (Platform.isNativeImage()) { - if (!instrumenterConfig.isProfilingEnabled() && profilingEnabled) { + if (!instrumenterConfig.isProfilingEnabled() && profilingEnabled.isActive()) { log.warn( "Profiling was not enabled during the native image build. " + "Please set DD_PROFILING_ENABLED=true in your native image build configuration if you want" + "to use profiling."); } } - return profilingEnabled && instrumenterConfig.isProfilingEnabled(); + return profilingEnabled.isActive() && instrumenterConfig.isProfilingEnabled(); } public boolean isProfilingTimelineEventsEnabled() { @@ -2759,7 +2780,7 @@ public boolean isProfilingRecordExceptionMessage() { } public boolean isDatadogProfilerEnabled() { - return profilingEnabled && isDatadogProfilerEnabled; + return isProfilingEnabled() && isDatadogProfilerEnabled; } public static boolean isDatadogProfilerEnablementOverridden() { diff --git a/internal-api/src/main/java/datadog/trace/api/InstrumenterConfig.java b/internal-api/src/main/java/datadog/trace/api/InstrumenterConfig.java index b92f6f93f63..5e915335899 100644 --- a/internal-api/src/main/java/datadog/trace/api/InstrumenterConfig.java +++ b/internal-api/src/main/java/datadog/trace/api/InstrumenterConfig.java @@ -68,6 +68,7 @@ import static datadog.trace.util.CollectionUtils.tryMakeImmutableList; import static datadog.trace.util.CollectionUtils.tryMakeImmutableSet; +import datadog.trace.api.profiling.ProfilingEnablement; import datadog.trace.bootstrap.config.provider.ConfigProvider; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.lang.reflect.Method; @@ -103,7 +104,7 @@ public class InstrumenterConfig { private final boolean traceEnabled; private final boolean traceOtelEnabled; private final boolean logs128bTraceIdEnabled; - private final boolean profilingEnabled; + private final ProfilingEnablement profilingEnabled; private final boolean ciVisibilityEnabled; private final ProductActivation appSecActivation; private final ProductActivation iastActivation; @@ -178,7 +179,9 @@ private InstrumenterConfig() { logs128bTraceIdEnabled = configProvider.getBoolean( TRACE_128_BIT_TRACEID_LOGGING_ENABLED, DEFAULT_TRACE_128_BIT_TRACEID_LOGGING_ENABLED); - profilingEnabled = configProvider.getBoolean(PROFILING_ENABLED, PROFILING_ENABLED_DEFAULT); + profilingEnabled = + ProfilingEnablement.of( + configProvider.getString(PROFILING_ENABLED, String.valueOf(PROFILING_ENABLED_DEFAULT))); if (!Platform.isNativeImageBuilder()) { ciVisibilityEnabled = @@ -301,7 +304,7 @@ public boolean isLogs128bTraceIdEnabled() { } public boolean isProfilingEnabled() { - return profilingEnabled; + return profilingEnabled.isActive(); } public boolean isCiVisibilityEnabled() { diff --git a/internal-api/src/main/java/datadog/trace/api/profiling/ProfilingEnablement.java b/internal-api/src/main/java/datadog/trace/api/profiling/ProfilingEnablement.java new file mode 100644 index 00000000000..418882760a3 --- /dev/null +++ b/internal-api/src/main/java/datadog/trace/api/profiling/ProfilingEnablement.java @@ -0,0 +1,32 @@ +package datadog.trace.api.profiling; + +public enum ProfilingEnablement { + ENABLED(true), + DISABLED(false), + AUTO(true); + + private final boolean active; + + ProfilingEnablement(boolean active) { + this.active = active; + } + + public boolean isActive() { + return active; + } + + public static ProfilingEnablement of(String value) { + if (value == null) { + return DISABLED; + } + switch (value.toLowerCase()) { + case "true": + case "1": + return ENABLED; + case "auto": + return AUTO; + default: + return DISABLED; + } + } +} diff --git a/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy b/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy index 232352b40cb..984ef7cf13f 100644 --- a/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy +++ b/internal-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy @@ -75,7 +75,9 @@ import static datadog.trace.api.config.ProfilingConfig.PROFILING_PROXY_PASSWORD import static datadog.trace.api.config.ProfilingConfig.PROFILING_PROXY_PORT import static datadog.trace.api.config.ProfilingConfig.PROFILING_PROXY_USERNAME import static datadog.trace.api.config.ProfilingConfig.PROFILING_START_DELAY +import static datadog.trace.api.config.ProfilingConfig.PROFILING_START_DELAY_DEFAULT import static datadog.trace.api.config.ProfilingConfig.PROFILING_START_FORCE_FIRST +import static datadog.trace.api.config.ProfilingConfig.PROFILING_START_FORCE_FIRST_DEFAULT import static datadog.trace.api.config.ProfilingConfig.PROFILING_TAGS import static datadog.trace.api.config.ProfilingConfig.PROFILING_TEMPLATE_OVERRIDE_FILE import static datadog.trace.api.config.ProfilingConfig.PROFILING_UPLOAD_COMPRESSION @@ -2440,4 +2442,27 @@ class ConfigTest extends DDSpecification { true | 11 | 11 false | 17 | 0 } + + def "check profiling SSI auto-enablement"() { + when: + def prop = new Properties() + prop.setProperty(PROFILING_ENABLED, enablementMode) + prop.setProperty(PROFILING_START_DELAY, "1") + prop.setProperty(PROFILING_START_FORCE_FIRST, "true") + + Config config = Config.get(prop) + + then: + config.profilingEnabled == expectedEnabled + config.profilingStartDelay == expectedStartDelay + config.profilingStartForceFirst == expectedStartForceFirst + + where: + // spotless:off + enablementMode | expectedEnabled | expectedStartDelay | expectedStartForceFirst + "true" | true | 1 | true + "false" | false | 1 | true + "auto" | true | PROFILING_START_DELAY_DEFAULT | PROFILING_START_FORCE_FIRST_DEFAULT + // spotless:on + } } diff --git a/internal-api/src/test/java/datadog/trace/api/profiling/ProfilingEnablementTest.java b/internal-api/src/test/java/datadog/trace/api/profiling/ProfilingEnablementTest.java new file mode 100644 index 00000000000..ef18e0ab455 --- /dev/null +++ b/internal-api/src/test/java/datadog/trace/api/profiling/ProfilingEnablementTest.java @@ -0,0 +1,34 @@ +package datadog.trace.api.profiling; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.stream.Stream; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class ProfilingEnablementTest { + + @ParameterizedTest + @MethodSource("provideValues") + void of(String value, ProfilingEnablement expected) { + assertEquals(expected, ProfilingEnablement.of(value)); + } + + private static Stream provideValues() { + return Stream.of( + Arguments.of("true", ProfilingEnablement.ENABLED), + Arguments.of("TRUE", ProfilingEnablement.ENABLED), + Arguments.of("tRuE", ProfilingEnablement.ENABLED), + Arguments.of("1", ProfilingEnablement.ENABLED), + Arguments.of("auto", ProfilingEnablement.AUTO), + Arguments.of("AUTO", ProfilingEnablement.AUTO), + Arguments.of("aUtO", ProfilingEnablement.AUTO), + Arguments.of("false", ProfilingEnablement.DISABLED), + Arguments.of("FALSE", ProfilingEnablement.DISABLED), + Arguments.of("fAlSe", ProfilingEnablement.DISABLED), + Arguments.of("0", ProfilingEnablement.DISABLED), + Arguments.of("anything", ProfilingEnablement.DISABLED), + Arguments.of(null, ProfilingEnablement.DISABLED)); + } +}