Skip to content

feat(feature-flags): wire source-agnostic activation and OpenFeature InitializeAsync - #9044

Merged
pavlokhrebto merged 107 commits into
masterfrom
pavlo.khrebto/EX-2703/ffe-module-wiring
Sep 14, 2026
Merged

pavlokhrebto merged 107 commits into
masterfrom
pavlo.khrebto/EX-2703/ffe-module-wiring

Conversation

@pavlokhrebto

@pavlokhrebto pavlokhrebto commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Summary of changes

Wires the agentless poller and RC subscription into FeatureFlagsModule with source-agnostic activation, and adds InitializeAsync through the OpenFeature provider lifecycle so delivery starts when application code initializes the provider.

This is PR 3 of a stacked PR series implementing agentless Feature Flags configuration delivery (FFL-2703), porting functionality from dd-trace-py#19331 and dd-trace-java#11892. Stacked on PR 1 #9040 and PR 2 #9042.

Reason for change

PR 1 added the configuration layer and PR 2 added the poller and parser. This PR connects them: the module now selects the delivery source at construction time, starts polling only when the provider is initialized, and waits for the first configuration before returning from InitializeAsync.

Implementation details

  • TracerSettings — replaces IsFlaggingProviderEnabled with FeatureFlagsSettings FeatureFlags property
  • FeatureFlagsModule — source-agnostic constructor:
    • RC subscription only when Source == RemoteConfig (gated, no longer always-on)
    • Create() checks settings.FeatureFlags.Enabled
    • Activate() starts the agentless poller or marks RC intent, with _deliveryStarted tracking
    • InitializeAsync() calls Activate(), waits for FirstConfigReceived with timeout, skips the wait if no delivery started
    • ApplyConfiguration() — public method used by both agentless and RC paths, signals FirstConfigReceived
    • Dispose() now also disposes the agentless source and unsubscribes RC
  • OpenFeatureSdkInitializeAsyncIntegration (new CallTarget) — intercepts FeatureFlagsSdk.InitializeAsync stub and calls FeatureFlagsModule.InitializeAsync
  • DatadogProvider.InitializeAsync — override that delegates to FeatureFlagsSdk.InitializeAsync
  • FeatureFlagsSdk.InitializeAsync — no-op stub in the OpenFeature package
  • supported_calltargets.g.json — registers the new integration
  • SpanEnrichmentIntegrationTests — suppresses [Obsolete] warning on FlaggingProviderEnabled

Test coverage

  • FeatureFlagsModuleTests (9 tests) — RC config update/reset, agentless source doesn't subscribe to RC, RC source subscribes and advertises capability, disabled returns null, InitializeAsync returns immediately when config already applied, returns when config arrives while waiting, returns on timeout without throwing, returns on cancellation without throwing, returns immediately when agentless source cannot start (no API key)

Other details

Stacked PRs:

  • PR 1 #9040: Configuration keys, settings, and endpoint derivation
  • PR 2 #9042: UFC parser and agentless HTTP poller
  • PR 3 (this): Module wiring and OpenFeature activation
  • PR 4: Manual API activation

System tests: DataDog/system-tests#7496

@pavlokhrebto pavlokhrebto changed the title Pavlo.khrebto/ex 2703/ffe module wiring feat(feature-flags): wire source-agnostic activation and OpenFeature InitializeAsync Aug 13, 2026
@pavlokhrebto pavlokhrebto added type:new-feature AI Generated Largely based on code generated by an AI or LLM. This label is the same across all dd-trace-* repos feature_flags labels Aug 13, 2026
@pr-commenter

pr-commenter Bot commented Aug 13, 2026

Copy link
Copy Markdown

Benchmarks

Benchmark execution time: 2026-09-14 07:31:31

Comparing candidate commit 41092bc in PR branch pavlo.khrebto/EX-2703/ffe-module-wiring with baseline commit d050f0e in branch master.

📊 Benchmarking dashboard

Found 0 performance improvements and 1 performance regressions! Performance is the same for 71 metrics, 0 unstable metrics, 68 known flaky benchmarks, 58 flaky benchmarks without significant changes.

Explanation

This is an A/B test comparing a candidate commit's performance against that of a baseline commit. Performance changes are noted in the tables below as:

  • 🟩 = significantly better candidate vs. baseline
  • 🟥 = significantly worse candidate vs. baseline

We compute a confidence interval (CI) over the relative difference of means between metrics from the candidate and baseline commits, considering the baseline as the reference.

If the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD), the change is considered significant.

Feel free to reach out to #apm-benchmarking-platform on Slack if you have any questions.

