feat: OpenTelemetry Tracing
#13899
Pull request
Supersedes #13776
What comes built in:
- Context propagation via headers (so if you're calling SvelteKit from a third-party service that is also traced, your spans will connect!)
- Server-side traces for:
handlesequence(sequenceedhandlefunctions will show up as children of each other and the root handle hook)load(includes universalloads when they're run on the server)- Actions
- Remote Functions, assuming you've activated their experimental flag
- A new file,
instrumentation.server.{js|ts}- This file is guaranteed to be run prior to importing your application code*, meaning it's a safe place to set up your instrumentation and exporters
- *It is guaranteed to run prior to importing your application code in ESM-compatible environments (Node, Vercel (non-edge), Netlify (non-edge), etc -- anything that supports top-level
await. It must be supported by your adapter. What this means practically is that, for "partially" supported platforms, your tracing code will still run, but auto-instrumentations may or may not work. All Svelte-owned adapters are launching with at least partial support, but we'd like to receive input from platform experts on whether we can improve this before this feature's experimental flag is removed.
If you want to try it, you need to do two things: Enable SvelteKit traces, and set up an exporter to send those traces somewhere. To enable SvelteKit Traces, add experimental: { tracing: { server: true, serverFile: true } } to your SvelteKit config. To set up an exporter, consult OpenTelemetry documentation for your provider. For example, your src/instrumentation.server.ts file would look like this for Node:
import { NodeSDK } from '@opentelemetry/sdk-node';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto';
import { createAddHookMessageChannel } from 'import-in-the-middle';
import { register } from 'module';
const { registerOptions } = createAddHookMessageChannel();
register('import-in-the-middle/hook.mjs', import.meta.url, registerOptions);
const sdk = new NodeSDK({
serviceName: 'test-sveltekit-tracing',
traceExporter: new OTLPTraceExporter(),
instrumentations: [getNodeAutoInstrumentations()]
});
sdk.start();
...and like this for Vercel:
import { registerOTel } from '@vercel/otel';
registerOTel({
serviceName: 'test-sveltekit-tracing'
});
We're punting on clientside tracing for now, as we do not feel the o11y community has sufficiently converged on approaches (see https://github.com/open-telemetry/community/blob/main/projects/browser-phase-1.md). When OTEL provides a stable and truly browser-native tracing platform, we'll be all over it. That being said, if you can get a clientside tracing setup working, it will interface with the SvelteKit backend correctly, assuming you send the correct context headers.
Please don't delete this checklist! Before submitting the PR, please make sure you do the following:
- It's really useful if your PR references an issue where it is discussed ahead of time. In many cases, features are absent for a reason. For large changes, please create an RFC: https://github.com/sveltejs/rfcs
- This message body should clearly illustrate what problems it solves.
- Ideally, include a test that fails without this PR but passes with it.
Tests
- Run the tests with
pnpm testand lint the project withpnpm lintandpnpm check
Changesets
- If your PR makes a change that should be noted in one or more packages' changelogs, generate a changeset by running
pnpm changesetand following the prompts. Changesets that add features should beminorand those that fix bugs should bepatch. Please prefix changeset messages withfeat:,fix:, orchore:.
Edits
- Please ensure that 'Allow edits from maintainers' is checked. PRs without this option may be closed.
Info
🦋 Changeset detected
Latest commit: ab91eed
The changes in this PR will be included in the next version bump.
This PR includes changesets to release 5 packages
| Name | Type |
|---|---|
| @sveltejs/kit | Minor |
| @sveltejs/adapter-cloudflare | Minor |
| @sveltejs/adapter-netlify | Minor |
| @sveltejs/adapter-vercel | Minor |
| @sveltejs/adapter-node | Minor |
Not sure what this means? Click here to learn what changesets are.
Click here if you're a maintainer who wants to add another changeset to this PR
Thanks! This looks good. I think all we need is a changeset and some documentation on how to get started. The instructions could be similar to the setup in the demo of #13900 (comment) or we might want to try and get something like #13776 merged next
cc: @manuel3108 @AdrianGonz97 would we want to add some kind of OpenTelemetry or Sentry add-on to the Svelte CLI in the future to make the setup more seamless?
nervous about that test failure, not sure why that's happening suddenly
would we want to add some kind of OpenTelemetry or Sentry add-on to the Svelte CLI in the future to make the setup more seamless?
If I understand the changes here correctly, this is going to be an experimental feature, right? In that case I think we shouldn't promote that in sv
It might be nice to start thinking about community add-ons again. Sentry could make a community add-on. Up to them then whether they'd like to rely on something experimental
It might be nice to start thinking about community add-ons again. Sentry could make a community add-on. Up to them then whether they'd like to rely on something experimental
Do you mean something like sv add sentry? Or rather an API (i.e. something like Astro integrations)?
(generally open to both ideas!)
Something like sv add sentry. We don't have the APIs for you to be able to create your own sv add-on yet, but it's on our roadmap.
I was playing around with this PR and got errors related to __SVELTEKIT_SERVER_TRACING_ENABLED__
Is this a known issue, am I doing something wrong?
kit installed as devDependency using "@sveltejs/kit": "https://pkg.pr.new/sveltejs/kit/@sveltejs/kit@4b64316",
svelte.config.js
const config = {
kit: {
experimental: {
tracing: { server: true }
}
}
};
vite dev/build/preview error
node:internal/event_target:1101
process.nextTick(() => { throw err; });
^
ReferenceError [Error]: __SVELTEKIT_SERVER_TRACING_ENABLED__ is not defined
at file:////home/konstantin/some-project/node_modules/@sveltejs/kit/src/runtime/telemetry/otel.js:6:1
at ModuleJob.run (node:internal/modules/esm/module_job:329:25)
at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:644:26)
at async get_hooks (file:////home/konstantin/some-project/.svelte-kit/output/server/chunks/internal.js:500:49)
at async file:////home/konstantin/some-project/.svelte-kit/output/server/index.js:3475:24
at async Server.init (file:////home/konstantin/some-project/.svelte-kit/output/server/index.js:3473:5)
at async prerender (file:////home/konstantin/some-project/node_modules/@sveltejs/kit/src/core/postbuild/prerender.js:473:2)
at async MessagePort.<anonymous> (file:////home/konstantin/some-project/node_modules/@sveltejs/kit/src/utils/fork.js:23:16)
Node.js v22.17.1
I was able to work around it with --import:
Fixed build with build.mjs
globalThis.__SVELTEKIT_SERVER_TRACING_ENABLED__ = 'true';
and node --import ./build.mjs node_modules/vite/bin/vite.js build
running dev/preview using instrument.server.mjs
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto';
import { NodeSDK } from '@opentelemetry/sdk-node';
import { createAddHookMessageChannel } from 'import-in-the-middle';
import { register } from 'module';
globalThis.__SVELTEKIT_SERVER_TRACING_ENABLED__ = 'true';
const { registerOptions } = createAddHookMessageChannel();
register('import-in-the-middle/hook.mjs', import.meta.url, registerOptions);
const sdk = new NodeSDK({
serviceName: 'hello-tracing',
traceExporter: new OTLPTraceExporter(),
instrumentations: [getNodeAutoInstrumentations()]
});
sdk.start();
console.log('sdk started');
node --import ./instrument.server.mjs node_modules/vite/bin/vite.js preview
@konstantinblaesi I'll take a look first thing next week when I'm back from vacation -- not expected behavior. I'm probably just holding Vite wrong.
@konstantinblaesi I'll take a look first thing next week when I'm back from vacation -- not expected behavior. I'm probably just holding Vite wrong.
cool thanks and have a nice vacation :)
Will this also enable tracing in vite dev mode ? So far I do not seem to get traces in jaeger using node --import ./instrument.server.mjs node_modules/vite/bin/vite.js dev
The traces from prod/preview mode are already helping us visualize performance issues, thanks for working on this 🥇
@konstantinblaesi I'm not yet sure why instrumentation doesn't work in dev, but there's a separate PR to add an instrumentation.server.ts file that is guaranteed to be loaded prior to your other code -- so that should enable it for sure.
@konstantinblaesi you should be able to play around with this on the latest pkg.pr.new links!
If tracing.server.js contains deployment target specific code, how does it work when users switch between different adapters or even deploy the same app to different providers regularly? Would it work if serverFile was an adapter level config?
Not quite sure why but appears to be out of date with the docs in this PR
feat: Add tracing to load, server actions, and handle/resolve (#13900)
* feat: Add tracing to `load`, server actions, and `handle`/`resolve` * feat: add universal IDs to client nodes * approve otp dep build * add links for docs * since tags * clarify * explain util * import the rest of the types through jsdoc import statements * generate types --------- Co-authored-by: Chew Tee Ming <[email protected]>
Co-authored-by: Rich Harris <[email protected]>
Co-authored-by: Rich Harris <[email protected]>
Pro tip: You can prefix GitHub URLs of issues, PRs or discussions with svcl.dev/ to view them on this page! Also try it on a GitHub release ;)