55 _INTERNAL_shouldSkipAiProviderWrapping ,
66 addAnthropicRequestAttributes ,
77 addAnthropicResponseAttributes ,
8- debug ,
98 defineIntegration ,
109 extractAnthropicRequestAttributes ,
1110 instrumentAsyncIterableStream ,
@@ -14,11 +13,11 @@ import {
1413 SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN ,
1514 shouldEnableTruncation ,
1615 startInactiveSpan ,
17- waitForTracingChannelBinding ,
1816} from '@sentry/core' ;
19- import { DEBUG_BUILD } from '../../debug-build' ;
2017import { CHANNELS } from '../../orchestrion/channels' ;
2118import { bindTracingChannelToSpan } from '../../tracing-channel' ;
19+ import { anthropicAiModuleNames } from '../../orchestrion/config/anthropic-ai' ;
20+ import { invokeOrchestrionInstrumentation } from '../../orchestrion/instrumentation' ;
2221
2322// Same name as the OTel integration by design: when enabled, the OTel 'Anthropic_AI'
2423// integration is dropped from the default set (see the Node opt-in loader).
@@ -47,43 +46,34 @@ interface AnthropicChannelContext {
4746 result ?: unknown ;
4847}
4948
50- let subscribed = false ;
51-
5249const _anthropicChannelIntegration = ( ( options : AnthropicAiOptions = { } ) => {
5350 return {
5451 name : INTEGRATION_NAME ,
55- setupOnce ( ) {
56- // tracingChannel is unavailable before Node 18.19 and prevent double-subscribe
57- if ( ! diagnosticsChannel . tracingChannel || subscribed ) {
58- return ;
59- }
60- subscribed = true ;
61-
62- // `bindTracingChannelToSpan` needs the async-context binding that `initOpenTelemetry()` registers
63- // after `setupOnce` runs, so wait for it before subscribing.
64- waitForTracingChannelBinding ( ( ) => {
65- for ( const { channel, operation, methodPath, stream } of INSTRUMENTED_CHANNELS ) {
66- DEBUG_BUILD && debug . log ( `[orchestrion:anthropic] subscribing to channel "${ channel } "` ) ;
67- bindTracingChannelToSpan (
68- diagnosticsChannel . tracingChannel < AnthropicChannelContext > ( channel ) ,
69- data => createGenAiSpan ( data , operation , methodPath , options ) ,
70- {
71- beforeSpanEnd : ( span , data ) => {
72- addAnthropicResponseAttributes (
73- span ,
74- data . result as AnthropicAiResponse ,
75- resolveAIRecordingOptions ( options ) . recordOutputs ,
76- ) ;
77- } ,
78- deferSpanEnd : ( { span, data } ) => wrapStreamResult ( span , data , stream , options ) ,
79- } ,
80- ) ;
81- }
82- } ) ;
52+ setup ( client ) {
53+ invokeOrchestrionInstrumentation ( client , anthropicAiModuleNames , instrumentAnthropic , [ options ] ) ;
8354 } ,
8455 } ;
8556} ) satisfies IntegrationFn ;
8657
58+ function instrumentAnthropic ( options : AnthropicAiOptions ) : void {
59+ for ( const { channel, operation, methodPath, stream } of INSTRUMENTED_CHANNELS ) {
60+ bindTracingChannelToSpan (
61+ diagnosticsChannel . tracingChannel < AnthropicChannelContext > ( channel ) ,
62+ data => createGenAiSpan ( data , operation , methodPath , options ) ,
63+ {
64+ beforeSpanEnd : ( span , data ) => {
65+ addAnthropicResponseAttributes (
66+ span ,
67+ data . result as AnthropicAiResponse ,
68+ resolveAIRecordingOptions ( options ) . recordOutputs ,
69+ ) ;
70+ } ,
71+ deferSpanEnd : ( { span, data } ) => wrapStreamResult ( span , data , stream , options ) ,
72+ } ,
73+ ) ;
74+ }
75+ }
76+
8777/**
8878 * Build the span for an instrumented call.
8979 * Returning `undefined` opts the payload out so no span is opened.
0 commit comments