Skip to content

fix(platform): Move instrumentation.ts to repo root so prod builds load it#18771

Merged
sergical merged 1 commit into
masterfrom
sergical/fix/instrumentation-discovery-prod-builds
Jul 20, 2026
Merged

fix(platform): Move instrumentation.ts to repo root so prod builds load it#18771
sergical merged 1 commit into
masterfrom
sergical/fix/instrumentation-discovery-prod-builds

Conversation

@sergical

Copy link
Copy Markdown
Member

DESCRIBE YOUR PR

Production builds of both docs.sentry.io and develop.sentry.dev have emitted zero server-side Sentry telemetry since Mar 5, 2026 — no middleware spans, no http.server spans, no docs.trace.sampled metrics, and no AI-agent/bot/user traffic classification. This one-file move fixes it.

Root cause: Next.js production builds discover middleware.ts and instrumentation.ts by scanning only rootDir — the parent of the pages/ (or app/) directory — with no src/ fallback (next/dist/build/index.js, identical logic in 15.1 and 15.5). For two years the repo had src/pages, so rootDir was src/ and both src/middleware.ts and src/instrumentation.ts were found. When #16687 moved pages/ to the repo root, rootDir flipped to the repo root: middleware broke visibly (redirects died) and was moved to the root in that same PR, but src/instrumentation.ts was left behind and silently dropped from the build — register() and Sentry.init stopped running in the node and edge runtimes entirely. Dev was unaffected because the dev bundler does check src/, which hid the breakage locally.

This also explains why the SDK bump in #18723 changed nothing in production: the sampler it fixed never executes, because the file that installs it is not in the build.

  • Move instrumentation.ts from src/ to the repo root (next to middleware.ts), importing tracesSampler via the sentry-docs path alias
  • instrumentation-client.ts intentionally stays in src/ — Next resolves it through a webpack alias that checks src/ first, which is why browser telemetry never broke

Verified with a local next build: before the move, .next/server/ contains no instrumentation entries; after it, instrumentation.js and edge-instrumentation.js are emitted and the edge bundle contains the DSN, tracesSampler, and the docs.trace.sampled metric emission.

Post-deploy verification (in sentry/docs and sentry/develop-docs):

  • spans · span.op:http.server.middleware · group by sdk.version, release → should show the current release on SDK 10.65
  • metrics · docs.trace.sampled · group by traffic_type → should split into ai_agent / bot / user instead of being absent

IS YOUR CHANGE URGENT?

Help us prioritize incoming PRs by letting us know when the change needs to go live.

  • Urgent deadline (GA date, etc.):
  • Other deadline:
  • None: Not urgent, can wait up to 1 week+

SLA

  • Teamwork makes the dream work, so please add a reviewer to your PRs.
  • Please give the docs team up to 1 week to review your PR unless you've added an urgent due date to it.
    Thanks in advance for your help!

PRE-MERGE CHECKLIST

Make sure you've checked the following before merging your changes:

  • Checked Vercel preview for correctness, including links
  • PR was reviewed and approved by any necessary SMEs (subject matter experts)
  • PR was reviewed and approved by a member of the Sentry docs team

🤖 Generated with Claude Code

…ad it

Next.js production builds discover middleware.ts and instrumentation.ts
by scanning only rootDir = parent of the pages/ (or app/) directory,
with no src/ fallback. When pages/ moved from src/pages to the repo
root (da6c9f8, Mar 5), rootDir flipped from src/ to the repo root.
middleware.ts broke visibly and was moved to the root in that commit,
but src/instrumentation.ts was left behind and silently stopped being
bundled: hasInstrumentationHook=false, no instrumentation.js or
edge-instrumentation.js entries, so register() and Sentry.init never
run in the node or edge runtime in production.

Since then both docs and develop-docs have emitted zero server-side
telemetry: no middleware spans, no http.server spans, no
docs.trace.sampled metrics, and no traffic classification. Dev was
unaffected because the dev bundler does check src/, which hid the
breakage locally.

Move instrumentation.ts to the repo root (next to middleware.ts) and
import tracesSampler via the sentry-docs path alias. Verified with a
local next build: .next/server/ gains instrumentation.js and
edge-instrumentation.js, and the edge bundle contains the DSN,
tracesSampler, and the docs.trace.sampled metric emission.
instrumentation-client.ts stays in src/ because Next resolves it
through a webpack alias that checks src/ first.

