@mastra/observability 1.18.4-alpha.1 → 1.19.0-alpha.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/dist/exporters/tracking.d.ts +7 -0
- package/dist/exporters/tracking.d.ts.map +1 -1
- package/dist/index.cjs +84 -19
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +84 -19
- package/dist/index.js.map +1 -1
- package/dist/instances/base.d.ts.map +1 -1
- package/dist/spans/base.d.ts +1 -1
- package/dist/spans/base.d.ts.map +1 -1
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -3179,6 +3179,7 @@ var BaseSpan = class BaseSpan {
|
|
|
3179
3179
|
exportSpan(includeInternalSpans) {
|
|
3180
3180
|
const hideInput = this.traceState?.hideInput ?? false;
|
|
3181
3181
|
const hideOutput = this.traceState?.hideOutput ?? false;
|
|
3182
|
+
const nestedUnderParent = this.traceState?.nestedUnderParent ?? false;
|
|
3182
3183
|
return {
|
|
3183
3184
|
id: this.id,
|
|
3184
3185
|
traceId: this.traceId,
|
|
@@ -3200,7 +3201,8 @@ var BaseSpan = class BaseSpan {
|
|
|
3200
3201
|
...this.isInternal ? { isInternal: true } : {},
|
|
3201
3202
|
parentSpanId: this.getParentSpanId(includeInternalSpans),
|
|
3202
3203
|
externalParentSpanId: this.getExportedExternalParentSpanId(includeInternalSpans),
|
|
3203
|
-
...
|
|
3204
|
+
...nestedUnderParent ? { nestedUnderParent: true } : {},
|
|
3205
|
+
...this.isRootSpan && !nestedUnderParent && this.tags?.length ? { tags: this.tags } : {}
|
|
3204
3206
|
};
|
|
3205
3207
|
}
|
|
3206
3208
|
get externalTraceId() {
|
|
@@ -3213,7 +3215,7 @@ var BaseSpan = class BaseSpan {
|
|
|
3213
3215
|
async executeInContext(fn) {
|
|
3214
3216
|
const bridge = this.observabilityInstance.getBridge();
|
|
3215
3217
|
if (bridge?.executeInContext) {
|
|
3216
|
-
const bridgeContextSpan = this.isInternal ? this.getParentSpan(false) : this;
|
|
3218
|
+
const bridgeContextSpan = this.isInternal || this.isExcluded ? this.getParentSpan(false) : this;
|
|
3217
3219
|
return bridge.executeInContext(bridgeContextSpan?.id ?? this.id, fn);
|
|
3218
3220
|
}
|
|
3219
3221
|
return fn();
|
|
@@ -3225,7 +3227,7 @@ var BaseSpan = class BaseSpan {
|
|
|
3225
3227
|
executeInContextSync(fn) {
|
|
3226
3228
|
const bridge = this.observabilityInstance.getBridge();
|
|
3227
3229
|
if (bridge?.executeInContextSync) {
|
|
3228
|
-
const bridgeContextSpan = this.isInternal ? this.getParentSpan(false) : this;
|
|
3230
|
+
const bridgeContextSpan = this.isInternal || this.isExcluded ? this.getParentSpan(false) : this;
|
|
3229
3231
|
return bridge.executeInContextSync(bridgeContextSpan?.id ?? this.id, fn);
|
|
3230
3232
|
}
|
|
3231
3233
|
return fn();
|
|
@@ -3270,7 +3272,7 @@ var DefaultSpan = class extends BaseSpan {
|
|
|
3270
3272
|
return;
|
|
3271
3273
|
}
|
|
3272
3274
|
const bridge = observabilityInstance.getBridge();
|
|
3273
|
-
if (bridge && !this.isInternal) {
|
|
3275
|
+
if (bridge && !this.isInternal && !this.isExcluded) {
|
|
3274
3276
|
const bridgeIds = bridge.createSpan(options);
|
|
3275
3277
|
if (bridgeIds) {
|
|
3276
3278
|
this.id = bridgeIds.spanId;
|
|
@@ -4747,6 +4749,11 @@ var BaseObservabilityInstance = class extends MastraBase {
|
|
|
4747
4749
|
tags,
|
|
4748
4750
|
requestContext
|
|
4749
4751
|
});
|
|
4752
|
+
if (!options.parent && traceState?.nestedUnderParent && (!tracingOptions?.traceId || span.traceId !== tracingOptions.traceId || !tracingOptions.parentSpanId || !(span instanceof BaseSpan) || span.externalParentSpanId !== tracingOptions.parentSpanId)) {
|
|
4753
|
+
const { nestedUnderParent: _ignored, ...ownTraceState } = traceState;
|
|
4754
|
+
span.traceState = ownTraceState;
|
|
4755
|
+
this.logger.debug("[Observability] Ignoring tracingOptions.nestUnderParent: the run did not join the requested trace under the requested parent");
|
|
4756
|
+
}
|
|
4750
4757
|
if (rest.type === SpanType.MODEL_GENERATION && this.config.excludeSpanTypes?.includes(SpanType.MODEL_GENERATION)) {
|
|
4751
4758
|
const attrs = rest.attributes;
|
|
4752
4759
|
const model = resolveModelId(attrs?.responseModel, attrs?.model);
|
|
@@ -4782,6 +4789,7 @@ var BaseObservabilityInstance = class extends MastraBase {
|
|
|
4782
4789
|
traceId: cached.traceId,
|
|
4783
4790
|
spanId: cached.id,
|
|
4784
4791
|
parentSpanId: cached.parentSpanId,
|
|
4792
|
+
externalParentSpanId: cached.externalParentSpanId,
|
|
4785
4793
|
startTime: cached.startTime instanceof Date ? cached.startTime : new Date(cached.startTime),
|
|
4786
4794
|
input: cached.input,
|
|
4787
4795
|
attributes: cached.attributes,
|
|
@@ -4789,7 +4797,11 @@ var BaseObservabilityInstance = class extends MastraBase {
|
|
|
4789
4797
|
entityType: cached.entityType,
|
|
4790
4798
|
entityId: cached.entityId,
|
|
4791
4799
|
entityName: cached.entityName,
|
|
4792
|
-
tracingPolicy: cached.isInternal ? { internal: InternalSpans.ALL } : void 0
|
|
4800
|
+
tracingPolicy: cached.isInternal ? { internal: InternalSpans.ALL } : void 0,
|
|
4801
|
+
traceState: cached.nestedUnderParent ? {
|
|
4802
|
+
requestContextKeys: [],
|
|
4803
|
+
nestedUnderParent: true
|
|
4804
|
+
} : void 0
|
|
4793
4805
|
});
|
|
4794
4806
|
this.wireSpanLifecycle(span);
|
|
4795
4807
|
return span;
|
|
@@ -4993,11 +5005,13 @@ var BaseObservabilityInstance = class extends MastraBase {
|
|
|
4993
5005
|
const allKeys = [...configuredKeys, ...additionalKeys];
|
|
4994
5006
|
const hideInput = tracingOptions?.hideInput;
|
|
4995
5007
|
const hideOutput = tracingOptions?.hideOutput;
|
|
4996
|
-
|
|
5008
|
+
const nestedUnderParent = tracingOptions?.nestUnderParent === true;
|
|
5009
|
+
if (allKeys.length === 0 && !hideInput && !hideOutput && !nestedUnderParent) return;
|
|
4997
5010
|
return {
|
|
4998
5011
|
requestContextKeys: allKeys,
|
|
4999
5012
|
...hideInput !== void 0 && { hideInput },
|
|
5000
|
-
...hideOutput !== void 0 && { hideOutput }
|
|
5013
|
+
...hideOutput !== void 0 && { hideOutput },
|
|
5014
|
+
...nestedUnderParent && { nestedUnderParent }
|
|
5001
5015
|
};
|
|
5002
5016
|
}
|
|
5003
5017
|
/**
|
|
@@ -5869,6 +5883,12 @@ var TraceData = class {
|
|
|
5869
5883
|
this.#waitingForParent.delete(args.spanId);
|
|
5870
5884
|
}
|
|
5871
5885
|
/**
|
|
5886
|
+
* Get the span IDs that have events waiting on them.
|
|
5887
|
+
*/
|
|
5888
|
+
getWaitingForSpanIds() {
|
|
5889
|
+
return [...this.#waitingForParent.keys()];
|
|
5890
|
+
}
|
|
5891
|
+
/**
|
|
5872
5892
|
* Get total count of events in all waiting queues.
|
|
5873
5893
|
*/
|
|
5874
5894
|
waitingQueueSize() {
|
|
@@ -6052,6 +6072,8 @@ var TrackingExporter = class extends BaseExporter {
|
|
|
6052
6072
|
#hardCapEnforcementInProgress = false;
|
|
6053
6073
|
/** Map of traceId to scheduled cleanup timeout */
|
|
6054
6074
|
#pendingCleanups = /* @__PURE__ */ new Map();
|
|
6075
|
+
/** Waiting-queue replays started by setImmediate that haven't finished yet */
|
|
6076
|
+
#activeReplays = /* @__PURE__ */ new Set();
|
|
6055
6077
|
/** Subclass configuration with resolved values */
|
|
6056
6078
|
config;
|
|
6057
6079
|
/** Maximum attempts to process a queued event before dropping */
|
|
@@ -6079,12 +6101,13 @@ var TrackingExporter = class extends BaseExporter {
|
|
|
6079
6101
|
*/
|
|
6080
6102
|
#scheduleProcessWaitingForRoot(traceId) {
|
|
6081
6103
|
setImmediate(() => {
|
|
6082
|
-
this.#
|
|
6104
|
+
if (this.#shutdownStarted) return;
|
|
6105
|
+
this.#trackReplay(this.#processWaitingForRoot(traceId).then(() => {}, (error) => {
|
|
6083
6106
|
this.logger.error(`${this.name}: Error processing waiting-for-root queue`, {
|
|
6084
6107
|
error,
|
|
6085
6108
|
traceId
|
|
6086
6109
|
});
|
|
6087
|
-
});
|
|
6110
|
+
}));
|
|
6088
6111
|
});
|
|
6089
6112
|
}
|
|
6090
6113
|
/**
|
|
@@ -6093,24 +6116,59 @@ var TrackingExporter = class extends BaseExporter {
|
|
|
6093
6116
|
*/
|
|
6094
6117
|
#scheduleProcessWaitingFor(traceId, spanId) {
|
|
6095
6118
|
setImmediate(() => {
|
|
6096
|
-
this.#
|
|
6119
|
+
if (this.#shutdownStarted) return;
|
|
6120
|
+
this.#trackReplay(this.#processWaitingFor(traceId, spanId).then(() => {}, (error) => {
|
|
6097
6121
|
this.logger.error(`${this.name}: Error processing waiting queue`, {
|
|
6098
6122
|
error,
|
|
6099
6123
|
traceId,
|
|
6100
6124
|
spanId
|
|
6101
6125
|
});
|
|
6102
|
-
});
|
|
6126
|
+
}));
|
|
6103
6127
|
});
|
|
6104
6128
|
}
|
|
6105
6129
|
/**
|
|
6130
|
+
* Track a running replay so flush() and shutdown() can wait for it.
|
|
6131
|
+
*/
|
|
6132
|
+
#trackReplay(replay) {
|
|
6133
|
+
this.#activeReplays.add(replay);
|
|
6134
|
+
replay.finally(() => this.#activeReplays.delete(replay));
|
|
6135
|
+
}
|
|
6136
|
+
/**
|
|
6137
|
+
* Process every queued event whose dependency has been built, without waiting for the
|
|
6138
|
+
* setImmediate-scheduled replays (which never fire under fake timers). Waits for replays
|
|
6139
|
+
* that are already running, then repeats until a pass makes no progress, so cascades
|
|
6140
|
+
* (root -> parent -> child -> end) are fully drained.
|
|
6141
|
+
*/
|
|
6142
|
+
async #drainWaitingQueues() {
|
|
6143
|
+
while (true) {
|
|
6144
|
+
while (this.#activeReplays.size > 0) await Promise.all(this.#activeReplays);
|
|
6145
|
+
let progressed = false;
|
|
6146
|
+
for (const [traceId, traceData] of this.#traceMap) try {
|
|
6147
|
+
if (traceData.isRootProcessed() && await this.#processWaitingForRoot(traceId) > 0) progressed = true;
|
|
6148
|
+
for (const spanId of traceData.getWaitingForSpanIds()) {
|
|
6149
|
+
if (!traceData.hasSpan({ spanId })) continue;
|
|
6150
|
+
if (await this.#processWaitingFor(traceId, spanId) > 0) progressed = true;
|
|
6151
|
+
}
|
|
6152
|
+
} catch (error) {
|
|
6153
|
+
this.logger.error(`${this.name}: Error draining waiting queues`, {
|
|
6154
|
+
error,
|
|
6155
|
+
traceId
|
|
6156
|
+
});
|
|
6157
|
+
}
|
|
6158
|
+
if (!progressed && this.#activeReplays.size === 0) return;
|
|
6159
|
+
}
|
|
6160
|
+
}
|
|
6161
|
+
/**
|
|
6106
6162
|
* Process all events waiting for root span.
|
|
6163
|
+
* Takes the queue before processing, so a concurrent call can't process the same events.
|
|
6164
|
+
* @returns The number of events that left the queue (processed, moved or dropped)
|
|
6107
6165
|
*/
|
|
6108
6166
|
async #processWaitingForRoot(traceId) {
|
|
6109
|
-
if (this.#shutdownStarted) return;
|
|
6110
6167
|
const traceData = this.#traceMap.get(traceId);
|
|
6111
|
-
if (!traceData) return;
|
|
6168
|
+
if (!traceData) return 0;
|
|
6112
6169
|
const queue = traceData.getEventsWaitingForRoot();
|
|
6113
|
-
if (queue.length === 0) return;
|
|
6170
|
+
if (queue.length === 0) return 0;
|
|
6171
|
+
traceData.clearWaitingForRoot();
|
|
6114
6172
|
this.logger.debug(`${this.name}: Processing ${queue.length} events waiting for root`, { traceId });
|
|
6115
6173
|
const toKeep = [];
|
|
6116
6174
|
const now = Date.now();
|
|
@@ -6146,23 +6204,25 @@ var TrackingExporter = class extends BaseExporter {
|
|
|
6146
6204
|
else toKeep.push(queuedEvent);
|
|
6147
6205
|
}
|
|
6148
6206
|
}
|
|
6149
|
-
traceData.clearWaitingForRoot();
|
|
6150
6207
|
for (const event of toKeep) traceData.addToWaitingQueue({
|
|
6151
6208
|
event: event.event,
|
|
6152
6209
|
waitingFor: "root",
|
|
6153
6210
|
attempts: event.attempts,
|
|
6154
6211
|
queuedAt: event.queuedAt
|
|
6155
6212
|
});
|
|
6213
|
+
return queue.length - toKeep.length;
|
|
6156
6214
|
}
|
|
6157
6215
|
/**
|
|
6158
6216
|
* Process events waiting for a specific parent span.
|
|
6217
|
+
* Takes the queue before processing, so a concurrent call can't process the same events.
|
|
6218
|
+
* @returns The number of events that left the queue (processed, moved or dropped)
|
|
6159
6219
|
*/
|
|
6160
6220
|
async #processWaitingFor(traceId, spanId) {
|
|
6161
|
-
if (this.#shutdownStarted) return;
|
|
6162
6221
|
const traceData = this.#traceMap.get(traceId);
|
|
6163
|
-
if (!traceData) return;
|
|
6222
|
+
if (!traceData) return 0;
|
|
6164
6223
|
const queue = traceData.getEventsWaitingFor({ spanId });
|
|
6165
|
-
if (queue.length === 0) return;
|
|
6224
|
+
if (queue.length === 0) return 0;
|
|
6225
|
+
traceData.clearWaitingFor({ spanId });
|
|
6166
6226
|
this.logger.debug(`${this.name}: Processing ${queue.length} events waiting for span`, {
|
|
6167
6227
|
traceId,
|
|
6168
6228
|
spanId
|
|
@@ -6192,13 +6252,13 @@ var TrackingExporter = class extends BaseExporter {
|
|
|
6192
6252
|
queuedEvent.attempts++;
|
|
6193
6253
|
if (!await this.#tryProcessQueuedEvent(queuedEvent, traceData)) toKeep.push(queuedEvent);
|
|
6194
6254
|
}
|
|
6195
|
-
traceData.clearWaitingFor({ spanId });
|
|
6196
6255
|
for (const event of toKeep) traceData.addToWaitingQueue({
|
|
6197
6256
|
event: event.event,
|
|
6198
6257
|
waitingFor: spanId,
|
|
6199
6258
|
attempts: event.attempts,
|
|
6200
6259
|
queuedAt: event.queuedAt
|
|
6201
6260
|
});
|
|
6261
|
+
return queue.length - toKeep.length;
|
|
6202
6262
|
}
|
|
6203
6263
|
/**
|
|
6204
6264
|
* Try to process a queued event.
|
|
@@ -6658,11 +6718,15 @@ var TrackingExporter = class extends BaseExporter {
|
|
|
6658
6718
|
* This is useful in serverless environments where you need to ensure spans
|
|
6659
6719
|
* are exported before the runtime instance is terminated.
|
|
6660
6720
|
*
|
|
6721
|
+
* Queued events whose dependencies have been built are processed first, so
|
|
6722
|
+
* a shutdown() right after flush() only aborts spans that are still open.
|
|
6723
|
+
*
|
|
6661
6724
|
* Subclasses should override _flush() to implement vendor-specific flush logic.
|
|
6662
6725
|
*/
|
|
6663
6726
|
async flush() {
|
|
6664
6727
|
if (this.isDisabled) return;
|
|
6665
6728
|
this.logger.debug(`${this.name}: Flushing`);
|
|
6729
|
+
if (!this.#shutdownStarted) await this.#drainWaitingQueues();
|
|
6666
6730
|
await this._flush();
|
|
6667
6731
|
}
|
|
6668
6732
|
/**
|
|
@@ -6682,6 +6746,7 @@ var TrackingExporter = class extends BaseExporter {
|
|
|
6682
6746
|
async shutdown() {
|
|
6683
6747
|
if (this.isDisabled) return;
|
|
6684
6748
|
this.#shutdownStarted = true;
|
|
6749
|
+
await this.#drainWaitingQueues();
|
|
6685
6750
|
await this._preShutdown();
|
|
6686
6751
|
for (const [traceId, timeout] of this.#pendingCleanups) {
|
|
6687
6752
|
clearTimeout(timeout);
|