@mastra/otel-exporter 0.0.0-extract-tool-ui-inp-playground-ui-20251024041825 → 0.0.0-feat-improve-processors-20251205191721

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;
@@ -223,45 +223,45 @@ var MastraReadableSpan = class {
223
223
  droppedAttributesCount = 0;
224
224
  droppedEventsCount = 0;
225
225
  droppedLinksCount = 0;
226
- constructor(aiSpan, attributes, kind, parentSpanId, resource, instrumentationLibrary) {
227
- this.name = aiSpan.name;
226
+ constructor(span, attributes, kind, parentSpanId, resource, instrumentationLibrary) {
227
+ this.name = span.name;
228
228
  this.kind = kind;
229
229
  this.attributes = attributes;
230
230
  this.parentSpanId = parentSpanId;
231
231
  this.links = [];
232
232
  this.events = [];
233
- this.startTime = this.dateToHrTime(aiSpan.startTime);
234
- this.endTime = aiSpan.endTime ? this.dateToHrTime(aiSpan.endTime) : this.startTime;
235
- this.ended = !!aiSpan.endTime;
236
- if (aiSpan.endTime) {
237
- 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();
238
238
  this.duration = [Math.floor(durationMs / 1e3), durationMs % 1e3 * 1e6];
239
239
  } else {
240
240
  this.duration = [0, 0];
241
241
  }
242
- if (aiSpan.errorInfo) {
242
+ if (span.errorInfo) {
243
243
  this.status = {
244
244
  code: SpanStatusCode.ERROR,
245
- message: aiSpan.errorInfo.message
245
+ message: span.errorInfo.message
246
246
  };
247
247
  this.events.push({
248
248
  name: "exception",
249
249
  attributes: {
250
- "exception.message": aiSpan.errorInfo.message,
250
+ "exception.message": span.errorInfo.message,
251
251
  "exception.type": "Error",
252
- ...aiSpan.errorInfo.details?.stack && {
253
- "exception.stacktrace": aiSpan.errorInfo.details.stack
252
+ ...span.errorInfo.details?.stack && {
253
+ "exception.stacktrace": span.errorInfo.details.stack
254
254
  }
255
255
  },
256
256
  time: this.startTime,
257
257
  droppedAttributesCount: 0
258
258
  });
259
- } else if (aiSpan.endTime) {
259
+ } else if (span.endTime) {
260
260
  this.status = { code: SpanStatusCode.OK };
261
261
  } else {
262
262
  this.status = { code: SpanStatusCode.UNSET };
263
263
  }
264
- if (aiSpan.isEvent) {
264
+ if (span.isEvent) {
265
265
  this.events.push({
266
266
  name: "instant_event",
267
267
  attributes: {},
@@ -270,14 +270,14 @@ var MastraReadableSpan = class {
270
270
  });
271
271
  }
272
272
  this.spanContext = () => ({
273
- traceId: aiSpan.traceId,
274
- spanId: aiSpan.id,
273
+ traceId: span.traceId,
274
+ spanId: span.id,
275
275
  traceFlags: TraceFlags.SAMPLED,
276
276
  isRemote: false
277
277
  });
278
278
  if (parentSpanId) {
279
279
  this.parentSpanContext = {
280
- traceId: aiSpan.traceId,
280
+ traceId: span.traceId,
281
281
  spanId: parentSpanId,
282
282
  traceFlags: TraceFlags.SAMPLED,
283
283
  isRemote: false
@@ -304,121 +304,118 @@ var MastraReadableSpan = class {
304
304
  // src/span-converter.ts
305
305
  var SPAN_KIND_MAPPING = {
306
306
  // Model operations are CLIENT spans (calling external AI services)
307
- [AISpanType.MODEL_GENERATION]: SpanKind.CLIENT,
308
- [AISpanType.MODEL_CHUNK]: SpanKind.CLIENT,
307
+ [SpanType.MODEL_GENERATION]: SpanKind.CLIENT,
308
+ [SpanType.MODEL_CHUNK]: SpanKind.CLIENT,
309
309
  // MCP tool calls are CLIENT (external service calls)
310
- [AISpanType.MCP_TOOL_CALL]: SpanKind.CLIENT,
310
+ [SpanType.MCP_TOOL_CALL]: SpanKind.CLIENT,
311
311
  // Root spans for agent/workflow are SERVER (entry points)
312
- [AISpanType.AGENT_RUN]: SpanKind.SERVER,
313
- [AISpanType.WORKFLOW_RUN]: SpanKind.SERVER
312
+ [SpanType.AGENT_RUN]: SpanKind.SERVER,
313
+ [SpanType.WORKFLOW_RUN]: SpanKind.SERVER
314
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
+ }
315
323
  var SpanConverter = class {
316
324
  resource;
317
325
  instrumentationLibrary;
318
326
  constructor(resource) {
319
327
  this.resource = resource;
320
328
  this.instrumentationLibrary = {
321
- name: "@mastra/otel",
329
+ name: "@mastra/otel-exporter",
322
330
  version: "1.0.0"
323
331
  };
324
332
  }
325
333
  /**
326
- * Convert a Mastra AI span to an OpenTelemetry ReadableSpan
334
+ * Convert a Mastra Span to an OpenTelemetry ReadableSpan
327
335
  * This preserves Mastra's trace and span IDs
328
336
  */
329
- convertSpan(aiSpan) {
330
- const spanKind = this.getSpanKind(aiSpan);
331
- const attributes = this.buildAttributes(aiSpan);
332
- const spanName = this.buildSpanName(aiSpan);
333
- 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 };
334
342
  return new MastraReadableSpan(
335
343
  otelSpan,
336
344
  attributes,
337
345
  spanKind,
338
- aiSpan.parentSpanId,
346
+ span.parentSpanId,
339
347
  // Use the parentSpanId from the Mastra span directly
340
348
  this.resource,
341
349
  this.instrumentationLibrary
342
350
  );
343
351
  }
344
- /**
345
- * Get the appropriate SpanKind based on span type and context
346
- */
347
- getSpanKind(aiSpan) {
348
- if (aiSpan.isRootSpan) {
349
- if (aiSpan.type === AISpanType.AGENT_RUN || aiSpan.type === AISpanType.WORKFLOW_RUN) {
350
- return SpanKind.SERVER;
351
- }
352
- }
353
- return SPAN_KIND_MAPPING[aiSpan.type] || SpanKind.INTERNAL;
354
- }
355
352
  /**
356
353
  * Build OTEL-compliant span name based on span type and attributes
357
354
  */
358
- buildSpanName(aiSpan) {
359
- switch (aiSpan.type) {
360
- case AISpanType.MODEL_GENERATION: {
361
- const attrs = aiSpan.attributes;
355
+ buildSpanName(Span) {
356
+ switch (Span.type) {
357
+ case SpanType.MODEL_GENERATION: {
358
+ const attrs = Span.attributes;
362
359
  const operation = attrs?.resultType === "tool_selection" ? "tool_selection" : "chat";
363
360
  const model = attrs?.model || "unknown";
364
361
  return `${operation} ${model}`;
365
362
  }
366
- case AISpanType.TOOL_CALL:
367
- case AISpanType.MCP_TOOL_CALL: {
368
- const toolAttrs = aiSpan.attributes;
363
+ case SpanType.TOOL_CALL:
364
+ case SpanType.MCP_TOOL_CALL: {
365
+ const toolAttrs = Span.attributes;
369
366
  const toolName = toolAttrs?.toolId || "unknown";
370
367
  return `tool.execute ${toolName}`;
371
368
  }
372
- case AISpanType.AGENT_RUN: {
373
- const agentAttrs = aiSpan.attributes;
369
+ case SpanType.AGENT_RUN: {
370
+ const agentAttrs = Span.attributes;
374
371
  const agentId = agentAttrs?.agentId || "unknown";
375
372
  return `agent.${agentId}`;
376
373
  }
377
- case AISpanType.WORKFLOW_RUN: {
378
- const workflowAttrs = aiSpan.attributes;
374
+ case SpanType.WORKFLOW_RUN: {
375
+ const workflowAttrs = Span.attributes;
379
376
  const workflowId = workflowAttrs?.workflowId || "unknown";
380
377
  return `workflow.${workflowId}`;
381
378
  }
382
- case AISpanType.WORKFLOW_STEP:
383
- return aiSpan.name;
379
+ case SpanType.WORKFLOW_STEP:
380
+ return Span.name;
384
381
  default:
385
- return aiSpan.name;
382
+ return Span.name;
386
383
  }
387
384
  }
388
385
  /**
389
- * Build OpenTelemetry attributes from Mastra AI span
386
+ * Build OpenTelemetry attributes from Mastra Span
390
387
  * Following OTEL Semantic Conventions for GenAI
391
388
  */
392
- buildAttributes(aiSpan) {
389
+ buildAttributes(Span) {
393
390
  const attributes = {};
394
- attributes["gen_ai.operation.name"] = this.getOperationName(aiSpan);
395
- attributes["span.kind"] = this.getSpanKindString(aiSpan);
396
- attributes["mastra.span.type"] = aiSpan.type;
397
- attributes["mastra.trace_id"] = aiSpan.traceId;
398
- attributes["mastra.span_id"] = aiSpan.id;
399
- if (aiSpan.parentSpanId) {
400
- attributes["mastra.parent_span_id"] = aiSpan.parentSpanId;
401
- }
402
- if (aiSpan.input !== void 0) {
403
- const inputStr = typeof aiSpan.input === "string" ? aiSpan.input : JSON.stringify(aiSpan.input);
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;
398
+ }
399
+ if (Span.input !== void 0) {
400
+ const inputStr = typeof Span.input === "string" ? Span.input : JSON.stringify(Span.input);
404
401
  attributes["input"] = inputStr;
405
- if (aiSpan.type === AISpanType.MODEL_GENERATION) {
402
+ if (Span.type === SpanType.MODEL_GENERATION) {
406
403
  attributes["gen_ai.prompt"] = inputStr;
407
- } 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) {
408
405
  attributes["gen_ai.tool.input"] = inputStr;
409
406
  }
410
407
  }
411
- if (aiSpan.output !== void 0) {
412
- 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);
413
410
  attributes["output"] = outputStr;
414
- if (aiSpan.type === AISpanType.MODEL_GENERATION) {
411
+ if (Span.type === SpanType.MODEL_GENERATION) {
415
412
  attributes["gen_ai.completion"] = outputStr;
416
- } 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) {
417
414
  attributes["gen_ai.tool.output"] = outputStr;
418
415
  }
419
416
  }
420
- if (aiSpan.type === AISpanType.MODEL_GENERATION && aiSpan.attributes) {
421
- const modelAttrs = aiSpan.attributes;
417
+ if (Span.type === SpanType.MODEL_GENERATION && Span.attributes) {
418
+ const modelAttrs = Span.attributes;
422
419
  if (modelAttrs.model) {
423
420
  attributes["gen_ai.request.model"] = modelAttrs.model;
424
421
  }
@@ -471,12 +468,12 @@ var SpanConverter = class {
471
468
  attributes["gen_ai.response.finish_reasons"] = modelAttrs.finishReason;
472
469
  }
473
470
  }
474
- if ((aiSpan.type === AISpanType.TOOL_CALL || aiSpan.type === AISpanType.MCP_TOOL_CALL) && aiSpan.attributes) {
475
- const toolAttrs = aiSpan.attributes;
471
+ if ((Span.type === SpanType.TOOL_CALL || Span.type === SpanType.MCP_TOOL_CALL) && Span.attributes) {
472
+ const toolAttrs = Span.attributes;
476
473
  if (toolAttrs.toolId) {
477
474
  attributes["gen_ai.tool.name"] = toolAttrs.toolId;
478
475
  }
479
- if (aiSpan.type === AISpanType.MCP_TOOL_CALL) {
476
+ if (Span.type === SpanType.MCP_TOOL_CALL) {
480
477
  const mcpAttrs = toolAttrs;
481
478
  if (mcpAttrs.mcpServer) {
482
479
  attributes["mcp.server"] = mcpAttrs.mcpServer;
@@ -493,8 +490,8 @@ var SpanConverter = class {
493
490
  attributes["gen_ai.tool.success"] = toolAttrs.success;
494
491
  }
495
492
  }
496
- if (aiSpan.type === AISpanType.AGENT_RUN && aiSpan.attributes) {
497
- const agentAttrs = aiSpan.attributes;
493
+ if (Span.type === SpanType.AGENT_RUN && Span.attributes) {
494
+ const agentAttrs = Span.attributes;
498
495
  if (agentAttrs.agentId) {
499
496
  attributes["agent.id"] = agentAttrs.agentId;
500
497
  attributes["gen_ai.agent.id"] = agentAttrs.agentId;
@@ -506,8 +503,8 @@ var SpanConverter = class {
506
503
  attributes["agent.available_tools"] = JSON.stringify(agentAttrs.availableTools);
507
504
  }
508
505
  }
509
- if (aiSpan.type === AISpanType.WORKFLOW_RUN && aiSpan.attributes) {
510
- const workflowAttrs = aiSpan.attributes;
506
+ if (Span.type === SpanType.WORKFLOW_RUN && Span.attributes) {
507
+ const workflowAttrs = Span.attributes;
511
508
  if (workflowAttrs.workflowId) {
512
509
  attributes["workflow.id"] = workflowAttrs.workflowId;
513
510
  }
@@ -515,19 +512,19 @@ var SpanConverter = class {
515
512
  attributes["workflow.status"] = workflowAttrs.status;
516
513
  }
517
514
  }
518
- if (aiSpan.errorInfo) {
515
+ if (Span.errorInfo) {
519
516
  attributes["error"] = true;
520
- attributes["error.type"] = aiSpan.errorInfo.id || "unknown";
521
- attributes["error.message"] = aiSpan.errorInfo.message;
522
- if (aiSpan.errorInfo.domain) {
523
- 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;
524
521
  }
525
- if (aiSpan.errorInfo.category) {
526
- attributes["error.category"] = aiSpan.errorInfo.category;
522
+ if (Span.errorInfo.category) {
523
+ attributes["error.category"] = Span.errorInfo.category;
527
524
  }
528
525
  }
529
- if (aiSpan.metadata) {
530
- Object.entries(aiSpan.metadata).forEach(([key, value]) => {
526
+ if (Span.metadata) {
527
+ Object.entries(Span.metadata).forEach(([key, value]) => {
531
528
  if (!attributes[key]) {
532
529
  if (value === null || value === void 0) {
533
530
  return;
@@ -540,12 +537,12 @@ var SpanConverter = class {
540
537
  }
541
538
  });
542
539
  }
543
- if (aiSpan.startTime) {
544
- attributes["mastra.start_time"] = aiSpan.startTime.toISOString();
540
+ if (Span.startTime) {
541
+ attributes["mastra.start_time"] = Span.startTime.toISOString();
545
542
  }
546
- if (aiSpan.endTime) {
547
- attributes["mastra.end_time"] = aiSpan.endTime.toISOString();
548
- 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();
549
546
  attributes["mastra.duration_ms"] = duration;
550
547
  }
551
548
  return attributes;
@@ -553,28 +550,28 @@ var SpanConverter = class {
553
550
  /**
554
551
  * Get the operation name based on span type for gen_ai.operation.name
555
552
  */
556
- getOperationName(aiSpan) {
557
- switch (aiSpan.type) {
558
- case AISpanType.MODEL_GENERATION: {
559
- const attrs = aiSpan.attributes;
553
+ getOperationName(Span) {
554
+ switch (Span.type) {
555
+ case SpanType.MODEL_GENERATION: {
556
+ const attrs = Span.attributes;
560
557
  return attrs?.resultType === "tool_selection" ? "tool_selection" : "chat";
561
558
  }
562
- case AISpanType.TOOL_CALL:
563
- case AISpanType.MCP_TOOL_CALL:
559
+ case SpanType.TOOL_CALL:
560
+ case SpanType.MCP_TOOL_CALL:
564
561
  return "tool.execute";
565
- case AISpanType.AGENT_RUN:
562
+ case SpanType.AGENT_RUN:
566
563
  return "agent.run";
567
- case AISpanType.WORKFLOW_RUN:
564
+ case SpanType.WORKFLOW_RUN:
568
565
  return "workflow.run";
569
566
  default:
570
- return aiSpan.type.replace(/_/g, ".");
567
+ return Span.type.replace(/_/g, ".");
571
568
  }
572
569
  }
573
570
  /**
574
571
  * Get span kind as string for attribute
575
572
  */
576
- getSpanKindString(aiSpan) {
577
- const kind = this.getSpanKind(aiSpan);
573
+ getSpanKindString(Span) {
574
+ const kind = getSpanKind(Span.type, Span.isRootSpan);
578
575
  switch (kind) {
579
576
  case SpanKind.SERVER:
580
577
  return "server";
@@ -592,21 +589,19 @@ var SpanConverter = class {
592
589
  }
593
590
  };
594
591
 
595
- // src/ai-tracing.ts
596
- var OtelExporter = class {
592
+ // src/tracing.ts
593
+ var OtelExporter = class extends BaseExporter {
597
594
  config;
598
595
  tracingConfig;
599
596
  spanConverter;
600
597
  processor;
601
598
  exporter;
602
599
  isSetup = false;
603
- isDisabled = false;
604
- logger;
605
600
  name = "opentelemetry";
606
601
  constructor(config) {
602
+ super(config);
607
603
  this.config = config;
608
604
  this.spanConverter = new SpanConverter();
609
- this.logger = new ConsoleLogger({ level: config.logLevel ?? "warn" });
610
605
  if (config.logLevel === "debug") {
611
606
  diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.DEBUG);
612
607
  }
@@ -614,8 +609,8 @@ var OtelExporter = class {
614
609
  /**
615
610
  * Initialize with tracing configuration
616
611
  */
617
- init(config) {
618
- this.tracingConfig = config;
612
+ init(options) {
613
+ this.tracingConfig = options.config;
619
614
  }
620
615
  async setupExporter() {
621
616
  if (this.isSetup || this.exporter) return;
@@ -728,11 +723,8 @@ var OtelExporter = class {
728
723
  await this.setupProcessor();
729
724
  this.isSetup = true;
730
725
  }
731
- async exportEvent(event) {
732
- if (this.isDisabled) {
733
- return;
734
- }
735
- if (event.type !== AITracingEventType.SPAN_ENDED) {
726
+ async _exportTracingEvent(event) {
727
+ if (event.type !== TracingEventType.SPAN_ENDED) {
736
728
  return;
737
729
  }
738
730
  const span = event.exportedSpan;
@@ -765,6 +757,6 @@ var OtelExporter = class {
765
757
  }
766
758
  };
767
759
 
768
- export { OtelExporter };
760
+ export { MastraReadableSpan, OtelExporter, SpanConverter, getSpanKind };
769
761
  //# sourceMappingURL=index.js.map
770
762
  //# sourceMappingURL=index.js.map