From c559b5273bf98fa4f2a6b11874c8f7dc2c9805d3 Mon Sep 17 00:00:00 2001 From: Nic Polumeyv <162764842+Nic-Polumeyv@users.noreply.github.com> Date: Thu, 30 Jul 2026 22:26:16 -0400 Subject: [PATCH 1/4] chore: extract record_traced_span for span + store ceremony --- .../kit/src/runtime/server/page/actions.js | 15 +- .../kit/src/runtime/server/page/load_data.js | 189 +++++++++--------- .../kit/src/runtime/telemetry/record_span.js | 27 ++- 3 files changed, 125 insertions(+), 106 deletions(-) diff --git a/packages/kit/src/runtime/server/page/actions.js b/packages/kit/src/runtime/server/page/actions.js index 315fff550560..fe66affae95b 100644 --- a/packages/kit/src/runtime/server/page/actions.js +++ b/packages/kit/src/runtime/server/page/actions.js @@ -4,12 +4,11 @@ import * as devalue from 'devalue'; import { DEV } from 'esm-env'; import { json } from '@sveltejs/kit'; import { HttpError, Redirect, ActionFailure, SvelteKitError } from '@sveltejs/kit/internal'; -import { with_request_store, merge_tracing } from '@sveltejs/kit/internal/server'; import { normalize_error } from '../../../utils/error.js'; import { is_form_content_type, negotiate } from '../../../utils/http.js'; import { create_replacer, with_version_header } from '../utils.js'; import { handle_error_and_jsonify } from '../errors.js'; -import { record_span } from '../../telemetry/record_span.js'; +import { record_traced_span } from '../../telemetry/record_span.js'; /** @param {RequestEvent} event */ export function is_action_json_request(event) { @@ -274,18 +273,16 @@ async function call_action(event, event_state, actions) { ); } - return record_span({ + return record_traced_span({ name: 'sveltekit.form_action', attributes: { 'sveltekit.form_action.name': name, 'http.route': event.route.id || 'unknown' }, - fn: async (current) => { - const traced_event = merge_tracing(event, current); - - const result = await with_request_store({ event: traced_event, state: event_state }, () => - action(traced_event) - ); + event, + state: event_state, + fn: async (traced_event, current) => { + const result = await action(traced_event); if (result instanceof ActionFailure) { current.setAttributes({ diff --git a/packages/kit/src/runtime/server/page/load_data.js b/packages/kit/src/runtime/server/page/load_data.js index 67c9c3c37c07..4b5d25b12748 100644 --- a/packages/kit/src/runtime/server/page/load_data.js +++ b/packages/kit/src/runtime/server/page/load_data.js @@ -2,8 +2,7 @@ import { DEV } from 'esm-env'; import { noop } from '../../../utils/functions.js'; import { disable_search, make_trackable } from '../../../utils/url.js'; import { validate_depends, validate_load_response } from '../../shared.js'; -import { with_request_store, merge_tracing } from '@sveltejs/kit/internal/server'; -import { record_span } from '../../telemetry/record_span.js'; +import { record_traced_span } from '../../telemetry/record_span.js'; import { base64_encode } from '../../utils.js'; import { NULL_BODY_STATUS } from '../constants.js'; import { get_node_type } from '../utils.js'; @@ -73,7 +72,7 @@ export async function load_server_data({ event, event_state, state, node, parent let done = false; - const result = await record_span({ + const result = await record_traced_span({ name: 'sveltekit.load', attributes: { 'sveltekit.load.node_id': node.server_id || 'unknown', @@ -81,96 +80,95 @@ export async function load_server_data({ event, event_state, state, node, parent 'sveltekit.load.environment': 'server', 'http.route': event.route.id || 'unknown' }, - fn: async (current) => { - const traced_event = merge_tracing(event, current); - const result = await with_request_store({ event: traced_event, state: event_state }, () => - load.call(null, { - ...traced_event, - fetch: (info, init) => { - const url = new URL(info instanceof Request ? info.url : info, event.url); - - if (DEV && done && !uses.dependencies.has(url.href)) { - console.warn( - `${node.server_id}: Calling \`event.fetch(...)\` in a promise handler after \`load(...)\` has returned will not cause the function to re-run when the dependency is invalidated` - ); - } + event, + state: event_state, + fn: async (traced_event) => { + const result = await load.call(null, { + ...traced_event, + fetch: (info, init) => { + const url = new URL(info instanceof Request ? info.url : info, event.url); + + if (DEV && done && !uses.dependencies.has(url.href)) { + console.warn( + `${node.server_id}: Calling \`event.fetch(...)\` in a promise handler after \`load(...)\` has returned will not cause the function to re-run when the dependency is invalidated` + ); + } - // Note: server fetches are not added to uses.depends due to security concerns - return event.fetch(info, init); - }, - /** @param {string[]} deps */ - depends: (...deps) => { - for (const dep of deps) { - const { href } = new URL(dep, event.url); - - if (DEV) { - validate_depends(node.server_id || 'missing route ID', dep); - - if (done && !uses.dependencies.has(href)) { - console.warn( - `${node.server_id}: Calling \`depends(...)\` in a promise handler after \`load(...)\` has returned will not cause the function to re-run when the dependency is invalidated` - ); - } - } + // Note: server fetches are not added to uses.depends due to security concerns + return event.fetch(info, init); + }, + /** @param {string[]} deps */ + depends: (...deps) => { + for (const dep of deps) { + const { href } = new URL(dep, event.url); - uses.dependencies.add(href); - } - }, - params: new Proxy(event.params, { - get: (target, key) => { - if (DEV && done && typeof key === 'string' && !uses.params.has(key)) { + if (DEV) { + validate_depends(node.server_id || 'missing route ID', dep); + + if (done && !uses.dependencies.has(href)) { console.warn( - `${node.server_id}: Accessing \`params.${String( - key - )}\` in a promise handler after \`load(...)\` has returned will not cause the function to re-run when the param changes` + `${node.server_id}: Calling \`depends(...)\` in a promise handler after \`load(...)\` has returned will not cause the function to re-run when the dependency is invalidated` ); } - - if (is_tracking) { - uses.params.add(key); - } - return target[/** @type {string} */ (key)]; } - }), - parent: async () => { - if (DEV && done && !uses.parent) { + + uses.dependencies.add(href); + } + }, + params: new Proxy(event.params, { + get: (target, key) => { + if (DEV && done && typeof key === 'string' && !uses.params.has(key)) { console.warn( - `${node.server_id}: Calling \`parent(...)\` in a promise handler after \`load(...)\` has returned will not cause the function to re-run when parent data changes` + `${node.server_id}: Accessing \`params.${String( + key + )}\` in a promise handler after \`load(...)\` has returned will not cause the function to re-run when the param changes` ); } if (is_tracking) { - uses.parent = true; + uses.params.add(key); } - return parent(); - }, - route: new Proxy(event.route, { - get: (target, key) => { - if (DEV && done && typeof key === 'string' && !uses.route) { - console.warn( - `${node.server_id}: Accessing \`route.${String( - key - )}\` in a promise handler after \`load(...)\` has returned will not cause the function to re-run when the route changes` - ); - } + return target[/** @type {string} */ (key)]; + } + }), + parent: async () => { + if (DEV && done && !uses.parent) { + console.warn( + `${node.server_id}: Calling \`parent(...)\` in a promise handler after \`load(...)\` has returned will not cause the function to re-run when parent data changes` + ); + } - if (is_tracking) { - uses.route = true; - } - return target[/** @type {'id'} */ (key)]; + if (is_tracking) { + uses.parent = true; + } + return parent(); + }, + route: new Proxy(event.route, { + get: (target, key) => { + if (DEV && done && typeof key === 'string' && !uses.route) { + console.warn( + `${node.server_id}: Accessing \`route.${String( + key + )}\` in a promise handler after \`load(...)\` has returned will not cause the function to re-run when the route changes` + ); } - }), - url, - untrack(fn) { - is_tracking = false; - try { - return fn(); - } finally { - is_tracking = true; + + if (is_tracking) { + uses.route = true; } + return target[/** @type {'id'} */ (key)]; } - }) - ); + }), + url, + untrack(fn) { + is_tracking = false; + try { + return fn(); + } finally { + is_tracking = true; + } + } + }); return result; } @@ -224,7 +222,9 @@ export async function load_data({ return server_data_node?.data ?? null; } - const result = await record_span({ + const child_state = { ...event_state, is_in_universal_load: true }; + + const result = await record_traced_span({ name: 'sveltekit.load', attributes: { 'sveltekit.load.node_id': node.universal_id || 'unknown', @@ -232,24 +232,21 @@ export async function load_data({ 'sveltekit.load.environment': 'server', 'http.route': event.route.id || 'unknown' }, - fn: async (current) => { - const traced_event = merge_tracing(event, current); - const child_state = { ...event_state, is_in_universal_load: true }; - - return await with_request_store({ event: traced_event, state: child_state }, () => - load.call(null, { - url: event.url, - params: event.params, - data: server_data_node?.data ?? null, - route: event.route, - fetch: create_universal_fetch(event, state, fetched, csr, resolve_opts), - setHeaders: event.setHeaders, - depends: noop, - parent, - untrack: (fn) => fn(), - tracing: traced_event.tracing - }) - ); + event, + state: child_state, + fn: async (traced_event) => { + return await load.call(null, { + url: event.url, + params: event.params, + data: server_data_node?.data ?? null, + route: event.route, + fetch: create_universal_fetch(event, state, fetched, csr, resolve_opts), + setHeaders: event.setHeaders, + depends: noop, + parent, + untrack: (fn) => fn(), + tracing: traced_event.tracing + }); } }); diff --git a/packages/kit/src/runtime/telemetry/record_span.js b/packages/kit/src/runtime/telemetry/record_span.js index eaabb1ea5e4c..c32d19da62cc 100644 --- a/packages/kit/src/runtime/telemetry/record_span.js +++ b/packages/kit/src/runtime/telemetry/record_span.js @@ -1,5 +1,8 @@ -/** @import { RecordSpan } from 'types' */ +/** @import { RequestEvent } from '@sveltejs/kit' */ +/** @import { Span } from '@opentelemetry/api' */ +/** @import { RecordSpan, RequestState } from 'types' */ import { HttpError, Redirect } from '@sveltejs/kit/internal'; +import { merge_tracing, with_request_store } from '@sveltejs/kit/internal/server'; import { noop_span } from './noop.js'; import { otel } from './otel.js'; @@ -63,3 +66,25 @@ export async function record_span({ name, attributes, fn }) { } }); } + +/** + * @template T + * @param {{ + * name: string; + * attributes: Parameters[0]['attributes']; + * event: RequestEvent; + * state: RequestState; + * fn: (event: RequestEvent, current: Span) => Promise; + * }} options + * @returns {Promise} + */ +export function record_traced_span({ name, attributes, event, state, fn }) { + return record_span({ + name, + attributes, + fn: (current) => { + const traced_event = merge_tracing(event, current); + return with_request_store({ event: traced_event, state }, () => fn(traced_event, current)); + } + }); +} From 6d776423dc6cf52f615660632b5745f6f25b6691 Mon Sep 17 00:00:00 2001 From: Nic Polumeyv <162764842+Nic-Polumeyv@users.noreply.github.com> Date: Thu, 30 Jul 2026 22:29:47 -0400 Subject: [PATCH 2/4] chore: simplify the helper types --- packages/kit/src/runtime/telemetry/record_span.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/kit/src/runtime/telemetry/record_span.js b/packages/kit/src/runtime/telemetry/record_span.js index c32d19da62cc..5238d79f80ca 100644 --- a/packages/kit/src/runtime/telemetry/record_span.js +++ b/packages/kit/src/runtime/telemetry/record_span.js @@ -71,10 +71,10 @@ export async function record_span({ name, attributes, fn }) { * @template T * @param {{ * name: string; - * attributes: Parameters[0]['attributes']; + * attributes: Record; * event: RequestEvent; * state: RequestState; - * fn: (event: RequestEvent, current: Span) => Promise; + * fn: (traced_event: RequestEvent, current: Span) => Promise; * }} options * @returns {Promise} */ From 55641f4b42b4b3f129f594690f995c257c811623 Mon Sep 17 00:00:00 2001 From: Nic Polumeyv <162764842+Nic-Polumeyv@users.noreply.github.com> Date: Thu, 30 Jul 2026 22:48:55 -0400 Subject: [PATCH 3/4] chore: use record_traced_span for remote calls and form posts --- .../src/runtime/server/remote-functions.js | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/packages/kit/src/runtime/server/remote-functions.js b/packages/kit/src/runtime/server/remote-functions.js index 08e0f988aaa5..a096eb705a45 100644 --- a/packages/kit/src/runtime/server/remote-functions.js +++ b/packages/kit/src/runtime/server/remote-functions.js @@ -3,7 +3,7 @@ import { json, error } from '@sveltejs/kit'; import { Redirect, SvelteKitError } from '@sveltejs/kit/internal'; -import { with_request_store, merge_tracing } from '@sveltejs/kit/internal/server'; +import { with_request_store } from '@sveltejs/kit/internal/server'; import { app_dir, base } from '$app/paths/internal/server'; import { is_form_content_type } from '../../utils/http.js'; import { create_remote_key, parse_remote_arg, split_remote_key, stringify } from '../shared.js'; @@ -11,7 +11,7 @@ import { handle_error_and_jsonify } from './errors.js'; import { normalize_error } from '../../utils/error.js'; import { check_incorrect_fail_use } from './page/actions.js'; import { DEV } from 'esm-env'; -import { record_span } from '../telemetry/record_span.js'; +import { record_traced_span } from '../telemetry/record_span.js'; import { deserialize_binary_form } from '../form-utils.js'; import { with_version_header } from './utils.js'; @@ -24,15 +24,20 @@ const KEEP_ALIVE_INTERVAL = 30_000; /** @type {typeof handle_remote_call_internal} */ export async function handle_remote_call(event, state, options, manifest, id) { - return record_span({ + return record_traced_span({ name: 'sveltekit.remote.call', attributes: { 'sveltekit.remote.call.id': id }, - fn: async (current) => { - const traced_event = merge_tracing(event, current); - const response = await with_request_store({ event: traced_event, state }, () => - handle_remote_call_internal(traced_event, state, options, manifest, id) + event, + state, + fn: async (traced_event) => { + const response = await handle_remote_call_internal( + traced_event, + state, + options, + manifest, + id ); return with_version_header(response); } @@ -515,17 +520,14 @@ function create_requested_map(refreshes) { /** @type {typeof handle_remote_form_post_internal} */ export async function handle_remote_form_post(event, state, manifest, id) { - return record_span({ + return record_traced_span({ name: 'sveltekit.remote.form.post', attributes: { 'sveltekit.remote.form.post.id': id }, - fn: (current) => { - const traced_event = merge_tracing(event, current); - return with_request_store({ event: traced_event, state }, () => - handle_remote_form_post_internal(traced_event, state, manifest, id) - ); - } + event, + state, + fn: (traced_event) => handle_remote_form_post_internal(traced_event, state, manifest, id) }); } From 424b6ab420a36060e1436358140a7b42544e0cd0 Mon Sep 17 00:00:00 2001 From: Nic Polumeyv <162764842+Nic-Polumeyv@users.noreply.github.com> Date: Thu, 30 Jul 2026 22:59:35 -0400 Subject: [PATCH 4/4] chore: expression-bodied load callbacks --- .../kit/src/runtime/server/page/load_data.js | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/packages/kit/src/runtime/server/page/load_data.js b/packages/kit/src/runtime/server/page/load_data.js index 4b5d25b12748..9cafea054f01 100644 --- a/packages/kit/src/runtime/server/page/load_data.js +++ b/packages/kit/src/runtime/server/page/load_data.js @@ -82,8 +82,8 @@ export async function load_server_data({ event, event_state, state, node, parent }, event, state: event_state, - fn: async (traced_event) => { - const result = await load.call(null, { + fn: async (traced_event) => + load.call(null, { ...traced_event, fetch: (info, init) => { const url = new URL(info instanceof Request ? info.url : info, event.url); @@ -168,10 +168,7 @@ export async function load_server_data({ event, event_state, state, node, parent is_tracking = true; } } - }); - - return result; - } + }) }); if (DEV) { @@ -234,8 +231,8 @@ export async function load_data({ }, event, state: child_state, - fn: async (traced_event) => { - return await load.call(null, { + fn: async (traced_event) => + load.call(null, { url: event.url, params: event.params, data: server_data_node?.data ?? null, @@ -246,8 +243,7 @@ export async function load_data({ parent, untrack: (fn) => fn(), tracing: traced_event.tracing - }); - } + }) }); if (DEV) {