@mastra/observability 1.8.0-alpha.1 → 1.9.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/CHANGELOG.md CHANGED
@@ -1,5 +1,90 @@
1
1
  # @mastra/observability
2
2
 
3
+ ## 1.9.0-alpha.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Added support for project-scoped CloudExporter collector routes for organization API keys. ([#15189](https://github.com/mastra-ai/mastra/pull/15189))
8
+
9
+ **What changed**
10
+ CloudExporter now accepts a `projectId` option and reads `MASTRA_PROJECT_ID` so remote writes can target project-scoped collector URLs when you authenticate with an organization API key.
11
+
12
+ ```ts
13
+ new CloudExporter({
14
+ accessToken: process.env.MASTRA_CLOUD_ACCESS_TOKEN,
15
+ projectId: process.env.MASTRA_PROJECT_ID,
16
+ });
17
+ ```
18
+
19
+ When `projectId` is set, base endpoints resolve to `/projects/:projectId/ai/{signal}/publish`. Without it, existing JWT-style `/ai/{signal}/publish` routes still work as before.
20
+
21
+ ### Patch Changes
22
+
23
+ - Updated dependencies [[`ef94400`](https://github.com/mastra-ai/mastra/commit/ef9440049402596b31f2ab976c5e4508f6cb6c91)]:
24
+ - @mastra/core@1.24.1-alpha.0
25
+
26
+ ## 1.8.0
27
+
28
+ ### Minor Changes
29
+
30
+ - Added CloudExporter support for Mastra Observability logs, metrics, scores, and feedback. ([#15124](https://github.com/mastra-ai/mastra/pull/15124))
31
+
32
+ CloudExporter now batches and uploads all Mastra Observability signals to Mastra Cloud, not just tracing spans.
33
+
34
+ This includes a breaking change to the CloudExporter endpoint format. We now pass a base endpoint URL and let let the exporter derive the standard publish paths automatically.
35
+
36
+ ```ts
37
+ import { CloudExporter, Observability } from '@mastra/observability';
38
+
39
+ const observability = new Observability({
40
+ configs: {
41
+ default: {
42
+ serviceName: 'my-app',
43
+ exporters: [
44
+ new CloudExporter({
45
+ endpoint: 'https://collector.example.com',
46
+ }),
47
+ ],
48
+ },
49
+ },
50
+ });
51
+
52
+ // Traces, logs, metrics, scores, and feedback now all publish through CloudExporter.
53
+ ```
54
+
55
+ After updating the exporter endpoint config, the exporter will continue to work for traces, and the same exporter will now also publish structured logs, auto-extracted metrics, scores, and feedback records.
56
+
57
+ - Added `excludeSpanTypes` and `spanFilter` options to `ObservabilityInstanceConfig` for selectively filtering spans before export. Use `excludeSpanTypes` to drop entire categories of spans by type (e.g., `MODEL_CHUNK`, `MODEL_STEP`) or `spanFilter` for fine-grained predicate-based filtering by attributes, metadata, entity, or any combination. Both options help reduce noise and costs in observability platforms that charge per-span. ([#15131](https://github.com/mastra-ai/mastra/pull/15131))
58
+
59
+ **`excludeSpanTypes` example:**
60
+
61
+ ```ts
62
+ excludeSpanTypes: [SpanType.MODEL_CHUNK, SpanType.MODEL_STEP, SpanType.WORKFLOW_SLEEP];
63
+ ```
64
+
65
+ **`spanFilter` example:**
66
+
67
+ ```ts
68
+ spanFilter: span => {
69
+ if (span.type === SpanType.MODEL_CHUNK) return false;
70
+ if (span.type === SpanType.TOOL_CALL && span.attributes?.success) return false;
71
+ return true;
72
+ };
73
+ ```
74
+
75
+ Resolves https://github.com/mastra-ai/mastra/issues/12710
76
+
77
+ ### Patch Changes
78
+
79
+ - ObservabilityBus now honors per-instance `serializationOptions` (maxStringLength, maxDepth, maxArrayLength, maxObjectKeys) when deep-cleaning log/metric/score/feedback payloads, matching the behavior of tracing spans. Previously these signals always used the built-in defaults regardless of user configuration. ([#15138](https://github.com/mastra-ai/mastra/pull/15138))
80
+
81
+ - Apply `deepClean()` to all observability signals (logs, metrics, scores, feedback) before fanning out to exporters and bridges. Previously only tracing spans were deep-cleaned at construction time, leaving free-form payload fields on other signals (e.g. `log.data`, `log.metadata`, `metric.metadata`, `metric.costContext.costMetadata`, `score.metadata`, `feedback.metadata`) susceptible to circular references, oversized strings, and other non-serializable values. Sanitization now happens centrally in `ObservabilityBus.emit()` so every signal leaving the bus is bounded and JSON-safe. ([#15135](https://github.com/mastra-ai/mastra/pull/15135))
82
+
83
+ - `deepClean()` now preserves data for `Map`, `Set`, and richer `Error` objects. Previously Maps and Sets were serialized as empty `{}` (entries silently dropped) and Errors only kept `name`/`message`. Maps are now converted to plain objects of entries, Sets to arrays (both respecting `maxObjectKeys`/`maxArrayLength` and cycle detection), and Errors additionally preserve `stack` and recursively cleaned `cause`. ([#15136](https://github.com/mastra-ai/mastra/pull/15136))
84
+
85
+ - Updated dependencies [[`8db7663`](https://github.com/mastra-ai/mastra/commit/8db7663c9a9c735828094c359d2e327fd4f8fba3), [`153e864`](https://github.com/mastra-ai/mastra/commit/153e86476b425db7cd0dc8490050096e92964a38), [`715710d`](https://github.com/mastra-ai/mastra/commit/715710d12fa47cf88e09d41f13843eddc29327b0), [`378c6c4`](https://github.com/mastra-ai/mastra/commit/378c6c4755726e8d8cf83a14809b350b90d46c62), [`9f91fd5`](https://github.com/mastra-ai/mastra/commit/9f91fd538ab2a44f8cc740bcad8e51205f74fbea), [`ba6fa9c`](https://github.com/mastra-ai/mastra/commit/ba6fa9cc0f3e1912c49fd70d4c3bb8c44903ddaa)]:
86
+ - @mastra/core@1.24.0
87
+
3
88
  ## 1.8.0-alpha.1
4
89
 
5
90
  ### Minor Changes
@@ -6,6 +6,7 @@ export interface CloudExporterConfig extends BaseExporterConfig {
6
6
  maxBatchWaitMs?: number;
7
7
  maxRetries?: number;
8
8
  accessToken?: string;
9
+ projectId?: string;
9
10
  endpoint?: string;
10
11
  tracesEndpoint?: string;
11
12
  logsEndpoint?: string;
@@ -15,7 +16,7 @@ export interface CloudExporterConfig extends BaseExporterConfig {
15
16
  }
16
17
  export declare class CloudExporter extends BaseExporter {
17
18
  name: string;
18
- private cloudConfig;
19
+ private readonly cloudConfig;
19
20
  private buffer;
20
21
  private flushTimer;
21
22
  private inFlightFlushes;
@@ -1 +1 @@
1
- {"version":3,"file":"cloud.d.ts","sourceRoot":"","sources":["../../src/exporters/cloud.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,YAAY,EAEZ,QAAQ,EACR,WAAW,EACX,UAAU,EACV,aAAa,EACd,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AAEjD,MAAM,WAAW,mBAAoB,SAAQ,kBAAkB;IAC7D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IAGpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAgLD,qBAAa,aAAc,SAAQ,YAAY;IAC7C,IAAI,SAAyC;IAE7C,OAAO,CAAC,WAAW,CAAsB;IACzC,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,UAAU,CAA+B;IACjD,OAAO,CAAC,eAAe,CAA4B;gBAEvC,MAAM,GAAE,mBAAwB;cA0D5B,mBAAmB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAWjE,UAAU,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAS1C,aAAa,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAShD,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAS9C,eAAe,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAS1D,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,cAAc;IAOtB,OAAO,CAAC,iBAAiB;IAOzB,OAAO,CAAC,gBAAgB;IAOxB,OAAO,CAAC,mBAAmB;IAO3B,OAAO,CAAC,eAAe;IAMvB,OAAO,CAAC,UAAU;IAelB,OAAO,CAAC,SAAS;IAMjB,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,cAAc;YAMR,mBAAmB;IAYjC,OAAO,CAAC,WAAW;IAiBnB,OAAO,CAAC,aAAa;YAoBP,WAAW;IAoDzB;;OAEG;YACW,WAAW;YAuBX,gBAAgB;IA+B9B,OAAO,CAAC,WAAW;IAUnB;;;;OAIG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA4BtB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAiChC"}
1
+ {"version":3,"file":"cloud.d.ts","sourceRoot":"","sources":["../../src/exporters/cloud.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,YAAY,EAEZ,QAAQ,EACR,WAAW,EACX,UAAU,EACV,aAAa,EACd,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AAEjD,MAAM,WAAW,mBAAoB,SAAQ,kBAAkB;IAC7D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IAGpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AA+LD,qBAAa,aAAc,SAAQ,YAAY;IAC7C,IAAI,SAAyC;IAE7C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAgC;IAC5D,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,UAAU,CAA+B;IACjD,OAAO,CAAC,eAAe,CAA4B;gBAEvC,MAAM,GAAE,mBAAwB;cAgE5B,mBAAmB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAWjE,UAAU,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAS1C,aAAa,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAShD,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAS9C,eAAe,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAS1D,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,cAAc;IAOtB,OAAO,CAAC,iBAAiB;IAOzB,OAAO,CAAC,gBAAgB;IAOxB,OAAO,CAAC,mBAAmB;IAO3B,OAAO,CAAC,eAAe;IAMvB,OAAO,CAAC,UAAU;IAelB,OAAO,CAAC,SAAS;IAMjB,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,cAAc;YAMR,mBAAmB;IAYjC,OAAO,CAAC,WAAW;IAiBnB,OAAO,CAAC,aAAa;YAoBP,WAAW;IAoDzB;;OAEG;YACW,WAAW;YAuBX,gBAAgB;IA+B9B,OAAO,CAAC,WAAW;IAUnB;;;;OAIG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA4BtB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAiChC"}
package/dist/index.cjs CHANGED
@@ -15051,14 +15051,7 @@ var SIGNAL_PUBLISH_SUFFIXES = {
15051
15051
  scores: "/scores/publish",
15052
15052
  feedback: "/feedback/publish"
15053
15053
  };
15054
- var SIGNAL_PUBLISH_PATHS = {
15055
- traces: "/ai/spans/publish",
15056
- logs: "/ai/logs/publish",
15057
- metrics: "/ai/metrics/publish",
15058
- scores: "/ai/scores/publish",
15059
- feedback: "/ai/feedback/publish"
15060
- };
15061
- var SIGNAL_PAYLOAD_KEYS = {
15054
+ var SIGNAL_PUBLISH_SEGMENTS = {
15062
15055
  traces: "spans",
15063
15056
  logs: "logs",
15064
15057
  metrics: "metrics",
@@ -15087,6 +15080,18 @@ function createInvalidEndpointError(endpoint, text, cause) {
15087
15080
  cause
15088
15081
  );
15089
15082
  }
15083
+ var VALID_PROJECT_ID = /^[a-zA-Z0-9_-]+$/;
15084
+ function createInvalidProjectIdError(projectId) {
15085
+ return new error$1.MastraError({
15086
+ id: `CLOUD_EXPORTER_INVALID_PROJECT_ID`,
15087
+ text: "CloudExporter projectId must only contain letters, numbers, hyphens, and underscores.",
15088
+ domain: error$1.ErrorDomain.MASTRA_OBSERVABILITY,
15089
+ category: error$1.ErrorCategory.USER,
15090
+ details: {
15091
+ projectId
15092
+ }
15093
+ });
15094
+ }
15090
15095
  function resolveBaseEndpoint(baseEndpoint) {
15091
15096
  const normalizedEndpoint = trimTrailingSlashes(baseEndpoint);
15092
15097
  const invalidText = 'CloudExporter endpoint must be a base origin like "https://collector.example.com" with no path, search, or hash.';
@@ -15103,10 +15108,17 @@ function resolveBaseEndpoint(baseEndpoint) {
15103
15108
  throw createInvalidEndpointError(baseEndpoint, invalidText, error48);
15104
15109
  }
15105
15110
  }
15106
- function buildSignalEndpoint(baseEndpoint, signal) {
15107
- return `${baseEndpoint}${SIGNAL_PUBLISH_PATHS[signal]}`;
15111
+ function buildSignalPath(signal, projectId) {
15112
+ const signalSegment = SIGNAL_PUBLISH_SEGMENTS[signal];
15113
+ if (!projectId) {
15114
+ return `/ai/${signalSegment}/publish`;
15115
+ }
15116
+ return `/projects/${projectId}/ai/${signalSegment}/publish`;
15117
+ }
15118
+ function buildSignalEndpoint(baseEndpoint, signal, projectId) {
15119
+ return `${baseEndpoint}${buildSignalPath(signal, projectId)}`;
15108
15120
  }
15109
- function resolveExplicitSignalEndpoint(signal, endpoint) {
15121
+ function resolveExplicitSignalEndpoint(signal, endpoint, projectId) {
15110
15122
  const normalizedEndpoint = trimTrailingSlashes(endpoint);
15111
15123
  const invalidText = `CloudExporter ${signal}Endpoint must be a base origin like "https://collector.example.com" or a full ${signal} publish URL ending in "${SIGNAL_PUBLISH_SUFFIXES[signal]}".`;
15112
15124
  try {
@@ -15117,7 +15129,7 @@ function resolveExplicitSignalEndpoint(signal, endpoint) {
15117
15129
  const normalizedOrigin = trimTrailingSlashes(parsedEndpoint.origin);
15118
15130
  const normalizedPathname = trimTrailingSlashes(parsedEndpoint.pathname);
15119
15131
  if (!normalizedPathname || normalizedPathname === "/") {
15120
- return buildSignalEndpoint(normalizedOrigin, signal);
15132
+ return buildSignalEndpoint(normalizedOrigin, signal, projectId);
15121
15133
  }
15122
15134
  if (normalizedPathname.endsWith(SIGNAL_PUBLISH_SUFFIXES[signal])) {
15123
15135
  return `${normalizedOrigin}${normalizedPathname}`;
@@ -15160,7 +15172,12 @@ var CloudExporter = class extends BaseExporter {
15160
15172
  inFlightFlushes = /* @__PURE__ */ new Set();
15161
15173
  constructor(config2 = {}) {
15162
15174
  super(config2);
15175
+ if (config2.projectId !== void 0 && !VALID_PROJECT_ID.test(config2.projectId)) {
15176
+ throw createInvalidProjectIdError(config2.projectId);
15177
+ }
15163
15178
  const accessToken = config2.accessToken ?? process.env.MASTRA_CLOUD_ACCESS_TOKEN;
15179
+ const rawProjectId = config2.projectId ?? process.env.MASTRA_PROJECT_ID;
15180
+ const projectId = rawProjectId && VALID_PROJECT_ID.test(rawProjectId) ? rawProjectId : void 0;
15164
15181
  if (!accessToken) {
15165
15182
  this.setDisabled("MASTRA_CLOUD_ACCESS_TOKEN environment variable not set.");
15166
15183
  }
@@ -15168,19 +15185,19 @@ var CloudExporter = class extends BaseExporter {
15168
15185
  let baseEndpoint;
15169
15186
  let tracesEndpoint;
15170
15187
  if (tracesEndpointOverride) {
15171
- tracesEndpoint = resolveExplicitSignalEndpoint("traces", tracesEndpointOverride);
15188
+ tracesEndpoint = resolveExplicitSignalEndpoint("traces", tracesEndpointOverride, projectId);
15172
15189
  } else {
15173
15190
  baseEndpoint = resolveBaseEndpoint(config2.endpoint ?? DEFAULT_CLOUD_ENDPOINT);
15174
- tracesEndpoint = buildSignalEndpoint(baseEndpoint, "traces");
15191
+ tracesEndpoint = buildSignalEndpoint(baseEndpoint, "traces", projectId);
15175
15192
  }
15176
15193
  const resolveConfiguredSignalEndpoint = (signal, explicitEndpoint) => {
15177
15194
  if (explicitEndpoint) {
15178
- return resolveExplicitSignalEndpoint(signal, explicitEndpoint);
15195
+ return resolveExplicitSignalEndpoint(signal, explicitEndpoint, projectId);
15179
15196
  }
15180
15197
  if (tracesEndpointOverride) {
15181
15198
  return deriveSignalEndpointFromTracesEndpoint(signal, tracesEndpoint);
15182
15199
  }
15183
- return buildSignalEndpoint(baseEndpoint, signal);
15200
+ return buildSignalEndpoint(baseEndpoint, signal, projectId);
15184
15201
  };
15185
15202
  this.cloudConfig = {
15186
15203
  logger: this.logger,
@@ -15404,7 +15421,7 @@ var CloudExporter = class extends BaseExporter {
15404
15421
  const options = {
15405
15422
  method: "POST",
15406
15423
  headers,
15407
- body: JSON.stringify({ [SIGNAL_PAYLOAD_KEYS[signal]]: records })
15424
+ body: JSON.stringify({ [SIGNAL_PUBLISH_SEGMENTS[signal]]: records })
15408
15425
  };
15409
15426
  await utils.fetchWithRetry(endpointMap[signal], options, this.cloudConfig.maxRetries);
15410
15427
  }