Enable APM
Install the bridge and start capturing spans
Capture Settings
SQL values, Redis keys and code location — off by default
Performance Analytics
Find the query or connection that is costing you
APM API
Query the same data programmatically
Spans
A span is one unit of work inside a request: aSELECT, a GET to Redis, a call to Stripe.
Every span carries the type of work, a name, when it started relative to the request, how long
it took, whether it succeeded, and a bag of metadata from the instrumentation that produced it.
Spans are captured by OpenTelemetry auto-instrumentation — you do not annotate
your code. Outbound HTTP over
http/https and global fetch is captured by the base client
instead, which is the path that records full request and response bodies; see
Outbound Requests for what that covers and what it cannot see.
Attribution
The subtle part of APM in Node.js is deciding which request a span belongs to. Apg query
finishes inside a pool callback, and an outbound response fires on a keep-alive socket that may
be shared with an entirely different request — so by the time a span ends, the async context is
no longer the caller’s.
ApiTraffic therefore captures the owning request when the operation starts and holds it until
the operation completes. That applies to OpenTelemetry spans, to the native outbound hook (the
context is taken synchronously at http.request()), and to the framework middlewares, which
hold their request instance rather than looking it up again when the response is sent.
If a request that clearly performs queries shows no waterfall, the usual cause is that APM was
never registered in that process, or that it was registered after the drivers were required.
See troubleshooting.
Fingerprints
Every span is fingerprinted so that the same logical operation collapses to a single identity no matter what values it ran with.SELECT * FROM users WHERE id = 42 and ... id = 91 normalize
to the same statement and therefore the same fingerprint, and Redis keys are masked to their
shape (user:*:profile) before fingerprinting.
Fingerprints are always computed from the normalized form, so turning value capture on or off
never splits an operation’s history in the analytics.
Per-request rollups
As spans are recorded, the SDK also accumulates per-request totals — time and count for database, Redis, cache, outbound HTTP, queue and RPC work — and sends them on the request itself. These rollups are what the dashboards read, which is why they stay fast regardless of how many spans you produce; the span store is only read when you drill into a single operation. Time not attributed to any dependency is reported as app time: the request duration minus the instrumented families, floored at zero. Because dependency work can overlap (concurrent queries), a heavily parallel request can show 0 ms of app time.Distributed traces
When a request arrives with a W3Ctraceparent header, ApiTraffic records its trace id on the
request; when it does not, the trace id from the first span is used. Requests that share a trace
id are grouped in the Distributed Trace tab of a request, so a call that crosses several of
your services reads as one timeline.
The trace id is taken from the original headers, before redaction, so redacting traceparent
does not break trace grouping.
Overhead and limits
APM is designed to be safe to leave on in production.- Fail-open. The bridge never throws into your code, never alters a wrapped call and never blocks the request path. On an internal error the span is dropped.
- Bounded per request. At most
maxSpansPerRequestspans (default500) are retained; overflow is counted, not buffered. Span metadata is capped atmaxSpanMetaBytes(default2048) per span. - Sampling.
spanSampleRateretains span detail for a fraction of requests. Rollups are still counted for every request, so the dashboards remain accurate while the span store shrinks. - No values by default. Statements are normalized and bind values discarded in-process, before anything leaves your server. See capture settings.