Add flag evaluation metrics via OTel counter and OpenFeature Hook#11040
Open
Add flag evaluation metrics via OTel counter and OpenFeature Hook#11040
Conversation
BenchmarksStartupParameters
See matching parameters
SummaryFound 0 performance improvements and 0 performance regressions! Performance is the same for 58 metrics, 13 unstable metrics. Startup time reports for petclinicgantt
title petclinic - global startup overhead: candidate=1.62.0-SNAPSHOT~da921984b2, baseline=1.62.0-SNAPSHOT~b266e2d0c2
dateFormat X
axisFormat %s
section tracing
Agent [baseline] (1.056 s) : 0, 1056454
Total [baseline] (11.049 s) : 0, 11049497
Agent [candidate] (1.062 s) : 0, 1061670
Total [candidate] (11.19 s) : 0, 11190343
section appsec
Agent [baseline] (1.248 s) : 0, 1248213
Total [baseline] (11.194 s) : 0, 11194058
Agent [candidate] (1.249 s) : 0, 1249481
Total [candidate] (11.121 s) : 0, 11120859
section iast
Agent [baseline] (1.243 s) : 0, 1242843
Total [baseline] (11.288 s) : 0, 11287911
Agent [candidate] (1.226 s) : 0, 1226436
Total [candidate] (11.355 s) : 0, 11355108
section profiling
Agent [baseline] (1.185 s) : 0, 1184820
Total [baseline] (11.045 s) : 0, 11044846
Agent [candidate] (1.185 s) : 0, 1184512
Total [candidate] (11.069 s) : 0, 11069416
gantt
title petclinic - break down per module: candidate=1.62.0-SNAPSHOT~da921984b2, baseline=1.62.0-SNAPSHOT~b266e2d0c2
dateFormat X
axisFormat %s
section tracing
crashtracking [baseline] (1.227 ms) : 0, 1227
crashtracking [candidate] (1.227 ms) : 0, 1227
BytebuddyAgent [baseline] (631.826 ms) : 0, 631826
BytebuddyAgent [candidate] (636.472 ms) : 0, 636472
AgentMeter [baseline] (29.315 ms) : 0, 29315
AgentMeter [candidate] (29.528 ms) : 0, 29528
GlobalTracer [baseline] (248.424 ms) : 0, 248424
GlobalTracer [candidate] (249.456 ms) : 0, 249456
AppSec [baseline] (32.074 ms) : 0, 32074
AppSec [candidate] (32.117 ms) : 0, 32117
Debugger [baseline] (60.445 ms) : 0, 60445
Debugger [candidate] (60.249 ms) : 0, 60249
Remote Config [baseline] (608.347 µs) : 0, 608
Remote Config [candidate] (617.152 µs) : 0, 617
Telemetry [baseline] (8.211 ms) : 0, 8211
Telemetry [candidate] (8.131 ms) : 0, 8131
Flare Poller [baseline] (8.201 ms) : 0, 8201
Flare Poller [candidate] (7.589 ms) : 0, 7589
section appsec
crashtracking [baseline] (1.228 ms) : 0, 1228
crashtracking [candidate] (1.226 ms) : 0, 1226
BytebuddyAgent [baseline] (661.04 ms) : 0, 661040
BytebuddyAgent [candidate] (662.049 ms) : 0, 662049
AgentMeter [baseline] (11.929 ms) : 0, 11929
AgentMeter [candidate] (12.051 ms) : 0, 12051
GlobalTracer [baseline] (249.028 ms) : 0, 249028
GlobalTracer [candidate] (249.65 ms) : 0, 249650
AppSec [baseline] (185.024 ms) : 0, 185024
AppSec [candidate] (184.75 ms) : 0, 184750
Debugger [baseline] (66.414 ms) : 0, 66414
Debugger [candidate] (66.163 ms) : 0, 66163
Remote Config [baseline] (610.008 µs) : 0, 610
Remote Config [candidate] (605.266 µs) : 0, 605
Telemetry [baseline] (8.465 ms) : 0, 8465
Telemetry [candidate] (8.545 ms) : 0, 8545
Flare Poller [baseline] (3.55 ms) : 0, 3550
Flare Poller [candidate] (3.548 ms) : 0, 3548
IAST [baseline] (24.665 ms) : 0, 24665
IAST [candidate] (24.51 ms) : 0, 24510
section iast
crashtracking [baseline] (1.249 ms) : 0, 1249
crashtracking [candidate] (1.242 ms) : 0, 1242
BytebuddyAgent [baseline] (816.038 ms) : 0, 816038
BytebuddyAgent [candidate] (802.339 ms) : 0, 802339
AgentMeter [baseline] (11.591 ms) : 0, 11591
AgentMeter [candidate] (11.425 ms) : 0, 11425
GlobalTracer [baseline] (241.858 ms) : 0, 241858
GlobalTracer [candidate] (239.838 ms) : 0, 239838
AppSec [baseline] (30.495 ms) : 0, 30495
AppSec [candidate] (31.229 ms) : 0, 31229
Debugger [baseline] (61.893 ms) : 0, 61893
Debugger [candidate] (59.596 ms) : 0, 59596
Remote Config [baseline] (536.15 µs) : 0, 536
Remote Config [candidate] (1.121 ms) : 0, 1121
Telemetry [baseline] (12.245 ms) : 0, 12245
Telemetry [candidate] (13.766 ms) : 0, 13766
Flare Poller [baseline] (3.591 ms) : 0, 3591
Flare Poller [candidate] (3.62 ms) : 0, 3620
IAST [baseline] (26.824 ms) : 0, 26824
IAST [candidate] (25.84 ms) : 0, 25840
section profiling
crashtracking [baseline] (1.194 ms) : 0, 1194
crashtracking [candidate] (1.186 ms) : 0, 1186
BytebuddyAgent [baseline] (691.212 ms) : 0, 691212
BytebuddyAgent [candidate] (692.067 ms) : 0, 692067
AgentMeter [baseline] (9.232 ms) : 0, 9232
AgentMeter [candidate] (9.183 ms) : 0, 9183
GlobalTracer [baseline] (207.271 ms) : 0, 207271
GlobalTracer [candidate] (207.061 ms) : 0, 207061
AppSec [baseline] (32.657 ms) : 0, 32657
AppSec [candidate] (32.429 ms) : 0, 32429
Debugger [baseline] (65.625 ms) : 0, 65625
Debugger [candidate] (65.485 ms) : 0, 65485
Remote Config [baseline] (581.128 µs) : 0, 581
Remote Config [candidate] (564.851 µs) : 0, 565
Telemetry [baseline] (7.862 ms) : 0, 7862
Telemetry [candidate] (7.796 ms) : 0, 7796
Flare Poller [baseline] (3.576 ms) : 0, 3576
Flare Poller [candidate] (3.6 ms) : 0, 3600
ProfilingAgent [baseline] (94.37 ms) : 0, 94370
ProfilingAgent [candidate] (93.881 ms) : 0, 93881
Profiling [baseline] (94.933 ms) : 0, 94933
Profiling [candidate] (94.452 ms) : 0, 94452
Startup time reports for insecure-bankgantt
title insecure-bank - global startup overhead: candidate=1.62.0-SNAPSHOT~da921984b2, baseline=1.62.0-SNAPSHOT~b266e2d0c2
dateFormat X
axisFormat %s
section tracing
Agent [baseline] (1.053 s) : 0, 1053323
Total [baseline] (8.824 s) : 0, 8824452
Agent [candidate] (1.057 s) : 0, 1056745
Total [candidate] (8.88 s) : 0, 8880199
section iast
Agent [baseline] (1.226 s) : 0, 1225847
Total [baseline] (9.576 s) : 0, 9576209
Agent [candidate] (1.235 s) : 0, 1235049
Total [candidate] (9.57 s) : 0, 9570425
gantt
title insecure-bank - break down per module: candidate=1.62.0-SNAPSHOT~da921984b2, baseline=1.62.0-SNAPSHOT~b266e2d0c2
dateFormat X
axisFormat %s
section tracing
crashtracking [baseline] (1.222 ms) : 0, 1222
crashtracking [candidate] (1.222 ms) : 0, 1222
BytebuddyAgent [baseline] (631.156 ms) : 0, 631156
BytebuddyAgent [candidate] (633.214 ms) : 0, 633214
AgentMeter [baseline] (29.285 ms) : 0, 29285
AgentMeter [candidate] (29.328 ms) : 0, 29328
GlobalTracer [baseline] (248.008 ms) : 0, 248008
GlobalTracer [candidate] (249.366 ms) : 0, 249366
AppSec [baseline] (31.936 ms) : 0, 31936
AppSec [candidate] (32.098 ms) : 0, 32098
Debugger [baseline] (58.91 ms) : 0, 58910
Debugger [candidate] (59.276 ms) : 0, 59276
Remote Config [baseline] (591.024 µs) : 0, 591
Remote Config [candidate] (603.228 µs) : 0, 603
Telemetry [baseline] (8.013 ms) : 0, 8013
Telemetry [candidate] (8.094 ms) : 0, 8094
Flare Poller [baseline] (8.126 ms) : 0, 8126
Flare Poller [candidate] (7.351 ms) : 0, 7351
section iast
crashtracking [baseline] (1.237 ms) : 0, 1237
crashtracking [candidate] (1.251 ms) : 0, 1251
BytebuddyAgent [baseline] (799.975 ms) : 0, 799975
BytebuddyAgent [candidate] (810.011 ms) : 0, 810011
AgentMeter [baseline] (11.453 ms) : 0, 11453
AgentMeter [candidate] (11.703 ms) : 0, 11703
GlobalTracer [baseline] (240.985 ms) : 0, 240985
GlobalTracer [candidate] (240.409 ms) : 0, 240409
AppSec [baseline] (29.864 ms) : 0, 29864
AppSec [candidate] (30.624 ms) : 0, 30624
Debugger [baseline] (62.243 ms) : 0, 62243
Debugger [candidate] (62.995 ms) : 0, 62995
Remote Config [baseline] (550.063 µs) : 0, 550
Remote Config [candidate] (1.101 ms) : 0, 1101
Telemetry [baseline] (13.499 ms) : 0, 13499
Telemetry [candidate] (11.272 ms) : 0, 11272
Flare Poller [baseline] (3.507 ms) : 0, 3507
Flare Poller [candidate] (3.503 ms) : 0, 3503
IAST [baseline] (26.161 ms) : 0, 26161
IAST [candidate] (25.754 ms) : 0, 25754
LoadParameters
See matching parameters
SummaryFound 5 performance improvements and 2 performance regressions! Performance is the same for 13 metrics, 16 unstable metrics.
Request duration reports for petclinicgantt
title petclinic - request duration [CI 0.99] : candidate=1.62.0-SNAPSHOT~da921984b2, baseline=1.62.0-SNAPSHOT~b266e2d0c2
dateFormat X
axisFormat %s
section baseline
no_agent (18.248 ms) : 18060, 18437
. : milestone, 18248,
appsec (18.733 ms) : 18546, 18920
. : milestone, 18733,
code_origins (18.134 ms) : 17956, 18311
. : milestone, 18134,
iast (18.899 ms) : 18710, 19089
. : milestone, 18899,
profiling (18.215 ms) : 18038, 18393
. : milestone, 18215,
tracing (19.434 ms) : 19239, 19630
. : milestone, 19434,
section candidate
no_agent (16.903 ms) : 16736, 17070
. : milestone, 16903,
appsec (18.472 ms) : 18285, 18659
. : milestone, 18472,
code_origins (18.019 ms) : 17844, 18194
. : milestone, 18019,
iast (17.456 ms) : 17284, 17629
. : milestone, 17456,
profiling (19.925 ms) : 19721, 20129
. : milestone, 19925,
tracing (17.88 ms) : 17704, 18056
. : milestone, 17880,
Request duration reports for insecure-bankgantt
title insecure-bank - request duration [CI 0.99] : candidate=1.62.0-SNAPSHOT~da921984b2, baseline=1.62.0-SNAPSHOT~b266e2d0c2
dateFormat X
axisFormat %s
section baseline
no_agent (1.237 ms) : 1226, 1248
. : milestone, 1237,
iast (3.302 ms) : 3258, 3346
. : milestone, 3302,
iast_FULL (6.014 ms) : 5953, 6075
. : milestone, 6014,
iast_GLOBAL (3.745 ms) : 3675, 3815
. : milestone, 3745,
profiling (2.196 ms) : 2176, 2215
. : milestone, 2196,
tracing (1.833 ms) : 1818, 1848
. : milestone, 1833,
section candidate
no_agent (1.251 ms) : 1239, 1263
. : milestone, 1251,
iast (3.232 ms) : 3196, 3269
. : milestone, 3232,
iast_FULL (6.211 ms) : 6147, 6275
. : milestone, 6211,
iast_GLOBAL (3.682 ms) : 3620, 3743
. : milestone, 3682,
profiling (2.171 ms) : 2150, 2192
. : milestone, 2171,
tracing (1.891 ms) : 1874, 1908
. : milestone, 1891,
DacapoParameters
See matching parameters
SummaryFound 0 performance improvements and 0 performance regressions! Performance is the same for 10 metrics, 2 unstable metrics. Execution time for biojavagantt
title biojava - execution time [CI 0.99] : candidate=1.62.0-SNAPSHOT~da921984b2, baseline=1.62.0-SNAPSHOT~b266e2d0c2
dateFormat X
axisFormat %s
section baseline
no_agent (15.612 s) : 15612000, 15612000
. : milestone, 15612000,
appsec (15.071 s) : 15071000, 15071000
. : milestone, 15071000,
iast (18.269 s) : 18269000, 18269000
. : milestone, 18269000,
iast_GLOBAL (18.338 s) : 18338000, 18338000
. : milestone, 18338000,
profiling (15.133 s) : 15133000, 15133000
. : milestone, 15133000,
tracing (14.646 s) : 14646000, 14646000
. : milestone, 14646000,
section candidate
no_agent (14.976 s) : 14976000, 14976000
. : milestone, 14976000,
appsec (15.15 s) : 15150000, 15150000
. : milestone, 15150000,
iast (18.303 s) : 18303000, 18303000
. : milestone, 18303000,
iast_GLOBAL (18.119 s) : 18119000, 18119000
. : milestone, 18119000,
profiling (14.909 s) : 14909000, 14909000
. : milestone, 14909000,
tracing (14.73 s) : 14730000, 14730000
. : milestone, 14730000,
Execution time for tomcatgantt
title tomcat - execution time [CI 0.99] : candidate=1.62.0-SNAPSHOT~da921984b2, baseline=1.62.0-SNAPSHOT~b266e2d0c2
dateFormat X
axisFormat %s
section baseline
no_agent (1.498 ms) : 1487, 1510
. : milestone, 1498,
appsec (2.553 ms) : 2498, 2608
. : milestone, 2553,
iast (2.292 ms) : 2222, 2362
. : milestone, 2292,
iast_GLOBAL (2.346 ms) : 2275, 2416
. : milestone, 2346,
profiling (2.536 ms) : 2372, 2700
. : milestone, 2536,
tracing (2.118 ms) : 2064, 2172
. : milestone, 2118,
section candidate
no_agent (1.498 ms) : 1486, 1510
. : milestone, 1498,
appsec (3.862 ms) : 3637, 4088
. : milestone, 3862,
iast (2.307 ms) : 2237, 2378
. : milestone, 2307,
iast_GLOBAL (2.332 ms) : 2262, 2403
. : milestone, 2332,
profiling (2.543 ms) : 2378, 2709
. : milestone, 2543,
tracing (2.12 ms) : 2066, 2174
. : milestone, 2120,
|
Record a `feature_flag.evaluations` OTel counter on every flag evaluation using an OpenFeature `finallyAfter` hook. The hook captures all evaluation paths including type mismatches that occur above the provider level. Attributes: feature_flag.key, feature_flag.result.variant, feature_flag.result.reason, error.type (on error), feature_flag.result.allocation_key (when present). Counter is a no-op when DD_METRICS_OTEL_ENABLED is false or opentelemetry-api is absent from the classpath.
Replace GlobalOpenTelemetry.getMeterProvider() with a dedicated SdkMeterProvider + OtlpHttpMetricExporter that sends metrics directly to the DD Agent's OTLP endpoint (default :4318/v1/metrics). This avoids the agent's OTel class shading issue where the agent relocates io.opentelemetry.api.* to datadog.trace.bootstrap.otel.api.*, making GlobalOpenTelemetry calls from the dd-openfeature jar hit the unshaded no-op provider instead of the agent's shim. Requires opentelemetry-sdk-metrics and opentelemetry-exporter-otlp on the application classpath. Falls back to no-op if absent. System tests: 11/17 pass. 6 failures are pre-existing DDEvaluator gaps (reason mapping, parse errors, type mismatch strictness).
- Add explicit null guard for details in FlagEvalHook.finallyAfter() - Add OTEL_EXPORTER_OTLP_ENDPOINT generic env var fallback with /v1/metrics path appended (per OTel spec fallback chain) - Add comments clarifying signal-specific vs generic endpoint behavior
When the OTel SDK jars are not on the application classpath, loading FlagEvalMetrics fails because field types reference OTel SDK classes (SdkMeterProvider). This propagated as an uncaught NoClassDefFoundError from the Provider constructor, crashing provider initialization. Fix: - Change meterProvider field type from SdkMeterProvider to Closeable (always on classpath), use local SdkMeterProvider variable inside try block - Catch NoClassDefFoundError in Provider constructor when creating FlagEvalMetrics - Null-safe getProviderHooks() and shutdown() when metrics is null
FlagEvalHook references FlagEvalMetrics in its field declaration. On JVMs that eagerly verify field types during class loading, constructing FlagEvalHook outside the try/catch could throw NoClassDefFoundError if OTel classes failed to load. Moving it inside the try block ensures both metrics and hook are null-safe when OTel is absent.
4cb7bab to
69c5529
Compare
Documents the published artifact setup, evaluation metrics dependencies (opentelemetry-sdk-metrics, opentelemetry-exporter-otlp), OTLP endpoint configuration, metric attributes, and requirements.
System.getenv() is forbidden by the project's forbiddenApis rules. Replace with ConfigHelper.env() which is the approved way to read environment variables. Add config-utils as compileOnly dependency.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What Does This Do
Records a
feature_flag.evaluationsOTel counter metric on every flag evaluation via an OpenFeaturefinallyAfterhook. The hook captures all evaluation paths including type mismatches that occur above the provider level in the OpenFeature SDK pipeline.Creates a dedicated
SdkMeterProviderwith anOtlpHttpMetricExporterthat sends metrics directly to the DD Agent's OTLP endpoint (/v1/metrics). This avoids the agent's OTel class shading (io.opentelemetry.api.*→datadog.trace.bootstrap.otel.api.*) which prevents usingGlobalOpenTelemetryfrom the publisheddd-openfeaturejar.Metric attributes:
feature_flag.keyfeature_flag.result.variantfeature_flag.result.reasonerror.typefeature_flag.result.allocation_keyNew files:
FlagEvalMetrics.java,FlagEvalHook.java,FlagEvalMetricsTest.java,FlagEvalHookTest.javaModified files:
Provider.java(addsgetProviderHooks()),ProviderTest.java,build.gradle.ktsMotivation
Evaluation metrics allow tracking how many times flags are evaluated, with which results, across sessions. This is the Java implementation of the evaluation logging spec (FFL-1942), matching the existing Python (dd-trace-py#17029) and Go (dd-trace-go#4489) implementations.
System tests: 11/17 pass. The 6 remaining failures are pre-existing DDEvaluator gaps (reason mapping, parse error codes) addressed in separate PRs (#11036, #10971).
References:
Additional Notes
opentelemetry-sdk-metrics,opentelemetry-exporter-otlp) arecompileOnly— applications must include them on the classpath for metrics to flow. Falls back to silent no-op when absent.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT→OTEL_EXPORTER_OTLP_ENDPOINT+/v1/metrics→http://localhost:4318/v1/metricsContributor Checklist
type:and (comp:orinst:) labelsclose,fix, or any linking keywords when referencing an issueJira ticket: FFL-1942