@mastra/otel-exporter 0.0.0-monorepo-binary-20251013210052 → 0.0.0-netlify-no-bundle-20251127120354

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
- import { AITracingEventType, AISpanType } from '@mastra/core/ai-tracing';
2
- import { ConsoleLogger } from '@mastra/core/logger';
3
- import { diag, DiagConsoleLogger, DiagLogLevel, SpanKind, SpanStatusCode, TraceFlags } from '@opentelemetry/api';
1
+ import { SpanType, TracingEventType } from '@mastra/core/observability';
2
+ import { BaseExporter } from '@mastra/observability';
3
+ import { SpanStatusCode, TraceFlags, SpanKind, diag, DiagConsoleLogger, DiagLogLevel } from '@opentelemetry/api';
4
4
  import { resourceFromAttributes } from '@opentelemetry/resources';
5
5
  import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base';
6
6
  import { ATTR_TELEMETRY_SDK_LANGUAGE, ATTR_TELEMETRY_SDK_VERSION, ATTR_TELEMETRY_SDK_NAME, ATTR_SERVICE_VERSION, ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions';
7
7
 
8
- // src/ai-tracing.ts
8
+ // src/tracing.ts
9
9
 
10
10
  // src/loadExporter.ts
11
11
  var OTLPHttpExporter;
@@ -207,6 +207,7 @@ var MastraReadableSpan = class {
207
207
  name;
208
208
  kind;
209
209
  spanContext;
210
+ parentSpanContext;
210
211
  parentSpanId;
211
212
  startTime;
212
213
  endTime;
@@ -222,45 +223,45 @@ var MastraReadableSpan = class {
222
223
  droppedAttributesCount = 0;
223
224
  droppedEventsCount = 0;
224
225
  droppedLinksCount = 0;
225
- constructor(aiSpan, attributes, kind, parentSpanId, resource, instrumentationLibrary) {
226
- this.name = aiSpan.name;
226
+ constructor(span, attributes, kind, parentSpanId, resource, instrumentationLibrary) {
227
+ this.name = span.name;
227
228
  this.kind = kind;
228
229
  this.attributes = attributes;
229
230
  this.parentSpanId = parentSpanId;
230
231
  this.links = [];
231
232
  this.events = [];
232
- this.startTime = this.dateToHrTime(aiSpan.startTime);
233
- this.endTime = aiSpan.endTime ? this.dateToHrTime(aiSpan.endTime) : this.startTime;
234
- this.ended = !!aiSpan.endTime;
235
- if (aiSpan.endTime) {
236
- const durationMs = aiSpan.endTime.getTime() - aiSpan.startTime.getTime();
233
+ this.startTime = this.dateToHrTime(span.startTime);
234
+ this.endTime = span.endTime ? this.dateToHrTime(span.endTime) : this.startTime;
235
+ this.ended = !!span.endTime;
236
+ if (span.endTime) {
237
+ const durationMs = span.endTime.getTime() - span.startTime.getTime();
237
238
  this.duration = [Math.floor(durationMs / 1e3), durationMs % 1e3 * 1e6];
238
239
  } else {
239
240
  this.duration = [0, 0];
240
241
  }
241
- if (aiSpan.errorInfo) {
242
+ if (span.errorInfo) {
242
243
  this.status = {
243
244
  code: SpanStatusCode.ERROR,
244
- message: aiSpan.errorInfo.message
245
+ message: span.errorInfo.message
245
246
  };
246
247
  this.events.push({
247
248
  name: "exception",
248
249
  attributes: {
249
- "exception.message": aiSpan.errorInfo.message,
250
+ "exception.message": span.errorInfo.message,
250
251
  "exception.type": "Error",
251
- ...aiSpan.errorInfo.details?.stack && {
252
- "exception.stacktrace": aiSpan.errorInfo.details.stack
252
+ ...span.errorInfo.details?.stack && {
253
+ "exception.stacktrace": span.errorInfo.details.stack
253
254
  }
254
255
  },
255
256
  time: this.startTime,
256
257
  droppedAttributesCount: 0
257
258
  });
258
- } else if (aiSpan.endTime) {
259
+ } else if (span.endTime) {
259
260
  this.status = { code: SpanStatusCode.OK };
260
261
  } else {
261
262
  this.status = { code: SpanStatusCode.UNSET };
262
263
  }
263
- if (aiSpan.isEvent) {
264
+ if (span.isEvent) {
264
265
  this.events.push({
265
266
  name: "instant_event",
266
267
  attributes: {},
@@ -269,11 +270,19 @@ var MastraReadableSpan = class {
269
270
  });
270
271
  }
271
272
  this.spanContext = () => ({
272
- traceId: aiSpan.traceId,
273
- spanId: aiSpan.id,
273
+ traceId: span.traceId,
274
+ spanId: span.id,
274
275
  traceFlags: TraceFlags.SAMPLED,
275
276
  isRemote: false
276
277
  });
278
+ if (parentSpanId) {
279
+ this.parentSpanContext = {
280
+ traceId: span.traceId,
281
+ spanId: parentSpanId,
282
+ traceFlags: TraceFlags.SAMPLED,
283
+ isRemote: false
284
+ };
285
+ }
277
286
  this.resource = resource || {};
278
287
  this.instrumentationLibrary = instrumentationLibrary || {
279
288
  name: "@mastra/otel",
@@ -294,180 +303,177 @@ var MastraReadableSpan = class {
294
303
 
295
304
  // src/span-converter.ts
296
305
  var SPAN_KIND_MAPPING = {
297
- // LLM operations are CLIENT spans (calling external AI services)
298
- [AISpanType.LLM_GENERATION]: SpanKind.CLIENT,
299
- [AISpanType.LLM_CHUNK]: SpanKind.CLIENT,
306
+ // Model operations are CLIENT spans (calling external AI services)
307
+ [SpanType.MODEL_GENERATION]: SpanKind.CLIENT,
308
+ [SpanType.MODEL_CHUNK]: SpanKind.CLIENT,
300
309
  // MCP tool calls are CLIENT (external service calls)
301
- [AISpanType.MCP_TOOL_CALL]: SpanKind.CLIENT,
310
+ [SpanType.MCP_TOOL_CALL]: SpanKind.CLIENT,
302
311
  // Root spans for agent/workflow are SERVER (entry points)
303
- [AISpanType.AGENT_RUN]: SpanKind.SERVER,
304
- [AISpanType.WORKFLOW_RUN]: SpanKind.SERVER
312
+ [SpanType.AGENT_RUN]: SpanKind.SERVER,
313
+ [SpanType.WORKFLOW_RUN]: SpanKind.SERVER
305
314
  };
315
+ function getSpanKind(type, isRootSpan) {
316
+ if (isRootSpan) {
317
+ if (type === SpanType.AGENT_RUN || type === SpanType.WORKFLOW_RUN) {
318
+ return SpanKind.SERVER;
319
+ }
320
+ }
321
+ return SPAN_KIND_MAPPING[type] || SpanKind.INTERNAL;
322
+ }
306
323
  var SpanConverter = class {
307
324
  resource;
308
325
  instrumentationLibrary;
309
326
  constructor(resource) {
310
327
  this.resource = resource;
311
328
  this.instrumentationLibrary = {
312
- name: "@mastra/otel",
329
+ name: "@mastra/otel-exporter",
313
330
  version: "1.0.0"
314
331
  };
315
332
  }
316
333
  /**
317
- * Convert a Mastra AI span to an OpenTelemetry ReadableSpan
334
+ * Convert a Mastra Span to an OpenTelemetry ReadableSpan
318
335
  * This preserves Mastra's trace and span IDs
319
336
  */
320
- convertSpan(aiSpan) {
321
- const spanKind = this.getSpanKind(aiSpan);
322
- const attributes = this.buildAttributes(aiSpan);
323
- const spanName = this.buildSpanName(aiSpan);
324
- const otelSpan = { ...aiSpan, name: spanName };
337
+ convertSpan(span) {
338
+ const spanKind = getSpanKind(span.type, span.isRootSpan);
339
+ const attributes = this.buildAttributes(span);
340
+ const spanName = this.buildSpanName(span);
341
+ const otelSpan = { ...span, name: spanName };
325
342
  return new MastraReadableSpan(
326
343
  otelSpan,
327
344
  attributes,
328
345
  spanKind,
329
- aiSpan.parentSpanId,
346
+ span.parentSpanId,
330
347
  // Use the parentSpanId from the Mastra span directly
331
348
  this.resource,
332
349
  this.instrumentationLibrary
333
350
  );
334
351
  }
335
- /**
336
- * Get the appropriate SpanKind based on span type and context
337
- */
338
- getSpanKind(aiSpan) {
339
- if (aiSpan.isRootSpan) {
340
- if (aiSpan.type === AISpanType.AGENT_RUN || aiSpan.type === AISpanType.WORKFLOW_RUN) {
341
- return SpanKind.SERVER;
342
- }
343
- }
344
- return SPAN_KIND_MAPPING[aiSpan.type] || SpanKind.INTERNAL;
345
- }
346
352
  /**
347
353
  * Build OTEL-compliant span name based on span type and attributes
348
354
  */
349
- buildSpanName(aiSpan) {
350
- switch (aiSpan.type) {
351
- case AISpanType.LLM_GENERATION: {
352
- const attrs = aiSpan.attributes;
355
+ buildSpanName(Span) {
356
+ switch (Span.type) {
357
+ case SpanType.MODEL_GENERATION: {
358
+ const attrs = Span.attributes;
353
359
  const operation = attrs?.resultType === "tool_selection" ? "tool_selection" : "chat";
354
360
  const model = attrs?.model || "unknown";
355
361
  return `${operation} ${model}`;
356
362
  }
357
- case AISpanType.TOOL_CALL:
358
- case AISpanType.MCP_TOOL_CALL: {
359
- const toolAttrs = aiSpan.attributes;
363
+ case SpanType.TOOL_CALL:
364
+ case SpanType.MCP_TOOL_CALL: {
365
+ const toolAttrs = Span.attributes;
360
366
  const toolName = toolAttrs?.toolId || "unknown";
361
367
  return `tool.execute ${toolName}`;
362
368
  }
363
- case AISpanType.AGENT_RUN: {
364
- const agentAttrs = aiSpan.attributes;
369
+ case SpanType.AGENT_RUN: {
370
+ const agentAttrs = Span.attributes;
365
371
  const agentId = agentAttrs?.agentId || "unknown";
366
372
  return `agent.${agentId}`;
367
373
  }
368
- case AISpanType.WORKFLOW_RUN: {
369
- const workflowAttrs = aiSpan.attributes;
374
+ case SpanType.WORKFLOW_RUN: {
375
+ const workflowAttrs = Span.attributes;
370
376
  const workflowId = workflowAttrs?.workflowId || "unknown";
371
377
  return `workflow.${workflowId}`;
372
378
  }
373
- case AISpanType.WORKFLOW_STEP:
374
- return aiSpan.name;
379
+ case SpanType.WORKFLOW_STEP:
380
+ return Span.name;
375
381
  default:
376
- return aiSpan.name;
382
+ return Span.name;
377
383
  }
378
384
  }
379
385
  /**
380
- * Build OpenTelemetry attributes from Mastra AI span
386
+ * Build OpenTelemetry attributes from Mastra Span
381
387
  * Following OTEL Semantic Conventions for GenAI
382
388
  */
383
- buildAttributes(aiSpan) {
389
+ buildAttributes(Span) {
384
390
  const attributes = {};
385
- attributes["gen_ai.operation.name"] = this.getOperationName(aiSpan);
386
- attributes["span.kind"] = this.getSpanKindString(aiSpan);
387
- attributes["mastra.span.type"] = aiSpan.type;
388
- attributes["mastra.trace_id"] = aiSpan.traceId;
389
- attributes["mastra.span_id"] = aiSpan.id;
390
- if (aiSpan.parentSpanId) {
391
- attributes["mastra.parent_span_id"] = aiSpan.parentSpanId;
391
+ attributes["gen_ai.operation.name"] = this.getOperationName(Span);
392
+ attributes["span.kind"] = this.getSpanKindString(Span);
393
+ attributes["mastra.span.type"] = Span.type;
394
+ attributes["mastra.trace_id"] = Span.traceId;
395
+ attributes["mastra.span_id"] = Span.id;
396
+ if (Span.parentSpanId) {
397
+ attributes["mastra.parent_span_id"] = Span.parentSpanId;
392
398
  }
393
- if (aiSpan.input !== void 0) {
394
- const inputStr = typeof aiSpan.input === "string" ? aiSpan.input : JSON.stringify(aiSpan.input);
399
+ if (Span.input !== void 0) {
400
+ const inputStr = typeof Span.input === "string" ? Span.input : JSON.stringify(Span.input);
395
401
  attributes["input"] = inputStr;
396
- if (aiSpan.type === AISpanType.LLM_GENERATION) {
402
+ if (Span.type === SpanType.MODEL_GENERATION) {
397
403
  attributes["gen_ai.prompt"] = inputStr;
398
- } else if (aiSpan.type === AISpanType.TOOL_CALL || aiSpan.type === AISpanType.MCP_TOOL_CALL) {
404
+ } else if (Span.type === SpanType.TOOL_CALL || Span.type === SpanType.MCP_TOOL_CALL) {
399
405
  attributes["gen_ai.tool.input"] = inputStr;
400
406
  }
401
407
  }
402
- if (aiSpan.output !== void 0) {
403
- const outputStr = typeof aiSpan.output === "string" ? aiSpan.output : JSON.stringify(aiSpan.output);
408
+ if (Span.output !== void 0) {
409
+ const outputStr = typeof Span.output === "string" ? Span.output : JSON.stringify(Span.output);
404
410
  attributes["output"] = outputStr;
405
- if (aiSpan.type === AISpanType.LLM_GENERATION) {
411
+ if (Span.type === SpanType.MODEL_GENERATION) {
406
412
  attributes["gen_ai.completion"] = outputStr;
407
- } else if (aiSpan.type === AISpanType.TOOL_CALL || aiSpan.type === AISpanType.MCP_TOOL_CALL) {
413
+ } else if (Span.type === SpanType.TOOL_CALL || Span.type === SpanType.MCP_TOOL_CALL) {
408
414
  attributes["gen_ai.tool.output"] = outputStr;
409
415
  }
410
416
  }
411
- if (aiSpan.type === AISpanType.LLM_GENERATION && aiSpan.attributes) {
412
- const llmAttrs = aiSpan.attributes;
413
- if (llmAttrs.model) {
414
- attributes["gen_ai.request.model"] = llmAttrs.model;
417
+ if (Span.type === SpanType.MODEL_GENERATION && Span.attributes) {
418
+ const modelAttrs = Span.attributes;
419
+ if (modelAttrs.model) {
420
+ attributes["gen_ai.request.model"] = modelAttrs.model;
415
421
  }
416
- if (llmAttrs.provider) {
417
- attributes["gen_ai.system"] = llmAttrs.provider;
422
+ if (modelAttrs.provider) {
423
+ attributes["gen_ai.system"] = modelAttrs.provider;
418
424
  }
419
- if (llmAttrs.usage) {
420
- const inputTokens = llmAttrs.usage.inputTokens ?? llmAttrs.usage.promptTokens;
421
- const outputTokens = llmAttrs.usage.outputTokens ?? llmAttrs.usage.completionTokens;
425
+ if (modelAttrs.usage) {
426
+ const inputTokens = modelAttrs.usage.inputTokens ?? modelAttrs.usage.promptTokens;
427
+ const outputTokens = modelAttrs.usage.outputTokens ?? modelAttrs.usage.completionTokens;
422
428
  if (inputTokens !== void 0) {
423
429
  attributes["gen_ai.usage.input_tokens"] = inputTokens;
424
430
  }
425
431
  if (outputTokens !== void 0) {
426
432
  attributes["gen_ai.usage.output_tokens"] = outputTokens;
427
433
  }
428
- if (llmAttrs.usage.totalTokens !== void 0) {
429
- attributes["gen_ai.usage.total_tokens"] = llmAttrs.usage.totalTokens;
434
+ if (modelAttrs.usage.totalTokens !== void 0) {
435
+ attributes["gen_ai.usage.total_tokens"] = modelAttrs.usage.totalTokens;
430
436
  }
431
- if (llmAttrs.usage.reasoningTokens !== void 0) {
432
- attributes["gen_ai.usage.reasoning_tokens"] = llmAttrs.usage.reasoningTokens;
437
+ if (modelAttrs.usage.reasoningTokens !== void 0) {
438
+ attributes["gen_ai.usage.reasoning_tokens"] = modelAttrs.usage.reasoningTokens;
433
439
  }
434
- if (llmAttrs.usage.cachedInputTokens !== void 0) {
435
- attributes["gen_ai.usage.cached_input_tokens"] = llmAttrs.usage.cachedInputTokens;
440
+ if (modelAttrs.usage.cachedInputTokens !== void 0) {
441
+ attributes["gen_ai.usage.cached_input_tokens"] = modelAttrs.usage.cachedInputTokens;
436
442
  }
437
443
  }
438
- if (llmAttrs.parameters) {
439
- if (llmAttrs.parameters.temperature !== void 0) {
440
- attributes["gen_ai.request.temperature"] = llmAttrs.parameters.temperature;
444
+ if (modelAttrs.parameters) {
445
+ if (modelAttrs.parameters.temperature !== void 0) {
446
+ attributes["gen_ai.request.temperature"] = modelAttrs.parameters.temperature;
441
447
  }
442
- if (llmAttrs.parameters.maxOutputTokens !== void 0) {
443
- attributes["gen_ai.request.max_tokens"] = llmAttrs.parameters.maxOutputTokens;
448
+ if (modelAttrs.parameters.maxOutputTokens !== void 0) {
449
+ attributes["gen_ai.request.max_tokens"] = modelAttrs.parameters.maxOutputTokens;
444
450
  }
445
- if (llmAttrs.parameters.topP !== void 0) {
446
- attributes["gen_ai.request.top_p"] = llmAttrs.parameters.topP;
451
+ if (modelAttrs.parameters.topP !== void 0) {
452
+ attributes["gen_ai.request.top_p"] = modelAttrs.parameters.topP;
447
453
  }
448
- if (llmAttrs.parameters.topK !== void 0) {
449
- attributes["gen_ai.request.top_k"] = llmAttrs.parameters.topK;
454
+ if (modelAttrs.parameters.topK !== void 0) {
455
+ attributes["gen_ai.request.top_k"] = modelAttrs.parameters.topK;
450
456
  }
451
- if (llmAttrs.parameters.presencePenalty !== void 0) {
452
- attributes["gen_ai.request.presence_penalty"] = llmAttrs.parameters.presencePenalty;
457
+ if (modelAttrs.parameters.presencePenalty !== void 0) {
458
+ attributes["gen_ai.request.presence_penalty"] = modelAttrs.parameters.presencePenalty;
453
459
  }
454
- if (llmAttrs.parameters.frequencyPenalty !== void 0) {
455
- attributes["gen_ai.request.frequency_penalty"] = llmAttrs.parameters.frequencyPenalty;
460
+ if (modelAttrs.parameters.frequencyPenalty !== void 0) {
461
+ attributes["gen_ai.request.frequency_penalty"] = modelAttrs.parameters.frequencyPenalty;
456
462
  }
457
- if (llmAttrs.parameters.stopSequences) {
458
- attributes["gen_ai.request.stop_sequences"] = JSON.stringify(llmAttrs.parameters.stopSequences);
463
+ if (modelAttrs.parameters.stopSequences) {
464
+ attributes["gen_ai.request.stop_sequences"] = JSON.stringify(modelAttrs.parameters.stopSequences);
459
465
  }
460
466
  }
461
- if (llmAttrs.finishReason) {
462
- attributes["gen_ai.response.finish_reasons"] = llmAttrs.finishReason;
467
+ if (modelAttrs.finishReason) {
468
+ attributes["gen_ai.response.finish_reasons"] = modelAttrs.finishReason;
463
469
  }
464
470
  }
465
- if ((aiSpan.type === AISpanType.TOOL_CALL || aiSpan.type === AISpanType.MCP_TOOL_CALL) && aiSpan.attributes) {
466
- const toolAttrs = aiSpan.attributes;
471
+ if ((Span.type === SpanType.TOOL_CALL || Span.type === SpanType.MCP_TOOL_CALL) && Span.attributes) {
472
+ const toolAttrs = Span.attributes;
467
473
  if (toolAttrs.toolId) {
468
474
  attributes["gen_ai.tool.name"] = toolAttrs.toolId;
469
475
  }
470
- if (aiSpan.type === AISpanType.MCP_TOOL_CALL) {
476
+ if (Span.type === SpanType.MCP_TOOL_CALL) {
471
477
  const mcpAttrs = toolAttrs;
472
478
  if (mcpAttrs.mcpServer) {
473
479
  attributes["mcp.server"] = mcpAttrs.mcpServer;
@@ -484,10 +490,11 @@ var SpanConverter = class {
484
490
  attributes["gen_ai.tool.success"] = toolAttrs.success;
485
491
  }
486
492
  }
487
- if (aiSpan.type === AISpanType.AGENT_RUN && aiSpan.attributes) {
488
- const agentAttrs = aiSpan.attributes;
493
+ if (Span.type === SpanType.AGENT_RUN && Span.attributes) {
494
+ const agentAttrs = Span.attributes;
489
495
  if (agentAttrs.agentId) {
490
496
  attributes["agent.id"] = agentAttrs.agentId;
497
+ attributes["gen_ai.agent.id"] = agentAttrs.agentId;
491
498
  }
492
499
  if (agentAttrs.maxSteps) {
493
500
  attributes["agent.max_steps"] = agentAttrs.maxSteps;
@@ -496,8 +503,8 @@ var SpanConverter = class {
496
503
  attributes["agent.available_tools"] = JSON.stringify(agentAttrs.availableTools);
497
504
  }
498
505
  }
499
- if (aiSpan.type === AISpanType.WORKFLOW_RUN && aiSpan.attributes) {
500
- const workflowAttrs = aiSpan.attributes;
506
+ if (Span.type === SpanType.WORKFLOW_RUN && Span.attributes) {
507
+ const workflowAttrs = Span.attributes;
501
508
  if (workflowAttrs.workflowId) {
502
509
  attributes["workflow.id"] = workflowAttrs.workflowId;
503
510
  }
@@ -505,19 +512,19 @@ var SpanConverter = class {
505
512
  attributes["workflow.status"] = workflowAttrs.status;
506
513
  }
507
514
  }
508
- if (aiSpan.errorInfo) {
515
+ if (Span.errorInfo) {
509
516
  attributes["error"] = true;
510
- attributes["error.type"] = aiSpan.errorInfo.id || "unknown";
511
- attributes["error.message"] = aiSpan.errorInfo.message;
512
- if (aiSpan.errorInfo.domain) {
513
- attributes["error.domain"] = aiSpan.errorInfo.domain;
517
+ attributes["error.type"] = Span.errorInfo.id || "unknown";
518
+ attributes["error.message"] = Span.errorInfo.message;
519
+ if (Span.errorInfo.domain) {
520
+ attributes["error.domain"] = Span.errorInfo.domain;
514
521
  }
515
- if (aiSpan.errorInfo.category) {
516
- attributes["error.category"] = aiSpan.errorInfo.category;
522
+ if (Span.errorInfo.category) {
523
+ attributes["error.category"] = Span.errorInfo.category;
517
524
  }
518
525
  }
519
- if (aiSpan.metadata) {
520
- Object.entries(aiSpan.metadata).forEach(([key, value]) => {
526
+ if (Span.metadata) {
527
+ Object.entries(Span.metadata).forEach(([key, value]) => {
521
528
  if (!attributes[key]) {
522
529
  if (value === null || value === void 0) {
523
530
  return;
@@ -530,12 +537,12 @@ var SpanConverter = class {
530
537
  }
531
538
  });
532
539
  }
533
- if (aiSpan.startTime) {
534
- attributes["mastra.start_time"] = aiSpan.startTime.toISOString();
540
+ if (Span.startTime) {
541
+ attributes["mastra.start_time"] = Span.startTime.toISOString();
535
542
  }
536
- if (aiSpan.endTime) {
537
- attributes["mastra.end_time"] = aiSpan.endTime.toISOString();
538
- const duration = aiSpan.endTime.getTime() - aiSpan.startTime.getTime();
543
+ if (Span.endTime) {
544
+ attributes["mastra.end_time"] = Span.endTime.toISOString();
545
+ const duration = Span.endTime.getTime() - Span.startTime.getTime();
539
546
  attributes["mastra.duration_ms"] = duration;
540
547
  }
541
548
  return attributes;
@@ -543,28 +550,28 @@ var SpanConverter = class {
543
550
  /**
544
551
  * Get the operation name based on span type for gen_ai.operation.name
545
552
  */
546
- getOperationName(aiSpan) {
547
- switch (aiSpan.type) {
548
- case AISpanType.LLM_GENERATION: {
549
- const attrs = aiSpan.attributes;
553
+ getOperationName(Span) {
554
+ switch (Span.type) {
555
+ case SpanType.MODEL_GENERATION: {
556
+ const attrs = Span.attributes;
550
557
  return attrs?.resultType === "tool_selection" ? "tool_selection" : "chat";
551
558
  }
552
- case AISpanType.TOOL_CALL:
553
- case AISpanType.MCP_TOOL_CALL:
559
+ case SpanType.TOOL_CALL:
560
+ case SpanType.MCP_TOOL_CALL:
554
561
  return "tool.execute";
555
- case AISpanType.AGENT_RUN:
562
+ case SpanType.AGENT_RUN:
556
563
  return "agent.run";
557
- case AISpanType.WORKFLOW_RUN:
564
+ case SpanType.WORKFLOW_RUN:
558
565
  return "workflow.run";
559
566
  default:
560
- return aiSpan.type.replace(/_/g, ".");
567
+ return Span.type.replace(/_/g, ".");
561
568
  }
562
569
  }
563
570
  /**
564
571
  * Get span kind as string for attribute
565
572
  */
566
- getSpanKindString(aiSpan) {
567
- const kind = this.getSpanKind(aiSpan);
573
+ getSpanKindString(Span) {
574
+ const kind = getSpanKind(Span.type, Span.isRootSpan);
568
575
  switch (kind) {
569
576
  case SpanKind.SERVER:
570
577
  return "server";
@@ -582,21 +589,19 @@ var SpanConverter = class {
582
589
  }
583
590
  };
584
591
 
585
- // src/ai-tracing.ts
586
- var OtelExporter = class {
592
+ // src/tracing.ts
593
+ var OtelExporter = class extends BaseExporter {
587
594
  config;
588
595
  tracingConfig;
589
596
  spanConverter;
590
597
  processor;
591
598
  exporter;
592
599
  isSetup = false;
593
- isDisabled = false;
594
- logger;
595
600
  name = "opentelemetry";
596
601
  constructor(config) {
602
+ super(config);
597
603
  this.config = config;
598
604
  this.spanConverter = new SpanConverter();
599
- this.logger = new ConsoleLogger({ level: config.logLevel ?? "warn" });
600
605
  if (config.logLevel === "debug") {
601
606
  diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.DEBUG);
602
607
  }
@@ -604,11 +609,11 @@ var OtelExporter = class {
604
609
  /**
605
610
  * Initialize with tracing configuration
606
611
  */
607
- init(config) {
608
- this.tracingConfig = config;
612
+ init(options) {
613
+ this.tracingConfig = options.config;
609
614
  }
610
615
  async setupExporter() {
611
- if (this.isSetup) return;
616
+ if (this.isSetup || this.exporter) return;
612
617
  if (!this.config.provider) {
613
618
  this.logger.error(
614
619
  '[OtelExporter] Provider configuration is required. Use the "custom" provider for generic endpoints.'
@@ -623,6 +628,10 @@ var OtelExporter = class {
623
628
  this.isSetup = true;
624
629
  return;
625
630
  }
631
+ if (this.config.exporter) {
632
+ this.exporter = this.config.exporter;
633
+ return;
634
+ }
626
635
  const endpoint = resolved.endpoint;
627
636
  const headers = resolved.headers;
628
637
  const protocol = resolved.protocol;
@@ -676,7 +685,10 @@ var OtelExporter = class {
676
685
  this.isSetup = true;
677
686
  return;
678
687
  }
679
- const resource = resourceFromAttributes({
688
+ }
689
+ async setupProcessor() {
690
+ if (this.processor || this.isSetup) return;
691
+ let resource = resourceFromAttributes({
680
692
  [ATTR_SERVICE_NAME]: this.tracingConfig?.serviceName || "mastra-service",
681
693
  [ATTR_SERVICE_VERSION]: "1.0.0",
682
694
  // Add telemetry SDK information
@@ -684,6 +696,12 @@ var OtelExporter = class {
684
696
  [ATTR_TELEMETRY_SDK_VERSION]: "1.0.0",
685
697
  [ATTR_TELEMETRY_SDK_LANGUAGE]: "nodejs"
686
698
  });
699
+ if (this.config.resourceAttributes) {
700
+ resource = resource.merge(
701
+ // Duplicate attributes from config will override defaults above
702
+ resourceFromAttributes(this.config.resourceAttributes)
703
+ );
704
+ }
687
705
  this.spanConverter = new SpanConverter(resource);
688
706
  this.processor = new BatchSpanProcessor(this.exporter, {
689
707
  maxExportBatchSize: this.config.batchSize || 512,
@@ -698,13 +716,15 @@ var OtelExporter = class {
698
716
  this.logger.debug(
699
717
  `[OtelExporter] Using BatchSpanProcessor (batch size: ${this.config.batchSize || 512}, delay: 5s)`
700
718
  );
719
+ }
720
+ async setup() {
721
+ if (this.isSetup) return;
722
+ await this.setupExporter();
723
+ await this.setupProcessor();
701
724
  this.isSetup = true;
702
725
  }
703
- async exportEvent(event) {
704
- if (this.isDisabled) {
705
- return;
706
- }
707
- if (event.type !== AITracingEventType.SPAN_ENDED) {
726
+ async _exportTracingEvent(event) {
727
+ if (event.type !== TracingEventType.SPAN_ENDED) {
708
728
  return;
709
729
  }
710
730
  const span = event.exportedSpan;
@@ -712,7 +732,7 @@ var OtelExporter = class {
712
732
  }
713
733
  async exportSpan(span) {
714
734
  if (!this.isSetup) {
715
- await this.setupExporter();
735
+ await this.setup();
716
736
  }
717
737
  if (this.isDisabled || !this.processor) {
718
738
  return;
@@ -737,6 +757,6 @@ var OtelExporter = class {
737
757
  }
738
758
  };
739
759
 
740
- export { OtelExporter };
760
+ export { MastraReadableSpan, OtelExporter, SpanConverter, getSpanKind };
741
761
  //# sourceMappingURL=index.js.map
742
762
  //# sourceMappingURL=index.js.map