@mastra/observability 1.6.0-alpha.1 → 1.6.0-alpha.3

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.cjs CHANGED
@@ -22,6 +22,47 @@ var __export = (target, all) => {
22
22
  for (var name in all)
23
23
  __defProp(target, name, { get: all[name], enumerable: true });
24
24
  };
25
+ function routeToHandler(handler, event, logger) {
26
+ try {
27
+ switch (event.type) {
28
+ case observability.TracingEventType.SPAN_STARTED:
29
+ case observability.TracingEventType.SPAN_UPDATED:
30
+ case observability.TracingEventType.SPAN_ENDED: {
31
+ const fn = handler.onTracingEvent ? handler.onTracingEvent.bind(handler) : handler.exportTracingEvent.bind(handler);
32
+ return catchAsyncResult(fn(event), handler.name, "tracing", logger);
33
+ }
34
+ case "log":
35
+ if (handler.onLogEvent) {
36
+ return catchAsyncResult(handler.onLogEvent(event), handler.name, "log", logger);
37
+ }
38
+ break;
39
+ case "metric":
40
+ if (handler.onMetricEvent) {
41
+ return catchAsyncResult(handler.onMetricEvent(event), handler.name, "metric", logger);
42
+ }
43
+ break;
44
+ case "score":
45
+ if (handler.onScoreEvent) {
46
+ return catchAsyncResult(handler.onScoreEvent(event), handler.name, "score", logger);
47
+ }
48
+ break;
49
+ case "feedback":
50
+ if (handler.onFeedbackEvent) {
51
+ return catchAsyncResult(handler.onFeedbackEvent(event), handler.name, "feedback", logger);
52
+ }
53
+ break;
54
+ }
55
+ } catch (err) {
56
+ logger.error(`[Observability] Handler error [handler=${handler.name}]:`, err);
57
+ }
58
+ }
59
+ function catchAsyncResult(result, handlerName, signal, logger) {
60
+ if (result && typeof result.then === "function") {
61
+ return result.catch((err) => {
62
+ logger.error(`[Observability] ${signal} handler error [handler=${handlerName}]:`, err);
63
+ });
64
+ }
65
+ }
25
66
 
26
67
  // ../../node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/classic/external.js
27
68
  var external_exports = {};
