Skip to content
Merged
Show file tree
Hide file tree
Changes from 68 commits
Commits
Show all changes
89 commits
Select commit Hold shift + click to select a range
0c3aad6
feat: Initial tracing setup (peer deps + utils)
elliott-with-the-longest-name-on-github Jun 17, 2025
62777fe
Merge branch 'main' into elliott/init-tracing
eltigerchino Jul 22, 2025
78a65ea
feat: Add tracing to `load`, server actions, and `handle`/`resolve` (…
elliott-with-the-longest-name-on-github Jul 23, 2025
f65b78f
Update packages/kit/src/exports/public.d.ts
elliott-with-the-longest-name-on-github Jul 23, 2025
77d447f
chore: Switch to `tracing: { server: boolean }`
elliott-with-the-longest-name-on-github Jul 23, 2025
965bfea
chore: Make enablement / importing of otel make more sense
elliott-with-the-longest-name-on-github Jul 23, 2025
65752bc
chore: merge_tracing function
elliott-with-the-longest-name-on-github Jul 23, 2025
e50615b
fix rich's bad comment that shouldn't have ever existed >:(
elliott-with-the-longest-name-on-github Jul 23, 2025
5b583ec
test stuff
elliott-with-the-longest-name-on-github Jul 23, 2025
90e961d
Update packages/kit/test/utils.js
elliott-with-the-longest-name-on-github Jul 23, 2025
dd516a9
i am truly among the dumbest
elliott-with-the-longest-name-on-github Jul 24, 2025
0cf24bc
Merge branch 'main' into elliott/init-tracing
elliott-with-the-longest-name-on-github Jul 24, 2025
962daf7
types
elliott-with-the-longest-name-on-github Jul 24, 2025
6a81d8b
remove now-useless comment
elliott-with-the-longest-name-on-github Jul 24, 2025
f143f5b
lockfile
elliott-with-the-longest-name-on-github Jul 24, 2025
fc3f734
fix dumb import analysis
elliott-with-the-longest-name-on-github Jul 24, 2025
4b64316
changeset
elliott-with-the-longest-name-on-github Jul 24, 2025
3192797
Merge branch 'main' into elliott/init-tracing
elliott-with-the-longest-name-on-github Aug 6, 2025
b6b7d6a
fix: conflict
elliott-with-the-longest-name-on-github Aug 6, 2025
60540ce
i do not know why this fixed it but it did
elliott-with-the-longest-name-on-github Aug 6, 2025
723d5a4
Merge remote-tracking branch 'origin/main' into elliott/init-tracing
elliott-with-the-longest-name-on-github Aug 7, 2025
091eaef
idk man
elliott-with-the-longest-name-on-github Aug 7, 2025
acf66e9
i do not understand why this fixed anything
elliott-with-the-longest-name-on-github Aug 7, 2025
587be22
chore: catalog node types
elliott-with-the-longest-name-on-github Aug 7, 2025
83a24aa
upstream
elliott-with-the-longest-name-on-github Aug 7, 2025
874717f
fix: idiocy on my part tbh
elliott-with-the-longest-name-on-github Aug 7, 2025
1d06059
optionally load tracing, add remote functions
elliott-with-the-longest-name-on-github Aug 8, 2025
4c95395
chore: Better attributes for actions
elliott-with-the-longest-name-on-github Aug 8, 2025
45d3eaa
only load module if exists
elliott-with-the-longest-name-on-github Aug 8, 2025
7a91d03
Merge remote-tracking branch 'origin/main' into elliott/init-tracing
elliott-with-the-longest-name-on-github Aug 8, 2025
cbfaa03
try this to prevent package issues
elliott-with-the-longest-name-on-github Aug 8, 2025
0001ab9
fix: unit tests
elliott-with-the-longest-name-on-github Aug 8, 2025
4486b21
fix again
elliott-with-the-longest-name-on-github Aug 8, 2025
30ffc68
move event.js to internal
elliott-with-the-longest-name-on-github Aug 11, 2025
b526831
move event-state to internal
elliott-with-the-longest-name-on-github Aug 11, 2025
5954ae4
changeset and docs
elliott-with-the-longest-name-on-github Aug 11, 2025
fb508f7
types
elliott-with-the-longest-name-on-github Aug 11, 2025
4ccef4b
types
elliott-with-the-longest-name-on-github Aug 11, 2025
21f84be
fix: use resolve module
elliott-with-the-longest-name-on-github Aug 12, 2025
eb3e876
feat: `tracing.server.ts` (#14117)
elliott-with-the-longest-name-on-github Aug 12, 2025
b57f927
Merge remote-tracking branch 'origin/main' into elliott/init-tracing
elliott-with-the-longest-name-on-github Aug 12, 2025
c73569c
server file option
elliott-with-the-longest-name-on-github Aug 12, 2025
f654784
docs
elliott-with-the-longest-name-on-github Aug 12, 2025
5f5129c
feedback
elliott-with-the-longest-name-on-github Aug 12, 2025
5c3cc72
fix: adapters
elliott-with-the-longest-name-on-github Aug 12, 2025
afc7e15
Merge remote-tracking branch 'origin/main' into elliott/init-tracing
elliott-with-the-longest-name-on-github Aug 12, 2025
8c804a6
fix event state
elliott-with-the-longest-name-on-github Aug 12, 2025
00eec4a
harder
elliott-with-the-longest-name-on-github Aug 12, 2025
5660820
exit hell
elliott-with-the-longest-name-on-github Aug 12, 2025
3a8b5ac
Update packages/kit/src/exports/vite/utils.js
elliott-with-the-longest-name-on-github Aug 12, 2025
8e0ba7a
address feedback
elliott-with-the-longest-name-on-github Aug 12, 2025
e65a25e
Update documentation/docs/30-advanced/68-observability.md
elliott-with-the-longest-name-on-github Aug 12, 2025
06486db
Update documentation/docs/30-advanced/68-observability.md
elliott-with-the-longest-name-on-github Aug 12, 2025
dc35aa1
Merge branch 'elliott/init-tracing' of github.com:sveltejs/kit into e…
elliott-with-the-longest-name-on-github Aug 12, 2025
512538e
Update documentation/docs/30-advanced/68-observability.md
elliott-with-the-longest-name-on-github Aug 12, 2025
4b09980
Update documentation/docs/30-advanced/68-observability.md
elliott-with-the-longest-name-on-github Aug 12, 2025
a111b7d
Update documentation/docs/30-advanced/68-observability.md
elliott-with-the-longest-name-on-github Aug 12, 2025
3188b73
we can't use here... long story but it breaks the docs
Rich-Harris Aug 12, 2025
268cd82
destroy event-state
elliott-with-the-longest-name-on-github Aug 13, 2025
8126882
Merge branch 'elliott/init-tracing' of github.com:sveltejs/kit into e…
elliott-with-the-longest-name-on-github Aug 13, 2025
738db55
Merge remote-tracking branch 'origin/main' into elliott/init-tracing
elliott-with-the-longest-name-on-github Aug 13, 2025
a1cad37
Update documentation/docs/30-advanced/68-observability.md
Rich-Harris Aug 13, 2025
3322f89
remove config
elliott-with-the-longest-name-on-github Aug 13, 2025
2fe0fbf
last feedbacks
elliott-with-the-longest-name-on-github Aug 13, 2025
2ad5182
Merge branch 'elliott/init-tracing' of github.com:sveltejs/kit into e…
elliott-with-the-longest-name-on-github Aug 13, 2025
98669e6
tests
elliott-with-the-longest-name-on-github Aug 13, 2025
0c03fbe
fix type generation and remove hack
eltigerchino Aug 13, 2025
f1d9fe2
Merge branch 'main' into elliott/init-tracing
eltigerchino Aug 13, 2025
54831e7
em dashes and tabs
Rich-Harris Aug 13, 2025
71b4cdd
Update packages/kit/src/exports/public.d.ts
Rich-Harris Aug 13, 2025
d15b9f5
bump since tags
Rich-Harris Aug 13, 2025
6edfc8a
Apply suggestions from code review
Rich-Harris Aug 13, 2025
b16c012
Update packages/kit/src/exports/vite/dev/index.js
Rich-Harris Aug 13, 2025
04b7fde
Merge branch 'main' into elliott/init-tracing
Rich-Harris Aug 13, 2025
6a73667
oops
Rich-Harris Aug 13, 2025
f34728a
Update documentation/docs/30-advanced/68-observability.md
Rich-Harris Aug 13, 2025
ace50a3
fix: type nightmares
elliott-with-the-longest-name-on-github Aug 13, 2025
bf8cb46
Merge branch 'elliott/init-tracing' of github.com:sveltejs/kit into e…
elliott-with-the-longest-name-on-github Aug 13, 2025
f0acd03
bump since tags
Rich-Harris Aug 14, 2025
7334888
smarter
elliott-with-the-longest-name-on-github Aug 14, 2025
7d26bf4
Merge branch 'elliott/init-tracing' of github.com:sveltejs/kit into e…
elliott-with-the-longest-name-on-github Aug 14, 2025
281cdb4
types
elliott-with-the-longest-name-on-github Aug 14, 2025
0a1834b
hopefully I oneshot this with my brain
elliott-with-the-longest-name-on-github Aug 14, 2025
bd73dc9
last fixes
elliott-with-the-longest-name-on-github Aug 14, 2025
50d942a
fix
elliott-with-the-longest-name-on-github Aug 14, 2025
d9ab921
fix
elliott-with-the-longest-name-on-github Aug 14, 2025
a7b2430
small docs addition
elliott-with-the-longest-name-on-github Aug 14, 2025
477e50e
fix
elliott-with-the-longest-name-on-github Aug 14, 2025
ab91eed
fix
elliott-with-the-longest-name-on-github Aug 14, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/early-taxis-make.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': minor
---

feat: OpenTelemetry tracing for `handle`, `sequence`, form actions, remote functions, and `load` functions running on the server
9 changes: 9 additions & 0 deletions .changeset/whole-bananas-sort.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@sveltejs/adapter-cloudflare': minor
'@sveltejs/adapter-netlify': minor
'@sveltejs/adapter-vercel': minor
'@sveltejs/adapter-node': minor
'@sveltejs/kit': minor
---

feat: add `tracing.server.ts` for tracing instrumentation and setup
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ my-project/
│ ├ error.html
│ ├ hooks.client.js
│ ├ hooks.server.js
│ └ service-worker.js
| ├ service-worker.js
│ └ tracing.server.js
├ static/
│ └ [your static assets]
├ tests/
Expand Down Expand Up @@ -54,6 +55,7 @@ The `src` directory contains the meat of your project. Everything except `src/ro
- `hooks.client.js` contains your client [hooks](hooks)
- `hooks.server.js` contains your server [hooks](hooks)
- `service-worker.js` contains your [service worker](service-workers)
- `tracing.server.js` contains your [tracing](observability) setup and instrumentation code

(Whether the project contains `.js` or `.ts` files depends on whether you opt to use TypeScript when you create your project.)

Expand Down
4 changes: 4 additions & 0 deletions documentation/docs/25-build-and-deploy/99-writing-adapters.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ export default function (options) {
// Return `true` if the route with the given `config` can use `read`
// from `$app/server` in production, return `false` if it can't.
// Or throw a descriptive error describing how to configure the deployment
},
tracing: () => {
// Return `true` if this adapter supports loading `tracing.server.js`.
// Return `false if it can't, or throw a descriptive error.
}
}
};
Expand Down
68 changes: 68 additions & 0 deletions documentation/docs/30-advanced/68-observability.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
---
title: Observability
---