More details about the CI and significant changes

You can imagine this CI as a range of values that is likely to contain the true difference of means between the candidate and baseline commits.

CIs of the difference of means are often centered around 0%, because often changes are not that big:

---------------------------------(------|---^--------)-------------------------------->
                              -0.6%    0%  0.3%     +1.2%
                                 |          |        |
         lower bound of the CI --'          |        |
sample mean (center of the CI) -------------'        |
         upper bound of the CI ----------------------'

As described above, a change is considered significant if the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD).

For instance, for an execution time metric, this confidence interval indicates a significantly worse performance:

----------------------------------------|---------|---(---------^---------)---------->
                                       0%        1%  1.3%      2.2%      3.1%
                                                  |   |         |         |
       significant impact threshold --------------'   |         |         |
                      lower bound of CI --------------'         |         |
       sample mean (center of the CI) --------------------------'         |
                      upper bound of CI ----------------------------------'

scenario:Benchmarks.Trace.HttpClientBenchmark.SendAsync net472

  • 🟥 throughput [-5295.438op/s; -4474.687op/s] or [-6.045%; -5.108%]

Known flaky benchmarks

These benchmarks are marked as flaky and will not trigger a failure. Modify FLAKY_BENCHMARKS_REGEX to control which benchmarks are marked as flaky.

scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_GetContext_Sampled net472

  • 🟥 throughput [-11526.768op/s; -10444.444op/s] or [-5.686%; -5.152%]

scenario:Benchmarks.Trace.ActivityBenchmark.StartStopWithChild net472

  • 🟥 throughput [-6732.460op/s; -6060.399op/s] or [-7.983%; -7.186%]

scenario:Benchmarks.Trace.ActivityBenchmark.StartStopWithChild netcoreapp3.1

  • 🟥 throughput [-10567.919op/s; -9008.748op/s] or [-10.745%; -9.160%]

scenario:Benchmarks.Trace.AgentWriterBenchmark.WriteAndFlushEnrichedTraces net472

  • 🟥 allocated_mem [+1.605KB; +1.605KB] or [+48.760%; +48.776%]
  • 🟥 execution_time [+307.273ms; +310.362ms] or [+152.480%; +154.013%]
  • 🟥 throughput [-56.346op/s; -51.902op/s] or [-10.138%; -9.338%]

scenario:Benchmarks.Trace.AgentWriterBenchmark.WriteAndFlushEnrichedTraces net6.0

  • 🟥 allocated_mem [+1.012KB; +1.012KB] or [+37.524%; +37.537%]
  • 🟥 execution_time [+377.003ms; +381.597ms] or [+297.855%; +301.485%]
  • 🟩 throughput [+69.513op/s; +70.935op/s] or [+9.165%; +9.353%]

scenario:Benchmarks.Trace.AgentWriterBenchmark.WriteAndFlushEnrichedTraces netcoreapp3.1

  • 🟥 allocated_mem [+1.088KB; +1.088KB] or [+40.343%; +40.355%]
  • 🟥 execution_time [+394.729ms; +398.947ms] or [+349.320%; +353.053%]

scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.AllCycleMoreComplexBody net472

  • 🟥 allocated_mem [+4.734KB; +4.734KB] or [+99.652%; +99.667%]
  • 🟥 throughput [-60345.054op/s; -59946.024op/s] or [-46.952%; -46.641%]

scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.AllCycleMoreComplexBody net6.0

  • 🟥 allocated_mem [+3.856KB; +3.856KB] or [+81.546%; +81.558%]
  • 🟩 execution_time [-15.703ms; -11.530ms] or [-7.334%; -5.385%]
  • 🟥 throughput [-61345.340op/s; -58584.531op/s] or [-44.779%; -42.763%]

scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.AllCycleMoreComplexBody netcoreapp3.1

  • 🟥 allocated_mem [+4.583KB; +4.584KB] or [+99.120%; +99.133%]
  • 🟥 throughput [-48899.551op/s; -46651.102op/s] or [-44.211%; -42.178%]

scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.AllCycleSimpleBody net472

  • 🟥 allocated_mem [+1.356KB; +1.356KB] or [+109.716%; +109.731%]
  • 🟥 throughput [-293796.927op/s; -290059.549op/s] or [-29.998%; -29.616%]

scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.AllCycleSimpleBody net6.0

  • 🟥 allocated_mem [+519 bytes; +520 bytes] or [+42.477%; +42.486%]
  • 🟩 execution_time [-26.480ms; -21.633ms] or [-11.809%; -9.647%]
  • 🟥 throughput [-101961.461op/s; -79309.997op/s] or [-10.893%; -8.473%]

scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.AllCycleSimpleBody netcoreapp3.1

  • 🟥 allocated_mem [+1.320KB; +1.320KB] or [+109.261%; +109.277%]
  • 🟥 throughput [-174561.914op/s; -158578.962op/s] or [-25.081%; -22.785%]

scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.ObjectExtractorMoreComplexBody net472

  • 🟥 allocated_mem [+3.378KB; +3.378KB] or [+89.003%; +89.017%]
  • 🟥 throughput [-72645.085op/s; -71864.092op/s] or [-48.889%; -48.364%]

scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.ObjectExtractorMoreComplexBody net6.0

  • 🟥 allocated_mem [+3.336KB; +3.336KB] or [+88.150%; +88.161%]
  • 🟥 throughput [-74953.645op/s; -72061.889op/s] or [-47.692%; -45.852%]

scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.ObjectExtractorMoreComplexBody netcoreapp3.1

  • 🟥 allocated_mem [+3.264KB; +3.264KB] or [+88.493%; +88.506%]
  • 🟥 throughput [-56115.464op/s; -53484.992op/s] or [-44.703%; -42.608%]

scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.ObjectExtractorSimpleBody net6.0

  • 🟩 throughput [+157357.768op/s; +214216.763op/s] or [+5.247%; +7.143%]

scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.ObjectExtractorSimpleBody netcoreapp3.1

  • 🟩 execution_time [-19.653ms; -14.979ms] or [-9.059%; -6.905%]

scenario:Benchmarks.Trace.Asm.AppSecEncoderBenchmark.EncodeArgs net472

  • 🟩 allocated_mem [-13.759KB; -13.756KB] or [-42.324%; -42.316%]
  • 🟥 execution_time [+300.397ms; +301.265ms] or [+150.098%; +150.532%]
  • 🟩 throughput [+1008.746op/s; +1030.237op/s] or [+11.141%; +11.379%]

scenario:Benchmarks.Trace.Asm.AppSecEncoderBenchmark.EncodeArgs net6.0

  • 🟩 allocated_mem [-13.722KB; -13.718KB] or [-42.341%; -42.329%]
  • 🟥 execution_time [+299.622ms; +302.853ms] or [+151.100%; +152.730%]
  • 🟩 throughput [+2296.850op/s; +2508.266op/s] or [+17.567%; +19.184%]

scenario:Benchmarks.Trace.Asm.AppSecEncoderBenchmark.EncodeArgs netcoreapp3.1

  • 🟩 allocated_mem [-13.722KB; -13.718KB] or [-42.341%; -42.329%]
  • 🟥 execution_time [+299.827ms; +302.193ms] or [+151.030%; +152.221%]
  • 🟩 throughput [+1783.092op/s; +1908.040op/s] or [+17.215%; +18.421%]

scenario:Benchmarks.Trace.Asm.AppSecEncoderBenchmark.EncodeLegacyArgs net472

  • 🟥 execution_time [+296.490ms; +297.495ms] or [+145.624%; +146.118%]
  • 🟩 throughput [+578.230op/s; +596.789op/s] or [+15.329%; +15.821%]

scenario:Benchmarks.Trace.Asm.AppSecEncoderBenchmark.EncodeLegacyArgs net6.0

  • 🟥 execution_time [+297.769ms; +299.325ms] or [+145.568%; +146.329%]
  • 🟩 throughput [+2770.272op/s; +2849.733op/s] or [+40.247%; +41.401%]

scenario:Benchmarks.Trace.Asm.AppSecEncoderBenchmark.EncodeLegacyArgs netcoreapp3.1

  • 🟥 execution_time [+299.945ms; +300.719ms] or [+149.912%; +150.299%]
  • 🟩 throughput [+1419.817op/s; +1434.356op/s] or [+28.182%; +28.471%]

scenario:Benchmarks.Trace.Asm.AppSecWafBenchmark.RunWafRealisticBenchmark net472

  • 🟩 execution_time [-146.298µs; -142.470µs] or [-30.037%; -29.251%]
  • 🟩 throughput [+853.180op/s; +877.885op/s] or [+41.554%; +42.757%]

scenario:Benchmarks.Trace.Asm.AppSecWafBenchmark.RunWafRealisticBenchmark net6.0

  • 🟩 execution_time [-126.675µs; -99.104µs] or [-29.053%; -22.730%]
  • 🟩 throughput [+730.776op/s; +868.783op/s] or [+31.771%; +37.771%]

