chore(benchmarks): add the observability-overhead harness and its findings - #189
Merged
Conversation
The date and the Trigger: label anchored the page to when it was written. The talk it came from still opens it; the provenance caveat now carries its own date instead of relying on the header's.
The README led with where the question came from before it said what the answer was. Section 1 is now the result and the one caveat that governs every number below it; the pyproject ignores collapse to one line.
lesnik512
force-pushed
the
research/observability-overhead
branch
from
September 7, 2026 05:37
b2ab928 to
1baa64c
Compare
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.
Why
Issues #184, #185, #186 and #187 all rest on measurements. Without the harness in the repo, those numbers are a claim in an issue body that nobody can check, re-run on their own hardware, or update when sentry-sdk or the OTel instrumentation changes.
The findings themselves, in one line: on a do-nothing endpoint through uvicorn, the full stack costs 70% of throughput (7978 → 2389 RPS), roughly half of that is recoverable, and OpenTelemetry is twice Sentry — which is not the ordering I expected, and is the reason #184 and #185 exist.
Design
Two suites, three measurement modes, one process per scenario.
sentry_scenarios.py— onesentry_sdk.init()knob at a time.stack_scenarios.py— the lite-bootstrap instruments, configured throughFastAPIBootstrapper, so the numbers are what a real service pays rather than what a synthetic wiring pays.run.pydrives the ASGI app in-process (isolates library cost, inflates the ratio);run_http.pydrives uvicorn withab -k(real ratio, noisier);micro.py/verify.py/profile_one.pyattribute a per-request total to individual calls.Three shapes are load-bearing and are not obvious from reading the files:
sentry_sdk.init()monkeypatchesStarlette.__call__,Middleware.__init__andlogging.Logger.callHandlers;set_tracer_provideris set-once; the Prometheus registry is global. None of it can be undone, so scenarios cannot share a process.errors_only_skip_txn,otel_samplerandotel_exclude_spansmonkeypatch the library to measure what a proposed change would be worth before anyone writes it. That is where the numbers in OpenTelemetry sampler is not configurable #184, Passexclude_spanstoFastAPIInstrumentorso ASGI send/receive spans are opt-out #185 and ASGI integrations build and discard a Transaction per request when tracing is disabled (~34 µs) getsentry/sentry-python#7400 come from.verify.pyexists because speed alone does not settle anything. It captures a real error event with an incomingsentry-traceheader and prints what survived. That is howhttp_methods_to_capture=()was caught silently breaking distributed trace linkage, and how the upstream proposal was shown to lose nothing.benchmarks/has no__init__.py, so coverage does not walk into it and the 100% gate is untouched — the same mechanism that already excludesscripts/. Thepyproject.tomlchange is three ruff per-file-ignores (INP001,T201,SLF001): standalone scripts that print tables and read sentry-sdk internals on purpose.Non-goals
lite_bootstrap/moves. The improvements stay as issues.benchmarks/README.mdis the lab notebook that would source it.Verification
Everything in the README was re-measured from this branch after the restructure. Sentry ablation reproduced within ~2% (
+60.9 µsvs the+61.3 µsin the note), the stack breakdown within ~3%, andverify.pyreproduced all four rows of the trade-off table exactly, includingerrors_only_no_txnlosing the incoming trace anderrors_only_skip_txnkeeping it.just lint-ci— clean (ruff format, ruff check, ty, eof-fixer)just test— 242 passed, coverage still 100.00%run.py,run_http.pyagainst uvicorn,micro.py,verify.py,profile_one.pyincluding--callers, andrepro_sentry_txn.pyin all three modesOne thing to push back on
benchmarks/README.mdis prose, and the repo's rule is that a fact lives inlite_bootstrap/, in a named test, or inREADME.md/docs/. My argument for the fourth home: it documents libraries this repo depends on rather than mechanism this repo owns, none of it is derivable by readinglite_bootstrap/, and it sits next to the code that produced it. If that does not hold, the alternative is to strip it to a usage-only README and let #187 carry the findings intodocs/.