Co-Authored-By: Claude <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 20, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
develop-docs Ready Ready Preview Jul 20, 2026 9:04pm
sentry-docs Ready Ready Preview Jul 20, 2026 9:04pm

Request Review

@sergical
sergical marked this pull request as ready for review July 20, 2026 20:56
Comment thread instrumentation.ts

@coolguyzone coolguyzone 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

@sergical
sergical merged commit 0ffabd3 into master Jul 20, 2026
24 checks passed
@sergical
sergical deleted the sergical/fix/instrumentation-discovery-prod-builds branch July 20, 2026 21:37
sergical added a commit that referenced this pull request Jul 22, 2026
…e sampling (#18775)

## DESCRIBE YOUR PR

Follow-up to #18771. That PR restored server-side Sentry, which exposed
a structural problem: **middleware root spans can never be classified at
sampling time.** The root span for a middleware request is Next.js's own
`Middleware.execute` OTEL span, created in a detached sandbox *before*
any request data reaches Sentry — so `tracesSampler` fires with no
headers and no user-agent. Result since the fix landed: ~100% of
middleware spans classify as `unknown` and get sampled at 30% —
including bots — ingesting ~264k/day spans that carry no information
(the span name is collapsed to `middleware GET`, no URL).

Rather than fighting this with send-time filtering wrappers, this PR
moves each signal to where the data actually lives:

- **`middleware.ts` counts every request.** It already classifies each
request to stamp `x-traffic-type`; now it classifies once and emits a
`docs.request.classified` counter (`traffic_type`, `device_type`, plus
the matched `agent` for AI traffic) for every request — no sampling,
100% accurate, and redirect requests are now counted too (previously
they were skipped). This metric is the system of record for
agent/bot/user traffic on the docs.
- **`tracesSampler` drops middleware root spans (rate 0) and becomes a
pure sampling function.** The proven classification for downstream node
routes is unchanged: `x-traffic-type` header first, user-agent fallback
— agents 100%, bots 0%, users 30%. All metric emission is removed from
the sampler.
- **Removes the temporary `beforeSendTransaction` hook** in
`instrumentation.ts` that renamed middleware transactions — dead code
once middleware spans stop flowing.

Net effect on ingestion: middleware span volume drops from ~264k/day to
zero (they carried no insight), metric volume stays roughly the same as
the old `docs.trace.sampled` emission, and per-request edge CPU goes
down (one classification instead of two, sampler exits immediately for
middleware spans).

**Dashboard note:** `docs.trace.sampled` stops being emitted. Queries
should move to `docs.request.classified`, which counts requests rather
than sampling decisions — a clean epoch, since 4.5 months of the old
metric are all-`unknown` zombie data anyway.

**Post-deploy verification** (`sentry/docs`, then
`sentry/develop-docs`):
- `metrics · docs.request.classified · group by traffic_type` → real
`ai_agent` / `bot` / `user` split; `group by agent` → which AI agents
consume the docs
- `spans · span.op:http.server.middleware · release:<new sha>` → should
drop to zero
- `spans · span.op:http.server release:<new sha> · group by ...` → node
route spans keep flowing with header-based classification

## IS YOUR CHANGE URGENT?

Help us prioritize incoming PRs by letting us know when the change needs
to go live.
- [ ] Urgent deadline (GA date, etc.): <!-- ENTER DATE HERE -->
- [ ] Other deadline: <!-- ENTER DATE HERE -->
- [x] None: Not urgent, can wait up to 1 week+

## SLA

- Teamwork makes the dream work, so please add a reviewer to your PRs.
- Please give the docs team up to 1 week to review your PR unless you've
added an urgent due date to it.
Thanks in advance for your help!

## PRE-MERGE CHECKLIST

*Make sure you've checked the following before merging your changes:*

- [ ] Checked Vercel preview for correctness, including links
- [ ] PR was reviewed and approved by any necessary SMEs (subject matter
experts)
- [ ] PR was reviewed and approved by a member of the [Sentry docs
team](https://github.com/orgs/getsentry/teams/docs)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants