@mastra/observability 1.17.1 → 1.17.2-alpha.1

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
@@ -221,10 +221,18 @@ function mergeSerializationOptions(userOptions) {
221
221
  }
222
222
  /**
223
223
  * Hard-cap any string to prevent unbounded growth.
224
+ *
225
+ * The cut never splits a UTF-16 surrogate pair: if it would land immediately
226
+ * after a lone high surrogate (U+D800..U+DBFF), it backs off one code unit so
227
+ * the pair is dropped as a whole. `JSON.stringify` emits a lone `\ud83d` for a
228
+ * split pair, which PostgreSQL rejects on a jsonb cast with 22P02
229
+ * ("Unicode low surrogate must follow a high surrogate").
224
230
  */
225
231
  function truncateString(s, maxChars) {
226
232
  if (s.length <= maxChars) return s;
227
- return s.slice(0, maxChars) + "…[truncated]";
233
+ const code = s.charCodeAt(maxChars - 1);
234
+ const safeEnd = code >= 55296 && code <= 56319 ? maxChars - 1 : maxChars;
235
+ return s.slice(0, safeEnd) + "…[truncated]";
228
236
  }
229
237
  function formatSerializationError(error) {
230
238
  return `[${error instanceof Error ? truncateString(error.message, 256) : "unknown error"}]`;
@@ -7098,8 +7106,8 @@ const FLUSH_SUCCEEDED = { failed: false };
7098
7106
  var MastraStorageExporter = class extends BaseExporter {
7099
7107
  name = "mastra-storage-exporter";
7100
7108
  #config;
7101
- #isInitializing = false;
7102
- #initPromises = /* @__PURE__ */ new Set();
7109
+ #initializationPromise;
7110
+ #wasUnavailable = false;
7103
7111
  #eventBuffer;
7104
7112
  #storage;
7105
7113
  #observabilityStorage;
@@ -7124,41 +7132,56 @@ var MastraStorageExporter = class extends BaseExporter {
7124
7132
  * Initialize the exporter (called after all dependencies are ready)
7125
7133
  */
7126
7134
  async init(options) {
7135
+ this.#emitDropEvent = options.emitDropEvent;
7136
+ this.#storage = options.mastra?.getStorage();
7137
+ if (!this.#storage) {
7138
+ this.logger.warn("MastraStorageExporter disabled: Storage not available. Traces will not be persisted.");
7139
+ return;
7140
+ }
7141
+ await this.ensureInitialized();
7142
+ }
7143
+ warnUnavailable(message, error) {
7144
+ if (this.#wasUnavailable) return;
7145
+ this.#wasUnavailable = true;
7146
+ if (error === void 0) {
7147
+ this.logger.warn(message);
7148
+ return;
7149
+ }
7150
+ this.logger.warn(message, { error: error instanceof Error ? error.message : String(error) });
7151
+ }
7152
+ async initializeStorage() {
7153
+ const storage = this.#storage;
7154
+ if (!storage) return;
7127
7155
  try {
7128
- this.#isInitializing = true;
7129
- this.#emitDropEvent = options.emitDropEvent;
7130
- this.#storage = options.mastra?.getStorage();
7131
- if (!this.#storage) {
7132
- this.logger.warn("MastraStorageExporter disabled: Storage not available. Traces will not be persisted.");
7133
- return;
7134
- }
7135
- this.#observabilityStorage = await this.#storage.getStore("observability");
7136
- if (!this.#observabilityStorage) {
7137
- this.logger.warn("MastraStorageExporter disabled: Observability storage not available. Traces will not be persisted.");
7138
- return;
7139
- }
7140
- if (!this.#resolvedStrategy) {
7141
- this.#resolvedStrategy = resolveTracingStorageStrategy(this.#config, this.#observabilityStorage, this.#storage.constructor.name, this.logger);
7142
- this.logger.debug("tracing storage exporter initialized", {
7143
- strategy: this.#resolvedStrategy,
7144
- source: this.#config.strategy !== "auto" ? "user" : "auto",
7145
- storageAdapter: this.#storage.constructor.name,
7146
- maxBatchSize: this.#config.maxBatchSize,
7147
- maxBatchWaitMs: this.#config.maxBatchWaitMs
7148
- });
7149
- }
7150
- if (this.#resolvedStrategy) this.#eventBuffer.init({ strategy: this.#resolvedStrategy });
7151
- } finally {
7152
- this.#isInitializing = false;
7153
- /**
7154
- * Assumes caller waits until export of a parent span is completed before calling
7155
- * export for child spans , order is not relevant for resolve
7156
- */
7157
- this.#initPromises.forEach((resolve) => {
7158
- resolve();
7159
- });
7160
- this.#initPromises.clear();
7156
+ this.#observabilityStorage = await storage.getStore("observability");
7157
+ } catch (error) {
7158
+ this.warnUnavailable("MastraStorageExporter unavailable: Failed to initialize observability storage. Traces will not be persisted until storage becomes available.", error);
7159
+ return;
7160
+ }
7161
+ if (!this.#observabilityStorage) {
7162
+ this.warnUnavailable("MastraStorageExporter unavailable: Observability storage not available. Traces will not be persisted until storage becomes available.");
7163
+ return;
7161
7164
  }
7165
+ this.#resolvedStrategy = resolveTracingStorageStrategy(this.#config, this.#observabilityStorage, storage.constructor.name, this.logger);
7166
+ this.#eventBuffer.init({ strategy: this.#resolvedStrategy });
7167
+ this.logger.debug("tracing storage exporter initialized", {
7168
+ strategy: this.#resolvedStrategy,
7169
+ source: this.#config.strategy !== "auto" ? "user" : "auto",
7170
+ storageAdapter: storage.constructor.name,
7171
+ maxBatchSize: this.#config.maxBatchSize,
7172
+ maxBatchWaitMs: this.#config.maxBatchWaitMs
7173
+ });
7174
+ if (this.#wasUnavailable) {
7175
+ this.#wasUnavailable = false;
7176
+ this.logger.info("MastraStorageExporter recovered: Observability storage is available. Traces will be persisted.");
7177
+ }
7178
+ }
7179
+ async ensureInitialized() {
7180
+ if (this.#observabilityStorage || !this.#storage) return;
7181
+ this.#initializationPromise ??= this.initializeStorage().finally(() => {
7182
+ this.#initializationPromise = void 0;
7183
+ });
7184
+ await this.#initializationPromise;
7162
7185
  }
7163
7186
  /**
7164
7187
  * Checks if buffer should be flushed based on size or time triggers
@@ -7410,7 +7433,7 @@ var MastraStorageExporter = class extends BaseExporter {
7410
7433
  }
7411
7434
  }
7412
7435
  async _exportTracingEvent(event) {
7413
- await this.waitForInit();
7436
+ await this.ensureInitialized();
7414
7437
  if (!this.#observabilityStorage) {
7415
7438
  this.logger.debug("Cannot store traces. Observability storage is not initialized");
7416
7439
  return;
@@ -7419,21 +7442,10 @@ var MastraStorageExporter = class extends BaseExporter {
7419
7442
  await this.handleBatchedFlush();
7420
7443
  }
7421
7444
  /**
7422
- * Resolves when an ongoing init call is finished
7423
- * Doesn't wait for the caller to call init
7424
- * @returns
7425
- */
7426
- async waitForInit() {
7427
- if (!this.#isInitializing) return;
7428
- return new Promise((resolve) => {
7429
- this.#initPromises.add(resolve);
7430
- });
7431
- }
7432
- /**
7433
7445
  * Handle metric events — buffer for batch flush.
7434
7446
  */
7435
7447
  async onMetricEvent(event) {
7436
- await this.waitForInit();
7448
+ await this.ensureInitialized();
7437
7449
  if (!this.#observabilityStorage) return;
7438
7450
  this.#eventBuffer.addEvent(event);
7439
7451
  await this.handleBatchedFlush();
@@ -7442,7 +7454,7 @@ var MastraStorageExporter = class extends BaseExporter {
7442
7454
  * Handle log events — buffer for batch flush.
7443
7455
  */
7444
7456
  async onLogEvent(event) {
7445
- await this.waitForInit();
7457
+ await this.ensureInitialized();
7446
7458
  if (!this.#observabilityStorage) return;
7447
7459
  this.#eventBuffer.addEvent(event);
7448
7460
  await this.handleBatchedFlush();
@@ -7451,7 +7463,7 @@ var MastraStorageExporter = class extends BaseExporter {
7451
7463
  * Handle score events — buffer for batch flush.
7452
7464
  */
7453
7465
  async onScoreEvent(event) {
7454
- await this.waitForInit();
7466
+ await this.ensureInitialized();
7455
7467
  if (!this.#observabilityStorage) return;
7456
7468
  this.#eventBuffer.addEvent(event);
7457
7469
  await this.handleBatchedFlush();
@@ -7460,7 +7472,7 @@ var MastraStorageExporter = class extends BaseExporter {
7460
7472
  * Handle feedback events — buffer for batch flush.
7461
7473
  */
7462
7474
  async onFeedbackEvent(event) {
7463
- await this.waitForInit();
7475
+ await this.ensureInitialized();
7464
7476
  if (!this.#observabilityStorage) return;
7465
7477
  this.#eventBuffer.addEvent(event);
7466
7478
  await this.handleBatchedFlush();