<blockquote class="since note">
<p>Available since 2.29</p>
</blockquote>

> [!NOTE] This feature is experimental. Expect bugs and breaking changes in minor versions (though we'll do our best to keep those to an absolute minimum). Please provide feedback!

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](https://opentelemetry.io) spans for the following:

- [`handle`](hooks#Server-hooks-handle) hook (`handle` functions running in a [`sequence`](@sveltejs-kit-hooks#sequence) will show up as children of each other and the root handle hook)
- [`load`](load) functions (includes universal `load` functions when they're run on the server)
- [Form actions](form-actions)
- [Remote functions](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/tracing.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.

To enable both of these features, add the following to your `svelte.config.js`:

```js
/// file: svelte.config.js
export default {
kit: {
+++experimental: {
tracing: {
server: true,
serverFile: true
}
}+++
}
};
```

> [!NOTE] Tracing -- and more significantly, tracing 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.

## Development quickstart

To view your first trace, you'll need to set up a local collector. We'll use [Jaeger](https://www.jaegertracing.io/docs/getting-started/) in this example, as they provide an easy-to-use quickstart command. Once your collector is running locally:

- Turn on the experimental flag mentioned above in your `svelte.config.js` file
- Use your package manager to install `@opentelemetry/sdk-node`, `@opentelemetry/auto-instrumentations-node`, `@opentelemetry/exporter-trace-otlp-proto`, and `import-in-the-middle`
```sh
npm i @opentelemetry/sdk-node @opentelemetry/auto-instrumentations-node @opentelemetry/exporter-trace-oltp-proto import-in-the-middle
```
- Create `src/tracing.server.ts` with the following:

```ts
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();
```

Any server-side requests will now begin generating traces, which you can view in Jaeger's web console at [localhost:16686](http://localhost:16686).
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"@parcel/watcher",
"esbuild",
"netlify-cli",
"protobufjs",
"rolldown",
"sharp",
"svelte-preprocess",
Expand Down
3 changes: 3 additions & 0 deletions packages/adapter-auto/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,9 @@ export default () => ({
supports_error(
'The read function imported from $app/server only works in certain environments'
);
},
tracing: () => {
supports_error('`tracing.server.js` only works in certain environments');
}
}
});
Expand Down
2 changes: 1 addition & 1 deletion packages/adapter-auto/package.json

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed we used the same version everywhere and that we've switched to catalog for a lot of these shared deps, so I went ahead and took care of this one

Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
"devDependencies": {
"@sveltejs/kit": "workspace:^",
"@sveltejs/vite-plugin-svelte": "catalog:",
"@types/node": "^18.19.119",
"@types/node": "catalog:",
"typescript": "^5.3.3",
"vitest": "catalog:"
},
Expand Down
9 changes: 8 additions & 1 deletion packages/adapter-cloudflare/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,12 @@ export default function (options = {}) {
ASSETS: assets_binding
}
});
if (builder.hasServerTracingFile()) {
builder.trace({
entrypoint: worker_dest,
tracing: `${builder.getServerDirectory()}/tracing.server.js`
});
}

// _headers
if (existsSync('_headers')) {
Expand Down Expand Up @@ -184,7 +190,8 @@ export default function (options = {}) {
}

return true;
}
},
tracing: () => true
}
};
}
Expand Down
2 changes: 1 addition & 1 deletion packages/adapter-cloudflare/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
"devDependencies": {
"@playwright/test": "catalog:",
"@sveltejs/kit": "workspace:^",
"@types/node": "^18.19.119",
"@types/node": "catalog:",
"esbuild": "^0.25.4",
"typescript": "^5.3.3",
"vitest": "catalog:"
Expand Down
53 changes: 48 additions & 5 deletions packages/adapter-netlify/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/** @import { BuildOptions } from 'esbuild' */
import { appendFileSync, existsSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';
import { dirname, join, resolve, posix } from 'node:path';
import { fileURLToPath } from 'node:url';
Expand Down Expand Up @@ -106,7 +107,8 @@ export default function ({ split = false, edge = edge_set_in_env_var } = {}) {
}

return true;
}
},
tracing: () => true
}
};
}
Expand Down Expand Up @@ -174,9 +176,8 @@ async function generate_edge_functions({ builder }) {
version: 1
};

