1
1
import { NodeSDK } from "@opentelemetry/sdk-node" ;
2
- import {
3
- SimpleSpanProcessor ,
4
- BatchSpanProcessor ,
5
- SpanProcessor ,
6
- ReadableSpan ,
7
- } from "@opentelemetry/sdk-trace-node" ;
2
+ import { SpanProcessor } from "@opentelemetry/sdk-trace-node" ;
8
3
import { baggageUtils } from "@opentelemetry/core" ;
9
- import { Span , context , diag } from "@opentelemetry/api" ;
4
+ import { context , diag } from "@opentelemetry/api" ;
10
5
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-proto" ;
11
6
import { Resource } from "@opentelemetry/resources" ;
12
7
import { SEMRESATTRS_SERVICE_NAME } from "@opentelemetry/semantic-conventions" ;
13
8
import { Instrumentation } from "@opentelemetry/instrumentation" ;
14
9
import { InitializeOptions } from "../interfaces" ;
15
- import {
16
- ASSOCATION_PROPERTIES_KEY ,
17
- ENTITY_NAME_KEY ,
18
- WORKFLOW_NAME_KEY ,
19
- } from "./tracing" ;
20
10
import { Telemetry } from "../telemetry/telemetry" ;
21
11
import { _configuration } from "../configuration" ;
22
- import {
23
- CONTEXT_KEY_ALLOW_TRACE_CONTENT ,
24
- SpanAttributes ,
25
- } from "@traceloop/ai-semantic-conventions" ;
12
+ import { CONTEXT_KEY_ALLOW_TRACE_CONTENT } from "@traceloop/ai-semantic-conventions" ;
26
13
import { AnthropicInstrumentation } from "@traceloop/instrumentation-anthropic" ;
27
14
import { OpenAIInstrumentation } from "@traceloop/instrumentation-openai" ;
28
15
import { AzureOpenAIInstrumentation } from "@traceloop/instrumentation-azure" ;
@@ -38,9 +25,10 @@ import { LangChainInstrumentation } from "@traceloop/instrumentation-langchain";
38
25
import { ChromaDBInstrumentation } from "@traceloop/instrumentation-chromadb" ;
39
26
import { QdrantInstrumentation } from "@traceloop/instrumentation-qdrant" ;
40
27
import { TogetherInstrumentation } from "@traceloop/instrumentation-together" ;
28
+ import { createSpanProcessor } from "./span-processor" ;
41
29
42
30
let _sdk : NodeSDK ;
43
- let _spanProcessor : SimpleSpanProcessor | BatchSpanProcessor ;
31
+ let _spanProcessor : SpanProcessor ;
44
32
let openAIInstrumentation : OpenAIInstrumentation | undefined ;
45
33
let anthropicInstrumentation : AnthropicInstrumentation | undefined ;
46
34
let azureOpenAIInstrumentation : AzureOpenAIInstrumentation | undefined ;
@@ -273,117 +261,14 @@ export const startTracing = (options: InitializeOptions) => {
273
261
url : `${ options . baseUrl } /v1/traces` ,
274
262
headers,
275
263
} ) ;
276
- _spanProcessor = options . disableBatch
277
- ? new SimpleSpanProcessor ( traceExporter )
278
- : new BatchSpanProcessor ( traceExporter ) ;
279
-
280
- _spanProcessor . onStart = ( span : Span ) => {
281
- const workflowName = context . active ( ) . getValue ( WORKFLOW_NAME_KEY ) ;
282
- if ( workflowName ) {
283
- span . setAttribute (
284
- SpanAttributes . TRACELOOP_WORKFLOW_NAME ,
285
- workflowName as string ,
286
- ) ;
287
- }
288
-
289
- const entityName = context . active ( ) . getValue ( ENTITY_NAME_KEY ) ;
290
- if ( entityName ) {
291
- span . setAttribute (
292
- SpanAttributes . TRACELOOP_ENTITY_PATH ,
293
- entityName as string ,
294
- ) ;
295
- }
296
-
297
- const associationProperties = context
298
- . active ( )
299
- . getValue ( ASSOCATION_PROPERTIES_KEY ) ;
300
- if ( associationProperties ) {
301
- for ( const [ key , value ] of Object . entries ( associationProperties ) ) {
302
- span . setAttribute (
303
- `${ SpanAttributes . TRACELOOP_ASSOCIATION_PROPERTIES } .${ key } ` ,
304
- value ,
305
- ) ;
306
- }
307
- }
308
- } ;
309
-
310
- const originalOnEnd = _spanProcessor . onEnd ?. bind ( _spanProcessor ) ;
311
- _spanProcessor . onEnd = ( span : ReadableSpan ) => {
312
- // Vercel AI Adapters
313
- const attributes = span . attributes ;
314
-
315
- // Adapt span names
316
- const nameMap : Record < string , string > = {
317
- "ai.generateText.doGenerate" : "ai.generateText.generate" ,
318
- "ai.streamText.doStream" : "ai.streamText.stream" ,
319
- } ;
320
- if ( span . name in nameMap ) {
321
- // Unfortuantely, the span name is not writable as this is not the intended behavior
322
- // but it is a workaround to set the correct span name
323
- ( span as any ) . name = nameMap [ span . name ] ;
324
- }
325
-
326
- if ( "ai.response.text" in attributes ) {
327
- attributes [ `${ SpanAttributes . LLM_COMPLETIONS } .0.content` ] =
328
- attributes [ "ai.response.text" ] ;
329
- attributes [ `${ SpanAttributes . LLM_COMPLETIONS } .0.role` ] = "assistant" ;
330
- delete attributes [ "ai.response.text" ] ;
331
- }
332
-
333
- if ( "ai.prompt.messages" in attributes ) {
334
- try {
335
- const messages = JSON . parse ( attributes [ "ai.prompt.messages" ] as string ) ;
336
- messages . forEach (
337
- ( msg : { role : string ; content : any } , index : number ) => {
338
- attributes [ `${ SpanAttributes . LLM_PROMPTS } .${ index } .content` ] =
339
- typeof msg . content === "string"
340
- ? msg . content
341
- : JSON . stringify ( msg . content ) ;
342
- attributes [ `${ SpanAttributes . LLM_PROMPTS } .${ index } .role` ] =
343
- msg . role ;
344
- } ,
345
- ) ;
346
- delete attributes [ "ai.prompt.messages" ] ;
347
- } catch ( e ) {
348
- //Skip if JSON parsing fails
349
- }
350
- }
351
-
352
- if ( "ai.usage.promptTokens" in attributes ) {
353
- attributes [ `${ SpanAttributes . LLM_USAGE_PROMPT_TOKENS } ` ] =
354
- attributes [ "ai.usage.promptTokens" ] ;
355
- delete attributes [ "ai.usage.promptTokens" ] ;
356
- }
357
-
358
- if ( "ai.usage.completionTokens" in attributes ) {
359
- attributes [ `${ SpanAttributes . LLM_USAGE_COMPLETION_TOKENS } ` ] =
360
- attributes [ "ai.usage.completionTokens" ] ;
361
- delete attributes [ "ai.usage.completionTokens" ] ;
362
- }
363
-
364
- if (
365
- attributes [ `${ SpanAttributes . LLM_USAGE_PROMPT_TOKENS } ` ] &&
366
- attributes [ `${ SpanAttributes . LLM_USAGE_COMPLETION_TOKENS } ` ]
367
- ) {
368
- attributes [ `${ SpanAttributes . LLM_USAGE_TOTAL_TOKENS } ` ] =
369
- Number ( attributes [ `${ SpanAttributes . LLM_USAGE_PROMPT_TOKENS } ` ] ) +
370
- Number ( attributes [ `${ SpanAttributes . LLM_USAGE_COMPLETION_TOKENS } ` ] ) ;
371
- }
372
-
373
- originalOnEnd ?.( span ) ;
374
- } ;
375
-
376
- if ( options . exporter ) {
377
- Telemetry . getInstance ( ) . capture ( "tracer:init" , {
378
- exporter : "custom" ,
379
- processor : options . disableBatch ? "simple" : "batch" ,
380
- } ) ;
381
- } else {
382
- Telemetry . getInstance ( ) . capture ( "tracer:init" , {
383
- exporter : options . baseUrl ?? "" ,
384
- processor : options . disableBatch ? "simple" : "batch" ,
385
- } ) ;
386
- }
264
+
265
+ _spanProcessor = createSpanProcessor ( {
266
+ apiKey : options . apiKey ,
267
+ baseUrl : options . baseUrl ,
268
+ disableBatch : options . disableBatch ,
269
+ exporter : traceExporter ,
270
+ headers,
271
+ } ) ;
387
272
388
273
const spanProcessors : SpanProcessor [ ] = [ _spanProcessor ] ;
389
274
if ( options . processor ) {
0 commit comments