scenario:Benchmarks.Trace.Asm.AppSecWafBenchmark.RunWafRealisticBenchmark netcoreapp3.1

  • 🟩 execution_time [-142.634µs; -120.498µs] or [-30.560%; -25.817%]
  • 🟩 throughput [+775.429op/s; +860.976op/s] or [+35.795%; +39.744%]

scenario:Benchmarks.Trace.Asm.AppSecWafBenchmark.RunWafRealisticBenchmarkWithAttack net472

  • 🟩 execution_time [-124.454µs; -119.774µs] or [-33.602%; -32.338%]
  • 🟩 throughput [+1301.399op/s; +1358.641op/s] or [+48.198%; +50.318%]

scenario:Benchmarks.Trace.Asm.AppSecWafBenchmark.RunWafRealisticBenchmarkWithAttack net6.0

  • 🟩 execution_time [-96.801µs; -73.149µs] or [-30.904%; -23.353%]
  • 🟩 throughput [+1072.932op/s; +1276.623op/s] or [+33.446%; +39.796%]

scenario:Benchmarks.Trace.Asm.AppSecWafBenchmark.RunWafRealisticBenchmarkWithAttack netcoreapp3.1

  • 🟩 execution_time [-138.617µs; -116.227µs] or [-37.920%; -31.795%]
  • 🟩 throughput [+1345.152op/s; +1482.245op/s] or [+48.272%; +53.192%]

scenario:Benchmarks.Trace.AspNetCoreBenchmark.SendRequest net472

  • 🟥 execution_time [+299.528ms; +300.254ms] or [+149.495%; +149.858%]

scenario:Benchmarks.Trace.AspNetCoreBenchmark.SendRequest net6.0

  • unstable execution_time [+322.126ms; +393.299ms] or [+350.004%; +427.336%]

scenario:Benchmarks.Trace.AspNetCoreBenchmark.SendRequest netcoreapp3.1

  • unstable execution_time [+268.321ms; +321.973ms] or [+203.733%; +244.471%]

scenario:Benchmarks.Trace.CIVisibilityProtocolWriterBenchmark.WriteAndFlushEnrichedTraces net472

  • unstable execution_time [+352.313ms; +413.935ms] or [+161.990%; +190.323%]
  • 🟥 throughput [-553.328op/s; -505.388op/s] or [-50.137%; -45.793%]

scenario:Benchmarks.Trace.CIVisibilityProtocolWriterBenchmark.WriteAndFlushEnrichedTraces net6.0

  • unstable execution_time [+208.265ms; +341.502ms] or [+88.754%; +145.534%]
  • 🟥 throughput [-668.032op/s; -584.589op/s] or [-44.558%; -38.992%]

scenario:Benchmarks.Trace.CIVisibilityProtocolWriterBenchmark.WriteAndFlushEnrichedTraces netcoreapp3.1

  • 🟥 execution_time [+324.538ms; +335.077ms] or [+194.111%; +200.415%]
  • 🟥 throughput [-385.504op/s; -347.355op/s] or [-26.842%; -24.186%]

scenario:Benchmarks.Trace.CharSliceBenchmark.OriginalCharSlice net6.0

  • 🟩 execution_time [-160.825µs; -123.717µs] or [-8.147%; -6.267%]
  • 🟩 throughput [+34.909op/s; +45.080op/s] or [+6.891%; +8.899%]

scenario:Benchmarks.Trace.ElasticsearchBenchmark.CallElasticsearch net472

  • 🟥 execution_time [+302.079ms; +303.675ms] or [+152.121%; +152.925%]

scenario:Benchmarks.Trace.ElasticsearchBenchmark.CallElasticsearch net6.0

  • 🟥 execution_time [+299.439ms; +300.939ms] or [+150.050%; +150.801%]
  • 🟩 throughput [+46755.960op/s; +50903.170op/s] or [+7.372%; +8.025%]

scenario:Benchmarks.Trace.ElasticsearchBenchmark.CallElasticsearch netcoreapp3.1

  • 🟥 execution_time [+300.421ms; +304.247ms] or [+150.919%; +152.841%]
  • 🟩 throughput [+29252.672op/s; +36941.103op/s] or [+6.162%; +7.782%]

scenario:Benchmarks.Trace.ElasticsearchBenchmark.CallElasticsearchAsync net472

  • 🟥 execution_time [+304.738ms; +306.265ms] or [+153.029%; +153.796%]