await esbuild.build({
entryPoints: [`${tmp}/entry.js`],
outfile: '.netlify/edge-functions/render.js',
/** @type {BuildOptions} */
const esbuild_config = {
bundle: true,
format: 'esm',
platform: 'browser',
Expand All @@ -194,7 +195,28 @@ async function generate_edge_functions({ builder }) {
// https://docs.netlify.com/edge-functions/api/#runtime-environment
external: builtinModules.map((id) => `node:${id}`),
alias: Object.fromEntries(builtinModules.map((id) => [id, `node:${id}`]))
});
};
await Promise.all([
esbuild.build({
entryPoints: [`${tmp}/entry.js`],
outfile: '.netlify/edge-functions/render.js',
...esbuild_config
}),
builder.hasServerTracingFile() &&
esbuild.build({
entryPoints: [`${builder.getServerDirectory()}/tracing.server.js`],
outfile: '.netlify/edge/tracing.server.js',
...esbuild_config
})
]);

if (builder.hasServerTracingFile()) {
builder.trace({
entrypoint: '.netlify/edge-functions/render.js',
tracing: '.netlify/edge/tracing.server.js',
start: '.netlify/edge/start.js'
});
}

writeFileSync('.netlify/edge-functions/manifest.json', JSON.stringify(edge_manifest));
}
Expand Down Expand Up @@ -272,6 +294,16 @@ function generate_lambda_functions({ builder, publish, split }) {

writeFileSync(`.netlify/functions-internal/${name}.mjs`, fn);
writeFileSync(`.netlify/functions-internal/${name}.json`, fn_config);
if (builder.hasServerTracingFile()) {
builder.trace({
entrypoint: `.netlify/functions-internal/${name}.mjs`,
tracing: '.netlify/server/tracing.server.js',
start: `.netlify/functions-start/${name}.start.mjs`,
module: {
exports: ['handler']
}
});
}

const redirect = `/.netlify/functions/${name} 200`;
redirects.push(`${pattern} ${redirect}`);
Expand All @@ -286,6 +318,17 @@ function generate_lambda_functions({ builder, publish, split }) {

writeFileSync(`.netlify/functions-internal/${FUNCTION_PREFIX}render.json`, fn_config);
writeFileSync(`.netlify/functions-internal/${FUNCTION_PREFIX}render.mjs`, fn);
if (builder.hasServerTracingFile()) {
builder.trace({
entrypoint: `.netlify/functions-internal/${FUNCTION_PREFIX}render.mjs`,
tracing: '.netlify/server/tracing.server.js',
start: `.netlify/functions-start/${FUNCTION_PREFIX}render.start.mjs`,
module: {
exports: ['handler']
}
});
}

redirects.push(`* /.netlify/functions/${FUNCTION_PREFIX}render 200`);
}

Expand Down
2 changes: 1 addition & 1 deletion packages/adapter-netlify/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
"@rollup/plugin-node-resolve": "^16.0.0",
"@sveltejs/kit": "workspace:^",
"@sveltejs/vite-plugin-svelte": "catalog:",
"@types/node": "^18.19.119",
"@types/node": "catalog:",
"@types/set-cookie-parser": "^2.4.7",
"rollup": "^4.14.2",
"typescript": "^5.3.3",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// this is just here to make sure the changes resulting from it work
7 changes: 6 additions & 1 deletion packages/adapter-netlify/test/apps/basic/svelte.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@ import adapter from '../../../index.js';
/** @type {import('@sveltejs/kit').Config} */
const config = {
kit: {
adapter: adapter()
adapter: adapter(),
experimental: {
tracing: {
serverFile: true
}
}
}
};

Expand Down
28 changes: 23 additions & 5 deletions packages/adapter-node/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,21 @@ export default function (opts = {}) {

const pkg = JSON.parse(readFileSync('package.json', 'utf8'));

/** @type {Record<string, string>} */
const input = {
index: `${tmp}/index.js`,
manifest: `${tmp}/manifest.js`
};

if (builder.hasServerTracingFile()) {
input['tracing.server'] = `${tmp}/tracing.server.js`;
}

// we bundle the Vite output so that deployments only need
// their production dependencies. Anything in devDependencies
// will get included in the bundled code
const bundle = await rollup({
input: {
index: `${tmp}/index.js`,
manifest: `${tmp}/manifest.js`
},
input,
external: [
// dependencies could have deep exports, so we need a regex
...Object.keys(pkg.dependencies || {}).map((d) => new RegExp(`^${d}(\\/.*)?$`))
Expand Down Expand Up @@ -89,10 +96,21 @@ export default function (opts = {}) {
ENV_PREFIX: JSON.stringify(envPrefix)
}
});

if (builder.hasServerTracingFile()) {
builder.trace({
entrypoint: `${out}/index.js`,
tracing: `${out}/server/tracing.server.js`,
module: {
exports: ['path', 'host', 'port', 'server']
}
});
}
},

supports: {
read: () => true
read: () => true,
tracing: () => true
}
};
}
2 changes: 1 addition & 1 deletion packages/adapter-node/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
"@polka/url": "^1.0.0-next.28",
"@sveltejs/kit": "workspace:^",
"@sveltejs/vite-plugin-svelte": "catalog:",
"@types/node": "^18.19.119",
"@types/node": "catalog:",
"polka": "^1.0.0-next.28",
"sirv": "^3.0.0",
"typescript": "^5.3.3",
Expand Down
2 changes: 1 addition & 1 deletion packages/adapter-static/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
"@playwright/test": "catalog:",
"@sveltejs/kit": "workspace:^",
"@sveltejs/vite-plugin-svelte": "catalog:",
"@types/node": "^18.19.119",
"@types/node": "catalog:",
"sirv": "^3.0.0",
"svelte": "^5.35.5",
"typescript": "^5.3.3",
Expand Down
Loading
Loading