diff --git a/internal-api/src/main/java/datadog/trace/api/ConfigCollector.java b/internal-api/src/main/java/datadog/trace/api/ConfigCollector.java index f4cfda6877b..6e4ebc0969c 100644 --- a/internal-api/src/main/java/datadog/trace/api/ConfigCollector.java +++ b/internal-api/src/main/java/datadog/trace/api/ConfigCollector.java @@ -27,6 +27,11 @@ public void put(String key, Object value, ConfigOrigin origin) { collected.put(key, setting); } + public void put(String key, Object value, ConfigOrigin origin, String configId) { + ConfigSetting setting = ConfigSetting.of(key, value, origin, configId); + collected.put(key, setting); + } + public void putAll(Map keysAndValues, ConfigOrigin origin) { // attempt merge+replace to avoid collector seeing partial update Map merged = diff --git a/internal-api/src/main/java/datadog/trace/api/ConfigSetting.java b/internal-api/src/main/java/datadog/trace/api/ConfigSetting.java index b688d5b477d..9b94b444a02 100644 --- a/internal-api/src/main/java/datadog/trace/api/ConfigSetting.java +++ b/internal-api/src/main/java/datadog/trace/api/ConfigSetting.java @@ -11,19 +11,26 @@ public final class ConfigSetting { public final String key; public final Object value; public final ConfigOrigin origin; + /** The config ID associated with this setting, or {@code null} if not applicable. */ + public final String configId; private static final Set CONFIG_FILTER_LIST = new HashSet<>( Arrays.asList("DD_API_KEY", "dd.api-key", "dd.profiling.api-key", "dd.profiling.apikey")); public static ConfigSetting of(String key, Object value, ConfigOrigin origin) { - return new ConfigSetting(key, value, origin); + return new ConfigSetting(key, value, origin, null); } - private ConfigSetting(String key, Object value, ConfigOrigin origin) { + public static ConfigSetting of(String key, Object value, ConfigOrigin origin, String configId) { + return new ConfigSetting(key, value, origin, configId); + } + + private ConfigSetting(String key, Object value, ConfigOrigin origin, String configId) { this.key = key; this.value = CONFIG_FILTER_LIST.contains(key) ? "" : value; this.origin = origin; + this.configId = configId; } public String normalizedKey() { @@ -99,12 +106,15 @@ public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; ConfigSetting that = (ConfigSetting) o; - return key.equals(that.key) && Objects.equals(value, that.value) && origin == that.origin; + return key.equals(that.key) + && Objects.equals(value, that.value) + && origin == that.origin + && Objects.equals(configId, that.configId); } @Override public int hashCode() { - return Objects.hash(key, value, origin); + return Objects.hash(key, value, origin, configId); } @Override @@ -117,6 +127,8 @@ public String toString() { + stringValue() + ", origin=" + origin + + ", configId=" + + configId + '}'; } } diff --git a/internal-api/src/main/java/datadog/trace/bootstrap/config/provider/ConfigProvider.java b/internal-api/src/main/java/datadog/trace/bootstrap/config/provider/ConfigProvider.java index 1edeb072c80..338cc40ff08 100644 --- a/internal-api/src/main/java/datadog/trace/bootstrap/config/provider/ConfigProvider.java +++ b/internal-api/src/main/java/datadog/trace/bootstrap/config/provider/ConfigProvider.java @@ -79,7 +79,7 @@ public String getString(String key, String defaultValue, String... aliases) { String value = source.get(key, aliases); if (value != null) { if (collectConfig) { - ConfigCollector.get().put(key, value, source.origin()); + ConfigCollector.get().put(key, value, source.origin(), getConfigIdFromSource(source)); } return value; } @@ -198,7 +198,7 @@ private T get(String key, T defaultValue, Class type, String... aliases) T value = ConfigConverter.valueOf(sourceValue, type); if (value != null) { if (collectConfig) { - ConfigCollector.get().put(key, sourceValue, source.origin()); + ConfigCollector.get().put(key, value, source.origin(), getConfigIdFromSource(source)); } return value; } @@ -247,6 +247,7 @@ public List getSpacedList(String key) { public Map getMergedMap(String key, String... aliases) { Map merged = new HashMap<>(); ConfigOrigin origin = ConfigOrigin.DEFAULT; + String configId = null; // System properties take precedence over env // prior art: // https://docs.spring.io/spring-boot/docs/1.5.6.RELEASE/reference/html/boot-features-external-config.html @@ -256,11 +257,12 @@ public Map getMergedMap(String key, String... aliases) { Map parsedMap = ConfigConverter.parseMap(value, key); if (!parsedMap.isEmpty()) { origin = sources[i].origin(); + configId = getConfigIdFromSource(sources[i]); } merged.putAll(parsedMap); } if (collectConfig) { - ConfigCollector.get().put(key, merged, origin); + ConfigCollector.get().put(key, merged, origin, configId); } return merged; } @@ -268,6 +270,7 @@ public Map getMergedMap(String key, String... aliases) { public Map getMergedTagsMap(String key, String... aliases) { Map merged = new HashMap<>(); ConfigOrigin origin = ConfigOrigin.DEFAULT; + String configId = null; // System properties take precedence over env // prior art: // https://docs.spring.io/spring-boot/docs/1.5.6.RELEASE/reference/html/boot-features-external-config.html @@ -278,11 +281,12 @@ public Map getMergedTagsMap(String key, String... aliases) { ConfigConverter.parseTraceTagsMap(value, ':', Arrays.asList(',', ' ')); if (!parsedMap.isEmpty()) { origin = sources[i].origin(); + configId = getConfigIdFromSource(sources[i]); } merged.putAll(parsedMap); } if (collectConfig) { - ConfigCollector.get().put(key, merged, origin); + ConfigCollector.get().put(key, merged, origin, configId); } return merged; } @@ -290,6 +294,7 @@ public Map getMergedTagsMap(String key, String... aliases) { public Map getOrderedMap(String key) { LinkedHashMap merged = new LinkedHashMap<>(); ConfigOrigin origin = ConfigOrigin.DEFAULT; + String configId = null; // System properties take precedence over env // prior art: // https://docs.spring.io/spring-boot/docs/1.5.6.RELEASE/reference/html/boot-features-external-config.html @@ -299,11 +304,12 @@ public Map getOrderedMap(String key) { Map parsedMap = ConfigConverter.parseOrderedMap(value, key); if (!parsedMap.isEmpty()) { origin = sources[i].origin(); + configId = getConfigIdFromSource(sources[i]); } merged.putAll(parsedMap); } if (collectConfig) { - ConfigCollector.get().put(key, merged, origin); + ConfigCollector.get().put(key, merged, origin, configId); } return merged; } @@ -312,6 +318,7 @@ public Map getMergedMapWithOptionalMappings( String defaultPrefix, boolean lowercaseKeys, String... keys) { Map merged = new HashMap<>(); ConfigOrigin origin = ConfigOrigin.DEFAULT; + String configId = null; // System properties take precedence over env // prior art: // https://docs.spring.io/spring-boot/docs/1.5.6.RELEASE/reference/html/boot-features-external-config.html @@ -323,11 +330,12 @@ public Map getMergedMapWithOptionalMappings( ConfigConverter.parseMapWithOptionalMappings(value, key, defaultPrefix, lowercaseKeys); if (!parsedMap.isEmpty()) { origin = sources[i].origin(); + configId = getConfigIdFromSource(sources[i]); } merged.putAll(parsedMap); } if (collectConfig) { - ConfigCollector.get().put(key, merged, origin); + ConfigCollector.get().put(key, merged, origin, configId); } } return merged; @@ -499,6 +507,13 @@ private static Properties loadConfigurationFile(ConfigProvider configProvider) { return properties; } + private static String getConfigIdFromSource(Source source) { + if (source instanceof StableConfigSource) { + return ((StableConfigSource) source).getConfigId(); + } + return null; + } + public abstract static class Source { public final String get(String key, String... aliases) { String value = get(key); diff --git a/internal-api/src/main/java/datadog/trace/bootstrap/config/provider/stableconfig/StableConfig.java b/internal-api/src/main/java/datadog/trace/bootstrap/config/provider/stableconfig/StableConfig.java index 58fa3c4f826..f7129309102 100644 --- a/internal-api/src/main/java/datadog/trace/bootstrap/config/provider/stableconfig/StableConfig.java +++ b/internal-api/src/main/java/datadog/trace/bootstrap/config/provider/stableconfig/StableConfig.java @@ -17,7 +17,7 @@ public final class StableConfig { public StableConfig(Object yaml) { Map map = (Map) yaml; - this.configId = String.valueOf(map.get("config_id")); + this.configId = map.get("config_id") == null ? null : String.valueOf(map.get("config_id")); this.apmConfigurationDefault = unmodifiableMap( (Map) map.getOrDefault("apm_configuration_default", emptyMap())); diff --git a/telemetry/src/main/java/datadog/telemetry/TelemetryRequestBody.java b/telemetry/src/main/java/datadog/telemetry/TelemetryRequestBody.java index 62fac7d9afe..f84a4331fd7 100644 --- a/telemetry/src/main/java/datadog/telemetry/TelemetryRequestBody.java +++ b/telemetry/src/main/java/datadog/telemetry/TelemetryRequestBody.java @@ -230,6 +230,9 @@ public void writeConfiguration(ConfigSetting configSetting) throws IOException { bodyWriter.name("value").value(configSetting.stringValue()); bodyWriter.setSerializeNulls(false); bodyWriter.name("origin").value(configSetting.origin.value); + if (configSetting.configId != null) { + bodyWriter.name("config_id").value(configSetting.configId); + } bodyWriter.endObject(); } diff --git a/telemetry/src/test/groovy/datadog/telemetry/EventSourceTest.groovy b/telemetry/src/test/groovy/datadog/telemetry/EventSourceTest.groovy index 5a492c18171..5da3f0a3ea1 100644 --- a/telemetry/src/test/groovy/datadog/telemetry/EventSourceTest.groovy +++ b/telemetry/src/test/groovy/datadog/telemetry/EventSourceTest.groovy @@ -56,7 +56,7 @@ class EventSourceTest extends DDSpecification{ where: eventType | eventQueueName | eventInstance - "Config Change" | "configChangeQueue" | new ConfigSetting("key", "value", ConfigOrigin.ENV) + "Config Change" | "configChangeQueue" | ConfigSetting.of("key", "value", ConfigOrigin.ENV) "Integration" | "integrationQueue" | new Integration("name", true) "Dependency" | "dependencyQueue" | new Dependency("name", "version", "type", null) "Metric" | "metricQueue" | new Metric()