Skip to content

feat: add /trace/manual_keep_drop endpoint to all weblogs - #7407

Merged
genesor merged 91 commits into
mainfrom
ben.db/feat-manual-keep-drop-endpoint
Jul 31, 2026
Merged

feat: add /trace/manual_keep_drop endpoint to all weblogs#7407
genesor merged 91 commits into
mainfrom
ben.db/feat-manual-keep-drop-endpoint

Conversation

@genesor

@genesor genesor commented Jul 29, 2026

Copy link
Copy Markdown
Member

Motivation

Nothing in the end-to-end suite can force a trace's sampling decision. The manual keep/drop API was only reachable from the parametric apps, so the "a manual decision overrides everything else" contract had no end-to-end coverage, and no weblog exposed an entry point for it.

Changes

New weblog endpoint

GET /trace/manual_keep_drop?decision=keep|drop applies the tracer's manual keep/drop API to the current trace and returns 200. A missing or invalid decision returns 400. Documented in docs/understand/weblogs/end-to-end_weblog.md.

Implemented in every end-to-end weblog, one commit per variant, using each library's own manual keep/drop API:

library mechanism weblogs
java GlobalTracer.get().activeSpan() + DDTags.MANUAL_KEEP / MANUAL_DROP spring-boot, spring-boot-3-native, vertx3, vertx4, akka-http, ratpack, play, jersey-grizzly2, resteasy-netty3
python tracer.current_span().set_tag(MANUAL_KEEP_KEY / MANUAL_DROP_KEY) flask, django, fastapi, tornado
nodejs tracer.scope().active().setTag(MANUAL_KEEP / MANUAL_DROP, true), constants from ext.tags express4, express5, express4-typescript, fastify, nextjs
dotnet Tracer.Instance.ActiveScope?.Span.SetTag(Tags.ManualKeep / ManualDrop, "true") weblog, via Endpoints/ManualKeepDropEndpoint.cs
ruby Datadog::Tracing.active_trace.keep! / .reject! rails42, rails52, rails61, rails72, rails80, sinatra14, sinatra22, sinatra32, sinatra41, rack
golang shared common.ManualKeepDrop handler + ext.ManualKeep / ext.ManualDrop net-http, gin, echo, chi, net-http-orchestrion, gqlgen, graphql-go, graph-gophers
php \DDTrace\set_priority_sampling(...) plain, symfony7x, laravel11x

cpp and rust are skipped: they have no end-to-end weblog, only parametric.

Notes on three of those choices:

  • golang: the handler lives once in app/_shared/common/common.go as an http.HandlerFunc, matching how rasp.LFI, common.Requestdownstream and dbm.StubDbmHandler are already shared. gin and echo reuse the existing ginHandleFunc / echoHandleFunc adapters.
  • php: set_priority_sampling is what \DDTrace\Span::setTag itself calls for the manual.keep / manual.drop tags. Writing the tag into span meta was not viable: in symfony and laravel \DDTrace\active_span() is the symfony.controller / laravel.action child span rather than the root, and the meta path is skipped entirely when a keep decision was propagated from upstream.
  • nodejs: express4 and express5 share utils/build/docker/nodejs/express/app.js, so a single commit covers both. nextjs uses global._ddtrace and the literal tag names, matching its neighbouring routes, which avoid direct dd-trace imports because of webpack bundling.

Parametric fix

utils/build/docker/nodejs/parametric/server.js destructured MANUAL_KEEP / MANUAL_DROP off the top level of dd-trace/ext, where they do not exist (they live under ext.tags). It was therefore calling span.setTag(undefined, true), so the existing nodejs parametric manual-keep coverage was asserting nothing.

Tests

tests/test_sampling_manual.py::Test_Manual_Sampling, SAMPLING scenario, @features.ensure_that_sampling_is_consistent_across_languages. Both directions are driven by an upstream distributed trace context, so each case asserts that the manual decision wins over a propagated one:

test upstream x-datadog-sampling-priority decision expected _sampling_priority_v1
test_manual_keep_overrides_upstream_drop 0 (auto reject) keep 2 (user keep)
test_manual_drop_overrides_upstream_keep 2 (user keep) drop -1 (user reject)

The SAMPLING scenario is used because it sets DD_TRACE_STATS_COMPUTATION_ENABLED=false, so dropped P-1 traces still reach the agent and the drop case is observable. A manual decision takes precedence over that scenario's 0.5 sample rate, so the rate does not affect either assertion.

