@apitraffic/apm adds everything that happens inside the request —
queries, cache calls, queues and RPC.
All of the OpenTelemetry weight lives in the APM package, so nothing is installed into your
application unless you add it.
Install
@apitraffic/apm and the packages you have.
Option 1 — Zero configuration
Callregister() before your application boots, so the auto-instrumentations can patch
pg, redis, mysql2 and friends before your code requires them. The usual way is a
preload file:
instrument.js
server.js
register() is idempotent and fail-open: if OpenTelemetry is missing, or another APM already owns
the tracer provider, it returns quietly and your application starts normally.
Option 2 — You already run OpenTelemetry
Do not double-instrument. Add our span processor to the provider you already have, and we ingest the spans you are already producing:ApiTrafficSpanExporter is also exported for pipelines that prefer a SpanExporter behind a
BatchSpanProcessor. Both funnel through the same mapping.
Configuration
Options can be passed toregister() or set as environment variables. An explicit option wins
over the environment variable, which wins over the default.
captureStatementParams and captureRedisKeys can also be turned on from the dashboard for a
bucket, without a redeploy and with an automatic expiry, and captureCallSite /
captureStackDepth are owned by the dashboard unless you set them here. See
capture settings.
Statement text and privacy
Statements and call stacks are stored and shown only for accounts with statement text enabled, everywhere: request pages, shared links, embeds, workflows, the API, the MCP tools and the Performance analytics. For other accounts they are removed before a request is stored (and again on every read, for requests stored earlier); spans keep their operation, fingerprint and call site. See capture settings.Statement text once per operation
A query’s normalized statement and caller stack are the same every time it runs, and they are the largest part of a span. WithsendStatementTextOnce on, a process sends them with the first span
of each operation (fingerprint) and leaves them off later spans of that operation for
statementTextResendSeconds. Those spans keep their fingerprint, name, type and call site, and
list what they left off in textOmitted; the request page fills the text back in from the other
spans of the request and from your account’s fingerprint dictionary.
- Text counts as sent only once the payload was delivered, and it is sent again after the resend interval, so a restart or a failed write on our side heals within that interval.
- A caller stack is left off only when that exact stack was already sent for the operation; an operation called from several places keeps sending each new stack.
- Each process keeps its own memory, so a fleet sends each statement once per process per interval.
register() of the bridge does not take it.
Outbound HTTP
Outbound calls made withhttp/https (including axios, got and request) are captured by the
base client, with full request and response bodies. Calls made with fetch/undici are captured
by the APM bridge as metadata-only spans. You do not need to configure anything for this; leaving
instrumentHttp off is what keeps a native call from being recorded twice.
Verify
- Start your application and exercise an endpoint that queries a database or calls another API.
- Open the request in Traffic and select the Waterfall tab. Each query, cache call and outbound request appears on the timeline with its duration and metadata.
- Open Performance to see the same operations aggregated across requests.
Troubleshooting
A request has no waterfall at all
A request has no waterfall at all
APM was probably not registered in that process, or was registered too late.
register() must
run before the database/cache modules are required — use node -r ./instrument.js to be sure.
Enable debug: true to see whether the bridge started and whether OpenTelemetry was found.Only outbound HTTP appears, no queries
Only outbound HTTP appears, no queries
The driver’s instrumentation was not applied. Check that the driver is one of the supported
modules, that it is required after
register(), and that it is not listed in
disabledInstrumentations.Waterfall stops partway through the request
Waterfall stops partway through the request
The per-request span cap (
maxSpansPerRequest, default 500) was reached — typically an N+1.
The dropped count is retained on the request, and the rollups still include the dropped work.Queries show where id = ? instead of the values
Queries show where id = ? instead of the values
That is the default. Values are stripped in-process before anything is sent. Turn them on
deliberately and temporarily from capture settings.
Outbound calls appear twice
Outbound calls appear twice
OpenTelemetry’s
http instrumentation is enabled alongside the native hook. Leave
instrumentHttp off (the default) unless you have disabled the native hook.