Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 10 additions & 0 deletions packages/core/src/tracing/vercel-ai/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -513,10 +513,20 @@ function processGenerateSpan(span: Span, name: string, attributes: SpanAttribute
}
}

const CLIENTS_WITH_VERCEL_AI_PROCESSORS = new WeakSet<Client>();

/**
* Add event processors to the given client to process Vercel AI spans.
*
* Idempotent: both the integration and the Next.js SDK register these, and duplicate hooks would
* process every span twice.
*/
export function addVercelAiProcessors(client: Client): void {
if (CLIENTS_WITH_VERCEL_AI_PROCESSORS.has(client)) {
return;
}
CLIENTS_WITH_VERCEL_AI_PROCESSORS.add(client);

client.on('spanStart', onVercelAiSpanStart);
// Note: We cannot do this on `spanEnd`, because the span cannot be mutated anymore at this point
client.addEventProcessor(Object.assign(vercelAiEventProcessor, { id: 'VercelAiEventProcessor' }));
Expand Down
9 changes: 9 additions & 0 deletions packages/nextjs/src/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import { HTTP_TARGET, URL_QUERY } from '@sentry/conventions/attributes';
import type { EventProcessor } from '@sentry/core';
import {
addVercelAiProcessors,
applySdkMetadata,
debug,
getClient,
Expand Down Expand Up @@ -210,6 +211,14 @@ export function init(options: NodeOptions): NodeClient | undefined {

const client = nodeInit(opts);

// Next.js bundles `ai`, so the integration can neither patch the module nor detect it via `Modules`
// (which only sees the app's own `package.json`, missing workspace and transitive deps). Register
// the processors here instead — after init, so an explicitly constructed `vercelAIIntegration()`
// can't override the default back to the broken behavior.
if (client?.getIntegrationByName('VercelAI')) {
addVercelAiProcessors(client);
}

client?.on('beforeSampling', ({ spanAttributes }, samplingDecision) => {
// There are situations where the Next.js Node.js server forwards requests for the Edge Runtime server (e.g. in
// middleware) and this causes spans for Sentry ingest requests to be created. These are not exempt from our tracing
Expand Down
Loading