@mastra/otel-exporter 0.3.3 → 1.0.0-beta.0
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/CHANGELOG.md +35 -64
- package/README.md +10 -10
- package/dist/index.cjs +107 -106
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +106 -105
- package/dist/index.js.map +1 -1
- package/dist/mastra-span.d.ts +2 -2
- package/dist/mastra-span.d.ts.map +1 -1
- package/dist/span-converter.d.ts +5 -5
- package/dist/span-converter.d.ts.map +1 -1
- package/dist/{ai-tracing.d.ts → tracing.d.ts} +6 -6
- package/dist/tracing.d.ts.map +1 -0
- package/dist/types.d.ts +3 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +9 -12
- package/dist/ai-tracing.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { TracingEventType, SpanType } from '@mastra/core/observability';
|
|
2
|
+
import { BaseExporter } from '@mastra/observability';
|
|
2
3
|
import { diag, DiagConsoleLogger, DiagLogLevel, SpanKind, SpanStatusCode, TraceFlags } from '@opentelemetry/api';
|
|
3
4
|
import { resourceFromAttributes } from '@opentelemetry/resources';
|
|
4
5
|
import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base';
|
|
5
6
|
import { ATTR_TELEMETRY_SDK_LANGUAGE, ATTR_TELEMETRY_SDK_VERSION, ATTR_TELEMETRY_SDK_NAME, ATTR_SERVICE_VERSION, ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions';
|
|
6
7
|
|
|
7
|
-
// src/
|
|
8
|
+
// src/tracing.ts
|
|
8
9
|
|
|
9
10
|
// src/loadExporter.ts
|
|
10
11
|
var OTLPHttpExporter;
|
|
@@ -222,45 +223,45 @@ var MastraReadableSpan = class {
|
|
|
222
223
|
droppedAttributesCount = 0;
|
|
223
224
|
droppedEventsCount = 0;
|
|
224
225
|
droppedLinksCount = 0;
|
|
225
|
-
constructor(
|
|
226
|
-
this.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(
|
|
233
|
-
this.endTime =
|
|
234
|
-
this.ended = !!
|
|
235
|
-
if (
|
|
236
|
-
const durationMs =
|
|
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 (
|
|
242
|
+
if (span.errorInfo) {
|
|
242
243
|
this.status = {
|
|
243
244
|
code: SpanStatusCode.ERROR,
|
|
244
|
-
message:
|
|
245
|
+
message: span.errorInfo.message
|
|
245
246
|
};
|
|
246
247
|
this.events.push({
|
|
247
248
|
name: "exception",
|
|
248
249
|
attributes: {
|
|
249
|
-
"exception.message":
|
|
250
|
+
"exception.message": span.errorInfo.message,
|
|
250
251
|
"exception.type": "Error",
|
|
251
|
-
...
|
|
252
|
-
"exception.stacktrace":
|
|
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 (
|
|
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 (
|
|
264
|
+
if (span.isEvent) {
|
|
264
265
|
this.events.push({
|
|
265
266
|
name: "instant_event",
|
|
266
267
|
attributes: {},
|
|
@@ -269,14 +270,14 @@ var MastraReadableSpan = class {
|
|
|
269
270
|
});
|
|
270
271
|
}
|
|
271
272
|
this.spanContext = () => ({
|
|
272
|
-
traceId:
|
|
273
|
-
spanId:
|
|
273
|
+
traceId: span.traceId,
|
|
274
|
+
spanId: span.id,
|
|
274
275
|
traceFlags: TraceFlags.SAMPLED,
|
|
275
276
|
isRemote: false
|
|
276
277
|
});
|
|
277
278
|
if (parentSpanId) {
|
|
278
279
|
this.parentSpanContext = {
|
|
279
|
-
traceId:
|
|
280
|
+
traceId: span.traceId,
|
|
280
281
|
spanId: parentSpanId,
|
|
281
282
|
traceFlags: TraceFlags.SAMPLED,
|
|
282
283
|
isRemote: false
|
|
@@ -303,13 +304,13 @@ var MastraReadableSpan = class {
|
|
|
303
304
|
// src/span-converter.ts
|
|
304
305
|
var SPAN_KIND_MAPPING = {
|
|
305
306
|
// Model operations are CLIENT spans (calling external AI services)
|
|
306
|
-
[
|
|
307
|
-
[
|
|
307
|
+
[SpanType.MODEL_GENERATION]: SpanKind.CLIENT,
|
|
308
|
+
[SpanType.MODEL_CHUNK]: SpanKind.CLIENT,
|
|
308
309
|
// MCP tool calls are CLIENT (external service calls)
|
|
309
|
-
[
|
|
310
|
+
[SpanType.MCP_TOOL_CALL]: SpanKind.CLIENT,
|
|
310
311
|
// Root spans for agent/workflow are SERVER (entry points)
|
|
311
|
-
[
|
|
312
|
-
[
|
|
312
|
+
[SpanType.AGENT_RUN]: SpanKind.SERVER,
|
|
313
|
+
[SpanType.WORKFLOW_RUN]: SpanKind.SERVER
|
|
313
314
|
};
|
|
314
315
|
var SpanConverter = class {
|
|
315
316
|
resource;
|
|
@@ -322,19 +323,19 @@ var SpanConverter = class {
|
|
|
322
323
|
};
|
|
323
324
|
}
|
|
324
325
|
/**
|
|
325
|
-
* Convert a Mastra
|
|
326
|
+
* Convert a Mastra Span to an OpenTelemetry ReadableSpan
|
|
326
327
|
* This preserves Mastra's trace and span IDs
|
|
327
328
|
*/
|
|
328
|
-
convertSpan(
|
|
329
|
-
const spanKind = this.getSpanKind(
|
|
330
|
-
const attributes = this.buildAttributes(
|
|
331
|
-
const spanName = this.buildSpanName(
|
|
332
|
-
const otelSpan = { ...
|
|
329
|
+
convertSpan(Span) {
|
|
330
|
+
const spanKind = this.getSpanKind(Span);
|
|
331
|
+
const attributes = this.buildAttributes(Span);
|
|
332
|
+
const spanName = this.buildSpanName(Span);
|
|
333
|
+
const otelSpan = { ...Span, name: spanName };
|
|
333
334
|
return new MastraReadableSpan(
|
|
334
335
|
otelSpan,
|
|
335
336
|
attributes,
|
|
336
337
|
spanKind,
|
|
337
|
-
|
|
338
|
+
Span.parentSpanId,
|
|
338
339
|
// Use the parentSpanId from the Mastra span directly
|
|
339
340
|
this.resource,
|
|
340
341
|
this.instrumentationLibrary
|
|
@@ -343,81 +344,81 @@ var SpanConverter = class {
|
|
|
343
344
|
/**
|
|
344
345
|
* Get the appropriate SpanKind based on span type and context
|
|
345
346
|
*/
|
|
346
|
-
getSpanKind(
|
|
347
|
-
if (
|
|
348
|
-
if (
|
|
347
|
+
getSpanKind(Span) {
|
|
348
|
+
if (Span.isRootSpan) {
|
|
349
|
+
if (Span.type === SpanType.AGENT_RUN || Span.type === SpanType.WORKFLOW_RUN) {
|
|
349
350
|
return SpanKind.SERVER;
|
|
350
351
|
}
|
|
351
352
|
}
|
|
352
|
-
return SPAN_KIND_MAPPING[
|
|
353
|
+
return SPAN_KIND_MAPPING[Span.type] || SpanKind.INTERNAL;
|
|
353
354
|
}
|
|
354
355
|
/**
|
|
355
356
|
* Build OTEL-compliant span name based on span type and attributes
|
|
356
357
|
*/
|
|
357
|
-
buildSpanName(
|
|
358
|
-
switch (
|
|
359
|
-
case
|
|
360
|
-
const attrs =
|
|
358
|
+
buildSpanName(Span) {
|
|
359
|
+
switch (Span.type) {
|
|
360
|
+
case SpanType.MODEL_GENERATION: {
|
|
361
|
+
const attrs = Span.attributes;
|
|
361
362
|
const operation = attrs?.resultType === "tool_selection" ? "tool_selection" : "chat";
|
|
362
363
|
const model = attrs?.model || "unknown";
|
|
363
364
|
return `${operation} ${model}`;
|
|
364
365
|
}
|
|
365
|
-
case
|
|
366
|
-
case
|
|
367
|
-
const toolAttrs =
|
|
366
|
+
case SpanType.TOOL_CALL:
|
|
367
|
+
case SpanType.MCP_TOOL_CALL: {
|
|
368
|
+
const toolAttrs = Span.attributes;
|
|
368
369
|
const toolName = toolAttrs?.toolId || "unknown";
|
|
369
370
|
return `tool.execute ${toolName}`;
|
|
370
371
|
}
|
|
371
|
-
case
|
|
372
|
-
const agentAttrs =
|
|
372
|
+
case SpanType.AGENT_RUN: {
|
|
373
|
+
const agentAttrs = Span.attributes;
|
|
373
374
|
const agentId = agentAttrs?.agentId || "unknown";
|
|
374
375
|
return `agent.${agentId}`;
|
|
375
376
|
}
|
|
376
|
-
case
|
|
377
|
-
const workflowAttrs =
|
|
377
|
+
case SpanType.WORKFLOW_RUN: {
|
|
378
|
+
const workflowAttrs = Span.attributes;
|
|
378
379
|
const workflowId = workflowAttrs?.workflowId || "unknown";
|
|
379
380
|
return `workflow.${workflowId}`;
|
|
380
381
|
}
|
|
381
|
-
case
|
|
382
|
-
return
|
|
382
|
+
case SpanType.WORKFLOW_STEP:
|
|
383
|
+
return Span.name;
|
|
383
384
|
default:
|
|
384
|
-
return
|
|
385
|
+
return Span.name;
|
|
385
386
|
}
|
|
386
387
|
}
|
|
387
388
|
/**
|
|
388
|
-
* Build OpenTelemetry attributes from Mastra
|
|
389
|
+
* Build OpenTelemetry attributes from Mastra Span
|
|
389
390
|
* Following OTEL Semantic Conventions for GenAI
|
|
390
391
|
*/
|
|
391
|
-
buildAttributes(
|
|
392
|
+
buildAttributes(Span) {
|
|
392
393
|
const attributes = {};
|
|
393
|
-
attributes["gen_ai.operation.name"] = this.getOperationName(
|
|
394
|
-
attributes["span.kind"] = this.getSpanKindString(
|
|
395
|
-
attributes["mastra.span.type"] =
|
|
396
|
-
attributes["mastra.trace_id"] =
|
|
397
|
-
attributes["mastra.span_id"] =
|
|
398
|
-
if (
|
|
399
|
-
attributes["mastra.parent_span_id"] =
|
|
394
|
+
attributes["gen_ai.operation.name"] = this.getOperationName(Span);
|
|
395
|
+
attributes["span.kind"] = this.getSpanKindString(Span);
|
|
396
|
+
attributes["mastra.span.type"] = Span.type;
|
|
397
|
+
attributes["mastra.trace_id"] = Span.traceId;
|
|
398
|
+
attributes["mastra.span_id"] = Span.id;
|
|
399
|
+
if (Span.parentSpanId) {
|
|
400
|
+
attributes["mastra.parent_span_id"] = Span.parentSpanId;
|
|
400
401
|
}
|
|
401
|
-
if (
|
|
402
|
-
const inputStr = typeof
|
|
402
|
+
if (Span.input !== void 0) {
|
|
403
|
+
const inputStr = typeof Span.input === "string" ? Span.input : JSON.stringify(Span.input);
|
|
403
404
|
attributes["input"] = inputStr;
|
|
404
|
-
if (
|
|
405
|
+
if (Span.type === SpanType.MODEL_GENERATION) {
|
|
405
406
|
attributes["gen_ai.prompt"] = inputStr;
|
|
406
|
-
} else if (
|
|
407
|
+
} else if (Span.type === SpanType.TOOL_CALL || Span.type === SpanType.MCP_TOOL_CALL) {
|
|
407
408
|
attributes["gen_ai.tool.input"] = inputStr;
|
|
408
409
|
}
|
|
409
410
|
}
|
|
410
|
-
if (
|
|
411
|
-
const outputStr = typeof
|
|
411
|
+
if (Span.output !== void 0) {
|
|
412
|
+
const outputStr = typeof Span.output === "string" ? Span.output : JSON.stringify(Span.output);
|
|
412
413
|
attributes["output"] = outputStr;
|
|
413
|
-
if (
|
|
414
|
+
if (Span.type === SpanType.MODEL_GENERATION) {
|
|
414
415
|
attributes["gen_ai.completion"] = outputStr;
|
|
415
|
-
} else if (
|
|
416
|
+
} else if (Span.type === SpanType.TOOL_CALL || Span.type === SpanType.MCP_TOOL_CALL) {
|
|
416
417
|
attributes["gen_ai.tool.output"] = outputStr;
|
|
417
418
|
}
|
|
418
419
|
}
|
|
419
|
-
if (
|
|
420
|
-
const modelAttrs =
|
|
420
|
+
if (Span.type === SpanType.MODEL_GENERATION && Span.attributes) {
|
|
421
|
+
const modelAttrs = Span.attributes;
|
|
421
422
|
if (modelAttrs.model) {
|
|
422
423
|
attributes["gen_ai.request.model"] = modelAttrs.model;
|
|
423
424
|
}
|
|
@@ -470,12 +471,12 @@ var SpanConverter = class {
|
|
|
470
471
|
attributes["gen_ai.response.finish_reasons"] = modelAttrs.finishReason;
|
|
471
472
|
}
|
|
472
473
|
}
|
|
473
|
-
if ((
|
|
474
|
-
const toolAttrs =
|
|
474
|
+
if ((Span.type === SpanType.TOOL_CALL || Span.type === SpanType.MCP_TOOL_CALL) && Span.attributes) {
|
|
475
|
+
const toolAttrs = Span.attributes;
|
|
475
476
|
if (toolAttrs.toolId) {
|
|
476
477
|
attributes["gen_ai.tool.name"] = toolAttrs.toolId;
|
|
477
478
|
}
|
|
478
|
-
if (
|
|
479
|
+
if (Span.type === SpanType.MCP_TOOL_CALL) {
|
|
479
480
|
const mcpAttrs = toolAttrs;
|
|
480
481
|
if (mcpAttrs.mcpServer) {
|
|
481
482
|
attributes["mcp.server"] = mcpAttrs.mcpServer;
|
|
@@ -492,8 +493,8 @@ var SpanConverter = class {
|
|
|
492
493
|
attributes["gen_ai.tool.success"] = toolAttrs.success;
|
|
493
494
|
}
|
|
494
495
|
}
|
|
495
|
-
if (
|
|
496
|
-
const agentAttrs =
|
|
496
|
+
if (Span.type === SpanType.AGENT_RUN && Span.attributes) {
|
|
497
|
+
const agentAttrs = Span.attributes;
|
|
497
498
|
if (agentAttrs.agentId) {
|
|
498
499
|
attributes["agent.id"] = agentAttrs.agentId;
|
|
499
500
|
attributes["gen_ai.agent.id"] = agentAttrs.agentId;
|
|
@@ -505,8 +506,8 @@ var SpanConverter = class {
|
|
|
505
506
|
attributes["agent.available_tools"] = JSON.stringify(agentAttrs.availableTools);
|
|
506
507
|
}
|
|
507
508
|
}
|
|
508
|
-
if (
|
|
509
|
-
const workflowAttrs =
|
|
509
|
+
if (Span.type === SpanType.WORKFLOW_RUN && Span.attributes) {
|
|
510
|
+
const workflowAttrs = Span.attributes;
|
|
510
511
|
if (workflowAttrs.workflowId) {
|
|
511
512
|
attributes["workflow.id"] = workflowAttrs.workflowId;
|
|
512
513
|
}
|
|
@@ -514,19 +515,19 @@ var SpanConverter = class {
|
|
|
514
515
|
attributes["workflow.status"] = workflowAttrs.status;
|
|
515
516
|
}
|
|
516
517
|
}
|
|
517
|
-
if (
|
|
518
|
+
if (Span.errorInfo) {
|
|
518
519
|
attributes["error"] = true;
|
|
519
|
-
attributes["error.type"] =
|
|
520
|
-
attributes["error.message"] =
|
|
521
|
-
if (
|
|
522
|
-
attributes["error.domain"] =
|
|
520
|
+
attributes["error.type"] = Span.errorInfo.id || "unknown";
|
|
521
|
+
attributes["error.message"] = Span.errorInfo.message;
|
|
522
|
+
if (Span.errorInfo.domain) {
|
|
523
|
+
attributes["error.domain"] = Span.errorInfo.domain;
|
|
523
524
|
}
|
|
524
|
-
if (
|
|
525
|
-
attributes["error.category"] =
|
|
525
|
+
if (Span.errorInfo.category) {
|
|
526
|
+
attributes["error.category"] = Span.errorInfo.category;
|
|
526
527
|
}
|
|
527
528
|
}
|
|
528
|
-
if (
|
|
529
|
-
Object.entries(
|
|
529
|
+
if (Span.metadata) {
|
|
530
|
+
Object.entries(Span.metadata).forEach(([key, value]) => {
|
|
530
531
|
if (!attributes[key]) {
|
|
531
532
|
if (value === null || value === void 0) {
|
|
532
533
|
return;
|
|
@@ -539,12 +540,12 @@ var SpanConverter = class {
|
|
|
539
540
|
}
|
|
540
541
|
});
|
|
541
542
|
}
|
|
542
|
-
if (
|
|
543
|
-
attributes["mastra.start_time"] =
|
|
543
|
+
if (Span.startTime) {
|
|
544
|
+
attributes["mastra.start_time"] = Span.startTime.toISOString();
|
|
544
545
|
}
|
|
545
|
-
if (
|
|
546
|
-
attributes["mastra.end_time"] =
|
|
547
|
-
const duration =
|
|
546
|
+
if (Span.endTime) {
|
|
547
|
+
attributes["mastra.end_time"] = Span.endTime.toISOString();
|
|
548
|
+
const duration = Span.endTime.getTime() - Span.startTime.getTime();
|
|
548
549
|
attributes["mastra.duration_ms"] = duration;
|
|
549
550
|
}
|
|
550
551
|
return attributes;
|
|
@@ -552,28 +553,28 @@ var SpanConverter = class {
|
|
|
552
553
|
/**
|
|
553
554
|
* Get the operation name based on span type for gen_ai.operation.name
|
|
554
555
|
*/
|
|
555
|
-
getOperationName(
|
|
556
|
-
switch (
|
|
557
|
-
case
|
|
558
|
-
const attrs =
|
|
556
|
+
getOperationName(Span) {
|
|
557
|
+
switch (Span.type) {
|
|
558
|
+
case SpanType.MODEL_GENERATION: {
|
|
559
|
+
const attrs = Span.attributes;
|
|
559
560
|
return attrs?.resultType === "tool_selection" ? "tool_selection" : "chat";
|
|
560
561
|
}
|
|
561
|
-
case
|
|
562
|
-
case
|
|
562
|
+
case SpanType.TOOL_CALL:
|
|
563
|
+
case SpanType.MCP_TOOL_CALL:
|
|
563
564
|
return "tool.execute";
|
|
564
|
-
case
|
|
565
|
+
case SpanType.AGENT_RUN:
|
|
565
566
|
return "agent.run";
|
|
566
|
-
case
|
|
567
|
+
case SpanType.WORKFLOW_RUN:
|
|
567
568
|
return "workflow.run";
|
|
568
569
|
default:
|
|
569
|
-
return
|
|
570
|
+
return Span.type.replace(/_/g, ".");
|
|
570
571
|
}
|
|
571
572
|
}
|
|
572
573
|
/**
|
|
573
574
|
* Get span kind as string for attribute
|
|
574
575
|
*/
|
|
575
|
-
getSpanKindString(
|
|
576
|
-
const kind = this.getSpanKind(
|
|
576
|
+
getSpanKindString(Span) {
|
|
577
|
+
const kind = this.getSpanKind(Span);
|
|
577
578
|
switch (kind) {
|
|
578
579
|
case SpanKind.SERVER:
|
|
579
580
|
return "server";
|
|
@@ -591,7 +592,7 @@ var SpanConverter = class {
|
|
|
591
592
|
}
|
|
592
593
|
};
|
|
593
594
|
|
|
594
|
-
// src/
|
|
595
|
+
// src/tracing.ts
|
|
595
596
|
var OtelExporter = class extends BaseExporter {
|
|
596
597
|
config;
|
|
597
598
|
tracingConfig;
|
|
@@ -611,8 +612,8 @@ var OtelExporter = class extends BaseExporter {
|
|
|
611
612
|
/**
|
|
612
613
|
* Initialize with tracing configuration
|
|
613
614
|
*/
|
|
614
|
-
init(
|
|
615
|
-
this.tracingConfig = config;
|
|
615
|
+
init(options) {
|
|
616
|
+
this.tracingConfig = options.config;
|
|
616
617
|
}
|
|
617
618
|
async setupExporter() {
|
|
618
619
|
if (this.isSetup || this.exporter) return;
|
|
@@ -725,8 +726,8 @@ var OtelExporter = class extends BaseExporter {
|
|
|
725
726
|
await this.setupProcessor();
|
|
726
727
|
this.isSetup = true;
|
|
727
728
|
}
|
|
728
|
-
async
|
|
729
|
-
if (event.type !==
|
|
729
|
+
async _exportTracingEvent(event) {
|
|
730
|
+
if (event.type !== TracingEventType.SPAN_ENDED) {
|
|
730
731
|
return;
|
|
731
732
|
}
|
|
732
733
|
const span = event.exportedSpan;
|