Skip to content

fix: stop tracing the internals of Nest's validation pipes and ConfigService - #78

Merged
kamilmysliwiec merged 1 commit into
masterfrom
fix/enhancer-entry-spans
Nov 7, 2026
Merged

kamilmysliwiec merged 1 commit into
masterfrom
fix/enhancer-entry-spans

Conversation

@kamilmysliwiec

@kamilmysliwiec kamilmysliwiec commented Nov 7, 2026 •

Copy link
Copy Markdown
Member

Two library classes make a burst of spans nobody reads.

  • ValidationPipe runs once per handler argument, and the agent made a span for every method it calls: transform, toValidate and transformPrimitive, a few microseconds each and each one billed. On 11-06 it was the busiest class after pg: 12.5M of 241.7M class-attributed calls (5.2%), in 297 of 638 projects. validate was reached on only 649k of 3.54M runs. On one REST app, 404,552 of 404,652 runs never reached it, and the pipe made about 40% of that app's class spans.
  • ConfigService (@nestjs/config) made 4.6M calls that day, in 220 projects. 2.7M of them were its private helpers (getFromInternalConfig, getFromValidatedEnv, isGetOptionsObject, getFromProcessEnv, setInCacheIfDefined, getFromCache), four or five behind each get.

Folding can't reach either, because it needs the same method more than 20 times under one parent. Together this removes about 14.5M spans a day, about 6% of class-attributed calls.

The change

  • On ValidationPipe, StandardSchemaValidationPipe and ParseFilePipe, only validate is a span. A run that validates nothing makes no span at all.
  • On ConfigService, only its public methods are spans: get, getOrThrow, set and setEnvFilePaths. A getOrThrow still shows the get it calls.

Everything else is traced as before: guards, interceptors, filters, Nest's other pipes (such as ParseIntPipe) and any class an application wrote.

  • Subclasses: the check asks which class holds the method, so what a subclass adds or overrides is still traced. Only what it inherits from the library class is dropped.
  • Matching: by class name plus a method only the library's class has (flattenValidationErrors, formatIssueMessages, validateFilesOrFile, getFromValidatedEnv).
    • StandardSchemaValidationPipe isn't in every supported @nestjs/common, and an app may carry a second copy of a package.
    • Nest's docs have readers write their own ValidationPipe, and plenty of apps have a ConfigService of their own. Those must keep all their spans.
    • A class that stops matching is traced like any other.
  • Calls from inside: the other methods still run against the proxy, so this.validate() inside transform makes its span, including from a subclass.

Tested

  • Unit: 1,503 passed, 5 skipped. The cases cover:
    • the real ValidationPipe, ParseFilePipe and StandardSchemaValidationPipe (skipped where it doesn't exist);
    • a ConfigService with @nestjs/config 4's shape;
    • subclasses, plus a hand-written ValidationPipe and an app's own ConfigService;
    • ParseIntPipe, a guard and an interceptor, unchanged.
  • Real ConfigService: checked against the real @nestjs/config 4.0.2 with the built decorator. get and getOrThrow were the only spans. The SDK doesn't depend on that package, so this check isn't committed.
  • End to end: src/instrument/validating-pipe-spans.int-spec.ts runs a real app with a global ValidationPipe and a guard, and fails without the fix.
  • Full integration run: 555 passed, 19 skipped, 2 failed. Both failures were in http-capture-scenarios, which uses none of these classes and passed 3 out of 3 reruns of that file alone. The same file flaked once in an earlier run.
  • Earlier CI failure: the Node 20 job's previous failure was EADDRINUSE in the gRPC OpenTelemetry e2e spec.
  • Not run locally: the older-Nest job.

@kamilmysliwiec kamilmysliwiec changed the title fix: trace only the entry method of guards, interceptors, pipes and filters fix: trace only validate on Nest's validation pipes Nov 7, 2026
@kamilmysliwiec
kamilmysliwiec force-pushed the fix/enhancer-entry-spans branch 2 times, most recently from 5a972f8 to 00c4c23 Compare November 7, 2026 08:37
…Service

`ValidationPipe` runs once per handler argument, and each run was three
spans of a few microseconds: `transform`, `toValidate` and
`transformPrimitive`. Across the hosted platform 82% of runs never reached
`validate`, and the pipe was the busiest class after `pg`. Each
`ConfigService.get` likewise made four or five spans of private helpers,
2.7M of its 4.6M a day. Folding can't reach either, because each repeats
only a few times under its parent.

On `ValidationPipe`, `StandardSchemaValidationPipe` and `ParseFilePipe` only
`validate` is a span now, and on `ConfigService` only its public methods.
What an application adds or overrides in a subclass is still traced, and so
is everything on guards, interceptors, filters, Nest's other pipes and the
classes an application wrote.
@kamilmysliwiec kamilmysliwiec changed the title fix: trace only validate on Nest's validation pipes fix: stop tracing the internals of Nest's validation pipes and ConfigService Nov 7, 2026
@kamilmysliwiec
kamilmysliwiec force-pushed the fix/enhancer-entry-spans branch from 00c4c23 to 8ace666 Compare November 7, 2026 09:07
@kamilmysliwiec
kamilmysliwiec merged commit 371988b into master Nov 7, 2026
5 checks passed
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.

1 participant