scenario:Benchmarks.Trace.ElasticsearchBenchmark.CallElasticsearchAsync net6.0

  • 🟥 execution_time [+296.006ms; +298.837ms] or [+146.362%; +147.761%]

scenario:Benchmarks.Trace.ElasticsearchBenchmark.CallElasticsearchAsync netcoreapp3.1

  • 🟥 execution_time [+303.047ms; +306.658ms] or [+153.597%; +155.427%]

scenario:Benchmarks.Trace.GraphQLBenchmark.ExecuteAsync net472

  • 🟥 execution_time [+299.361ms; +302.162ms] or [+150.252%; +151.658%]

scenario:Benchmarks.Trace.GraphQLBenchmark.ExecuteAsync net6.0

  • 🟥 execution_time [+300.165ms; +302.548ms] or [+149.605%; +150.793%]
  • 🟩 throughput [+47195.627op/s; +54871.796op/s] or [+9.372%; +10.896%]

scenario:Benchmarks.Trace.GraphQLBenchmark.ExecuteAsync netcoreapp3.1

  • 🟥 execution_time [+301.672ms; +305.164ms] or [+150.079%; +151.816%]

scenario:Benchmarks.Trace.ILoggerBenchmark.EnrichedLog net6.0

  • 🟩 execution_time [-16.518ms; -12.864ms] or [-7.681%; -5.982%]

scenario:Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatAspectBenchmark net472

  • unstable execution_time [+10.798µs; +57.416µs] or [+2.667%; +14.182%]

scenario:Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatAspectBenchmark net6.0

  • 🟩 allocated_mem [-20.519KB; -20.497KB] or [-7.485%; -7.477%]
  • unstable execution_time [-25.184µs; +32.795µs] or [-4.977%; +6.482%]
  • unstable throughput [-118.076op/s; +83.072op/s] or [-5.892%; +4.145%]

scenario:Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatAspectBenchmark netcoreapp3.1

  • 🟩 allocated_mem [-14.944KB; -14.924KB] or [-5.448%; -5.441%]
  • unstable execution_time [-57.593µs; +6.548µs] or [-9.981%; +1.135%]
  • unstable throughput [-1.079op/s; +176.336op/s] or [-0.062%; +10.074%]

scenario:Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatBenchmark net6.0

  • 🟥 execution_time [+8.390µs; +11.992µs] or [+19.832%; +28.346%]
  • 🟥 throughput [-5516.182op/s; -3827.373op/s] or [-23.221%; -16.112%]

scenario:Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatBenchmark netcoreapp3.1

  • unstable execution_time [-14.183µs; -5.927µs] or [-22.005%; -9.195%]
  • unstable throughput [+1562.584op/s; +3339.301op/s] or [+9.587%; +20.488%]

scenario:Benchmarks.Trace.Log4netBenchmark.EnrichedLog net472

  • 🟥 execution_time [+302.858ms; +304.414ms] or [+153.081%; +153.868%]

scenario:Benchmarks.Trace.Log4netBenchmark.EnrichedLog net6.0

  • 🟥 execution_time [+302.746ms; +305.564ms] or [+154.097%; +155.531%]

scenario:Benchmarks.Trace.Log4netBenchmark.EnrichedLog netcoreapp3.1

  • 🟥 execution_time [+297.791ms; +301.099ms] or [+149.081%; +150.737%]

scenario:Benchmarks.Trace.RedisBenchmark.SendReceive net472

  • 🟥 throughput [-30436.420op/s; -28780.265op/s] or [-8.426%; -7.967%]

scenario:Benchmarks.Trace.RedisBenchmark.SendReceive net6.0

  • 🟩 throughput [+30265.210op/s; +36895.481op/s] or [+5.729%; +6.984%]

scenario:Benchmarks.Trace.SerilogBenchmark.EnrichedLog net472

  • 🟥 execution_time [+299.686ms; +301.630ms] or [+149.366%; +150.336%]

scenario:Benchmarks.Trace.SerilogBenchmark.EnrichedLog net6.0

  • 🟥 execution_time [+302.322ms; +304.077ms] or [+151.812%; +152.693%]

scenario:Benchmarks.Trace.SerilogBenchmark.EnrichedLog netcoreapp3.1

  • 🟥 execution_time [+303.264ms; +306.209ms] or [+153.796%; +155.289%]

scenario:Benchmarks.Trace.SingleSpanAspNetCoreBenchmark.SingleSpanAspNetCore net472

  • 🟥 execution_time [+301.219ms; +301.991ms] or [+150.250%; +150.635%]
  • 🟩 throughput [+60793638.177op/s; +61118980.821op/s] or [+44.274%; +44.511%]

scenario:Benchmarks.Trace.SingleSpanAspNetCoreBenchmark.SingleSpanAspNetCore net6.0

  • 🟥 execution_time [+423.846ms; +426.738ms] or [+527.128%; +530.725%]

scenario:Benchmarks.Trace.SingleSpanAspNetCoreBenchmark.SingleSpanAspNetCore netcoreapp3.1

  • 🟥 execution_time [+299.666ms; +300.708ms] or [+149.467%; +149.986%]

scenario:Benchmarks.Trace.SpanBenchmark.StartFinishScope net6.0

  • 🟩 throughput [+69652.464op/s; +81409.710op/s] or [+6.503%; +7.601%]

scenario:Benchmarks.Trace.SpanBenchmark.StartFinishScope netcoreapp3.1

  • 🟩 throughput [+43806.235op/s; +62900.436op/s] or [+5.070%; +7.281%]

scenario:Benchmarks.Trace.SpanBenchmark.StartFinishSpan net6.0

  • 🟩 throughput [+66774.172op/s; +98959.602op/s] or [+5.168%; +7.660%]

scenario:Benchmarks.Trace.SpanBenchmark.StartFinishSpan netcoreapp3.1

  • 🟩 throughput [+64911.888op/s; +73413.233op/s] or [+6.447%; +7.291%]

scenario:Benchmarks.Trace.SpanBenchmark.StartFinishTwoScopes net6.0

  • 🟩 throughput [+41509.329op/s; +48768.869op/s] or [+7.537%; +8.856%]

scenario:Benchmarks.Trace.TraceAnnotationsBenchmark.RunOnMethodBegin net6.0

  • 🟩 throughput [+60082.119op/s; +80007.098op/s] or [+6.713%; +8.939%]

Known flaky benchmarks without significant changes:

  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_AddEvent_Sampled net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_AddEvent_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_AddEvent_Sampled netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_GetContext_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_GetContext_Sampled netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_SetAttributes_Sampled net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_SetAttributes_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_SetAttributes_Sampled netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_SetStatus_Sampled net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_SetStatus_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_SetStatus_Sampled netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_UpdateName_Sampled net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_UpdateName_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_UpdateName_Sampled netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_AddEvent_Sampled net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_AddEvent_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_AddEvent_Sampled netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_GetContext_Sampled net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_GetContext_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_GetContext_Sampled netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_RecordException_Sampled net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_RecordException_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_RecordException_Sampled netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_SetAttributes_Sampled net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_SetAttributes_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_SetAttributes_Sampled netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_SetStatus_Sampled net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_SetStatus_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_SetStatus_Sampled netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_UpdateName_Sampled net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_UpdateName_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_UpdateName_Sampled netcoreapp3.1
  • scenario:Benchmarks.Trace.ActivityBenchmark.StartStopWithChild net6.0
  • scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.ObjectExtractorSimpleBody net472
  • scenario:Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSlice net472
  • scenario:Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSlice net6.0
  • scenario:Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSlice netcoreapp3.1
  • scenario:Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSliceWithPool net472
  • scenario:Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSliceWithPool net6.0
  • scenario:Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSliceWithPool netcoreapp3.1
  • scenario:Benchmarks.Trace.CharSliceBenchmark.OriginalCharSlice net472
  • scenario:Benchmarks.Trace.CharSliceBenchmark.OriginalCharSlice netcoreapp3.1
  • scenario:Benchmarks.Trace.ILoggerBenchmark.EnrichedLog net472
  • scenario:Benchmarks.Trace.ILoggerBenchmark.EnrichedLog netcoreapp3.1
  • scenario:Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatBenchmark net472
  • scenario:Benchmarks.Trace.RedisBenchmark.SendReceive netcoreapp3.1
  • scenario:Benchmarks.Trace.SpanBenchmark.StartFinishScope net472
  • scenario:Benchmarks.Trace.SpanBenchmark.StartFinishSpan net472
  • scenario:Benchmarks.Trace.SpanBenchmark.StartFinishTwoScopes net472
  • scenario:Benchmarks.Trace.SpanBenchmark.StartFinishTwoScopes netcoreapp3.1
  • scenario:Benchmarks.Trace.TraceAnnotationsBenchmark.RunOnMethodBegin net472
  • scenario:Benchmarks.Trace.TraceAnnotationsBenchmark.RunOnMethodBegin netcoreapp3.1

@dd-trace-dotnet-ci-bot

dd-trace-dotnet-ci-bot Bot commented Aug 14, 2026

Copy link
Copy Markdown

Execution-Time Benchmarks Report ⏱️

Execution-time results for samples comparing This PR (9044) and master.

✅ No regressions detected

📄 View the full report (charts + all metrics) →

@pavlokhrebto
pavlokhrebto marked this pull request as ready for review August 14, 2026 14:38
@pavlokhrebto
pavlokhrebto requested review from a team as code owners August 14, 2026 14:38
@pavlokhrebto
pavlokhrebto requested review from sameerank and typotter and removed request for a team August 14, 2026 14:38

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 613a808d7d

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread tracer/src/Datadog.Trace/FeatureFlags/FeatureFlagsModule.cs Outdated
Comment thread tracer/src/Datadog.Trace/Configuration/TracerSettings.cs Outdated
Comment thread tracer/src/Datadog.Trace/FeatureFlags/FeatureFlagsModule.cs Outdated
Comment thread tracer/src/Datadog.Trace/FeatureFlags/FeatureFlagsModule.cs Outdated
Comment thread tracer/src/Datadog.Trace/Configuration/TracerSettings.cs Outdated
Comment thread tracer/src/Datadog.Trace/FeatureFlags/FeatureFlagsModule.cs Outdated
Comment thread tracer/src/Datadog.Trace/FeatureFlags/FeatureFlagsModule.cs Outdated
Comment thread tracer/src/Datadog.Trace/FeatureFlags/FeatureFlagsModule.cs Outdated
Comment thread tracer/src/Datadog.Trace/FeatureFlags/FeatureFlagsModule.cs Outdated
Comment thread tracer/src/Datadog.Trace/FeatureFlags/FeatureFlagsModule.cs Outdated
Comment thread tracer/src/Datadog.Trace/FeatureFlags/FeatureFlagsModule.cs Outdated
Comment thread tracer/src/Datadog.Trace/FeatureFlags/FeatureFlagsModule.cs Outdated
Comment thread tracer/src/Datadog.FeatureFlags.OpenFeature/Sdk/FeatureFlagsSdk.cs Outdated
@aarsilv

aarsilv commented Sep 8, 2026

Copy link
Copy Markdown

🤖 Comment from Claude working with Aaron Silverman:

[P2] Five description items disagree with the code, and the four largest changes are missing.

Description Code
"InitializeAsync() ... skips the wait if no delivery started" line 213 throws FeatureFlagsDeliveryUnavailableException
"FeatureFlagsModuleTests (9 tests)" 14 [Fact], 13 new
"returns immediately when agentless source cannot start" that test asserts ThrowAsync
"TracerSettings replaces IsFlaggingProviderEnabled with FeatureFlagsSettings FeatureFlags" FeatureFlags already exists on master; this PR only deletes the old property
"ApplyConfiguration() public method" internal bool ApplyConfiguration(...)

Please add:

  • Feature Flags now default to enabled, with agentless as the default source. This PR is the first
    reader of FeatureFlagsSettings.Enabled, so the default takes effect here. An application that has
    the OpenFeature provider installed and never set the legacy key starts agentless polling on first
    provider use when DD_API_KEY is present. An application without the provider package allocates the
    module and never activates it, so it makes no requests.
  • The DatadogProvider event payload rewrite, which fixes master emitting a ProviderReady-typed
    payload for configuration updates. The new public InitializeAsync override is also
    customer-visible: it changes what SetProviderAsync waits for.
  • The fallback Activate() in both evaluate integrations.
  • FeatureFlagsDeliveryUnavailableException, whose message reaches customers verbatim.

@bouwkast bouwkast left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have one main question on the Initialization logic

Feel free to re-request my review 👍

Comment thread tracer/src/Datadog.FeatureFlags.OpenFeature/DatadogProvider.cs Outdated
Comment thread tracer/src/Datadog.FeatureFlags.OpenFeature/DatadogProvider.cs
@pavlokhrebto
pavlokhrebto merged commit 2fc9759 into master Sep 14, 2026
145 checks passed
@pavlokhrebto
pavlokhrebto deleted the pavlo.khrebto/EX-2703/ffe-module-wiring branch September 14, 2026 10:11
@github-actions github-actions Bot added this to the vNext-v3 milestone Sep 14, 2026
pavlokhrebto added a commit that referenced this pull request Sep 17, 2026
…9260)

## Summary of changes

Removes `Datadog.Trace.FeatureFlags.FeatureFlagsSdk`, the manual
non-OpenFeature Feature Flags
API, from `Datadog.Trace.Manual`, along with its three CallTargets and
its test sample.
OpenFeature (`Datadog.FeatureFlags.OpenFeature`) becomes the only way to
evaluate flags in .NET.

