@mastra/otel-exporter 0.0.0-just-snapshot-20251014192224 → 0.0.0-main-test-05-11-2025-2-20251105214713
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 +144 -3
- package/README.md +9 -9
- package/dist/index.cjs +162 -145
- 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 +162 -145
- package/dist/index.js.map +1 -1
- package/dist/mastra-span.d.ts +3 -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/tracing.d.ts +27 -0
- package/dist/tracing.d.ts.map +1 -0
- package/dist/types.d.ts +6 -3
- package/dist/types.d.ts.map +1 -1
- package/package.json +11 -7
- package/dist/ai-tracing.d.ts +0 -26
- package/dist/ai-tracing.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { TracingEventType, SpanType } from '@mastra/core/observability';
|
|
2
|
+
import { BaseExporter } from '@mastra/observability';
|
|
3
3
|
import { diag, DiagConsoleLogger, DiagLogLevel, SpanKind, SpanStatusCode, TraceFlags } 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/
|
|
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(
|
|
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,11 +270,19 @@ 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
|
});
|
|
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,14 +303,14 @@ var MastraReadableSpan = class {
|
|
|
294
303
|
|
|
295
304
|
// src/span-converter.ts
|
|
296
305
|
var SPAN_KIND_MAPPING = {
|
|
297
|
-
//
|
|
298
|
-
[
|
|
299
|
-
[
|
|
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
|
-
[
|
|
310
|
+
[SpanType.MCP_TOOL_CALL]: SpanKind.CLIENT,
|
|
302
311
|
// Root spans for agent/workflow are SERVER (entry points)
|
|
303
|
-
[
|
|
304
|
-
[
|
|
312
|
+
[SpanType.AGENT_RUN]: SpanKind.SERVER,
|
|
313
|
+
[SpanType.WORKFLOW_RUN]: SpanKind.SERVER
|
|
305
314
|
};
|
|
306
315
|
var SpanConverter = class {
|
|
307
316
|
resource;
|
|
@@ -314,19 +323,19 @@ var SpanConverter = class {
|
|
|
314
323
|
};
|
|
315
324
|
}
|
|
316
325
|
/**
|
|
317
|
-
* Convert a Mastra
|
|
326
|
+
* Convert a Mastra Span to an OpenTelemetry ReadableSpan
|
|
318
327
|
* This preserves Mastra's trace and span IDs
|
|
319
328
|
*/
|
|
320
|
-
convertSpan(
|
|
321
|
-
const spanKind = this.getSpanKind(
|
|
322
|
-
const attributes = this.buildAttributes(
|
|
323
|
-
const spanName = this.buildSpanName(
|
|
324
|
-
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 };
|
|
325
334
|
return new MastraReadableSpan(
|
|
326
335
|
otelSpan,
|
|
327
336
|
attributes,
|
|
328
337
|
spanKind,
|
|
329
|
-
|
|
338
|
+
Span.parentSpanId,
|
|
330
339
|
// Use the parentSpanId from the Mastra span directly
|
|
331
340
|
this.resource,
|
|
332
341
|
this.instrumentationLibrary
|
|
@@ -335,139 +344,139 @@ var SpanConverter = class {
|
|
|
335
344
|
/**
|
|
336
345
|
* Get the appropriate SpanKind based on span type and context
|
|
337
346
|
*/
|
|
338
|
-
getSpanKind(
|
|
339
|
-
if (
|
|
340
|
-
if (
|
|
347
|
+
getSpanKind(Span) {
|
|
348
|
+
if (Span.isRootSpan) {
|
|
349
|
+
if (Span.type === SpanType.AGENT_RUN || Span.type === SpanType.WORKFLOW_RUN) {
|
|
341
350
|
return SpanKind.SERVER;
|
|
342
351
|
}
|
|
343
352
|
}
|
|
344
|
-
return SPAN_KIND_MAPPING[
|
|
353
|
+
return SPAN_KIND_MAPPING[Span.type] || SpanKind.INTERNAL;
|
|
345
354
|
}
|
|
346
355
|
/**
|
|
347
356
|
* Build OTEL-compliant span name based on span type and attributes
|
|
348
357
|
*/
|
|
349
|
-
buildSpanName(
|
|
350
|
-
switch (
|
|
351
|
-
case
|
|
352
|
-
const attrs =
|
|
358
|
+
buildSpanName(Span) {
|
|
359
|
+
switch (Span.type) {
|
|
360
|
+
case SpanType.MODEL_GENERATION: {
|
|
361
|
+
const attrs = Span.attributes;
|
|
353
362
|
const operation = attrs?.resultType === "tool_selection" ? "tool_selection" : "chat";
|
|
354
363
|
const model = attrs?.model || "unknown";
|
|
355
364
|
return `${operation} ${model}`;
|
|
356
365
|
}
|
|
357
|
-
case
|
|
358
|
-
case
|
|
359
|
-
const toolAttrs =
|
|
366
|
+
case SpanType.TOOL_CALL:
|
|
367
|
+
case SpanType.MCP_TOOL_CALL: {
|
|
368
|
+
const toolAttrs = Span.attributes;
|
|
360
369
|
const toolName = toolAttrs?.toolId || "unknown";
|
|
361
370
|
return `tool.execute ${toolName}`;
|
|
362
371
|
}
|
|
363
|
-
case
|
|
364
|
-
const agentAttrs =
|
|
372
|
+
case SpanType.AGENT_RUN: {
|
|
373
|
+
const agentAttrs = Span.attributes;
|
|
365
374
|
const agentId = agentAttrs?.agentId || "unknown";
|
|
366
375
|
return `agent.${agentId}`;
|
|
367
376
|
}
|
|
368
|
-
case
|
|
369
|
-
const workflowAttrs =
|
|
377
|
+
case SpanType.WORKFLOW_RUN: {
|
|
378
|
+
const workflowAttrs = Span.attributes;
|
|
370
379
|
const workflowId = workflowAttrs?.workflowId || "unknown";
|
|
371
380
|
return `workflow.${workflowId}`;
|
|
372
381
|
}
|
|
373
|
-
case
|
|
374
|
-
return
|
|
382
|
+
case SpanType.WORKFLOW_STEP:
|
|
383
|
+
return Span.name;
|
|
375
384
|
default:
|
|
376
|
-
return
|
|
385
|
+
return Span.name;
|
|
377
386
|
}
|
|
378
387
|
}
|
|
379
388
|
/**
|
|
380
|
-
* Build OpenTelemetry attributes from Mastra
|
|
389
|
+
* Build OpenTelemetry attributes from Mastra Span
|
|
381
390
|
* Following OTEL Semantic Conventions for GenAI
|
|
382
391
|
*/
|
|
383
|
-
buildAttributes(
|
|
392
|
+
buildAttributes(Span) {
|
|
384
393
|
const attributes = {};
|
|
385
|
-
attributes["gen_ai.operation.name"] = this.getOperationName(
|
|
386
|
-
attributes["span.kind"] = this.getSpanKindString(
|
|
387
|
-
attributes["mastra.span.type"] =
|
|
388
|
-
attributes["mastra.trace_id"] =
|
|
389
|
-
attributes["mastra.span_id"] =
|
|
390
|
-
if (
|
|
391
|
-
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;
|
|
392
401
|
}
|
|
393
|
-
if (
|
|
394
|
-
const inputStr = typeof
|
|
402
|
+
if (Span.input !== void 0) {
|
|
403
|
+
const inputStr = typeof Span.input === "string" ? Span.input : JSON.stringify(Span.input);
|
|
395
404
|
attributes["input"] = inputStr;
|
|
396
|
-
if (
|
|
405
|
+
if (Span.type === SpanType.MODEL_GENERATION) {
|
|
397
406
|
attributes["gen_ai.prompt"] = inputStr;
|
|
398
|
-
} else if (
|
|
407
|
+
} else if (Span.type === SpanType.TOOL_CALL || Span.type === SpanType.MCP_TOOL_CALL) {
|
|
399
408
|
attributes["gen_ai.tool.input"] = inputStr;
|
|
400
409
|
}
|
|
401
410
|
}
|
|
402
|
-
if (
|
|
403
|
-
const outputStr = typeof
|
|
411
|
+
if (Span.output !== void 0) {
|
|
412
|
+
const outputStr = typeof Span.output === "string" ? Span.output : JSON.stringify(Span.output);
|
|
404
413
|
attributes["output"] = outputStr;
|
|
405
|
-
if (
|
|
414
|
+
if (Span.type === SpanType.MODEL_GENERATION) {
|
|
406
415
|
attributes["gen_ai.completion"] = outputStr;
|
|
407
|
-
} else if (
|
|
416
|
+
} else if (Span.type === SpanType.TOOL_CALL || Span.type === SpanType.MCP_TOOL_CALL) {
|
|
408
417
|
attributes["gen_ai.tool.output"] = outputStr;
|
|
409
418
|
}
|
|
410
419
|
}
|
|
411
|
-
if (
|
|
412
|
-
const
|
|
413
|
-
if (
|
|
414
|
-
attributes["gen_ai.request.model"] =
|
|
420
|
+
if (Span.type === SpanType.MODEL_GENERATION && Span.attributes) {
|
|
421
|
+
const modelAttrs = Span.attributes;
|
|
422
|
+
if (modelAttrs.model) {
|
|
423
|
+
attributes["gen_ai.request.model"] = modelAttrs.model;
|
|
415
424
|
}
|
|
416
|
-
if (
|
|
417
|
-
attributes["gen_ai.system"] =
|
|
425
|
+
if (modelAttrs.provider) {
|
|
426
|
+
attributes["gen_ai.system"] = modelAttrs.provider;
|
|
418
427
|
}
|
|
419
|
-
if (
|
|
420
|
-
const inputTokens =
|
|
421
|
-
const outputTokens =
|
|
428
|
+
if (modelAttrs.usage) {
|
|
429
|
+
const inputTokens = modelAttrs.usage.inputTokens ?? modelAttrs.usage.promptTokens;
|
|
430
|
+
const outputTokens = modelAttrs.usage.outputTokens ?? modelAttrs.usage.completionTokens;
|
|
422
431
|
if (inputTokens !== void 0) {
|
|
423
432
|
attributes["gen_ai.usage.input_tokens"] = inputTokens;
|
|
424
433
|
}
|
|
425
434
|
if (outputTokens !== void 0) {
|
|
426
435
|
attributes["gen_ai.usage.output_tokens"] = outputTokens;
|
|
427
436
|
}
|
|
428
|
-
if (
|
|
429
|
-
attributes["gen_ai.usage.total_tokens"] =
|
|
437
|
+
if (modelAttrs.usage.totalTokens !== void 0) {
|
|
438
|
+
attributes["gen_ai.usage.total_tokens"] = modelAttrs.usage.totalTokens;
|
|
430
439
|
}
|
|
431
|
-
if (
|
|
432
|
-
attributes["gen_ai.usage.reasoning_tokens"] =
|
|
440
|
+
if (modelAttrs.usage.reasoningTokens !== void 0) {
|
|
441
|
+
attributes["gen_ai.usage.reasoning_tokens"] = modelAttrs.usage.reasoningTokens;
|
|
433
442
|
}
|
|
434
|
-
if (
|
|
435
|
-
attributes["gen_ai.usage.cached_input_tokens"] =
|
|
443
|
+
if (modelAttrs.usage.cachedInputTokens !== void 0) {
|
|
444
|
+
attributes["gen_ai.usage.cached_input_tokens"] = modelAttrs.usage.cachedInputTokens;
|
|
436
445
|
}
|
|
437
446
|
}
|
|
438
|
-
if (
|
|
439
|
-
if (
|
|
440
|
-
attributes["gen_ai.request.temperature"] =
|
|
447
|
+
if (modelAttrs.parameters) {
|
|
448
|
+
if (modelAttrs.parameters.temperature !== void 0) {
|
|
449
|
+
attributes["gen_ai.request.temperature"] = modelAttrs.parameters.temperature;
|
|
441
450
|
}
|
|
442
|
-
if (
|
|
443
|
-
attributes["gen_ai.request.max_tokens"] =
|
|
451
|
+
if (modelAttrs.parameters.maxOutputTokens !== void 0) {
|
|
452
|
+
attributes["gen_ai.request.max_tokens"] = modelAttrs.parameters.maxOutputTokens;
|
|
444
453
|
}
|
|
445
|
-
if (
|
|
446
|
-
attributes["gen_ai.request.top_p"] =
|
|
454
|
+
if (modelAttrs.parameters.topP !== void 0) {
|
|
455
|
+
attributes["gen_ai.request.top_p"] = modelAttrs.parameters.topP;
|
|
447
456
|
}
|
|
448
|
-
if (
|
|
449
|
-
attributes["gen_ai.request.top_k"] =
|
|
457
|
+
if (modelAttrs.parameters.topK !== void 0) {
|
|
458
|
+
attributes["gen_ai.request.top_k"] = modelAttrs.parameters.topK;
|
|
450
459
|
}
|
|
451
|
-
if (
|
|
452
|
-
attributes["gen_ai.request.presence_penalty"] =
|
|
460
|
+
if (modelAttrs.parameters.presencePenalty !== void 0) {
|
|
461
|
+
attributes["gen_ai.request.presence_penalty"] = modelAttrs.parameters.presencePenalty;
|
|
453
462
|
}
|
|
454
|
-
if (
|
|
455
|
-
attributes["gen_ai.request.frequency_penalty"] =
|
|
463
|
+
if (modelAttrs.parameters.frequencyPenalty !== void 0) {
|
|
464
|
+
attributes["gen_ai.request.frequency_penalty"] = modelAttrs.parameters.frequencyPenalty;
|
|
456
465
|
}
|
|
457
|
-
if (
|
|
458
|
-
attributes["gen_ai.request.stop_sequences"] = JSON.stringify(
|
|
466
|
+
if (modelAttrs.parameters.stopSequences) {
|
|
467
|
+
attributes["gen_ai.request.stop_sequences"] = JSON.stringify(modelAttrs.parameters.stopSequences);
|
|
459
468
|
}
|
|
460
469
|
}
|
|
461
|
-
if (
|
|
462
|
-
attributes["gen_ai.response.finish_reasons"] =
|
|
470
|
+
if (modelAttrs.finishReason) {
|
|
471
|
+
attributes["gen_ai.response.finish_reasons"] = modelAttrs.finishReason;
|
|
463
472
|
}
|
|
464
473
|
}
|
|
465
|
-
if ((
|
|
466
|
-
const toolAttrs =
|
|
474
|
+
if ((Span.type === SpanType.TOOL_CALL || Span.type === SpanType.MCP_TOOL_CALL) && Span.attributes) {
|
|
475
|
+
const toolAttrs = Span.attributes;
|
|
467
476
|
if (toolAttrs.toolId) {
|
|
468
477
|
attributes["gen_ai.tool.name"] = toolAttrs.toolId;
|
|
469
478
|
}
|
|
470
|
-
if (
|
|
479
|
+
if (Span.type === SpanType.MCP_TOOL_CALL) {
|
|
471
480
|
const mcpAttrs = toolAttrs;
|
|
472
481
|
if (mcpAttrs.mcpServer) {
|
|
473
482
|
attributes["mcp.server"] = mcpAttrs.mcpServer;
|
|
@@ -484,10 +493,11 @@ var SpanConverter = class {
|
|
|
484
493
|
attributes["gen_ai.tool.success"] = toolAttrs.success;
|
|
485
494
|
}
|
|
486
495
|
}
|
|
487
|
-
if (
|
|
488
|
-
const agentAttrs =
|
|
496
|
+
if (Span.type === SpanType.AGENT_RUN && Span.attributes) {
|
|
497
|
+
const agentAttrs = Span.attributes;
|
|
489
498
|
if (agentAttrs.agentId) {
|
|
490
499
|
attributes["agent.id"] = agentAttrs.agentId;
|
|
500
|
+
attributes["gen_ai.agent.id"] = agentAttrs.agentId;
|
|
491
501
|
}
|
|
492
502
|
if (agentAttrs.maxSteps) {
|
|
493
503
|
attributes["agent.max_steps"] = agentAttrs.maxSteps;
|
|
@@ -496,8 +506,8 @@ var SpanConverter = class {
|
|
|
496
506
|
attributes["agent.available_tools"] = JSON.stringify(agentAttrs.availableTools);
|
|
497
507
|
}
|
|
498
508
|
}
|
|
499
|
-
if (
|
|
500
|
-
const workflowAttrs =
|
|
509
|
+
if (Span.type === SpanType.WORKFLOW_RUN && Span.attributes) {
|
|
510
|
+
const workflowAttrs = Span.attributes;
|
|
501
511
|
if (workflowAttrs.workflowId) {
|
|
502
512
|
attributes["workflow.id"] = workflowAttrs.workflowId;
|
|
503
513
|
}
|
|
@@ -505,19 +515,19 @@ var SpanConverter = class {
|
|
|
505
515
|
attributes["workflow.status"] = workflowAttrs.status;
|
|
506
516
|
}
|
|
507
517
|
}
|
|
508
|
-
if (
|
|
518
|
+
if (Span.errorInfo) {
|
|
509
519
|
attributes["error"] = true;
|
|
510
|
-
attributes["error.type"] =
|
|
511
|
-
attributes["error.message"] =
|
|
512
|
-
if (
|
|
513
|
-
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;
|
|
514
524
|
}
|
|
515
|
-
if (
|
|
516
|
-
attributes["error.category"] =
|
|
525
|
+
if (Span.errorInfo.category) {
|
|
526
|
+
attributes["error.category"] = Span.errorInfo.category;
|
|
517
527
|
}
|
|
518
528
|
}
|
|
519
|
-
if (
|
|
520
|
-
Object.entries(
|
|
529
|
+
if (Span.metadata) {
|
|
530
|
+
Object.entries(Span.metadata).forEach(([key, value]) => {
|
|
521
531
|
if (!attributes[key]) {
|
|
522
532
|
if (value === null || value === void 0) {
|
|
523
533
|
return;
|
|
@@ -530,12 +540,12 @@ var SpanConverter = class {
|
|
|
530
540
|
}
|
|
531
541
|
});
|
|
532
542
|
}
|
|
533
|
-
if (
|
|
534
|
-
attributes["mastra.start_time"] =
|
|
543
|
+
if (Span.startTime) {
|
|
544
|
+
attributes["mastra.start_time"] = Span.startTime.toISOString();
|
|
535
545
|
}
|
|
536
|
-
if (
|
|
537
|
-
attributes["mastra.end_time"] =
|
|
538
|
-
const duration =
|
|
546
|
+
if (Span.endTime) {
|
|
547
|
+
attributes["mastra.end_time"] = Span.endTime.toISOString();
|
|
548
|
+
const duration = Span.endTime.getTime() - Span.startTime.getTime();
|
|
539
549
|
attributes["mastra.duration_ms"] = duration;
|
|
540
550
|
}
|
|
541
551
|
return attributes;
|
|
@@ -543,28 +553,28 @@ var SpanConverter = class {
|
|
|
543
553
|
/**
|
|
544
554
|
* Get the operation name based on span type for gen_ai.operation.name
|
|
545
555
|
*/
|
|
546
|
-
getOperationName(
|
|
547
|
-
switch (
|
|
548
|
-
case
|
|
549
|
-
const attrs =
|
|
556
|
+
getOperationName(Span) {
|
|
557
|
+
switch (Span.type) {
|
|
558
|
+
case SpanType.MODEL_GENERATION: {
|
|
559
|
+
const attrs = Span.attributes;
|
|
550
560
|
return attrs?.resultType === "tool_selection" ? "tool_selection" : "chat";
|
|
551
561
|
}
|
|
552
|
-
case
|
|
553
|
-
case
|
|
562
|
+
case SpanType.TOOL_CALL:
|
|
563
|
+
case SpanType.MCP_TOOL_CALL:
|
|
554
564
|
return "tool.execute";
|
|
555
|
-
case
|
|
565
|
+
case SpanType.AGENT_RUN:
|
|
556
566
|
return "agent.run";
|
|
557
|
-
case
|
|
567
|
+
case SpanType.WORKFLOW_RUN:
|
|
558
568
|
return "workflow.run";
|
|
559
569
|
default:
|
|
560
|
-
return
|
|
570
|
+
return Span.type.replace(/_/g, ".");
|
|
561
571
|
}
|
|
562
572
|
}
|
|
563
573
|
/**
|
|
564
574
|
* Get span kind as string for attribute
|
|
565
575
|
*/
|
|
566
|
-
getSpanKindString(
|
|
567
|
-
const kind = this.getSpanKind(
|
|
576
|
+
getSpanKindString(Span) {
|
|
577
|
+
const kind = this.getSpanKind(Span);
|
|
568
578
|
switch (kind) {
|
|
569
579
|
case SpanKind.SERVER:
|
|
570
580
|
return "server";
|
|
@@ -582,21 +592,19 @@ var SpanConverter = class {
|
|
|
582
592
|
}
|
|
583
593
|
};
|
|
584
594
|
|
|
585
|
-
// src/
|
|
586
|
-
var OtelExporter = class {
|
|
595
|
+
// src/tracing.ts
|
|
596
|
+
var OtelExporter = class extends BaseExporter {
|
|
587
597
|
config;
|
|
588
598
|
tracingConfig;
|
|
589
599
|
spanConverter;
|
|
590
600
|
processor;
|
|
591
601
|
exporter;
|
|
592
602
|
isSetup = false;
|
|
593
|
-
isDisabled = false;
|
|
594
|
-
logger;
|
|
595
603
|
name = "opentelemetry";
|
|
596
604
|
constructor(config) {
|
|
605
|
+
super(config);
|
|
597
606
|
this.config = config;
|
|
598
607
|
this.spanConverter = new SpanConverter();
|
|
599
|
-
this.logger = new ConsoleLogger({ level: config.logLevel ?? "warn" });
|
|
600
608
|
if (config.logLevel === "debug") {
|
|
601
609
|
diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.DEBUG);
|
|
602
610
|
}
|
|
@@ -604,11 +612,11 @@ var OtelExporter = class {
|
|
|
604
612
|
/**
|
|
605
613
|
* Initialize with tracing configuration
|
|
606
614
|
*/
|
|
607
|
-
init(
|
|
608
|
-
this.tracingConfig = config;
|
|
615
|
+
init(options) {
|
|
616
|
+
this.tracingConfig = options.config;
|
|
609
617
|
}
|
|
610
618
|
async setupExporter() {
|
|
611
|
-
if (this.isSetup) return;
|
|
619
|
+
if (this.isSetup || this.exporter) return;
|
|
612
620
|
if (!this.config.provider) {
|
|
613
621
|
this.logger.error(
|
|
614
622
|
'[OtelExporter] Provider configuration is required. Use the "custom" provider for generic endpoints.'
|
|
@@ -623,6 +631,10 @@ var OtelExporter = class {
|
|
|
623
631
|
this.isSetup = true;
|
|
624
632
|
return;
|
|
625
633
|
}
|
|
634
|
+
if (this.config.exporter) {
|
|
635
|
+
this.exporter = this.config.exporter;
|
|
636
|
+
return;
|
|
637
|
+
}
|
|
626
638
|
const endpoint = resolved.endpoint;
|
|
627
639
|
const headers = resolved.headers;
|
|
628
640
|
const protocol = resolved.protocol;
|
|
@@ -676,6 +688,9 @@ var OtelExporter = class {
|
|
|
676
688
|
this.isSetup = true;
|
|
677
689
|
return;
|
|
678
690
|
}
|
|
691
|
+
}
|
|
692
|
+
async setupProcessor() {
|
|
693
|
+
if (this.processor || this.isSetup) return;
|
|
679
694
|
let resource = resourceFromAttributes({
|
|
680
695
|
[ATTR_SERVICE_NAME]: this.tracingConfig?.serviceName || "mastra-service",
|
|
681
696
|
[ATTR_SERVICE_VERSION]: "1.0.0",
|
|
@@ -704,13 +719,15 @@ var OtelExporter = class {
|
|
|
704
719
|
this.logger.debug(
|
|
705
720
|
`[OtelExporter] Using BatchSpanProcessor (batch size: ${this.config.batchSize || 512}, delay: 5s)`
|
|
706
721
|
);
|
|
722
|
+
}
|
|
723
|
+
async setup() {
|
|
724
|
+
if (this.isSetup) return;
|
|
725
|
+
await this.setupExporter();
|
|
726
|
+
await this.setupProcessor();
|
|
707
727
|
this.isSetup = true;
|
|
708
728
|
}
|
|
709
|
-
async
|
|
710
|
-
if (
|
|
711
|
-
return;
|
|
712
|
-
}
|
|
713
|
-
if (event.type !== AITracingEventType.SPAN_ENDED) {
|
|
729
|
+
async _exportTracingEvent(event) {
|
|
730
|
+
if (event.type !== TracingEventType.SPAN_ENDED) {
|
|
714
731
|
return;
|
|
715
732
|
}
|
|
716
733
|
const span = event.exportedSpan;
|
|
@@ -718,7 +735,7 @@ var OtelExporter = class {
|
|
|
718
735
|
}
|
|
719
736
|
async exportSpan(span) {
|
|
720
737
|
if (!this.isSetup) {
|
|
721
|
-
await this.
|
|
738
|
+
await this.setup();
|
|
722
739
|
}
|
|
723
740
|
if (this.isDisabled || !this.processor) {
|
|
724
741
|
return;
|