From d8d7991703d724ca5a1e59fcf0f2eb6a767a07d0 Mon Sep 17 00:00:00 2001 From: Richard Startin Date: Mon, 30 Oct 2023 15:13:13 +0000 Subject: [PATCH] add inert lightweight mode option for profiling --- .../java/datadog/trace/bootstrap/Agent.java | 9 ++---- .../trace/agent/tooling/AgentInstaller.java | 2 +- .../profiling/agent/ProfilingAgent.java | 3 +- .../trace/api/config/ProfilingConfig.java | 2 +- .../java/datadog/trace/core/StatusLogger.java | 2 +- .../datadog/trace/core/util/SystemAccess.java | 4 ++- .../trace/core/CoreSpanBuilderTest.groovy | 8 +++-- .../main/java/datadog/trace/api/Config.java | 8 +++-- .../datadog/trace/api/InstrumenterConfig.java | 16 +++++----- .../datadog/trace/api/ProductActivation.java | 29 +++++++++++++++++-- 10 files changed, 56 insertions(+), 27 deletions(-) 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 a2343f12474..0156df597ec 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 @@ -14,11 +14,7 @@ import static datadog.trace.util.Strings.propertyNameToSystemPropertyName; import static datadog.trace.util.Strings.toEnvVar; -import datadog.trace.api.Config; -import datadog.trace.api.EndpointCheckpointer; -import datadog.trace.api.Platform; -import datadog.trace.api.StatsDClientManager; -import datadog.trace.api.WithGlobalTracer; +import datadog.trace.api.*; import datadog.trace.api.config.AppSecConfig; import datadog.trace.api.config.CiVisibilityConfig; import datadog.trace.api.config.CwsConfig; @@ -853,7 +849,8 @@ public void withTracer(TracerAPI tracer) { * on JFR. */ private static ProfilingContextIntegration createProfilingContextIntegration() { - if (Config.get().isProfilingEnabled() && !Platform.isWindows()) { + if (Config.get().getProfilingActivation().atLeast(ProductActivation.ENABLED_LIGHTWEIGHT) + && !Platform.isWindows()) { try { return (ProfilingContextIntegration) AGENT_CLASSLOADER diff --git a/dd-java-agent/agent-builder/src/main/java/datadog/trace/agent/tooling/AgentInstaller.java b/dd-java-agent/agent-builder/src/main/java/datadog/trace/agent/tooling/AgentInstaller.java index fe4673541e3..63249d682e2 100644 --- a/dd-java-agent/agent-builder/src/main/java/datadog/trace/agent/tooling/AgentInstaller.java +++ b/dd-java-agent/agent-builder/src/main/java/datadog/trace/agent/tooling/AgentInstaller.java @@ -223,7 +223,7 @@ public static Set getEnabledSystems() { if (cfg.isTraceEnabled()) { enabledSystems.add(Instrumenter.TargetSystem.TRACING); } - if (cfg.isProfilingEnabled()) { + if (cfg.getProfilingActivation().atLeast(ProductActivation.ENABLED_INACTIVE)) { enabledSystems.add(Instrumenter.TargetSystem.PROFILING); } if (cfg.getAppSecActivation() != ProductActivation.FULLY_DISABLED) { diff --git a/dd-java-agent/agent-profiling/src/main/java/com/datadog/profiling/agent/ProfilingAgent.java b/dd-java-agent/agent-profiling/src/main/java/com/datadog/profiling/agent/ProfilingAgent.java index 3a0832f5c8e..454af21f775 100644 --- a/dd-java-agent/agent-profiling/src/main/java/com/datadog/profiling/agent/ProfilingAgent.java +++ b/dd-java-agent/agent-profiling/src/main/java/com/datadog/profiling/agent/ProfilingAgent.java @@ -15,6 +15,7 @@ import com.datadog.profiling.uploader.ProfileUploader; import datadog.trace.api.Config; import datadog.trace.api.Platform; +import datadog.trace.api.ProductActivation; import datadog.trace.api.config.ProfilingConfig; import datadog.trace.bootstrap.config.provider.ConfigProvider; import java.io.IOException; @@ -102,7 +103,7 @@ public static synchronized void run(final boolean isStartingFirst, ClassLoader a // early startup is disabled; return; } - if (!config.isProfilingEnabled()) { + if (!config.getProfilingActivation().atLeast(ProductActivation.ENABLED_LIGHTWEIGHT)) { log.debug("Profiling: disabled"); return; } diff --git a/dd-trace-api/src/main/java/datadog/trace/api/config/ProfilingConfig.java b/dd-trace-api/src/main/java/datadog/trace/api/config/ProfilingConfig.java index 0f166d804f1..8c8120ea4f2 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/config/ProfilingConfig.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/config/ProfilingConfig.java @@ -8,7 +8,7 @@ */ public final class ProfilingConfig { public static final String PROFILING_ENABLED = "profiling.enabled"; - public static final boolean PROFILING_ENABLED_DEFAULT = false; + public static final String PROFILING_ENABLED_DEFAULT = "false"; public static final String PROFILING_ALLOCATION_ENABLED = "profiling.allocation.enabled"; public static final String PROFILING_HEAP_ENABLED = "profiling.heap.enabled"; public static final boolean PROFILING_HEAP_ENABLED_DEFAULT = false; diff --git a/dd-trace-core/src/main/java/datadog/trace/core/StatusLogger.java b/dd-trace-core/src/main/java/datadog/trace/core/StatusLogger.java index 4f822f43e44..79bfaa18e78 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/StatusLogger.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/StatusLogger.java @@ -111,7 +111,7 @@ public void toJson(JsonWriter writer, Config config) throws IOException { writer.name("logs_correlation_enabled"); writer.value(config.isLogsInjectionEnabled()); writer.name("profiling_enabled"); - writer.value(config.isProfilingEnabled()); + writer.value(config.getProfilingActivation().toString()); writer.name("remote_config_enabled"); writer.value(config.isRemoteConfigEnabled()); writer.name("debugger_enabled"); diff --git a/dd-trace-core/src/main/java/datadog/trace/core/util/SystemAccess.java b/dd-trace-core/src/main/java/datadog/trace/core/util/SystemAccess.java index da82cf71625..8b7d81d8854 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/util/SystemAccess.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/util/SystemAccess.java @@ -1,6 +1,7 @@ package datadog.trace.core.util; import datadog.trace.api.Config; +import datadog.trace.api.ProductActivation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -19,7 +20,8 @@ public static void disableJmx() { /** Enable JMX accesses */ public static void enableJmx() { - if (!Config.get().isProfilingEnabled() && !Config.get().isHealthMetricsEnabled()) { + if (Config.get().getProfilingActivation() != ProductActivation.FULLY_ENABLED + && !Config.get().isHealthMetricsEnabled()) { log.debug("Will not enable JMX access. Profiling and metrics are both disabled."); return; } diff --git a/dd-trace-core/src/test/groovy/datadog/trace/core/CoreSpanBuilderTest.groovy b/dd-trace-core/src/test/groovy/datadog/trace/core/CoreSpanBuilderTest.groovy index 735b6d313cc..a99040e250d 100644 --- a/dd-trace-core/src/test/groovy/datadog/trace/core/CoreSpanBuilderTest.groovy +++ b/dd-trace-core/src/test/groovy/datadog/trace/core/CoreSpanBuilderTest.groovy @@ -1,5 +1,7 @@ package datadog.trace.core +import datadog.trace.api.ProductActivation + import static datadog.trace.api.DDTags.PROFILING_ENABLED import static datadog.trace.api.DDTags.SCHEMA_VERSION_TAG_KEY @@ -79,7 +81,7 @@ class CoreSpanBuilderTest extends DDCoreSpecification { (LANGUAGE_TAG_KEY): LANGUAGE_TAG_VALUE, (PID_TAG) : Config.get().getProcessId(), (SCHEMA_VERSION_TAG_KEY) : SpanNaming.instance().version(), - (PROFILING_ENABLED) : Config.get().isProfilingEnabled() ? 1 : 0 + (PROFILING_ENABLED) : Config.get().getProfilingActivation().atLeast(ProductActivation.FULLY_ENABLED) ? 1 : 0 ] when: @@ -356,7 +358,7 @@ class CoreSpanBuilderTest extends DDCoreSpecification { (LANGUAGE_TAG_KEY) : LANGUAGE_TAG_VALUE, (THREAD_NAME) : thread.name, (THREAD_ID): thread.id, (PID_TAG): Config.get().getProcessId(), (SCHEMA_VERSION_TAG_KEY): SpanNaming.instance().version(), - (PROFILING_ENABLED) : Config.get().isProfilingEnabled() ? 1 : 0 + (PROFILING_ENABLED) : Config.get().getProfilingActivation().atLeast(ProductActivation.FULLY_ENABLED) ? 1 : 0 ] where: @@ -379,7 +381,7 @@ class CoreSpanBuilderTest extends DDCoreSpecification { (LANGUAGE_TAG_KEY) : LANGUAGE_TAG_VALUE, (PID_TAG) : Config.get().getProcessId(), (SCHEMA_VERSION_TAG_KEY): SpanNaming.instance().version(), - (PROFILING_ENABLED) : Config.get().isProfilingEnabled() ? 1 : 0 + (PROFILING_ENABLED) : Config.get().getProfilingActivation().atLeast(ProductActivation.FULLY_ENABLED) ? 1 : 0 ] cleanup: 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 901628614b7..4ddc1d025f8 100644 --- a/internal-api/src/main/java/datadog/trace/api/Config.java +++ b/internal-api/src/main/java/datadog/trace/api/Config.java @@ -2285,8 +2285,8 @@ public String getSpanSamplingRulesFile() { return spanSamplingRulesFile; } - public boolean isProfilingEnabled() { - return instrumenterConfig.isProfilingEnabled(); + public ProductActivation getProfilingActivation() { + return instrumenterConfig.getProfilingActivation(); } public boolean isProfilingAgentless() { @@ -3005,7 +3005,9 @@ public Map getLocalRootSpanTags() { result.putAll(runtimeTags); result.put(LANGUAGE_TAG_KEY, LANGUAGE_TAG_VALUE); result.put(SCHEMA_VERSION_TAG_KEY, SpanNaming.instance().version()); - result.put(PROFILING_ENABLED, isProfilingEnabled() ? 1 : 0); + result.put( + PROFILING_ENABLED, + getProfilingActivation().atLeast(ProductActivation.FULLY_ENABLED) ? 1 : 0); if (reportHostName) { final String hostName = getHostName(); 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 56838ad3067..61dfd4ca725 100644 --- a/internal-api/src/main/java/datadog/trace/api/InstrumenterConfig.java +++ b/internal-api/src/main/java/datadog/trace/api/InstrumenterConfig.java @@ -88,7 +88,7 @@ public class InstrumenterConfig { private final boolean traceEnabled; private final boolean traceOtelEnabled; private final boolean logs128bTraceIdEnabled; - private final boolean profilingEnabled; + private final ProductActivation profilingActivation; private final boolean ciVisibilityEnabled; private final ProductActivation appSecActivation; private final ProductActivation iastActivation; @@ -147,7 +147,9 @@ private InstrumenterConfig() { TRACE_128_BIT_TRACEID_LOGGING_ENABLED, DEFAULT_TRACE_128_BIT_TRACEID_LOGGING_ENABLED); if (!Platform.isNativeImageBuilder()) { - profilingEnabled = configProvider.getBoolean(PROFILING_ENABLED, PROFILING_ENABLED_DEFAULT); + profilingActivation = + ProductActivation.fromString( + configProvider.getString(PROFILING_ENABLED, PROFILING_ENABLED_DEFAULT)); ciVisibilityEnabled = configProvider.getBoolean(CIVISIBILITY_ENABLED, DEFAULT_CIVISIBILITY_ENABLED); appSecActivation = @@ -160,7 +162,7 @@ private InstrumenterConfig() { telemetryEnabled = configProvider.getBoolean(TELEMETRY_ENABLED, DEFAULT_TELEMETRY_ENABLED); } else { // disable these features in native-image - profilingEnabled = false; + profilingActivation = ProductActivation.FULLY_DISABLED; ciVisibilityEnabled = false; appSecActivation = ProductActivation.FULLY_DISABLED; iastActivation = ProductActivation.FULLY_DISABLED; @@ -248,8 +250,8 @@ public boolean isLogs128bTraceIdEnabled() { return logs128bTraceIdEnabled; } - public boolean isProfilingEnabled() { - return profilingEnabled; + public ProductActivation getProfilingActivation() { + return profilingActivation; } public boolean isCiVisibilityEnabled() { @@ -431,8 +433,8 @@ public String toString() { + traceOtelEnabled + ", logs128bTraceIdEnabled=" + logs128bTraceIdEnabled - + ", profilingEnabled=" - + profilingEnabled + + ", profilingActivation=" + + profilingActivation + ", ciVisibilityEnabled=" + ciVisibilityEnabled + ", appSecActivation=" diff --git a/internal-api/src/main/java/datadog/trace/api/ProductActivation.java b/internal-api/src/main/java/datadog/trace/api/ProductActivation.java index 834afb815cc..616ce8cc0bc 100644 --- a/internal-api/src/main/java/datadog/trace/api/ProductActivation.java +++ b/internal-api/src/main/java/datadog/trace/api/ProductActivation.java @@ -5,17 +5,37 @@ public enum ProductActivation { * The product is initialized, its instrumentation is applied and the logic in the instrumentation * advice is applied. It cannot be disabled at runtime. */ - FULLY_ENABLED, + FULLY_ENABLED(2), /** * Completely disabled. The product is not initialized in any way. It cannot be enabled at * runtime. */ - FULLY_DISABLED, + FULLY_DISABLED(-1), /** * The product is initialized, its instrumentation applied, but its logic is disabled to the * greatest extent possible. It can be enabled and disabled at runtime through remote config. */ - ENABLED_INACTIVE; + ENABLED_INACTIVE(0), + + /** + * The product is enabled but in a product-defined lightweight mode, some features are disabled. + */ + ENABLED_LIGHTWEIGHT(1); + + private final int level; + + ProductActivation(int level) { + this.level = level; + } + + /** + * Product activations are expected to be ordered, so that each level is enables and does not + * disable features available at the previous level. This allows asserting a minimum level of + * activation. + */ + public boolean atLeast(ProductActivation productActivation) { + return level >= productActivation.level; + } public static ProductActivation fromString(String s) { if ("true".equalsIgnoreCase(s) || "1".equals(s)) { @@ -24,6 +44,9 @@ public static ProductActivation fromString(String s) { if ("inactive".equalsIgnoreCase(s)) { return ENABLED_INACTIVE; } + if ("lightweight".equalsIgnoreCase(s)) { + return ENABLED_LIGHTWEIGHT; + } return FULLY_DISABLED; } }