## Reason for change

.NET was the only tracer with a second, Datadog-specific evaluation
surface — Java, Go and Node
ship OpenFeature only. If OpenFeature is the intended supported
approach, the duplicate is better
removed now, while Feature Flags is experimental and gated behind
`DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED`, than after customers adopt
it.

The surface shipped in v3.36.0 (#7896). It is undocumented and excluded
from the public API
snapshot: `PublicApiTestsBase` skips types carrying both
`[Browsable(false)]` and
`[EditorBrowsable(Never)]`, so `FeatureFlagsSdk` appears nowhere in

`PublicApiTests.Datadog.Trace.Manual.PublicApiHasNotChanged.verified.txt`.

It also makes sense to remove it now while no customers use it.

## Implementation details

Deleted:
- `Datadog.Trace.Manual/FeatureFlags/` — `FeatureFlagsSdk`,
`EvaluationContext`, `IEvaluation.Manual`
- `ManualInstrumentation/FeatureFlags/` — the `Evaluate`, `IsAvailable`
and
  `RegisterOnNewConfigEventHandler` CallTargets
- the three `<Compile Include>` links in `Datadog.Trace.Manual.csproj`
(`EvaluationReason`,
`ValueType`, `IEvaluation`). `Datadog.FeatureFlags.OpenFeature.csproj`
links its own copies
  straight from `Datadog.Trace` and is unaffected
- the `Samples.FeatureFlags` project, with its `Datadog.Trace.sln` and
CODEOWNERS entries

`Program.cs` was shared by both samples through a `<Compile Include>`
link, so it moves into
`Samples.OpenFeature` and the link is dropped.

Generated files regenerated with `CompileManagedSrc` and
`RegenerateSolutions`. The diffs are pure
deletions of the three rows, with no signature renumbering.

## Test coverage

`FeatureFlagsTests`, `OpenFeatureFeatureFlagsTests` and
`FeatureFlagsTestsBase` collapse into a
single `FeatureFlagsTests` on the OpenFeature sample. Coverage of the
manual surface goes away
with the surface itself.

Two sample-side improvements come with the move:
- `Samples.OpenFeature`'s `Evaluator.Init()` awaits `SetProviderAsync`
instead of calling `.Wait()`
- a new `<INITIALIZED: READY>` probe and assertion — the only coverage
of the OpenFeature
  `InitializeAsync` CallTarget merged in #9044

## Other details

Breaking change for anyone calling
`Datadog.Trace.FeatureFlags.FeatureFlagsSdk` directly.
pavlokhrebto added a commit that referenced this pull request Sep 18, 2026
…ump the OpenFeature package (#9264)

## Summary of changes

- `FeatureFlagsModule.RegisterOnNewConfigEventHandler` now invokes the
handler immediately when a configuration is already held.
- `Datadog.FeatureFlags.OpenFeature` package version 2.3.0 → 2.3.1.

## Reason for change

The Remote Configuration subscription is live from module construction,
which is tracer startup. Application code builds the provider and
registers the configuration handler much later. The handler only fired
on a change, so a configuration that arrived in that window never
reached it, and an application that waits on the handler as its
readiness signal waits forever.

`Datadog.FeatureFlags.OpenFeature` 2.3.0 is already published on
nuget.org and is immutable. The `InitializeAsync` fix in #9044 rewrites
a method that lives in that package, so it cannot reach any customer
until the package version moves.

## Implementation details

Registration reads `_evaluator`. A non-null value means a configuration
was applied, so the handler is invoked once at registration. The invoke
is wrapped in a try/catch that logs a warning, matching
`ApplyConfiguration`: the handler is application code and must not fail
the caller.

2.3.1 follows the scheme documented in the csproj: the first two digits
mirror the referenced OpenFeature version, the third digit is our own
patch counter. The `OpenFeature` `PackageReference` stays at 2.3.0.

## Test coverage

Three facts in `FeatureFlagsModuleTests`: the handler runs when it
registers after a configuration was applied, it does not run when no
configuration has arrived, and a throwing handler does not propagate out
of registration.

## Other details

Both changes address FFL-2468. The remaining half of that ticket, the
`InitializeAsync` wait, is already on master via #9044. Together with
this PR the next release carries the complete fix.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI Generated Largely based on code generated by an AI or LLM. This label is the same across all dd-trace-* repos docker_image_artifacts Use to label PRs for which you would need a Docker Image created for. feature_flags type:new-feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants