Observability
Available since 2.29
Sometimes, you may need to observe how your application is behaving in order to improve performance or find the root cause of a pesky bug. To help with this, SvelteKit can emit server-side OpenTelemetry spans for the following:
- The
handle
hook andhandle
functions running in asequence
(these will show up as children of each other and the roothandle
hook) - Server
load
functions and universalload
functions when they’re run on the server - Form actions
- Remote functions
Just telling SvelteKit to emit spans won’t get you far, though — you need to actually collect them somewhere to be able to view them. SvelteKit provides src/instrumentation.server.ts
as a place to write your tracing setup and instrumentation code. It’s guaranteed to be run prior to your application code being imported, providing your deployment platform supports it and your adapter is aware of it.
Both of these features are currently experimental, meaning they are likely to contain bugs and are subject to change without notice. You must opt in by adding the kit.experimental.tracing.server
and kit.experimental.instrumentation.server
option in your svelte.config.js
:
/** @type {import('@sveltejs/kit').Config} */
const const config: {
kit: {
experimental: {
tracing: {
server: boolean;
};
instrumentation: {
server: boolean;
};
};
};
}
config = {
kit: {
experimental: {
tracing: {
server: boolean;
};
instrumentation: {
server: boolean;
};
};
}
kit: {
experimental: {
tracing: {
server: boolean;
};
instrumentation: {
server: boolean;
};
}
experimental: {
tracing: {
server: boolean;
}
tracing: {
server: boolean
server: true
},
instrumentation: {
server: boolean;
}instrumentation: {
server: boolean
server: true
}
}
}
};
export default const config: {
kit: {
experimental: {
tracing: {
server: boolean;
};
instrumentation: {
server: boolean;
};
};
};
}
config;Tracing — and more significantly, observability instrumentation — can have a nontrivial overhead. Before you go all-in on tracing, consider whether or not you really need it, or if it might be more appropriate to turn it on in development and preview environments only.
Augmenting the built-in tracing
SvelteKit provides access to the root
span and the current
span on the request event. The root span is the one associated with your root handle
function, and the current span could be associated with handle
, load
, a form action, or a remote function, depending on the context. You can annotate these spans with any attributes you wish to record:
import { function getRequestEvent(): RequestEvent
Returns the current RequestEvent
. Can be used inside server hooks, server load
functions, actions, and endpoints (and functions called by them).
In environments without AsyncLocalStorage
, this must be called synchronously (i.e. not after an await
).
getRequestEvent } from '$app/server';
import { function getAuthenticatedUser(): Promise<{
id: string;
}>
getAuthenticatedUser } from '$lib/auth-core';
async function function authenticate(): Promise<void>
authenticate() {
const const user: {
id: string;
}
user = await function getAuthenticatedUser(): Promise<{
id: string;
}>
getAuthenticatedUser();
const const event: RequestEvent<Record<string, string>, string | null>
event = function getRequestEvent(): RequestEvent
Returns the current RequestEvent
. Can be used inside server hooks, server load
functions, actions, and endpoints (and functions called by them).
In environments without AsyncLocalStorage
, this must be called synchronously (i.e. not after an await
).
getRequestEvent();
const event: RequestEvent<Record<string, string>, string | null>
event.RequestEvent<Record<string, string>, string | null>.tracing: {
enabled: boolean;
root: Span;
current: Span;
}
Access to spans for tracing. If tracing is not enabled, these spans will do nothing.
tracing.root: Span
The root span for the request. This span is named sveltekit.handle.root
.
root.setAttribute('userId', const user: {
id: string;
}
user.id: string
id);
}
Development quickstart
To view your first trace, you’ll need to set up a local collector. We’ll use Jaeger in this example, as they provide an easy-to-use quickstart command. Once your collector is running locally:
- Turn on the experimental flags mentioned earlier in your
svelte.config.js
file - Use your package manager to install the dependencies you’ll need:
npm i @opentelemetry/sdk-node @opentelemetry/auto-instrumentations-node @opentelemetry/exporter-trace-oltp-proto import-in-the-middle
- Create
src/instrumentation.server.js
with the following:
import { import NodeSDK
NodeSDK } from '@opentelemetry/sdk-node';
import { import getNodeAutoInstrumentations
getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
import { import OTLPTraceExporter
OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto';
import { import createAddHookMessageChannel
createAddHookMessageChannel } from 'import-in-the-middle';
import { function register<Data = any>(specifier: string | URL, parentURL?: string | URL, options?: Module.RegisterOptions<Data>): void (+1 overload)
Register a module that exports hooks that customize Node.js module
resolution and loading behavior. See
Customization hooks.
register } from 'node:module';
const { const registerOptions: any
registerOptions } = import createAddHookMessageChannel
createAddHookMessageChannel();
register<any>(specifier: string | URL, parentURL?: string | URL, options?: Module.RegisterOptions<any> | undefined): void (+1 overload)
Register a module that exports hooks that customize Node.js module
resolution and loading behavior. See
Customization hooks.
register('import-in-the-middle/hook.mjs', import.meta.ImportMeta.url: string
The absolute file:
URL of the module.
url, const registerOptions: any
registerOptions);
const const sdk: any
sdk = new import NodeSDK
NodeSDK({
serviceName: string
serviceName: 'test-sveltekit-tracing',
traceExporter: any
traceExporter: new import OTLPTraceExporter
OTLPTraceExporter(),
instrumentations: any[]
instrumentations: [import getNodeAutoInstrumentations
getNodeAutoInstrumentations()]
});
const sdk: any
sdk.start();
Now, server-side requests will begin generating traces, which you can view in Jaeger’s web console at localhost:16686.
@opentelemetry/api
SvelteKit uses @opentelemetry/api
to generate its spans. This is declared as an optional peer dependency so that users not needing traces see no impact on install size or runtime performance. In most cases, if you’re configuring your application to collect SvelteKit’s spans, you’ll end up installing a library like @opentelemetry/sdk-node
or @vercel/otel
, which in turn depend on @opentelemetry/api
, which will satisfy SvelteKit’s dependency as well. If you see an error from SvelteKit telling you it can’t find @opentelemetry/api
, it may just be because you haven’t set up your trace collection yet. If you have done that and are still seeing the error, you can install @opentelemetry/api
yourself.
Edit this page on GitHub llms.txt