From 29a5eeafe72f5bd347ada64d0fbd6cb21d64fd96 Mon Sep 17 00:00:00 2001 From: "sentry-junior[bot]" <264270552+sentry-junior[bot]@users.noreply.github.com> Date: Thu, 29 Oct 2026 13:07:13 +0000 Subject: [PATCH 1/2] ref: Pass optional span attributes directly instead of conditional spreads Span attributes that are undefined are dropped when the span is created, so wrapping them in conditional spreads is unnecessary. Co-Authored-By: Francesco Gringl-Novy --- packages/angular/src/tracing.ts | 4 +--- .../src/performance/interactions.ts | 8 ++++---- .../src/tracing/browserTracingIntegration.ts | 2 +- .../worker/instrumentQueueProducer.ts | 2 +- .../instrumentations/worker/instrumentR2.ts | 2 +- .../appRouterRoutingInstrumentation.ts | 8 ++++---- .../pagesRouterRoutingInstrumentation.ts | 2 +- .../src/server/createServerInstrumentation.ts | 2 +- packages/react/src/profiler.tsx | 10 +++++----- packages/react/src/tanstackrouter.ts | 4 ++-- .../v3/client/browserTracingIntegration.ts | 2 +- packages/server-utils/src/ai/flue/index.ts | 4 ++-- packages/server-utils/src/ai/flue/utils.ts | 8 ++++---- .../server-utils/src/ai/pi-durable/models.ts | 12 ++++++------ .../server-utils/src/ai/pi-durable/tools.ts | 4 ++-- .../server-utils/src/ai/typesafe/index.ts | 2 +- .../integrations/express/instrumentation.ts | 2 +- .../server-utils/src/integrations/mysql.ts | 6 +++--- .../vercel-ai/vercel-ai-dc-subscriber.ts | 19 ++++++++++--------- packages/solid/src/tanstackrouter.ts | 4 ++-- packages/svelte/src/performance.ts | 4 ++-- packages/vue/src/tanstackrouter.ts | 4 ++-- packages/vue/src/tracing.ts | 4 ++-- 23 files changed, 59 insertions(+), 60 deletions(-) diff --git a/packages/angular/src/tracing.ts b/packages/angular/src/tracing.ts index 3a50bf232339..c5884695121c 100644 --- a/packages/angular/src/tracing.ts +++ b/packages/angular/src/tracing.ts @@ -159,9 +159,7 @@ export class TraceService implements OnDestroy { [SENTRY_OP]: ROUTER, [SENTRY_ORIGIN]: 'auto.ui.angular', [URL_FULL]: strippedUrl, - ...(navigationEvent.navigationTrigger && { - navigationTrigger: navigationEvent.navigationTrigger, - }), + navigationTrigger: navigationEvent.navigationTrigger, }, }), ) || null; diff --git a/packages/browser-utils/src/performance/interactions.ts b/packages/browser-utils/src/performance/interactions.ts index 33913a40c619..3112c7b6a4ac 100644 --- a/packages/browser-utils/src/performance/interactions.ts +++ b/packages/browser-utils/src/performance/interactions.ts @@ -217,10 +217,10 @@ function registerInteractionListener( [SENTRY_SEGMENT_NAME_SOURCE]: hasSpanStreaming ? streamedNameSource : latestRoute.source || 'url', [SENTRY_ORIGIN]: 'auto.browser.interactions', ...(hasSpanStreaming && { [SENTRY_SEGMENT_NAME]: streamedName }), - ...(latestRoute.routeId && { [ROUTER_NAVIGATION_ROUTE_ID]: latestRoute.routeId }), - ...(latestRoute.urlTemplate && { [URL_TEMPLATE]: latestRoute.urlTemplate }), - ...(latestRoute.httpRoute && { [HTTP_ROUTE]: latestRoute.httpRoute }), - ...(latestRoute.urlPath && { [URL_PATH]: latestRoute.urlPath }), + [ROUTER_NAVIGATION_ROUTE_ID]: latestRoute.routeId, + [URL_TEMPLATE]: latestRoute.urlTemplate, + [HTTP_ROUTE]: latestRoute.httpRoute, + [URL_PATH]: latestRoute.urlPath, ...(latestRoute.urlFull && { [URL_FULL]: filterCollectedUrl(latestRoute.urlFull) }), }, }, diff --git a/packages/browser/src/tracing/browserTracingIntegration.ts b/packages/browser/src/tracing/browserTracingIntegration.ts index b02a5d5ebcca..e21b40a86f27 100644 --- a/packages/browser/src/tracing/browserTracingIntegration.ts +++ b/packages/browser/src/tracing/browserTracingIntegration.ts @@ -367,7 +367,7 @@ export const browserTracingIntegration = ((options: Partial( [MESSAGING_DESTINATION_NAME]: bindingName, [MESSAGING_OPERATION_TYPE]: 'send', [MESSAGING_OPERATION_NAME]: 'send', - ...(messageCount !== undefined && { [MESSAGING_BATCH_MESSAGE_COUNT]: messageCount }), + [MESSAGING_BATCH_MESSAGE_COUNT]: messageCount, [MESSAGING_MESSAGE_BODY_SIZE]: bodySize, [SENTRY_OP]: QUEUE_PUBLISH, [SENTRY_ORIGIN]: ORIGIN, diff --git a/packages/cloudflare/src/instrumentations/worker/instrumentR2.ts b/packages/cloudflare/src/instrumentations/worker/instrumentR2.ts index a2ffdf72e50a..afc740cc250f 100644 --- a/packages/cloudflare/src/instrumentations/worker/instrumentR2.ts +++ b/packages/cloudflare/src/instrumentations/worker/instrumentR2.ts @@ -64,7 +64,7 @@ function createSpanOptions(bindingName: string, r2Op: R2OperationKey, key?: stri attributes: { [CLOUDFLARE_R2_OPERATION]: operation, [CLOUDFLARE_R2_BUCKET]: bindingName, - ...(requestKey !== undefined && { [CLOUDFLARE_R2_REQUEST_KEY]: requestKey }), + [CLOUDFLARE_R2_REQUEST_KEY]: requestKey, ...(isR2ListOptions(key) && key.prefix !== undefined && { [CLOUDFLARE_R2_REQUEST_PREFIX]: key.prefix }), ...(isR2ListOptions(key) && key.delimiter !== undefined && { [CLOUDFLARE_R2_REQUEST_DELIMITER]: key.delimiter }), [SENTRY_OP]: op, diff --git a/packages/nextjs/src/client/routing/appRouterRoutingInstrumentation.ts b/packages/nextjs/src/client/routing/appRouterRoutingInstrumentation.ts index ba6e5c88986e..d48f48cde5ea 100644 --- a/packages/nextjs/src/client/routing/appRouterRoutingInstrumentation.ts +++ b/packages/nextjs/src/client/routing/appRouterRoutingInstrumentation.ts @@ -150,7 +150,7 @@ export function appRouterInstrumentPageLoad(client: Client): void { [SENTRY_SEGMENT_NAME_SOURCE]: parameterizedPathname ? 'route' : 'url', [URL_PATH]: WINDOW.location.pathname, [URL_FULL]: documentUrl, - ...(parameterizedPathname && { [URL_TEMPLATE]: parameterizedPathname }), + [URL_TEMPLATE]: parameterizedPathname, }, }; @@ -258,7 +258,7 @@ export function appRouterInstrumentNavigation(client: Client): void { [SENTRY_SEGMENT_NAME_SOURCE]: parameterizedPathname ? 'route' : 'url', // oxlint-disable-next-line typescript/no-deprecated -- Preserve the existing attribute name. [NAVIGATION_TYPE]: `router.${navigationType}`, - ...(parameterizedPathname && { [URL_TEMPLATE]: parameterizedPathname }), + [URL_TEMPLATE]: parameterizedPathname, }, }, { url: getAbsoluteUrl(normalizedHref) }, @@ -296,7 +296,7 @@ export function appRouterInstrumentNavigation(client: Client): void { [SENTRY_SEGMENT_NAME_SOURCE]: parameterizedPathname ? 'route' : 'url', // oxlint-disable-next-line typescript/no-deprecated -- Preserve the existing attribute name. [NAVIGATION_TYPE]: traversal?.navigationType ?? 'browser.popstate', - ...(parameterizedPathname && { [URL_TEMPLATE]: parameterizedPathname }), + [URL_TEMPLATE]: parameterizedPathname, }, }, // The full location rather than just the pathname, so the span's `url.full` keeps the @@ -394,7 +394,7 @@ function patchRouter(client: Client, router: NextRouter, currentNavigationSpanRe [SENTRY_SEGMENT_NAME_SOURCE]: parameterizedPathname ? 'route' : 'url', // oxlint-disable-next-line typescript/no-deprecated -- Preserve the existing attribute name. [NAVIGATION_TYPE]: `router.${routerFunctionName}`, - ...(parameterizedPathname && { [URL_TEMPLATE]: parameterizedPathname }), + [URL_TEMPLATE]: parameterizedPathname, }, }, { url: getAbsoluteUrl(normalizedHref) }, diff --git a/packages/nextjs/src/client/routing/pagesRouterRoutingInstrumentation.ts b/packages/nextjs/src/client/routing/pagesRouterRoutingInstrumentation.ts index 7335d0465bda..c37599e69fcb 100644 --- a/packages/nextjs/src/client/routing/pagesRouterRoutingInstrumentation.ts +++ b/packages/nextjs/src/client/routing/pagesRouterRoutingInstrumentation.ts @@ -109,7 +109,7 @@ export function pagesRouterInstrumentPageLoad(client: Client): void { [SENTRY_OP]: PAGELOAD, [SENTRY_ORIGIN]: 'auto.pageload.nextjs.pages_router_instrumentation', [SENTRY_SEGMENT_NAME_SOURCE]: route ? 'route' : 'url', - ...(route && { [URL_TEMPLATE]: route }), + [URL_TEMPLATE]: route, ...(params && { ...params }), }, }, diff --git a/packages/react-router/src/server/createServerInstrumentation.ts b/packages/react-router/src/server/createServerInstrumentation.ts index ebf16d85c87d..892663c37a46 100644 --- a/packages/react-router/src/server/createServerInstrumentation.ts +++ b/packages/react-router/src/server/createServerInstrumentation.ts @@ -240,7 +240,7 @@ export function createSentryServerInstrumentation( [SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api', 'react_router.route.id': routeId, [HTTP_ROUTE]: routePattern, - ...(middlewareName && { 'react_router.middleware.name': middlewareName }), + 'react_router.middleware.name': middlewareName, 'react_router.middleware.index': middlewareIndex, }, }, diff --git a/packages/react/src/profiler.tsx b/packages/react/src/profiler.tsx index 508d9e508bdf..0c1c3fd874d5 100644 --- a/packages/react/src/profiler.tsx +++ b/packages/react/src/profiler.tsx @@ -66,7 +66,7 @@ class Profiler extends React.Component { attributes: { [SENTRY_OP]: UI_MOUNT, [SENTRY_ORIGIN]: 'auto.ui.react.profiler', - ...(componentName && { [UI_COMPONENT_NAME]: componentName }), + [UI_COMPONENT_NAME]: componentName, ...(hasSpanStreaming && { [SENTRY_DESCRIPTION]: description }), }, }); @@ -102,7 +102,7 @@ class Profiler extends React.Component { attributes: { [SENTRY_OP]: UI_UPDATE, [SENTRY_ORIGIN]: 'auto.ui.react.profiler', - ...(componentName && { [UI_COMPONENT_NAME]: componentName }), + [UI_COMPONENT_NAME]: componentName, 'ui.react.changed_props': changedProps, ...(hasSpanStreaming && { [SENTRY_DESCRIPTION]: description }), }, @@ -142,7 +142,7 @@ class Profiler extends React.Component { attributes: { [SENTRY_OP]: UI_RENDER, [SENTRY_ORIGIN]: 'auto.ui.react.profiler', - ...(componentName && { [UI_COMPONENT_NAME]: componentName }), + [UI_COMPONENT_NAME]: componentName, ...(hasSpanStreaming && { [SENTRY_DESCRIPTION]: description }), }, }); @@ -229,7 +229,7 @@ function useProfiler( attributes: { [SENTRY_OP]: UI_MOUNT, [SENTRY_ORIGIN]: 'auto.ui.react.profiler', - ...(componentName && { [UI_COMPONENT_NAME]: componentName }), + [UI_COMPONENT_NAME]: componentName, ...(hasSpanStreaming && { [SENTRY_DESCRIPTION]: description }), }, }); @@ -257,7 +257,7 @@ function useProfiler( attributes: { [SENTRY_OP]: UI_RENDER, [SENTRY_ORIGIN]: 'auto.ui.react.profiler', - ...(componentName && { [UI_COMPONENT_NAME]: componentName }), + [UI_COMPONENT_NAME]: componentName, ...(hasSpanStreaming && { [SENTRY_DESCRIPTION]: description }), }, }); diff --git a/packages/react/src/tanstackrouter.ts b/packages/react/src/tanstackrouter.ts index 41eec4694aae..e7f1c20f8e2e 100644 --- a/packages/react/src/tanstackrouter.ts +++ b/packages/react/src/tanstackrouter.ts @@ -106,7 +106,7 @@ export function tanstackRouterBrowserTracingIntegration( [SENTRY_OP]: PAGELOAD, [SENTRY_ORIGIN]: 'auto.pageload.react.tanstack_router', [SENTRY_SEGMENT_NAME_SOURCE]: routeMatch ? 'route' : 'url', - ...(routeMatch && { [URL_TEMPLATE]: routeMatch.routeId }), + [URL_TEMPLATE]: routeMatch?.routeId, ...routeMatchToParamSpanAttributes(routeMatch), }, }); @@ -163,7 +163,7 @@ export function tanstackRouterBrowserTracingIntegration( [SENTRY_OP]: NAVIGATION, [SENTRY_ORIGIN]: 'auto.navigation.react.tanstack_router', [SENTRY_SEGMENT_NAME_SOURCE]: routeMatch ? 'route' : 'url', - ...(routeMatch && { [URL_TEMPLATE]: routeMatch.routeId }), + [URL_TEMPLATE]: routeMatch?.routeId, ...routeMatchToParamSpanAttributes(routeMatch), }, }, diff --git a/packages/remix/src/v3/client/browserTracingIntegration.ts b/packages/remix/src/v3/client/browserTracingIntegration.ts index 5e07ca200934..3142c834c966 100644 --- a/packages/remix/src/v3/client/browserTracingIntegration.ts +++ b/packages/remix/src/v3/client/browserTracingIntegration.ts @@ -107,7 +107,7 @@ function instrumentNavigationApi(client: Client): void { name: route ?? (hasSpanStreamingEnabled(client) ? NAVIGATION_SPAN_NAME_FALLBACK : pathname), attributes: { [SENTRY_SEGMENT_NAME_SOURCE]: route ? 'route' : 'url', - ...(route && { [URL_TEMPLATE]: route }), + [URL_TEMPLATE]: route, [SENTRY_ORIGIN]: 'auto.navigation.remix_v3', }, }, diff --git a/packages/server-utils/src/ai/flue/index.ts b/packages/server-utils/src/ai/flue/index.ts index d4856f95f2ac..b5f969c8a16e 100644 --- a/packages/server-utils/src/ai/flue/index.ts +++ b/packages/server-utils/src/ai/flue/index.ts @@ -144,8 +144,8 @@ export function createFlueInstrumentation(options: FlueOptions = {}): FlueInstru attributes: { [SENTRY_ORIGIN]: FLUE_ORIGIN, [GEN_AI_OPERATION_NAME]: 'invoke_agent', - ...(ctx.agentName ? { [GEN_AI_AGENT_NAME]: ctx.agentName } : {}), - ...(ctx.conversationId ? { [GEN_AI_CONVERSATION_ID]: ctx.conversationId } : {}), + [GEN_AI_AGENT_NAME]: ctx.agentName, + [GEN_AI_CONVERSATION_ID]: ctx.conversationId, }, }, async (span: Span) => { diff --git a/packages/server-utils/src/ai/flue/utils.ts b/packages/server-utils/src/ai/flue/utils.ts index 7f22256bf319..399a2aec3580 100644 --- a/packages/server-utils/src/ai/flue/utils.ts +++ b/packages/server-utils/src/ai/flue/utils.ts @@ -123,10 +123,10 @@ export function startTurnSpan(observation: FlueObservation, turnSpans: SpanTrack attributes: { [SENTRY_ORIGIN]: FLUE_ORIGIN, [GEN_AI_OPERATION_NAME]: 'chat', - ...(observation.conversationId ? { [GEN_AI_CONVERSATION_ID]: observation.conversationId } : {}), + [GEN_AI_CONVERSATION_ID]: observation.conversationId, // No conventional attribute for this; it is the only way to tell a compaction turn from a // user-facing one. - ...(observation.purpose ? { 'flue.turn.purpose': observation.purpose } : {}), + 'flue.turn.purpose': observation.purpose, }, }), ); @@ -207,8 +207,8 @@ export function startToolSpan(observation: FlueObservation, toolSpans: SpanTrack attributes: { [SENTRY_ORIGIN]: FLUE_ORIGIN, [GEN_AI_OPERATION_NAME]: 'execute_tool', - ...(toolName ? { [GEN_AI_TOOL_NAME]: toolName } : {}), - ...(observation.conversationId ? { [GEN_AI_CONVERSATION_ID]: observation.conversationId } : {}), + [GEN_AI_TOOL_NAME]: toolName, + [GEN_AI_CONVERSATION_ID]: observation.conversationId, ...(recordInputs && observation.args !== undefined ? { [GEN_AI_TOOL_CALL_ARGUMENTS]: stringify(observation.args) } : {}), diff --git a/packages/server-utils/src/ai/pi-durable/models.ts b/packages/server-utils/src/ai/pi-durable/models.ts index b50a5cdb0420..196973159d70 100644 --- a/packages/server-utils/src/ai/pi-durable/models.ts +++ b/packages/server-utils/src/ai/pi-durable/models.ts @@ -117,14 +117,14 @@ function traceModelRequest( attributes: { [SENTRY_ORIGIN]: PI_DURABLE_ORIGIN, [GEN_AI_OPERATION_NAME]: 'chat', - ...(model.provider ? { [GEN_AI_PROVIDER_NAME]: model.provider } : {}), - ...(model.id ? { [GEN_AI_REQUEST_MODEL]: model.id } : {}), - ...(conversationId ? { [GEN_AI_CONVERSATION_ID]: conversationId } : {}), + [GEN_AI_PROVIDER_NAME]: model.provider, + [GEN_AI_REQUEST_MODEL]: model.id, + [GEN_AI_CONVERSATION_ID]: conversationId, ...getServerAttributes(model), ...(streaming ? { [GEN_AI_RESPONSE_STREAMING]: true } : {}), - ...(callOptions?.temperature !== undefined ? { [GEN_AI_REQUEST_TEMPERATURE]: callOptions.temperature } : {}), - ...(callOptions?.maxTokens !== undefined ? { [GEN_AI_REQUEST_MAX_TOKENS]: callOptions.maxTokens } : {}), - ...(callOptions?.reasoning ? { [GEN_AI_REQUEST_REASONING_LEVEL]: callOptions.reasoning } : {}), + [GEN_AI_REQUEST_TEMPERATURE]: callOptions?.temperature, + [GEN_AI_REQUEST_MAX_TOKENS]: callOptions?.maxTokens, + [GEN_AI_REQUEST_REASONING_LEVEL]: callOptions?.reasoning, ...(recordInputs && context ? getRequestContentAttributes(context) : {}), }, }, diff --git a/packages/server-utils/src/ai/pi-durable/tools.ts b/packages/server-utils/src/ai/pi-durable/tools.ts index 8ccf21155549..6a6ced8f8787 100644 --- a/packages/server-utils/src/ai/pi-durable/tools.ts +++ b/packages/server-utils/src/ai/pi-durable/tools.ts @@ -122,8 +122,8 @@ export function instrumentTool(tool: PiTool, runs: PiRuns, options: GenAiOptions [SENTRY_ORIGIN]: PI_DURABLE_ORIGIN, [GEN_AI_OPERATION_NAME]: 'execute_tool', [GEN_AI_TOOL_NAME]: tool.name, - ...(tool.description ? { [GEN_AI_TOOL_DESCRIPTION]: tool.description } : {}), - ...(api?.callId ? { [GEN_AI_TOOL_CALL_ID_ATTRIBUTE]: api.callId } : {}), + [GEN_AI_TOOL_DESCRIPTION]: tool.description, + [GEN_AI_TOOL_CALL_ID_ATTRIBUTE]: api?.callId, ...(api?.conversationId !== undefined ? { [GEN_AI_CONVERSATION_ID]: toSentryConversationId(runs, api.conversationId) } : {}), diff --git a/packages/server-utils/src/ai/typesafe/index.ts b/packages/server-utils/src/ai/typesafe/index.ts index 65d24e6fc3f8..7bffea993239 100644 --- a/packages/server-utils/src/ai/typesafe/index.ts +++ b/packages/server-utils/src/ai/typesafe/index.ts @@ -50,7 +50,7 @@ function getRequestAttributes( [SENTRY_ORIGIN]: TYPESAFE_ORIGIN, [GEN_AI_OPERATION_NAME]: 'decide', [GEN_AI_PROVIDER_NAME]: TYPESAFE_PROVIDER_NAME, - ...(model ? { [GEN_AI_REQUEST_MODEL]: model } : {}), + [GEN_AI_REQUEST_MODEL]: model, ...(recordInputs ? { [GEN_AI_INPUT_MESSAGES]: getEvaluationInputMessages(request) } : {}), }; } diff --git a/packages/server-utils/src/integrations/express/instrumentation.ts b/packages/server-utils/src/integrations/express/instrumentation.ts index a3d079c6bd2b..cac3ede931ff 100644 --- a/packages/server-utils/src/integrations/express/instrumentation.ts +++ b/packages/server-utils/src/integrations/express/instrumentation.ts @@ -344,7 +344,7 @@ function getSpanForLayer(data: HandleChannelContext, options: ExpressIntegration [SENTRY_OP]: EXPRESS_TYPE_TO_SPAN_OP[type], [ATTR_EXPRESS_NAME]: name, [ATTR_EXPRESS_TYPE]: type, - ...(matchedRoute ? { [HTTP_ROUTE]: matchedRoute } : {}), + [HTTP_ROUTE]: matchedRoute, }, }); diff --git a/packages/server-utils/src/integrations/mysql.ts b/packages/server-utils/src/integrations/mysql.ts index de538d52afd7..1a68350361e6 100644 --- a/packages/server-utils/src/integrations/mysql.ts +++ b/packages/server-utils/src/integrations/mysql.ts @@ -98,9 +98,9 @@ function instrumentMysql(): void { [SENTRY_ORIGIN]: 'auto.db.mysql', // oxlint-disable-next-line typescript/no-deprecated -- Preserve the existing attribute name. [DB_CONNECTION_STRING]: getJDBCString(host, portIsNumber ? portNumber : undefined, database), - ...(database ? { [DB_NAMESPACE]: database } : {}), - ...(user ? { [DB_USER]: user } : {}), - ...(queryText ? { [DB_QUERY_TEXT]: queryText } : {}), + [DB_NAMESPACE]: database, + [DB_USER]: user, + [DB_QUERY_TEXT]: queryText, [DB_QUERY_SUMMARY]: querySummary, [SERVER_ADDRESS]: host, [SERVER_PORT]: portIsNumber ? portNumber : undefined, diff --git a/packages/server-utils/src/integrations/vercel-ai/vercel-ai-dc-subscriber.ts b/packages/server-utils/src/integrations/vercel-ai/vercel-ai-dc-subscriber.ts index 2943aa7dddb2..f7525a94e9dd 100644 --- a/packages/server-utils/src/integrations/vercel-ai/vercel-ai-dc-subscriber.ts +++ b/packages/server-utils/src/integrations/vercel-ai/vercel-ai-dc-subscriber.ts @@ -453,10 +453,11 @@ export function createSpanFromMessage( const baseAttributes: SpanAttributes = { [SENTRY_ORIGIN]: ORIGIN, ...telemetryMetadataAttributes(event.telemetryMetadata), - ...(provider ? { [GEN_AI_PROVIDER_NAME]: provider, [VERCEL_AI_MODEL_PROVIDER_ATTRIBUTE]: provider } : {}), - ...(modelId ? { [GEN_AI_REQUEST_MODEL]: modelId } : {}), - ...(maxRetries !== undefined ? { [VERCEL_AI_SETTINGS_MAX_RETRIES_ATTRIBUTE]: maxRetries } : {}), - ...(conversationId ? { [GEN_AI_CONVERSATION_ID]: conversationId } : {}), + [GEN_AI_PROVIDER_NAME]: provider, + [VERCEL_AI_MODEL_PROVIDER_ATTRIBUTE]: provider, + [GEN_AI_REQUEST_MODEL]: modelId, + [VERCEL_AI_SETTINGS_MAX_RETRIES_ATTRIBUTE]: maxRetries, + [GEN_AI_CONVERSATION_ID]: conversationId, }; switch (type) { @@ -547,7 +548,7 @@ function buildInvokeAgentSpan( ...baseAttributes, [VERCEL_AI_OPERATION_ID_ATTRIBUTE]: operationId, [GEN_AI_RESPONSE_STREAMING]: isStream, - ...(functionId ? { [GEN_AI_FUNCTION_ID]: functionId } : {}), + [GEN_AI_FUNCTION_ID]: functionId, ...(recordInputs ? buildInputMessageAttributes(event) : {}), }); if (isStream && callId) { @@ -591,11 +592,11 @@ function buildToolSpan( recordInputs && toolName ? resolveToolDescription(asString(event.callId), toolName, event.tools) : undefined; return startGenAiSpan('execute_tool', toolName, { [SENTRY_ORIGIN]: ORIGIN, - ...(toolName ? { [GEN_AI_TOOL_NAME]: toolName } : {}), - ...(toolCallId ? { [GEN_AI_TOOL_CALL_ID_ATTRIBUTE]: toolCallId } : {}), - ...(description ? { [GEN_AI_TOOL_DESCRIPTION]: description } : {}), + [GEN_AI_TOOL_NAME]: toolName, + [GEN_AI_TOOL_CALL_ID_ATTRIBUTE]: toolCallId, + [GEN_AI_TOOL_DESCRIPTION]: description, ...(recordInputs && toolInput !== undefined ? { [GEN_AI_TOOL_CALL_ARGUMENTS]: stringify(toolInput) } : {}), - ...(conversationId ? { [GEN_AI_CONVERSATION_ID]: conversationId } : {}), + [GEN_AI_CONVERSATION_ID]: conversationId, }); } diff --git a/packages/solid/src/tanstackrouter.ts b/packages/solid/src/tanstackrouter.ts index fd64dce25235..ae8d8eb278a6 100644 --- a/packages/solid/src/tanstackrouter.ts +++ b/packages/solid/src/tanstackrouter.ts @@ -99,7 +99,7 @@ export function tanstackRouterBrowserTracingIntegration( [SENTRY_OP]: PAGELOAD, [SENTRY_ORIGIN]: 'auto.pageload.solid.tanstack_router', [SENTRY_SEGMENT_NAME_SOURCE]: routeMatch ? 'route' : 'url', - ...(routeMatch && { [URL_TEMPLATE]: routeMatch.routeId }), + [URL_TEMPLATE]: routeMatch?.routeId, ...routeMatchToParamSpanAttributes(routeMatch), }, }); @@ -158,7 +158,7 @@ export function tanstackRouterBrowserTracingIntegration( [SENTRY_OP]: NAVIGATION, [SENTRY_ORIGIN]: 'auto.navigation.solid.tanstack_router', [SENTRY_SEGMENT_NAME_SOURCE]: routeMatch ? 'route' : 'url', - ...(routeMatch && { [URL_TEMPLATE]: routeMatch.routeId }), + [URL_TEMPLATE]: routeMatch?.routeId, ...routeMatchToParamSpanAttributes(routeMatch), }, }, diff --git a/packages/svelte/src/performance.ts b/packages/svelte/src/performance.ts index 59f7c1b8174a..9ed815a12b39 100644 --- a/packages/svelte/src/performance.ts +++ b/packages/svelte/src/performance.ts @@ -65,7 +65,7 @@ function recordInitSpan(componentName: string | undefined, description: string): attributes: { [SENTRY_OP]: UI_MOUNT, [SENTRY_ORIGIN]: 'auto.ui.svelte', - ...(componentName && { [UI_COMPONENT_NAME]: componentName }), + [UI_COMPONENT_NAME]: componentName, ...(hasSpanStreaming && { [SENTRY_DESCRIPTION]: description }), }, }); @@ -87,7 +87,7 @@ function recordUpdateSpans(componentName: string | undefined, description: strin attributes: { [SENTRY_OP]: UI_UPDATE, [SENTRY_ORIGIN]: 'auto.ui.svelte', - ...(componentName && { [UI_COMPONENT_NAME]: componentName }), + [UI_COMPONENT_NAME]: componentName, ...(hasSpanStreaming && { [SENTRY_DESCRIPTION]: description }), }, }); diff --git a/packages/vue/src/tanstackrouter.ts b/packages/vue/src/tanstackrouter.ts index f485c6cb3fd3..3d704405041f 100644 --- a/packages/vue/src/tanstackrouter.ts +++ b/packages/vue/src/tanstackrouter.ts @@ -105,7 +105,7 @@ export function tanstackRouterBrowserTracingIntegration( [SENTRY_OP]: PAGELOAD, [SENTRY_ORIGIN]: 'auto.pageload.vue.tanstack_router', [SENTRY_SEGMENT_NAME_SOURCE]: routeMatch ? 'route' : 'url', - ...(routeMatch && { [URL_TEMPLATE]: routeMatch.routeId }), + [URL_TEMPLATE]: routeMatch?.routeId, ...routeMatchToParamSpanAttributes(routeMatch), }, }); @@ -165,7 +165,7 @@ export function tanstackRouterBrowserTracingIntegration( [SENTRY_OP]: NAVIGATION, [SENTRY_ORIGIN]: 'auto.navigation.vue.tanstack_router', [SENTRY_SEGMENT_NAME_SOURCE]: routeMatch ? 'route' : 'url', - ...(routeMatch && { [URL_TEMPLATE]: routeMatch.routeId }), + [URL_TEMPLATE]: routeMatch?.routeId, ...routeMatchToParamSpanAttributes(routeMatch), }, }, diff --git a/packages/vue/src/tracing.ts b/packages/vue/src/tracing.ts index 822ef2909a45..35bc74b5bd1d 100644 --- a/packages/vue/src/tracing.ts +++ b/packages/vue/src/tracing.ts @@ -146,7 +146,7 @@ export const createTracingMixins = (options: Partial = {}): Mixi attributes: { [SENTRY_OP]: UI_RENDER, [SENTRY_ORIGIN]: 'auto.ui.vue', - ...(conventionComponentName && { [UI_COMPONENT_NAME]: conventionComponentName }), + [UI_COMPONENT_NAME]: conventionComponentName, ...(hasSpanStreaming && { [SENTRY_DESCRIPTION]: description }), }, onlyIfParent: true, @@ -197,7 +197,7 @@ export const createTracingMixins = (options: Partial = {}): Mixi attributes: { [SENTRY_OP]: VUE_OPERATION_TO_SPAN_OP[operation], [SENTRY_ORIGIN]: 'auto.ui.vue', - ...(conventionComponentName && { [UI_COMPONENT_NAME]: conventionComponentName }), + [UI_COMPONENT_NAME]: conventionComponentName, ...(hasSpanStreaming && { [SENTRY_DESCRIPTION]: description }), }, // UI spans should only be created if there is an active root span (transaction) From 7926dc6c73ce1f2587cbfffec8c3f28780c37356 Mon Sep 17 00:00:00 2001 From: "sentry-junior[bot]" <264270552+sentry-junior[bot]@users.noreply.github.com> Date: Fri, 30 Oct 2026 10:52:54 +0000 Subject: [PATCH 2/2] fix: Keep omitting empty component names from span attributes --- packages/react/src/profiler.tsx | 10 +++++----- packages/svelte/src/performance.ts | 4 ++-- packages/vue/src/tracing.ts | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/react/src/profiler.tsx b/packages/react/src/profiler.tsx index 0c1c3fd874d5..a81a50199c7a 100644 --- a/packages/react/src/profiler.tsx +++ b/packages/react/src/profiler.tsx @@ -66,7 +66,7 @@ class Profiler extends React.Component { attributes: { [SENTRY_OP]: UI_MOUNT, [SENTRY_ORIGIN]: 'auto.ui.react.profiler', - [UI_COMPONENT_NAME]: componentName, + [UI_COMPONENT_NAME]: componentName || undefined, ...(hasSpanStreaming && { [SENTRY_DESCRIPTION]: description }), }, }); @@ -102,7 +102,7 @@ class Profiler extends React.Component { attributes: { [SENTRY_OP]: UI_UPDATE, [SENTRY_ORIGIN]: 'auto.ui.react.profiler', - [UI_COMPONENT_NAME]: componentName, + [UI_COMPONENT_NAME]: componentName || undefined, 'ui.react.changed_props': changedProps, ...(hasSpanStreaming && { [SENTRY_DESCRIPTION]: description }), }, @@ -142,7 +142,7 @@ class Profiler extends React.Component { attributes: { [SENTRY_OP]: UI_RENDER, [SENTRY_ORIGIN]: 'auto.ui.react.profiler', - [UI_COMPONENT_NAME]: componentName, + [UI_COMPONENT_NAME]: componentName || undefined, ...(hasSpanStreaming && { [SENTRY_DESCRIPTION]: description }), }, }); @@ -229,7 +229,7 @@ function useProfiler( attributes: { [SENTRY_OP]: UI_MOUNT, [SENTRY_ORIGIN]: 'auto.ui.react.profiler', - [UI_COMPONENT_NAME]: componentName, + [UI_COMPONENT_NAME]: componentName || undefined, ...(hasSpanStreaming && { [SENTRY_DESCRIPTION]: description }), }, }); @@ -257,7 +257,7 @@ function useProfiler( attributes: { [SENTRY_OP]: UI_RENDER, [SENTRY_ORIGIN]: 'auto.ui.react.profiler', - [UI_COMPONENT_NAME]: componentName, + [UI_COMPONENT_NAME]: componentName || undefined, ...(hasSpanStreaming && { [SENTRY_DESCRIPTION]: description }), }, }); diff --git a/packages/svelte/src/performance.ts b/packages/svelte/src/performance.ts index 9ed815a12b39..d05bd8f92f02 100644 --- a/packages/svelte/src/performance.ts +++ b/packages/svelte/src/performance.ts @@ -65,7 +65,7 @@ function recordInitSpan(componentName: string | undefined, description: string): attributes: { [SENTRY_OP]: UI_MOUNT, [SENTRY_ORIGIN]: 'auto.ui.svelte', - [UI_COMPONENT_NAME]: componentName, + [UI_COMPONENT_NAME]: componentName || undefined, ...(hasSpanStreaming && { [SENTRY_DESCRIPTION]: description }), }, }); @@ -87,7 +87,7 @@ function recordUpdateSpans(componentName: string | undefined, description: strin attributes: { [SENTRY_OP]: UI_UPDATE, [SENTRY_ORIGIN]: 'auto.ui.svelte', - [UI_COMPONENT_NAME]: componentName, + [UI_COMPONENT_NAME]: componentName || undefined, ...(hasSpanStreaming && { [SENTRY_DESCRIPTION]: description }), }, }); diff --git a/packages/vue/src/tracing.ts b/packages/vue/src/tracing.ts index 35bc74b5bd1d..a447828e6c11 100644 --- a/packages/vue/src/tracing.ts +++ b/packages/vue/src/tracing.ts @@ -146,7 +146,7 @@ export const createTracingMixins = (options: Partial = {}): Mixi attributes: { [SENTRY_OP]: UI_RENDER, [SENTRY_ORIGIN]: 'auto.ui.vue', - [UI_COMPONENT_NAME]: conventionComponentName, + [UI_COMPONENT_NAME]: conventionComponentName || undefined, ...(hasSpanStreaming && { [SENTRY_DESCRIPTION]: description }), }, onlyIfParent: true, @@ -197,7 +197,7 @@ export const createTracingMixins = (options: Partial = {}): Mixi attributes: { [SENTRY_OP]: VUE_OPERATION_TO_SPAN_OP[operation], [SENTRY_ORIGIN]: 'auto.ui.vue', - [UI_COMPONENT_NAME]: conventionComponentName, + [UI_COMPONENT_NAME]: conventionComponentName || undefined, ...(hasSpanStreaming && { [SENTRY_DESCRIPTION]: description }), }, // UI spans should only be created if there is an active root span (transaction)