Impact

The drop direction is new ground: the parametric suite only ever covered manual keep overriding an upstream drop. Asserting the reverse surfaced two library gaps, both declared in the manifests so they run as xfail and turn into an xpass when fixed.

library declaration reason
java bug (APMAPI-2194) on test_manual_drop_overrides_upstream_keep APMAPI-2194: manual.keep goes through DDSpanContext.forceKeep(), an unconditional update that deliberately wins over an already propagated decision, while manual.drop goes through setSamplingPriority(), a compare-and-set from UNSET that refuses when the priority is locked. Keep can override, drop cannot.
nodejs bug (APMAPI-1720) on the whole class APMAPI-1720: PrioritySampler.sample() returns early whenever a priority already exists, before it reads the manual tags, so neither direction is honoured.

APMAPI-2194 is filed separately rather than folded into APMAPI-1720 because 1720's analysis only covers the keep direction and lists java as working.

dotnet, golang, php, python and ruby honour both directions.

Weblogs with no SDK to call also get declarations, since they run the SAMPLING scenario:

manifest declaration
c.yml (perl-mojolicious) missing_feature, dd-trace-c does not implement manual keep/drop
cpp_httpd.yml missing_feature, endpoint not implemented
cpp_kong.yml, cpp_nginx.yml irrelevant, proxy rather than an application
java_otel.yml, nodejs_otel.yml, python_otel.yml irrelevant, the OpenTelemetry test library has no Datadog manual keep/drop

Workflow

  1. ⚠️ Create your PR as draft ⚠️
  2. Work on you PR until the CI passes
  3. Mark it as ready for review
    • Test logic is modified? -> Get a review from RFC owner.
    • Framework is modified, or non obvious usage of it -> get a review from R&P team

🚀 Once your PR is reviewed and the CI green, you can merge it!

🛟 #apm-shared-testing 🛟

Reviewer checklist

  • Anything but tests/ or manifests/ is modified ? I have the approval from R&P team
  • A docker base image is modified?
    • the relevant build-XXX-image label is present
  • A scenario is added, removed or renamed?

@github-actions

github-actions Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

CODEOWNERS have been resolved as:

