From 02f2a4d7fd6cbd7b2a67c39889e8b3a8d56b101c Mon Sep 17 00:00:00 2001 From: Vickie Boettcher Date: Wed, 12 Aug 2026 13:00:06 -0400 Subject: [PATCH 1/3] Populate source.name and source.version on flag_evaluations and exposures EVP FeatureFlagEvpContext.from builds the top-level context map shared by both the flagevaluation and exposures EVP writers. Add source.name ("dd-trace-java") and source.version (TracerVersion.TRACER_VERSION) so the SDK identity facets are populated on both EVP streams. This closes the gap noted in the Feature Flag Observability Telemetry Roadmap where the Java server SDK emitted no SDK/tracer name or version on the flag_evaluations EVP stream. Co-Authored-By: Claude --- .../com/datadog/featureflag/FeatureFlagEvpContext.java | 10 +++++++++- .../com/datadog/featureflag/ExposureWriterTests.java | 4 ++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/products/feature-flagging/feature-flagging-lib/src/main/java/com/datadog/featureflag/FeatureFlagEvpContext.java b/products/feature-flagging/feature-flagging-lib/src/main/java/com/datadog/featureflag/FeatureFlagEvpContext.java index c964efa6c7f..84de91330bb 100644 --- a/products/feature-flagging/feature-flagging-lib/src/main/java/com/datadog/featureflag/FeatureFlagEvpContext.java +++ b/products/feature-flagging/feature-flagging-lib/src/main/java/com/datadog/featureflag/FeatureFlagEvpContext.java @@ -1,5 +1,6 @@ package com.datadog.featureflag; +import datadog.communication.ddagent.TracerVersion; import datadog.trace.api.Config; import java.util.HashMap; import java.util.Map; @@ -8,8 +9,11 @@ final class FeatureFlagEvpContext { private FeatureFlagEvpContext() {} + /** The name of the SDK emitting the feature flag evaluation/exposure EVP data. */ + private static final String SOURCE_NAME = "dd-trace-java"; + static Map from(final Config config) { - final Map context = new HashMap<>(4); + final Map context = new HashMap<>(6); context.put("service", config.getServiceName() == null ? "unknown" : config.getServiceName()); if (config.getEnv() != null) { context.put("env", config.getEnv()); @@ -17,6 +21,10 @@ static Map from(final Config config) { if (config.getVersion() != null) { context.put("version", config.getVersion()); } + // SDK identity — populates the `source.name` / `source.version` facets on the + // `flag_evaluations` and `exposures` EVP streams. See FFL-2995. + context.put("source.name", SOURCE_NAME); + context.put("source.version", TracerVersion.TRACER_VERSION); return context; } } diff --git a/products/feature-flagging/feature-flagging-lib/src/test/java/com/datadog/featureflag/ExposureWriterTests.java b/products/feature-flagging/feature-flagging-lib/src/test/java/com/datadog/featureflag/ExposureWriterTests.java index 76b9e2602d8..73fee60fdc8 100644 --- a/products/feature-flagging/feature-flagging-lib/src/test/java/com/datadog/featureflag/ExposureWriterTests.java +++ b/products/feature-flagging/feature-flagging-lib/src/test/java/com/datadog/featureflag/ExposureWriterTests.java @@ -15,6 +15,7 @@ import com.squareup.moshi.Moshi; import datadog.communication.ddagent.DDAgentFeaturesDiscovery; import datadog.communication.ddagent.SharedCommunicationObjects; +import datadog.communication.ddagent.TracerVersion; import datadog.trace.agent.test.server.http.JavaTestHttpServer; import datadog.trace.agent.test.server.http.JavaTestHttpServer.HandlerApi; import datadog.trace.api.Config; @@ -287,6 +288,9 @@ private static void assertContext( assertEquals(service == null ? "unknown" : service, context.get("service")); assertOptionalContextValue(context, "env", env); assertOptionalContextValue(context, "version", version); + // SDK identity populated by FeatureFlagEvpContext (FFL-2995). + assertEquals("dd-trace-java", context.get("source.name")); + assertEquals(TracerVersion.TRACER_VERSION, context.get("source.version")); } private static void assertOptionalContextValue( From 8ed8522f9ff7c1465532e9ca92fde949dc37ab5f Mon Sep 17 00:00:00 2001 From: Vickie Boettcher Date: Wed, 12 Aug 2026 13:12:09 -0400 Subject: [PATCH 2/3] Tighten comments: drop ticket refs and redundant javadoc --- .../java/com/datadog/featureflag/FeatureFlagEvpContext.java | 5 ++--- .../java/com/datadog/featureflag/ExposureWriterTests.java | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/products/feature-flagging/feature-flagging-lib/src/main/java/com/datadog/featureflag/FeatureFlagEvpContext.java b/products/feature-flagging/feature-flagging-lib/src/main/java/com/datadog/featureflag/FeatureFlagEvpContext.java index 84de91330bb..181dab8495b 100644 --- a/products/feature-flagging/feature-flagging-lib/src/main/java/com/datadog/featureflag/FeatureFlagEvpContext.java +++ b/products/feature-flagging/feature-flagging-lib/src/main/java/com/datadog/featureflag/FeatureFlagEvpContext.java @@ -9,7 +9,6 @@ final class FeatureFlagEvpContext { private FeatureFlagEvpContext() {} - /** The name of the SDK emitting the feature flag evaluation/exposure EVP data. */ private static final String SOURCE_NAME = "dd-trace-java"; static Map from(final Config config) { @@ -21,8 +20,8 @@ static Map from(final Config config) { if (config.getVersion() != null) { context.put("version", config.getVersion()); } - // SDK identity — populates the `source.name` / `source.version` facets on the - // `flag_evaluations` and `exposures` EVP streams. See FFL-2995. + // SDK identity — populates the `source.name` / `source.version` facets on both the + // `flag_evaluations` and `exposures` EVP streams (this map is shared by both writers). context.put("source.name", SOURCE_NAME); context.put("source.version", TracerVersion.TRACER_VERSION); return context; diff --git a/products/feature-flagging/feature-flagging-lib/src/test/java/com/datadog/featureflag/ExposureWriterTests.java b/products/feature-flagging/feature-flagging-lib/src/test/java/com/datadog/featureflag/ExposureWriterTests.java index 73fee60fdc8..4c47133d8d7 100644 --- a/products/feature-flagging/feature-flagging-lib/src/test/java/com/datadog/featureflag/ExposureWriterTests.java +++ b/products/feature-flagging/feature-flagging-lib/src/test/java/com/datadog/featureflag/ExposureWriterTests.java @@ -288,7 +288,7 @@ private static void assertContext( assertEquals(service == null ? "unknown" : service, context.get("service")); assertOptionalContextValue(context, "env", env); assertOptionalContextValue(context, "version", version); - // SDK identity populated by FeatureFlagEvpContext (FFL-2995). + // SDK identity populated by FeatureFlagEvpContext. assertEquals("dd-trace-java", context.get("source.name")); assertEquals(TracerVersion.TRACER_VERSION, context.get("source.version")); } From 4aa5a6f90a25fa38a4455a3fc7930e835c9947fd Mon Sep 17 00:00:00 2001 From: Vickie Boettcher Date: Fri, 14 Aug 2026 11:34:03 -0400 Subject: [PATCH 3/3] fix(openfeature): emit source.name/version per-event, not in batch context MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The flagevaluation track schema (logs-backend flagevaluation.conf) declares source.name/source.version as top-level per-event fields, siblings of flag/variant/targeting_key. The previous implementation put them in the batch context envelope alongside service/env/version, which the EVP indexer maps to context.source.* — an undeclared facet that causes the indexer to drop the entire event. Move source to the FlagEvaluationEvent top level (as a nested source object {name,version}) so it lands on the declared source.name/source.version facets. Verified end-to-end via ffe-dogfooding against staging: Java flagevaluation events now index in the staging flag_evaluations data source. Generated with Claude Code Co-Authored-By: Claude --- .../featureflag/FeatureFlagEvpContext.java | 13 +++++-------- .../featureflag/FlagEvaluationPayloads.java | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/products/feature-flagging/feature-flagging-lib/src/main/java/com/datadog/featureflag/FeatureFlagEvpContext.java b/products/feature-flagging/feature-flagging-lib/src/main/java/com/datadog/featureflag/FeatureFlagEvpContext.java index 181dab8495b..255c2377905 100644 --- a/products/feature-flagging/feature-flagging-lib/src/main/java/com/datadog/featureflag/FeatureFlagEvpContext.java +++ b/products/feature-flagging/feature-flagging-lib/src/main/java/com/datadog/featureflag/FeatureFlagEvpContext.java @@ -1,6 +1,5 @@ package com.datadog.featureflag; -import datadog.communication.ddagent.TracerVersion; import datadog.trace.api.Config; import java.util.HashMap; import java.util.Map; @@ -9,10 +8,8 @@ final class FeatureFlagEvpContext { private FeatureFlagEvpContext() {} - private static final String SOURCE_NAME = "dd-trace-java"; - static Map from(final Config config) { - final Map context = new HashMap<>(6); + final Map context = new HashMap<>(4); context.put("service", config.getServiceName() == null ? "unknown" : config.getServiceName()); if (config.getEnv() != null) { context.put("env", config.getEnv()); @@ -20,10 +17,10 @@ static Map from(final Config config) { if (config.getVersion() != null) { context.put("version", config.getVersion()); } - // SDK identity — populates the `source.name` / `source.version` facets on both the - // `flag_evaluations` and `exposures` EVP streams (this map is shared by both writers). - context.put("source.name", SOURCE_NAME); - context.put("source.version", TracerVersion.TRACER_VERSION); + // SDK identity (source.name / source.version) is emitted per-event at the top level + // (sibling of flag/variant/targeting_key), matching the flagevaluation track schema in + // logs-backend. Putting it in the batch context would map it to context.source.*, which is + // not a declared facet and causes the indexer to drop the event. return context; } } diff --git a/products/feature-flagging/feature-flagging-lib/src/main/java/com/datadog/featureflag/FlagEvaluationPayloads.java b/products/feature-flagging/feature-flagging-lib/src/main/java/com/datadog/featureflag/FlagEvaluationPayloads.java index 3a8734fd516..95ce3e0b082 100644 --- a/products/feature-flagging/feature-flagging-lib/src/main/java/com/datadog/featureflag/FlagEvaluationPayloads.java +++ b/products/feature-flagging/feature-flagging-lib/src/main/java/com/datadog/featureflag/FlagEvaluationPayloads.java @@ -1,5 +1,6 @@ package com.datadog.featureflag; +import datadog.communication.ddagent.TracerVersion; import com.squareup.moshi.JsonAdapter; import com.squareup.moshi.Moshi; import com.squareup.moshi.Types; @@ -157,6 +158,9 @@ private byte[] toByteArray() { } } + private static final String SOURCE_NAME = "dd-trace-java"; + private static final String SOURCE_VERSION = TracerVersion.TRACER_VERSION; + static class FlagEvaluationEvent { public final long timestamp; public final FlagKeyObject flag; @@ -168,6 +172,7 @@ static class FlagEvaluationEvent { public final String targeting_key; public final Boolean runtime_default_used; public final EventContext context; + public final SourceObject source; public final ErrorObject error; FlagEvaluationEvent( @@ -196,6 +201,7 @@ static class FlagEvaluationEvent { (evaluationAttrs != null && !evaluationAttrs.isEmpty()) ? new EventContext(evaluationAttrs) : null; + this.source = new SourceObject(SOURCE_NAME, SOURCE_VERSION); this.error = (errorMessage != null && !errorMessage.isEmpty()) ? new ErrorObject(errorMessage) : null; } @@ -284,6 +290,16 @@ static class ErrorObject { } } + static class SourceObject { + public final String name; + public final String version; + + SourceObject(final String name, final String version) { + this.name = name; + this.version = version; + } + } + static class EventContext { public final Map evaluation;