@@ -15901,7 +15942,7 @@ var TestExporter = class extends BaseExporter {
15901
15942
  this.#trackEvent("log");
15902
15943
  if (this.#config.storeLogs) {
15903
15944
  const log = event.log;
15904
- const traceId = log.correlationContext?.traceId;
15945
+ const traceId = log.traceId;
15905
15946
  const logMessage = `[TestExporter] log.${log.level}: "${log.message}"${traceId ? ` (trace: ${traceId.slice(-8)})` : ""}`;
15906
15947
  this.#debugLogs.push(logMessage);
15907
15948
  }
@@ -16019,7 +16060,7 @@ var TestExporter = class extends BaseExporter {
16019
16060
  getByTraceId(traceId) {
16020
16061
  const events = this.#tracingEvents.filter((e) => e.exportedSpan.traceId === traceId);
16021
16062
  const spans = this.#getUniqueSpansFromEvents(events);
16022
- const logs = this.#logEvents.filter((e) => e.log.correlationContext?.traceId === traceId).map((e) => e.log);
16063
+ const logs = this.#logEvents.filter((e) => e.log.traceId === traceId).map((e) => e.log);
16023
16064
  const scores = this.#scoreEvents.filter((e) => e.score.traceId === traceId).map((e) => e.score);
16024
16065
  const feedback = this.#feedbackEvents.filter((e) => e.feedback.traceId === traceId).map((e) => e.feedback);
16025
16066
  return { events, spans, logs, scores, feedback };
@@ -16086,7 +16127,7 @@ var TestExporter = class extends BaseExporter {
16086
16127
  traceIds.add(event.exportedSpan.traceId);
16087
16128
  }
16088
16129
  for (const event of this.#logEvents) {
16089
- if (event.log.correlationContext?.traceId) traceIds.add(event.log.correlationContext.traceId);
16130
+ if (event.log.traceId) traceIds.add(event.log.traceId);
16090
16131
  }
16091
16132
  for (const event of this.#scoreEvents) {
16092
16133
  traceIds.add(event.score.traceId);
@@ -16121,7 +16162,7 @@ var TestExporter = class extends BaseExporter {
16121
16162
  * Get logs for a specific trace
16122
16163
  */
16123
16164
  getLogsByTraceId(traceId) {
16124
- return this.#logEvents.filter((e) => e.log.correlationContext?.traceId === traceId).map((e) => e.log);
16165
+ return this.#logEvents.filter((e) => e.log.traceId === traceId).map((e) => e.log);
16125
16166
  }
16126
16167
  // ============================================================================
16127
16168
  // Metric Query Methods
@@ -16995,47 +17036,6 @@ var BaseObservabilityEventBus = class _BaseObservabilityEventBus extends base.Ma
16995
17036
  this.subscribers.clear();
16996
17037
  }
16997
17038
  };
16998
- function routeToHandler(handler, event, logger) {
16999
- try {
17000
- switch (event.type) {
17001
- case observability.TracingEventType.SPAN_STARTED:
17002
- case observability.TracingEventType.SPAN_UPDATED:
17003
- case observability.TracingEventType.SPAN_ENDED: {
17004
- const fn = handler.onTracingEvent ? handler.onTracingEvent.bind(handler) : handler.exportTracingEvent.bind(handler);
17005
- return catchAsyncResult(fn(event), handler.name, "tracing", logger);
17006
- }
17007
- case "log":
17008
- if (handler.onLogEvent) {
17009
- return catchAsyncResult(handler.onLogEvent(event), handler.name, "log", logger);
17010
- }
17011
- break;
17012
- case "metric":
17013
- if (handler.onMetricEvent) {
17014
- return catchAsyncResult(handler.onMetricEvent(event), handler.name, "metric", logger);
17015
- }
17016
- break;
17017
- case "score":
17018
- if (handler.onScoreEvent) {
17019
- return catchAsyncResult(handler.onScoreEvent(event), handler.name, "score", logger);
17020
- }
17021
- break;
17022
- case "feedback":
17023
- if (handler.onFeedbackEvent) {
17024
- return catchAsyncResult(handler.onFeedbackEvent(event), handler.name, "feedback", logger);
17025
- }
17026
- break;
17027
- }
17028
- } catch (err) {
17029
- logger.error(`[Observability] Handler error [handler=${handler.name}]:`, err);
17030
- }
17031
- }
17032
- function catchAsyncResult(result, handlerName, signal, logger) {
17033
- if (result && typeof result.then === "function") {
17034
- return result.catch((err) => {
17035
- logger.error(`[Observability] ${signal} handler error [handler=${handlerName}]:`, err);
17036
- });
17037
- }
17038
- }
17039
17039
 
17040
17040
  // src/bus/observability-bus.ts
17041
17041
  var MAX_FLUSH_ITERATIONS = 3;
@@ -17195,9 +17195,12 @@ var LoggerContextImpl = class {
17195
17195
  * mutations after construction do not affect emitted logs.
17196
17196
  */
17197
17197
  constructor(config2) {
17198
+ const correlationContext = config2.correlationContext ? { ...config2.correlationContext } : void 0;
17198
17199
  this.config = {
17199
17200
  ...config2,
17200
- correlationContext: config2.correlationContext ? { ...config2.correlationContext } : void 0,
17201
+ traceId: config2.traceId ?? correlationContext?.traceId,
17202
+ spanId: config2.spanId ?? correlationContext?.spanId,
17203
+ correlationContext,
17201
17204
  metadata: config2.metadata ? structuredClone(config2.metadata) : void 0
17202
17205
  };
17203
17206
  }
@@ -17234,6 +17237,8 @@ var LoggerContextImpl = class {
17234
17237
  level,
17235
17238
  message,
17236
17239
  data,
17240
+ traceId: this.config.traceId,
17241
+ spanId: this.config.spanId,
17237
17242
  correlationContext: this.config.correlationContext,
17238
17243
  metadata: this.config.metadata
17239
17244
  };
@@ -17244,6 +17249,8 @@ var LoggerContextImpl = class {
17244
17249
 
17245
17250
  // src/context/metrics.ts
17246
17251
  var MetricsContextImpl = class {
17252
+ traceId;
17253
+ spanId;
17247
17254
  correlationContext;
17248
17255
  metadata;
17249
17256
  cardinalityFilter;
@@ -17254,6 +17261,8 @@ var MetricsContextImpl = class {
17254
17261
  */
17255
17262
  constructor(config2) {
17256
17263
  this.correlationContext = config2.correlationContext ? { ...config2.correlationContext } : void 0;
17264
+ this.traceId = config2.traceId ?? this.correlationContext?.traceId;
17265
+ this.spanId = config2.spanId ?? this.correlationContext?.spanId;
17257
17266
  this.metadata = config2.metadata ? structuredClone(config2.metadata) : void 0;
17258
17267
  this.cardinalityFilter = config2.cardinalityFilter;
17259
17268
  this.observabilityBus = config2.observabilityBus;
@@ -17267,6 +17276,8 @@ var MetricsContextImpl = class {
17267
17276
  const costContext = options?.costContext ? cloneCostContext(options.costContext) : void 0;
17268
17277
  const exportedMetric = {
17269
17278
  timestamp: /* @__PURE__ */ new Date(),
17279
+ traceId: this.traceId,
17280
+ spanId: this.spanId,
17270
17281
  name,
17271
17282
  value,
17272
17283
  labels: filteredLabels,
@@ -18903,6 +18914,9 @@ var DefaultSpan = class extends BaseSpan {
18903
18914
  if (this.isEvent) {
18904
18915
  return;
18905
18916
  }
18917
+ if (options.name !== void 0) {
18918
+ this.name = options.name;
18919
+ }
18906
18920
  if (options.input !== void 0) {
18907
18921
  this.input = deepClean(options.input, this.deepCleanOptions);
18908
18922
  }
@@ -19198,6 +19212,8 @@ var BaseObservabilityInstance = class extends base.MastraBase {
19198
19212
  const correlationContext = span?.getCorrelationContext?.();
19199
19213
  const metadata = span?.metadata ? structuredClone(span.metadata) : void 0;
19200
19214
  return new LoggerContextImpl({
19215
+ traceId: span?.traceId,
19216
+ spanId: span?.id,
19201
19217
  correlationContext,
19202
19218
  metadata,
19203
19219
  observabilityBus: this.observabilityBus
@@ -19212,6 +19228,8 @@ var BaseObservabilityInstance = class extends base.MastraBase {
19212
19228
  const correlationContext = span?.getCorrelationContext?.();
19213
19229
  const metadata = span?.metadata ? structuredClone(span.metadata) : void 0;
19214
19230
  return new MetricsContextImpl({
19231
+ traceId: span?.traceId,
19232
+ spanId: span?.id,
19215
19233
  correlationContext,
19216
19234
  metadata,
19217
19235
  cardinalityFilter: this.cardinalityFilter,
@@ -19226,6 +19244,13 @@ var BaseObservabilityInstance = class extends base.MastraBase {
19226
19244
  emitObservabilityEvent(event) {
19227
19245
  this.observabilityBus.emit(event);
19228
19246
  }
19247
+ /**
19248
+ * Internal hook used by RecordedTrace/RecordedSpan hydration to route
19249
+ * non-tracing annotation events back through the normal exporter pipeline.
19250
+ */
19251
+ __emitRecordedEvent(event) {
19252
+ this.emitObservabilityEvent(event);
19253
+ }
19229
19254
  // ============================================================================
19230
19255
  // Span Lifecycle Management
19231
19256
  // ============================================================================
@@ -19500,6 +19525,311 @@ var DefaultObservabilityInstance = class extends BaseObservabilityInstance {
19500
19525
  }
19501
19526
  };
19502
19527
 
19528
+ // src/recorded.ts
19529
+ function nullToUndefined(value) {
19530
+ return value ?? void 0;
19531
+ }
19532
+ function mergeMetadata(base, extra) {
19533
+ if (!base && !extra) return void 0;
19534
+ return {
19535
+ ...base ?? {},
19536
+ ...extra ?? {}
19537
+ };
19538
+ }
19539
+ function normalizeErrorInfo(error48) {
19540
+ if (!error48 || typeof error48 !== "object" || !("message" in error48) || typeof error48.message !== "string") {
19541
+ return void 0;
19542
+ }
19543
+ return {
19544
+ message: error48.message,
19545
+ id: "id" in error48 && typeof error48.id === "string" ? error48.id : void 0,
19546
+ domain: "domain" in error48 && typeof error48.domain === "string" ? error48.domain : void 0,
19547
+ category: "category" in error48 && typeof error48.category === "string" ? error48.category : void 0,
19548
+ details: "details" in error48 && error48.details && typeof error48.details === "object" ? error48.details : void 0
19549
+ };
19550
+ }
19551
+ function buildCorrelationContext(span, rootSpan, parent) {
19552
+ return {
19553
+ tags: rootSpan.tags ?? void 0,
19554
+ entityType: nullToUndefined(span.entityType),
19555
+ entityId: nullToUndefined(span.entityId),
19556
+ entityName: nullToUndefined(span.entityName),
19557
+ parentEntityType: parent?.entityType ?? void 0,
19558
+ parentEntityId: parent?.entityId ?? void 0,
19559
+ parentEntityName: parent?.entityName ?? void 0,
19560
+ rootEntityType: nullToUndefined(rootSpan.entityType),
19561
+ rootEntityId: nullToUndefined(rootSpan.entityId),
19562
+ rootEntityName: nullToUndefined(rootSpan.entityName),
19563
+ userId: nullToUndefined(span.userId),
19564
+ organizationId: nullToUndefined(span.organizationId),
19565
+ resourceId: nullToUndefined(span.resourceId),
19566
+ runId: nullToUndefined(span.runId),
19567
+ sessionId: nullToUndefined(span.sessionId),
19568
+ threadId: nullToUndefined(span.threadId),
19569
+ requestId: nullToUndefined(span.requestId),
19570
+ environment: nullToUndefined(span.environment),
19571
+ source: nullToUndefined(span.source),
19572
+ serviceName: nullToUndefined(span.serviceName),
19573
+ experimentId: nullToUndefined(span.experimentId)
19574
+ };
19575
+ }
19576
+ function buildRecordedScoreEvent(args) {
19577
+ const { span, rootSpan, parent, score, spanId } = args;
19578
+ return {
19579
+ type: "score",
19580
+ score: {
19581
+ timestamp: /* @__PURE__ */ new Date(),
19582
+ traceId: span.traceId,
19583
+ spanId,
19584
+ scorerId: score.scorerId,
19585
+ scorerVersion: score.scorerVersion,
19586
+ source: score.source,
19587
+ scoreSource: score.scoreSource,
19588
+ score: score.score,
19589
+ reason: score.reason,
19590
+ experimentId: score.experimentId,
19591
+ scoreTraceId: score.scoreTraceId,
19592
+ correlationContext: buildCorrelationContext(span, rootSpan, parent),
19593
+ metadata: mergeMetadata(span.metadata, score.metadata)
19594
+ }
19595
+ };
19596
+ }
19597
+ function buildRecordedFeedbackEvent(args) {
19598
+ const { span, rootSpan, parent, feedback, spanId } = args;
19599
+ return {
19600
+ type: "feedback",
19601
+ feedback: {
19602
+ timestamp: /* @__PURE__ */ new Date(),
19603
+ traceId: span.traceId,
19604
+ spanId,
19605
+ source: feedback.source,
19606
+ feedbackSource: feedback.feedbackSource,
19607
+ feedbackType: feedback.feedbackType,
19608
+ value: feedback.value,
19609
+ userId: feedback.userId,
19610
+ feedbackUserId: feedback.feedbackUserId,
19611
+ comment: feedback.comment,
19612
+ sourceId: feedback.sourceId,
19613
+ experimentId: feedback.experimentId,
19614
+ correlationContext: buildCorrelationContext(span, rootSpan, parent),
19615
+ metadata: mergeMetadata(span.metadata, feedback.metadata)
19616
+ }
19617
+ };
19618
+ }
19619
+ function findSpanById(spans, spanId) {
19620
+ if (!spanId) return void 0;
19621
+ return spans.find((span) => span.spanId === spanId);
19622
+ }
19623
+ function buildRecordedScoreEventFromTrace(args) {
19624
+ const rootSpan = findRootSpan(args.trace.spans);
19625
+ if (!rootSpan) return null;
19626
+ const span = args.spanId ? findSpanById(args.trace.spans, args.spanId) : rootSpan;
19627
+ if (!span) return null;
19628
+ const parent = span.parentSpanId ? findSpanById(args.trace.spans, span.parentSpanId) : void 0;
19629
+ return buildRecordedScoreEvent({
19630
+ span,
19631
+ rootSpan,
19632
+ parent,
19633
+ score: args.score,
19634
+ spanId: args.spanId
19635
+ });
19636
+ }
19637
+ function buildRecordedFeedbackEventFromTrace(args) {
19638
+ const rootSpan = findRootSpan(args.trace.spans);
19639
+ if (!rootSpan) return null;
19640
+ const span = args.spanId ? findSpanById(args.trace.spans, args.spanId) : rootSpan;
19641
+ if (!span) return null;
19642
+ const parent = span.parentSpanId ? findSpanById(args.trace.spans, span.parentSpanId) : void 0;
19643
+ return buildRecordedFeedbackEvent({
19644
+ span,
19645
+ rootSpan,
19646
+ parent,
19647
+ feedback: args.feedback,
19648
+ spanId: args.spanId
19649
+ });
19650
+ }
19651
+ var RecordedSpanImpl = class {
19652
+ id;
19653
+ traceId;
19654
+ name;
19655
+ type;
19656
+ entityType;
19657
+ entityId;
19658
+ entityName;
19659
+ startTime;
19660
+ endTime;
19661
+ attributes;
19662
+ metadata;
19663
+ tags;
19664
+ input;
19665
+ output;
19666
+ errorInfo;
19667
+ requestContext;
19668
+ isEvent;
19669
+ isRootSpan;
19670
+ parentSpanId;
19671
+ parent;
19672
+ children = [];
19673
+ #raw;
19674
+ #rootSpan;
19675
+ #emitRecordedEvent;
19676
+ #canEmitRecordedEvent;
19677
+ #debugRecordedAnnotationUnavailable;
19678
+ constructor(args) {
19679
+ const { raw, rootSpan, emitRecordedEvent, canEmitRecordedEvent, debugRecordedAnnotationUnavailable } = args;
19680
+ this.#raw = raw;
19681
+ this.#rootSpan = rootSpan;
19682
+ this.#emitRecordedEvent = emitRecordedEvent;
19683
+ this.#canEmitRecordedEvent = canEmitRecordedEvent;
19684
+ this.#debugRecordedAnnotationUnavailable = debugRecordedAnnotationUnavailable;
19685
+ this.id = raw.spanId;
19686
+ this.traceId = raw.traceId;
19687
+ this.name = raw.name;
19688
+ this.type = raw.spanType;
19689
+ this.entityType = raw.entityType ?? void 0;
19690
+ this.entityId = raw.entityId ?? void 0;
19691
+ this.entityName = raw.entityName ?? void 0;
19692
+ this.startTime = raw.startedAt;
19693
+ this.endTime = raw.endedAt ?? void 0;
19694
+ this.attributes = raw.attributes ?? void 0;
19695
+ this.metadata = raw.metadata ?? void 0;
19696
+ this.tags = raw.tags ?? void 0;
19697
+ this.input = raw.input ?? void 0;
19698
+ this.output = raw.output ?? void 0;
19699
+ this.errorInfo = normalizeErrorInfo(raw.error);
19700
+ this.requestContext = raw.requestContext ?? void 0;
19701
+ this.isEvent = raw.isEvent;
19702
+ this.isRootSpan = !raw.parentSpanId;
19703
+ this.parentSpanId = raw.parentSpanId ?? void 0;
19704
+ }
19705
+ async addScore(score) {
19706
+ if (!this.#canEmitRecordedEvent()) {
19707
+ this.#debugRecordedAnnotationUnavailable({ kind: "score", traceId: this.traceId, spanId: this.id });
19708
+ return;
19709
+ }
19710
+ await this.#emitRecordedEvent(
19711
+ buildRecordedScoreEvent({
19712
+ span: this.#raw,
19713
+ rootSpan: this.#rootSpan,
19714
+ parent: this.parent,
19715
+ score,
19716
+ spanId: this.id
19717
+ })
19718
+ );
19719
+ }
19720
+ async addFeedback(feedback) {
19721
+ if (!this.#canEmitRecordedEvent()) {
19722
+ this.#debugRecordedAnnotationUnavailable({ kind: "feedback", traceId: this.traceId, spanId: this.id });
19723
+ return;
19724
+ }
19725
+ await this.#emitRecordedEvent(
19726
+ buildRecordedFeedbackEvent({
19727
+ span: this.#raw,
19728
+ rootSpan: this.#rootSpan,
19729
+ parent: this.parent,
19730
+ feedback,
19731
+ spanId: this.id
19732
+ })
19733
+ );
19734
+ }
19735
+ };
19736
+ var RecordedTraceImpl = class {
19737
+ traceId;
19738
+ rootSpan;
19739
+ spans;
19740
+ #rootRecord;
19741
+ #emitRecordedEvent;
19742
+ #spanMap;
19743
+ #canEmitRecordedEvent;
19744
+ #debugRecordedAnnotationUnavailable;
19745
+ constructor(args) {
19746
+ this.traceId = args.traceId;
19747
+ this.rootSpan = args.rootSpan;
19748
+ this.#rootRecord = args.rootRecord;
19749
+ this.spans = args.spans;
19750
+ this.#emitRecordedEvent = args.emitRecordedEvent;
19751
+ this.#spanMap = new Map(args.spans.map((span) => [span.id, span]));
19752
+ this.#canEmitRecordedEvent = args.canEmitRecordedEvent;
19753
+ this.#debugRecordedAnnotationUnavailable = args.debugRecordedAnnotationUnavailable;
19754
+ }
19755
+ getSpan(spanId) {
19756
+ return this.#spanMap.get(spanId) ?? null;
19757
+ }
19758
+ async addScore(score) {
19759
+ if (!this.#canEmitRecordedEvent()) {
19760
+ this.#debugRecordedAnnotationUnavailable({ kind: "score", traceId: this.traceId });
19761
+ return;
19762
+ }
19763
+ await this.#emitRecordedEvent(
19764
+ buildRecordedScoreEvent({
19765
+ span: this.#rootRecord,
19766
+ rootSpan: this.#rootRecord,
19767
+ score
19768
+ })
19769
+ );
19770
+ }
19771
+ async addFeedback(feedback) {
19772
+ if (!this.#canEmitRecordedEvent()) {
19773
+ this.#debugRecordedAnnotationUnavailable({ kind: "feedback", traceId: this.traceId });
19774
+ return;
19775
+ }
19776
+ await this.#emitRecordedEvent(
19777
+ buildRecordedFeedbackEvent({
19778
+ span: this.#rootRecord,
19779
+ rootSpan: this.#rootRecord,
19780
+ feedback
19781
+ })
19782
+ );
19783
+ }
19784
+ };
19785
+ function findRootSpan(spans) {
19786
+ const spanIds = new Set(spans.map((span) => span.spanId));
19787
+ return spans.find((span) => !span.parentSpanId || !spanIds.has(span.parentSpanId)) ?? spans[0];
19788
+ }
19789
+ function hydrateRecordedTrace(args) {
19790
+ const {
19791
+ trace,
19792
+ emitRecordedEvent,
19793
+ canEmitRecordedEvent = () => true,
19794
+ debugRecordedAnnotationUnavailable = () => {
19795
+ }
19796
+ } = args;
19797
+ const rootSpan = findRootSpan(trace.spans);
19798
+ if (!rootSpan) {
19799
+ return null;
19800
+ }
19801
+ const recordedSpans = trace.spans.map(
19802
+ (raw) => new RecordedSpanImpl({
19803
+ raw,
19804
+ rootSpan,
19805
+ emitRecordedEvent,
19806
+ canEmitRecordedEvent,
19807
+ debugRecordedAnnotationUnavailable
19808
+ })
19809
+ );
19810
+ const spanMap = new Map(recordedSpans.map((span) => [span.id, span]));
19811
+ for (const span of recordedSpans) {
19812
+ if (!span.parentSpanId) continue;
19813
+ const parent = spanMap.get(span.parentSpanId);
19814
+ if (!parent) continue;
19815
+ span.parent = parent;
19816
+ parent.children.push(span);
19817
+ }
19818
+ const hydratedRootSpan = spanMap.get(rootSpan.spanId);
19819
+ if (!hydratedRootSpan) {
19820
+ return null;
19821
+ }
19822
+ return new RecordedTraceImpl({
19823
+ traceId: trace.traceId,
19824
+ rootSpan: hydratedRootSpan,
19825
+ rootRecord: rootSpan,
19826
+ spans: recordedSpans,
19827
+ emitRecordedEvent,
19828
+ canEmitRecordedEvent,
19829
+ debugRecordedAnnotationUnavailable
19830
+ });
19831
+ }
19832
+
19503
19833
  // src/registry.ts
19504
19834
  var ObservabilityRegistry = class {
19505
19835
  #instances = /* @__PURE__ */ new Map();
@@ -19740,6 +20070,7 @@ function isInstance(obj) {
19740
20070
  }
19741
20071
  var Observability = class extends base.MastraBase {
19742
20072
  #registry = new ObservabilityRegistry();
20073
+ #mastra;
19743
20074
  constructor(config2) {
19744
20075
  super({
19745
20076
  component: logger.RegisteredLogger.OBSERVABILITY,
@@ -19814,6 +20145,7 @@ var Observability = class extends base.MastraBase {
19814
20145
  setMastraContext(options) {
19815
20146
  const instances = this.listInstances();
19816
20147
  const { mastra } = options;
20148
+ this.#mastra = mastra;
19817
20149
  instances.forEach((instance) => {
19818
20150
  const config2 = instance.getConfig();
19819
20151
  const exporters = instance.getExporters();
@@ -19842,6 +20174,60 @@ var Observability = class extends base.MastraBase {
19842
20174
  getSelectedInstance(options) {
19843
20175
  return this.#registry.getSelected(options);
19844
20176
  }
20177
+ async getRecordedTrace(args) {
20178
+ const observabilityStorage = await this.#getObservabilityStorage();
20179
+ if (!observabilityStorage) {
20180
+ return null;
20181
+ }
20182
+ const trace = await observabilityStorage.getTrace({ traceId: args.traceId });
20183
+ if (!trace) {
20184
+ return null;
20185
+ }
20186
+ return hydrateRecordedTrace({
20187
+ trace,
20188
+ emitRecordedEvent: (event) => this.#emitRecordedEvent(event),
20189
+ canEmitRecordedEvent: () => !!this.#getRecordedTraceInstance(),
20190
+ debugRecordedAnnotationUnavailable: ({ kind, traceId, spanId }) => {
20191
+ this.logger?.debug(
20192
+ kind === "score" ? "addScore() is unavailable; rehydrate the trace before calling addScore()" : "addFeedback() is unavailable; rehydrate the trace before calling addFeedback()",
20193
+ {
20194
+ traceId,
20195
+ spanId
20196
+ }
20197
+ );
20198
+ }
20199
+ });
20200
+ }
20201
+ async addScore(args) {
20202
+ const trace = await this.#getStoredTrace(args.traceId);
20203
+ if (!trace) {
20204
+ return;
20205
+ }
20206
+ const event = buildRecordedScoreEventFromTrace({
20207
+ trace,
20208
+ spanId: args.spanId,
20209
+ score: args.score
20210
+ });
20211
+ if (!event) {
20212
+ return;
20213
+ }
20214
+ await this.#emitRecordedEvent(event);
20215
+ }
20216
+ async addFeedback(args) {
20217
+ const trace = await this.#getStoredTrace(args.traceId);
20218
+ if (!trace) {
20219
+ return;
20220
+ }
20221
+ const event = buildRecordedFeedbackEventFromTrace({
20222
+ trace,
20223
+ spanId: args.spanId,
20224
+ feedback: args.feedback
20225
+ });
20226
+ if (!event) {
20227
+ return;
20228
+ }
20229
+ await this.#emitRecordedEvent(event);
20230
+ }
19845
20231
  /** Register a named observability instance, optionally marking it as default. */
19846
20232
  registerInstance(name, instance, isDefault = false) {
19847
20233
  this.#registry.register(name, instance, isDefault);
@@ -19878,6 +20264,45 @@ var Observability = class extends base.MastraBase {
19878
20264
  async shutdown() {
19879
20265
  await this.#registry.shutdown();
19880
20266
  }
20267
+ async #getObservabilityStorage() {
20268
+ const storage = this.#mastra?.getStorage();
20269
+ if (!storage) {
20270
+ return null;
20271
+ }
20272
+ return await storage.getStore("observability") ?? null;
20273
+ }
20274
+ async #getStoredTrace(traceId) {
20275
+ const observabilityStorage = await this.#getObservabilityStorage();
20276
+ if (!observabilityStorage) {
20277
+ return null;
20278
+ }
20279
+ return observabilityStorage.getTrace({ traceId });
20280
+ }
20281
+ #getRecordedTraceInstance() {
20282
+ return this.getDefaultInstance() ?? Array.from(this.listInstances().values())[0];
20283
+ }
20284
+ async #emitRecordedEvent(event) {
20285
+ const instance = this.#getRecordedTraceInstance();
20286
+ if (!instance) {
20287
+ this.logger?.debug(
20288
+ event.type === "score" ? "Score event was dropped because no observability instance is registered" : "Feedback event was dropped because no observability instance is registered",
20289
+ { eventType: event.type }
20290
+ );
20291
+ return;
20292
+ }
20293
+ if (instance instanceof BaseObservabilityInstance) {
20294
+ instance.__emitRecordedEvent(event);
20295
+ return;
20296
+ }
20297
+ const bridge = instance.getBridge();
20298
+ const handlerResults = [
20299
+ ...instance.getExporters().map((exporter) => routeToHandler(exporter, event, this.logger)),
20300
+ ...bridge ? [routeToHandler(bridge, event, this.logger)] : []
20301
+ ].filter((result) => !!result && typeof result.then === "function");
20302
+ if (handlerResults.length > 0) {
20303
+ await Promise.allSettled(handlerResults);
20304
+ }
20305
+ }
19881
20306
  };
19882
20307
 
19883
20308
  // src/tracing-options.ts