From d550f175ed6c92cd8c0c8ac801aeb846eda1c86b Mon Sep 17 00:00:00 2001 From: Matthew Li Date: Tue, 7 Apr 2026 14:55:23 -0400 Subject: [PATCH 1/5] adding logback env var to supported-configurations.json --- metadata/supported-configurations.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/metadata/supported-configurations.json b/metadata/supported-configurations.json index 8f2eec5b73d..92de4676295 100644 --- a/metadata/supported-configurations.json +++ b/metadata/supported-configurations.json @@ -7761,6 +7761,14 @@ "aliases": ["DD_TRACE_INTEGRATION_LOGS_INTAKE_LOG4J_2_ENABLED", "DD_INTEGRATION_LOGS_INTAKE_LOG4J_2_ENABLED"] } ], + "DD_TRACE_LOGS_INTAKE_LOGBACK_ENABLED": [ + { + "version": "A", + "type": "boolean", + "default": "true", + "aliases": ["DD_TRACE_INTEGRATION_LOGS_INTAKE_LOGBACK_ENABLED", "DD_INTEGRATION_LOGS_INTAKE_LOGBACK_ENABLED"] + } + ], "DD_TRACE_MAVEN_ENABLED": [ { "version": "A", From c44baa36b5afd875619b66ba2039aad9f0b4aaeb Mon Sep 17 00:00:00 2001 From: Matthew Li Date: Wed, 8 Apr 2026 12:52:15 -0400 Subject: [PATCH 2/5] adding spring-messaging-kotlin --- metadata/supported-configurations.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/metadata/supported-configurations.json b/metadata/supported-configurations.json index 92de4676295..48e8ea945d9 100644 --- a/metadata/supported-configurations.json +++ b/metadata/supported-configurations.json @@ -10129,6 +10129,14 @@ "aliases": ["DD_TRACE_INTEGRATION_SPRING_MESSAGING_ENABLED", "DD_INTEGRATION_SPRING_MESSAGING_ENABLED"] } ], + "DD_TRACE_SPRING_MESSAGING_KOTLIN_ENABLED": [ + { + "version": "A", + "type": "boolean", + "default": "true", + "aliases": ["DD_TRACE_INTEGRATION_SPRING_MESSAGING_KOTLIN_ENABLED", "DD_INTEGRATION_SPRING_MESSAGING_KOTLIN_ENABLED"] + } + ], "DD_TRACE_SPRING_PATH_FILTER_ENABLED": [ { "version": "A", From f8b124ad2ce8e47db6b923343a6319327ab97abd Mon Sep 17 00:00:00 2001 From: Matthew Li Date: Wed, 8 Apr 2026 14:01:46 -0400 Subject: [PATCH 3/5] adding profiling config --- metadata/supported-configurations.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/metadata/supported-configurations.json b/metadata/supported-configurations.json index 48e8ea945d9..ac7935039e3 100644 --- a/metadata/supported-configurations.json +++ b/metadata/supported-configurations.json @@ -2577,6 +2577,14 @@ "aliases": [] } ], + "DD_PROFILING_ASYNC_LIVEHEAP_TRACK_SIZE_ENABLED": [ + { + "version": "A", + "type": "boolean", + "default": "true", + "aliases": [] + } + ], "DD_PROFILING_ASYNC_LOGLEVEL": [ { "version": "A", From f1e72e58949a1102acac9e788acda56d2dbca591 Mon Sep 17 00:00:00 2001 From: Matthew Li Date: Wed, 8 Apr 2026 16:10:18 -0400 Subject: [PATCH 4/5] updating config inversion linter to include profiling specific handling --- .gitlab-ci.yml | 2 +- .../plugin/config/ConfigInversionLinter.kt | 149 ++++++++++++++---- metadata/supported-configurations.json | 8 + 3 files changed, 127 insertions(+), 32 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 939a9025109..a09e9822afb 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -402,7 +402,7 @@ config-inversion-linter: needs: [] script: - ./gradlew --version - - ./gradlew logEnvVarUsages checkEnvironmentVariablesUsage checkConfigStrings + - ./gradlew logEnvVarUsages checkEnvironmentVariablesUsage checkConfigStrings checkDatadogProfilerConfigs test_published_artifacts: extends: .gradle_build diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/config/ConfigInversionLinter.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/config/ConfigInversionLinter.kt index 74c184a47ae..85dd8c46d15 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/config/ConfigInversionLinter.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/config/ConfigInversionLinter.kt @@ -1,11 +1,12 @@ package datadog.gradle.plugin.config -import com.github.javaparser.ParserConfiguration import com.github.javaparser.StaticJavaParser -import com.github.javaparser.ast.CompilationUnit import com.github.javaparser.ast.Modifier import com.github.javaparser.ast.body.FieldDeclaration import com.github.javaparser.ast.body.VariableDeclarator +import com.github.javaparser.ast.expr.Expression +import com.github.javaparser.ast.expr.MethodCallExpr +import com.github.javaparser.ast.expr.NameExpr import com.github.javaparser.ast.expr.StringLiteralExpr import com.github.javaparser.ast.nodeTypes.NodeWithModifiers import org.gradle.api.GradleException @@ -14,6 +15,7 @@ import org.gradle.api.Project import org.gradle.api.tasks.SourceSet import org.gradle.api.tasks.SourceSetContainer import org.gradle.kotlin.dsl.getByType +import java.io.File import java.net.URLClassLoader import java.nio.file.Path @@ -23,6 +25,7 @@ class ConfigInversionLinter : Plugin { registerLogEnvVarUsages(target, extension) registerCheckEnvironmentVariablesUsage(target) registerCheckConfigStringsTask(target, extension) + registerCheckDatadogProfilerConfigTask(target, extension) } } @@ -202,38 +205,16 @@ private fun registerCheckConfigStringsTask(project: Project, extension: Supporte val supported = configFields.supported val aliasMapping = configFields.aliasMapping - var parserConfig = ParserConfiguration() - parserConfig.setLanguageLevel(ParserConfiguration.LanguageLevel.JAVA_8) - - StaticJavaParser.setConfiguration(parserConfig) - val violations = buildList { configDir.listFiles()?.forEach { file -> val fileName = file.name - val cu: CompilationUnit = StaticJavaParser.parse(file) - - cu.findAll(VariableDeclarator::class.java).forEach { varDecl -> - varDecl.parentNode - .map { it as? FieldDeclaration } - .ifPresent { field -> - if (field.hasModifiers(Modifier.Keyword.PUBLIC, Modifier.Keyword.STATIC, Modifier.Keyword.FINAL) && - varDecl.typeAsString == "String") { - - val fieldName = varDecl.nameAsString - if (fieldName.endsWith("_DEFAULT")) return@ifPresent - val init = varDecl.initializer.orElse(null) ?: return@ifPresent - - if (init !is StringLiteralExpr) return@ifPresent - val rawValue = init.value - - val normalized = normalize(rawValue) - if (normalized !in supported && normalized !in aliasMapping) { - val line = varDecl.range.map { it.begin.line }.orElse(1) - add("$fileName:$line -> Config '$rawValue' normalizes to '$normalized' " + - "which is missing from '${extension.jsonFile.get()}'") - } - } - } + extractStringConstants(file).forEach { (fieldName, entry) -> + if (fieldName.endsWith("_DEFAULT")) return@forEach + val normalized = normalize(entry.value) + if (normalized !in supported && normalized !in aliasMapping) { + add("$fileName:${entry.line} -> Config '${entry.value}' normalizes to '$normalized' " + + "which is missing from '${extension.jsonFile.get()}'") + } } } } @@ -248,3 +229,109 @@ private fun registerCheckConfigStringsTask(project: Project, extension: Supporte } } } + +/** + * Registers `checkDatadogProfilerConfigs` to validate that every `.ddprof.` config key used as a + * primary key in `DatadogProfilerConfig`'s static helpers also has its async-translated form + * (`profiling.ddprof.*` → `profiling.async.*`) documented in `supported-configurations.json`. + * + * The raw form is already validated by `checkConfigStrings`. This task only covers the additional + * async form produced by `DatadogProfilerConfig.normalizeKey`. + */ +private fun registerCheckDatadogProfilerConfigTask(project: Project, extension: SupportedTracerConfigurations) { + val ownerPath = extension.configOwnerPath + val generatedFile = extension.className + + project.tasks.register("checkDatadogProfilerConfigs") { + group = "verification" + description = "Validates all configs read in DatadogProfilerConfig are documented in supported-configurations.json" + + val mainSourceSetOutput = ownerPath.map { + project.project(it) + .extensions.getByType() + .named(SourceSet.MAIN_SOURCE_SET_NAME) + .map { main -> main.output } + } + inputs.files(mainSourceSetOutput) + + doLast { + val repoRoot = project.rootProject.projectDir.toPath() + + // Only ProfilingConfig.java is needed — all .ddprof. keys are defined there + val constantMap = extractStringConstants( + repoRoot.resolve("dd-trace-api/src/main/java/datadog/trace/api/config/ProfilingConfig.java").toFile() + ) + + val configFields = loadConfigFields(mainSourceSetOutput.get().get(), generatedFile.get()) + val supported = configFields.supported + val aliasMapping = configFields.aliasMapping + + val ddprofConfigFile = repoRoot.resolve( + "dd-java-agent/agent-profiling/profiling-ddprof/src/main/java/com/datadog/profiling/ddprof/DatadogProfilerConfig.java" + ).toFile() + val cu = StaticJavaParser.parse(ddprofConfigFile) + + val helperMethodNames = setOf("getBoolean", "getInteger", "getLong", "getString") + val violations = mutableListOf() + + cu.findAll(MethodCallExpr::class.java).forEach { call -> + // Only care about static helper calls: getXxx(configProvider, primaryKey, default, ...aliases) + // Direct configProvider.getXxx() calls are already covered by checkConfigStrings + if (call.scope.isPresent) return@forEach + if (call.nameAsString !in helperMethodNames) return@forEach + val args = call.arguments + if (args.size < 2 || args[0] !is NameExpr || (args[0] as NameExpr).nameAsString != "configProvider") return@forEach + + // Primary key goes through normalizeKey — validate its async-translated form + val primaryKeyEntry = resolveConstant(args[1], constantMap) ?: return@forEach + checkDocumented(primaryKeyEntry, supported, aliasMapping, call, violations, extension) + } + + if (violations.isNotEmpty()) { + violations.forEach { logger.error(it) } + throw GradleException("Undocumented configs found in DatadogProfilerConfig. Please add the above to '${extension.jsonFile.get()}'.") + } else { + logger.info("All DatadogProfilerConfig configs are documented.") + } + } + } +} + +private data class ConstantEntry(val value: String, val line: Int) + +private fun extractStringConstants(file: File): Map { + val map = mutableMapOf() + StaticJavaParser.parse(file).findAll(VariableDeclarator::class.java).forEach { varDecl -> + val field = varDecl.parentNode.map { it as? FieldDeclaration }.orElse(null) ?: return@forEach + if (field.hasModifiers(Modifier.Keyword.PUBLIC, Modifier.Keyword.STATIC, Modifier.Keyword.FINAL) + && varDecl.typeAsString == "String") { + val init = varDecl.initializer.orElse(null) as? StringLiteralExpr ?: return@forEach + val line = varDecl.range.map { it.begin.line }.orElse(-1) + map[varDecl.nameAsString] = ConstantEntry(init.value, line) + } + } + return map +} + +private fun resolveConstant(expr: Expression?, constantMap: Map): ConstantEntry? = when (expr) { + is StringLiteralExpr -> ConstantEntry(expr.value, -1) + is NameExpr -> constantMap[expr.nameAsString] + else -> null +} + +// Only check the async-translated form produced by DatadogProfilerConfig.normalizeKey. +private fun checkDocumented( + entry: ConstantEntry, + supported: Set, + aliasMapping: Map, + call: MethodCallExpr, + violations: MutableList, + extension: SupportedTracerConfigurations +) { + if (!entry.value.contains(".ddprof.")) return + val asyncNormalized = normalize(entry.value.replace(".ddprof.", ".async.")) + if (asyncNormalized !in supported && asyncNormalized !in aliasMapping) { + val callLine = call.range.map { it.begin.line }.orElse(-1) + violations.add("ProfilingConfig.java:${entry.line} (DatadogProfilerConfig.java:$callLine) -> '${entry.value}' (async form) → '$asyncNormalized' is missing from '${extension.jsonFile.get()}'") + } +} diff --git a/metadata/supported-configurations.json b/metadata/supported-configurations.json index 8f2eec5b73d..536e71ad4b0 100644 --- a/metadata/supported-configurations.json +++ b/metadata/supported-configurations.json @@ -2577,6 +2577,14 @@ "aliases": [] } ], + "DD_PROFILING_ASYNC_LIVEHEAP_TRACK_SIZE_ENABLED": [ + { + "version": "A", + "type": "boolean", + "default": "true", + "aliases": [] + } + ], "DD_PROFILING_ASYNC_LOGLEVEL": [ { "version": "A", From cca00b9df3d98031e4c21735555dd3447ea4e655 Mon Sep 17 00:00:00 2001 From: Matthew Li Date: Wed, 8 Apr 2026 16:13:51 -0400 Subject: [PATCH 5/5] removing config --- metadata/supported-configurations.json | 8 -------- 1 file changed, 8 deletions(-) diff --git a/metadata/supported-configurations.json b/metadata/supported-configurations.json index 536e71ad4b0..8f2eec5b73d 100644 --- a/metadata/supported-configurations.json +++ b/metadata/supported-configurations.json @@ -2577,14 +2577,6 @@ "aliases": [] } ], - "DD_PROFILING_ASYNC_LIVEHEAP_TRACK_SIZE_ENABLED": [ - { - "version": "A", - "type": "boolean", - "default": "true", - "aliases": [] - } - ], "DD_PROFILING_ASYNC_LOGLEVEL": [ { "version": "A",