tests/test_sampling_manual.py                                           @DataDog/system-tests-core
utils/build/docker/dotnet/weblog/Endpoints/ManualKeepDropEndpoint.cs    @DataDog/apm-dotnet @DataDog/asm-dotnet @DataDog/system-tests-core
utils/build/docker/nodejs/nextjs/src/app/trace/manual_keep_drop/route.js  @DataDog/dd-trace-js @DataDog/system-tests-core
utils/build/docker/php/weblogs/plain/trace_manual_keep_drop.php         @DataDog/apm-php @DataDog/system-tests-core
.github/workflows/run-end-to-end.yml                                    @DataDog/system-tests-core
.github/workflows/system-tests.yml                                      @DataDog/system-tests-core
docs/understand/weblogs/end-to-end_weblog.md                            @DataDog/system-tests-core
manifests/c.yml                                                         @DataDog/system-tests-core
manifests/cpp_httpd.yml                                                 @DataDog/dd-trace-cpp
manifests/cpp_kong.yml                                                  @DataDog/system-tests-core
manifests/cpp_nginx.yml                                                 @DataDog/dd-trace-cpp
manifests/dotnet.yml                                                    @DataDog/apm-dotnet @DataDog/asm-dotnet
manifests/golang.yml                                                    @DataDog/dd-trace-go-guild
manifests/java.yml                                                      @DataDog/asm-java @DataDog/apm-java
manifests/java_otel.yml                                                 @DataDog/system-tests-core
manifests/nodejs.yml                                                    @DataDog/dd-trace-js
manifests/nodejs_otel.yml                                               @DataDog/system-tests-core
manifests/php.yml                                                       @DataDog/apm-php @DataDog/asm-php
manifests/python_otel.yml                                               @DataDog/apm-python @DataDog/asm-python
manifests/ruby.yml                                                      @DataDog/ruby-guild @DataDog/asm-ruby
manifests/rust.yml                                                      @DataDog/apm-rust
utils/build/docker/golang/app/_shared/common/common.go                  @DataDog/dd-trace-go-guild @DataDog/system-tests-core
utils/build/docker/golang/app/chi/main.go                               @DataDog/dd-trace-go-guild @DataDog/system-tests-core
utils/build/docker/golang/app/echo/main.go                              @DataDog/dd-trace-go-guild @DataDog/system-tests-core
utils/build/docker/golang/app/gin/main.go                               @DataDog/dd-trace-go-guild @DataDog/system-tests-core
utils/build/docker/golang/app/gqlgen/server.go                          @DataDog/dd-trace-go-guild @DataDog/system-tests-core
utils/build/docker/golang/app/graph-gophers/main.go                     @DataDog/dd-trace-go-guild @DataDog/system-tests-core
utils/build/docker/golang/app/graphql-go/main.go                        @DataDog/dd-trace-go-guild @DataDog/system-tests-core
utils/build/docker/golang/app/net-http-orchestrion/main.go              @DataDog/dd-trace-go-guild @DataDog/system-tests-core
utils/build/docker/golang/app/net-http-span-pool/main.go                @DataDog/dd-trace-go-guild @DataDog/system-tests-core
utils/build/docker/golang/app/net-http/main.go                          @DataDog/dd-trace-go-guild @DataDog/system-tests-core
utils/build/docker/java/akka-http/src/main/scala/com/datadoghq/akka_http/AppSecRoutes.scala  @DataDog/apm-java @DataDog/asm-java @DataDog/system-tests-core
utils/build/docker/java/jersey-grizzly2/src/main/java/com/datadoghq/jersey/MyResource.java  @DataDog/apm-java @DataDog/asm-java @DataDog/system-tests-core
utils/build/docker/java/play/app/controllers/AppSecController.scala     @DataDog/apm-java @DataDog/asm-java @DataDog/system-tests-core
utils/build/docker/java/play/conf/routes                                @DataDog/apm-java @DataDog/asm-java @DataDog/system-tests-core
utils/build/docker/java/ratpack/src/main/java/com/datadoghq/ratpack/Main.java  @DataDog/apm-java @DataDog/asm-java @DataDog/system-tests-core
utils/build/docker/java/resteasy-netty3/src/main/java/com/datadoghq/resteasy/MyResource.java  @DataDog/apm-java @DataDog/asm-java @DataDog/system-tests-core
utils/build/docker/java/spring-boot-3-native/src/main/java/com/datadoghq/springbootnative/WebController.java  @DataDog/apm-java @DataDog/asm-java @DataDog/system-tests-core
utils/build/docker/java/spring-boot/src/main/java/com/datadoghq/system_tests/springboot/App.java  @DataDog/apm-java @DataDog/asm-java @DataDog/system-tests-core
utils/build/docker/java/vertx3/src/main/java/com/datadoghq/vertx3/Main.java  @DataDog/apm-java @DataDog/asm-java @DataDog/system-tests-core
utils/build/docker/java/vertx4/src/main/java/com/datadoghq/vertx4/Main.java  @DataDog/apm-java @DataDog/asm-java @DataDog/system-tests-core
utils/build/docker/nodejs/express/app.js                                @DataDog/dd-trace-js @DataDog/system-tests-core
utils/build/docker/nodejs/express4-typescript/app.ts                    @DataDog/dd-trace-js @DataDog/system-tests-core
utils/build/docker/nodejs/fastify/app.js                                @DataDog/dd-trace-js @DataDog/system-tests-core
utils/build/docker/nodejs/parametric/server.js                          @DataDog/dd-trace-js @DataDog/system-tests-core
utils/build/docker/php/common/rewrite-rules.conf                        @DataDog/apm-php @DataDog/system-tests-core
utils/build/docker/php/weblogs/laravel11x/routes/web.php                @DataDog/apm-php @DataDog/system-tests-core
utils/build/docker/php/weblogs/symfony7x/src/Controller/AppController.php  @DataDog/apm-php @DataDog/system-tests-core
utils/build/docker/python/django/app/urls.py                            @DataDog/apm-python @DataDog/asm-python @DataDog/system-tests-core
utils/build/docker/python/fastapi/main.py                               @DataDog/apm-python @DataDog/asm-python @DataDog/system-tests-core
utils/build/docker/python/flask/app.py                                  @DataDog/apm-python @DataDog/asm-python @DataDog/system-tests-core
utils/build/docker/python/tornado/main.py                               @DataDog/apm-python @DataDog/asm-python @DataDog/system-tests-core
utils/build/docker/ruby/rack/config.ru                                  @DataDog/ruby-guild @DataDog/asm-ruby @DataDog/system-tests-core
utils/build/docker/ruby/rails42/app/controllers/system_test_controller.rb  @DataDog/ruby-guild @DataDog/asm-ruby @DataDog/system-tests-core
utils/build/docker/ruby/rails42/config/routes.rb                        @DataDog/ruby-guild @DataDog/asm-ruby @DataDog/system-tests-core
utils/build/docker/ruby/rails52/app/controllers/system_test_controller.rb  @DataDog/ruby-guild @DataDog/asm-ruby @DataDog/system-tests-core
utils/build/docker/ruby/rails52/config/routes.rb                        @DataDog/ruby-guild @DataDog/asm-ruby @DataDog/system-tests-core
utils/build/docker/ruby/rails61/app/controllers/system_test_controller.rb  @DataDog/ruby-guild @DataDog/asm-ruby @DataDog/system-tests-core
utils/build/docker/ruby/rails61/config/routes.rb                        @DataDog/ruby-guild @DataDog/asm-ruby @DataDog/system-tests-core
utils/build/docker/ruby/rails72/app/controllers/system_test_controller.rb  @DataDog/ruby-guild @DataDog/asm-ruby @DataDog/system-tests-core
utils/build/docker/ruby/rails72/config/routes.rb                        @DataDog/ruby-guild @DataDog/asm-ruby @DataDog/system-tests-core
utils/build/docker/ruby/rails80/app/controllers/system_test_controller.rb  @DataDog/ruby-guild @DataDog/asm-ruby @DataDog/system-tests-core
utils/build/docker/ruby/rails80/config/routes.rb                        @DataDog/ruby-guild @DataDog/asm-ruby @DataDog/system-tests-core
utils/build/docker/ruby/sinatra14/app.rb                                @DataDog/ruby-guild @DataDog/asm-ruby @DataDog/system-tests-core
utils/build/docker/ruby/sinatra22/app.rb                                @DataDog/ruby-guild @DataDog/asm-ruby @DataDog/system-tests-core
utils/build/docker/ruby/sinatra32/app.rb                                @DataDog/ruby-guild @DataDog/asm-ruby @DataDog/system-tests-core
utils/build/docker/ruby/sinatra41/app.rb                                @DataDog/ruby-guild @DataDog/asm-ruby @DataDog/system-tests-core
utils/build/docker/rust/axum/src/main.rs                                @DataDog/apm-rust @DataDog/system-tests-core

@datadog-official

datadog-official Bot commented Jul 29, 2026

Copy link
Copy Markdown

Tests

🎉 All green!

🧪 All tests passed
❄️ No new flaky tests detected

🔄 Datadog auto-retried 2 jobs - 2 passed on retry View in Datadog

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 0137f2c | Docs | Datadog PR Page | Give us feedback!

@genesor
genesor marked this pull request as ready for review July 29, 2026 11:36
@genesor
genesor requested review from a team as code owners July 29, 2026 11:36
@genesor
genesor requested review from Yun-Kim, claponcet, dromanol, florentinl, mcculls, ncybul and zacharycmontoya and removed request for a team July 29, 2026 11:36

@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: 475f02ddb8

ℹ️ 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 manifests/java.yml
Comment thread tests/test_sampling_manual.py
Comment thread manifests/java.yml
Comment thread tests/test_sampling_manual.py

@zacharycmontoya zacharycmontoya left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM for .NET

@bm1549 bm1549 left a comment

Copy link
Copy Markdown
Contributor

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.

Comment thread utils/build/docker/nodejs/express/app.js
Comment thread utils/build/docker/golang/app/_shared/common/common.go
Comment thread utils/build/docker/php/weblogs/plain/trace_manual_keep_drop.php
Comment thread utils/build/docker/ruby/rack/config.ru

@bm1549 bm1549 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Overall Codex has some suggestions about manifest versions and a PR label, which I agree with

Outside of that, this is all good to go

Comment thread utils/build/docker/python/flask/app.py
@genesor
genesor force-pushed the ben.db/feat-manual-keep-drop-endpoint branch from fcf4630 to 98a80cd Compare July 30, 2026 10:15
@genesor
genesor requested a review from a team as a code owner July 30, 2026 10:15
@genesor
genesor force-pushed the ben.db/feat-manual-keep-drop-endpoint branch from 98a80cd to a984740 Compare July 30, 2026 10:16

@vpellan vpellan left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM for shared and ruby part

@genesor
genesor merged commit 49f5b23 into main Jul 31, 2026
1359 of 1363 checks passed
@genesor
genesor deleted the ben.db/feat-manual-keep-drop-endpoint branch July 31, 2026 13:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants