@mastra/pg 1.30.0-alpha.1 → 1.30.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/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/index.cjs +255 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +255 -3
- package/dist/index.js.map +1 -1
- package/dist/storage/domains/observability/v-next/index.d.ts +3 -2
- package/dist/storage/domains/observability/v-next/index.d.ts.map +1 -1
- package/dist/storage/domains/observability/v-next/span-query.d.ts +43 -0
- package/dist/storage/domains/observability/v-next/span-query.d.ts.map +1 -0
- package/dist/storage/domains/observability/v-next/trace-aggregate.d.ts.map +1 -1
- package/dist/storage/domains/observability/v-next/trace-query.d.ts +7 -1
- package/dist/storage/domains/observability/v-next/trace-query.d.ts.map +1 -1
- package/package.json +3 -3
package/dist/docs/SKILL.md
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -18280,6 +18280,166 @@ async function queryThreads(client, schema, plan, timeoutMs) {
|
|
|
18280
18280
|
}) : null }
|
|
18281
18281
|
});
|
|
18282
18282
|
}
|
|
18283
|
+
/** Compile a span-row filter with exactly the same rules as trace span predicates. */
|
|
18284
|
+
function compileSpanQueryPredicate(predicate, offset) {
|
|
18285
|
+
return compileScalarPredicate(predicate, SPAN_FIELDS, offset);
|
|
18286
|
+
}
|
|
18287
|
+
//#endregion
|
|
18288
|
+
//#region src/storage/domains/observability/v-next/span-query.ts
|
|
18289
|
+
const identityFields = [
|
|
18290
|
+
"organizationId",
|
|
18291
|
+
"resourceId",
|
|
18292
|
+
"traceId",
|
|
18293
|
+
"spanId"
|
|
18294
|
+
];
|
|
18295
|
+
const fields = [
|
|
18296
|
+
...identityFields,
|
|
18297
|
+
"parentSpanId",
|
|
18298
|
+
"name",
|
|
18299
|
+
"spanType",
|
|
18300
|
+
"entityType",
|
|
18301
|
+
"entityId",
|
|
18302
|
+
"entityName",
|
|
18303
|
+
"entityVersionId",
|
|
18304
|
+
"parentEntityVersionId",
|
|
18305
|
+
"rootEntityVersionId",
|
|
18306
|
+
"runId",
|
|
18307
|
+
"sessionId",
|
|
18308
|
+
"userId"
|
|
18309
|
+
];
|
|
18310
|
+
const identities = identityFields.map((field) => `"${field}"`).join(", ");
|
|
18311
|
+
const identityOrder = identityFields.map((field) => `"${field}" COLLATE "C" ASC NULLS LAST`).join(", ");
|
|
18312
|
+
function selectedKeys(rows, values) {
|
|
18313
|
+
return rows.map((row) => `(${identityFields.map((field) => {
|
|
18314
|
+
values.push(row[field]);
|
|
18315
|
+
return `"${field}" ${field === "traceId" || field === "spanId" ? "=" : "IS NOT DISTINCT FROM"} $${values.length}::text`;
|
|
18316
|
+
}).join(" AND ")})`).join(" OR ");
|
|
18317
|
+
}
|
|
18318
|
+
function afterCursor(plan, values) {
|
|
18319
|
+
if (!plan.cursor) return "TRUE";
|
|
18320
|
+
const cursor = plan.cursor;
|
|
18321
|
+
values.push(cursor.sortValue);
|
|
18322
|
+
const timestamp = `$${values.length}::timestamptz`;
|
|
18323
|
+
const field = `s."${plan.orderBy.field}"`;
|
|
18324
|
+
const terms = [`${field} ${plan.orderBy.direction === "asc" ? ">" : "<"} ${timestamp}`];
|
|
18325
|
+
const equal = [`${field} = ${timestamp}`];
|
|
18326
|
+
for (const key of identityFields) {
|
|
18327
|
+
const ref = `s."${key}" COLLATE "C"`;
|
|
18328
|
+
const value = cursor[key];
|
|
18329
|
+
if (value === null) equal.push(`${ref} IS NULL`);
|
|
18330
|
+
else {
|
|
18331
|
+
values.push(value);
|
|
18332
|
+
const parameter = `$${values.length}::text COLLATE "C"`;
|
|
18333
|
+
terms.push(`(${equal.join(" AND ")} AND (${ref} > ${parameter} OR ${ref} IS NULL))`);
|
|
18334
|
+
equal.push(`${ref} = ${parameter}`);
|
|
18335
|
+
}
|
|
18336
|
+
}
|
|
18337
|
+
return `(${terms.join(" OR ")})`;
|
|
18338
|
+
}
|
|
18339
|
+
function compilePostgresSpanQuery(schema, plan) {
|
|
18340
|
+
const values = [plan.timeRange.from, plan.timeRange.to];
|
|
18341
|
+
const scope = [];
|
|
18342
|
+
if (plan.scope) {
|
|
18343
|
+
values.push(plan.scope.organizationId);
|
|
18344
|
+
scope.push(`"organizationId" = $${values.length}`);
|
|
18345
|
+
if (plan.scope.resourceId !== void 0) {
|
|
18346
|
+
values.push(plan.scope.resourceId);
|
|
18347
|
+
scope.push(`"resourceId" = $${values.length}`);
|
|
18348
|
+
}
|
|
18349
|
+
}
|
|
18350
|
+
const predicate = plan.where ? compileSpanQueryPredicate(plan.where, values.length + 1) : {
|
|
18351
|
+
sql: "TRUE",
|
|
18352
|
+
values: []
|
|
18353
|
+
};
|
|
18354
|
+
values.push(...predicate.values);
|
|
18355
|
+
const after = afterCursor(plan, values);
|
|
18356
|
+
values.push(plan.limit + 1);
|
|
18357
|
+
const table = qualifiedTable(schema, TABLE_SPAN_EVENTS);
|
|
18358
|
+
return {
|
|
18359
|
+
text: `WITH candidate_ids AS MATERIALIZED (
|
|
18360
|
+
SELECT DISTINCT ${identities} FROM ${table}
|
|
18361
|
+
WHERE "startedAt" >= $1 AND "startedAt" < $2 AND "endedAt" >= $1 AND NOT "isPending"
|
|
18362
|
+
${scope.length ? `AND ${scope.join(" AND ")}` : ""}
|
|
18363
|
+
), current_spans AS MATERIALIZED (
|
|
18364
|
+
SELECT DISTINCT ON (${identities})
|
|
18365
|
+
${fields.map((field) => `"${field}"`).join(", ")}, "startedAt", "endedAt", "cursorId"::text AS version,
|
|
18366
|
+
CASE WHEN jsonb_typeof(attributes -> 'model') = 'string' THEN attributes ->> 'model' END AS model,
|
|
18367
|
+
CASE WHEN jsonb_typeof(attributes -> 'provider') = 'string' THEN attributes ->> 'provider' END AS provider,
|
|
18368
|
+
(EXTRACT(EPOCH FROM ("endedAt" - "startedAt")) * 1000)::float8 AS "durationMs",
|
|
18369
|
+
CASE WHEN error IS NULL THEN 'success' ELSE 'error' END AS status,
|
|
18370
|
+
error IS NOT NULL AS "hasError"
|
|
18371
|
+
FROM ${table} e
|
|
18372
|
+
WHERE NOT "isPending" AND "endedAt" >= $1 AND (
|
|
18373
|
+
"organizationId" IS NULL, COALESCE("organizationId", ''), "resourceId" IS NULL, COALESCE("resourceId", ''), "traceId", "spanId"
|
|
18374
|
+
) IN (
|
|
18375
|
+
SELECT "organizationId" IS NULL, COALESCE("organizationId", ''), "resourceId" IS NULL, COALESCE("resourceId", ''), "traceId", "spanId" FROM candidate_ids
|
|
18376
|
+
) ${scope.length ? `AND ${scope.join(" AND ")}` : ""}
|
|
18377
|
+
ORDER BY ${identities}, "endedAt" DESC, "cursorId" DESC
|
|
18378
|
+
), candidates AS (
|
|
18379
|
+
SELECT *, CASE WHEN "hasError" THEN 'error' ELSE NULL END AS error FROM current_spans
|
|
18380
|
+
)
|
|
18381
|
+
SELECT ${[
|
|
18382
|
+
...identityFields,
|
|
18383
|
+
"parentSpanId",
|
|
18384
|
+
"name",
|
|
18385
|
+
"spanType",
|
|
18386
|
+
"entityType",
|
|
18387
|
+
"entityId",
|
|
18388
|
+
"entityName",
|
|
18389
|
+
"model",
|
|
18390
|
+
"provider",
|
|
18391
|
+
"startedAt",
|
|
18392
|
+
"endedAt",
|
|
18393
|
+
"durationMs",
|
|
18394
|
+
"status",
|
|
18395
|
+
"version"
|
|
18396
|
+
].map((field) => `s."${field}"`).join(", ")}
|
|
18397
|
+
FROM candidates s WHERE s."startedAt" >= $1 AND s."startedAt" < $2 AND (${predicate.sql}) AND ${after}
|
|
18398
|
+
ORDER BY s."${plan.orderBy.field}" ${plan.orderBy.direction === "asc" ? "ASC" : "DESC"}, ${identityOrder}
|
|
18399
|
+
LIMIT $${values.length}`,
|
|
18400
|
+
values
|
|
18401
|
+
};
|
|
18402
|
+
}
|
|
18403
|
+
async function querySpans(client, schema, plan, timeoutMs) {
|
|
18404
|
+
const deadline = performance.now() + _mastra_core_storage.resolveTraceQueryTimeoutMs(timeoutMs);
|
|
18405
|
+
return runWithPostgresTraceQueryTimeout(client, timeoutMs, async (tx) => {
|
|
18406
|
+
const query = compilePostgresSpanQuery(schema, plan);
|
|
18407
|
+
const rows = await tx.any(query.text, query.values);
|
|
18408
|
+
const selected = rows.map(({ version: _version, startedAt, endedAt, ...row }) => ({
|
|
18409
|
+
...row,
|
|
18410
|
+
startedAt: startedAt.toISOString(),
|
|
18411
|
+
endedAt: endedAt.toISOString()
|
|
18412
|
+
}));
|
|
18413
|
+
const page = rows.slice(0, plan.limit);
|
|
18414
|
+
if (!page.length) return _mastra_core_storage.buildSpanQueryResponse(plan, selected, [], []);
|
|
18415
|
+
const remaining = async () => {
|
|
18416
|
+
const ms = Math.floor(deadline - performance.now());
|
|
18417
|
+
if (ms <= 0) throw new _mastra_core_storage.TraceQueryExecutionError();
|
|
18418
|
+
await tx.query(`SELECT set_config('statement_timeout', $1, true)`, [`${ms}ms`]);
|
|
18419
|
+
};
|
|
18420
|
+
await remaining();
|
|
18421
|
+
const payloadValues = [];
|
|
18422
|
+
const payloadWhere = page.map((row) => {
|
|
18423
|
+
const key = selectedKeys([row], payloadValues);
|
|
18424
|
+
payloadValues.push(row.version);
|
|
18425
|
+
return `(${key} AND "cursorId" = $${payloadValues.length}::bigint)`;
|
|
18426
|
+
}).join(" OR ");
|
|
18427
|
+
const payloads = await tx.any(`SELECT ${identities},
|
|
18428
|
+
left(input::text, ${_mastra_core_storage.SPAN_QUERY_MAX_PREVIEW_CHARACTERS + 1}) AS "inputPreview", left(output::text, ${_mastra_core_storage.SPAN_QUERY_MAX_PREVIEW_CHARACTERS + 1}) AS "outputPreview"
|
|
18429
|
+
FROM ${qualifiedTable(schema, TABLE_SPAN_EVENTS)} WHERE ${payloadWhere}`, payloadValues);
|
|
18430
|
+
await remaining();
|
|
18431
|
+
const metricValues = [];
|
|
18432
|
+
const metricWhere = selectedKeys(page, metricValues);
|
|
18433
|
+
const metrics = await tx.any(`SELECT ${identities}, name, "estimatedCost", "costUnit",
|
|
18434
|
+
"costMetadata" ->> 'allocation' AS allocation, COALESCE("costMetadata" ? 'error', false) AS "costError"
|
|
18435
|
+
FROM (SELECT DISTINCT ON (${identities}, "metricId") ${identities}, name, "estimatedCost", "costUnit", "costMetadata" FROM ${qualifiedTable(schema, TABLE_METRIC_EVENTS)}
|
|
18436
|
+
WHERE (${metricWhere}) AND name LIKE 'mastra_model_%'
|
|
18437
|
+
ORDER BY ${identities}, "metricId", "cursorId" DESC) m
|
|
18438
|
+
LIMIT ${_mastra_core_storage.SPAN_QUERY_MAX_COST_METRICS + 1}`, metricValues);
|
|
18439
|
+
if (metrics.length > _mastra_core_storage.SPAN_QUERY_MAX_COST_METRICS) throw new _mastra_core_storage.TraceQueryResourceLimitError();
|
|
18440
|
+
return _mastra_core_storage.buildSpanQueryResponse(plan, selected, payloads, metrics);
|
|
18441
|
+
}, { repeatableRead: true });
|
|
18442
|
+
}
|
|
18283
18443
|
//#endregion
|
|
18284
18444
|
//#region src/storage/domains/observability/v-next/trace-aggregate.ts
|
|
18285
18445
|
/** Trace-root column expressions (alias `r`) for each groupable dimension; same values `where` sees. */
|
|
@@ -18348,13 +18508,32 @@ function compilePostgresTraceAggregate(schema, plan) {
|
|
|
18348
18508
|
if (intervalMs === void 0) throw new Error(`Unsupported trusted trace-aggregate interval: ${plan.interval}`);
|
|
18349
18509
|
factColumns.push(`to_timestamp(floor(EXTRACT(EPOCH FROM r."startedAt") * 1000 / ${intervalMs}) * ${intervalMs} / 1000.0) AS "bucket"`);
|
|
18350
18510
|
}
|
|
18511
|
+
const measureKinds = new Set(plan.measures.map((measure) => measureRule(measure.name)?.kind));
|
|
18512
|
+
const hasCost = measureKinds.has("cost");
|
|
18513
|
+
let usageJoin = "";
|
|
18514
|
+
if (hasCost || measureKinds.has("tokens")) {
|
|
18515
|
+
ctes.push(...compileUsageCtes(schema, plan, param));
|
|
18516
|
+
usageJoin = "\n LEFT JOIN usage u ON u.\"traceId\" = r.\"traceId\"";
|
|
18517
|
+
USAGE_METRIC_NAMES.forEach((_, index) => factColumns.push(`CASE WHEN u."traceId" IS NOT NULL THEN COALESCE(u."t${index}", 0) END AS "t${index}"`));
|
|
18518
|
+
factColumns.push(`u."traceId" IS NOT NULL AS "usageBearing"`, `CASE WHEN u."priced" THEN u."cost" END AS "traceCost"`, `COALESCE(u."priced" AND NOT u."pricingFailure", FALSE) AS "covered"`, `u."unitMin"`, `u."unitMax"`);
|
|
18519
|
+
}
|
|
18351
18520
|
ctes.push(`facts AS (
|
|
18352
18521
|
SELECT ${factColumns.join(",\n ")}
|
|
18353
|
-
FROM candidates r
|
|
18522
|
+
FROM candidates r${usageJoin}
|
|
18354
18523
|
)`);
|
|
18524
|
+
const mixedUnitsSql = (alias) => `MIN(${alias}"unitMin" COLLATE "C") <> MAX(${alias}"unitMax" COLLATE "C")`;
|
|
18355
18525
|
const measureSql = (name, alias = "") => {
|
|
18356
18526
|
const column = (name) => `${alias}"${name}"`;
|
|
18357
18527
|
if (name === "count") return "COUNT(*)::float8";
|
|
18528
|
+
const rule = measureRule(name);
|
|
18529
|
+
if (rule?.kind === "tokens" && rule.metricNames) {
|
|
18530
|
+
const value = rule.metricNames.map((metricName) => column(`t${usageMetricIndex(metricName)}`)).join(" + ");
|
|
18531
|
+
return `(${rule.statistic === "avg" ? "AVG" : "SUM"}(${value}))::float8`;
|
|
18532
|
+
}
|
|
18533
|
+
if (rule?.kind === "cost") {
|
|
18534
|
+
const aggregate = rule.statistic === "avg" ? "AVG" : "SUM";
|
|
18535
|
+
return `(CASE WHEN ${mixedUnitsSql(alias)} THEN NULL ELSE ${aggregate}(${column("traceCost")}) END)::float8`;
|
|
18536
|
+
}
|
|
18358
18537
|
if (name === "errorCount") return `(COUNT(*) FILTER (WHERE ${column("isError")}))::float8`;
|
|
18359
18538
|
if (name === "errorRate") return `(COUNT(*) FILTER (WHERE ${column("isError")}))::float8 / COUNT(*)`;
|
|
18360
18539
|
if (name === "duration.avg") return `AVG(${column("durationMs")})`;
|
|
@@ -18392,8 +18571,17 @@ function compilePostgresTraceAggregate(schema, plan) {
|
|
|
18392
18571
|
const orderSql = [`${orderTarget} ${direction} NULLS LAST`, ...dimensionColumns.map((column) => `${column} COLLATE "C" ASC NULLS LAST`)].join(", ");
|
|
18393
18572
|
const groupSql = dimensionColumns.length > 0 ? dimensionColumns.join(", ") : "()";
|
|
18394
18573
|
const limitParameter = param(plan.limit + 1);
|
|
18574
|
+
const costColumns = (alias) => {
|
|
18575
|
+
if (!hasCost) return [];
|
|
18576
|
+
const mixedUnit = param(_mastra_core_storage.TRACE_AGGREGATE_MIXED_COST_UNIT);
|
|
18577
|
+
return [`(COUNT(*) FILTER (WHERE ${alias}"covered"))::float8 / NULLIF(COUNT(*) FILTER (WHERE ${alias}"usageBearing"), 0) AS "costCoverage"`, `CASE WHEN ${mixedUnitsSql(alias)} THEN ${mixedUnit}::text ELSE MIN(${alias}"unitMin" COLLATE "C") END AS "costUnit"`];
|
|
18578
|
+
};
|
|
18395
18579
|
if (plan.interval === void 0) {
|
|
18396
|
-
const projected = [
|
|
18580
|
+
const projected = [
|
|
18581
|
+
...dimensionColumns,
|
|
18582
|
+
...plan.measures.map((measure, index) => `${measureSql(measure.name)} AS "m${index}"`),
|
|
18583
|
+
...costColumns("")
|
|
18584
|
+
];
|
|
18397
18585
|
return {
|
|
18398
18586
|
text: `WITH ${ctes.join(",\n")}
|
|
18399
18587
|
SELECT ${projected.join(", ")}
|
|
@@ -18419,6 +18607,7 @@ LIMIT ${limitParameter}`,
|
|
|
18419
18607
|
...dimensionColumns.map((column) => `f.${column}`),
|
|
18420
18608
|
"f.\"bucket\"",
|
|
18421
18609
|
...plan.measures.map((measure, index) => `${measureSql(measure.name, "f.")} AS "m${index}"`),
|
|
18610
|
+
...costColumns("f."),
|
|
18422
18611
|
`(SELECT COUNT(*) FROM ranked) > ${maxRankParameter} AS "truncated"`
|
|
18423
18612
|
];
|
|
18424
18613
|
return {
|
|
@@ -18436,6 +18625,59 @@ ORDER BY g."rank" ASC, f."bucket" ASC`,
|
|
|
18436
18625
|
values
|
|
18437
18626
|
};
|
|
18438
18627
|
}
|
|
18628
|
+
const USAGE_METRIC_NAMES = _mastra_core_storage.TRACE_AGGREGATE_USAGE_METRIC_NAMES;
|
|
18629
|
+
function measureRule(name) {
|
|
18630
|
+
return _mastra_core_storage.isTraceAggregateCanonicalMeasure(name) ? _mastra_core_storage.TRACE_AGGREGATE_MEASURE_REGISTRY[name] : void 0;
|
|
18631
|
+
}
|
|
18632
|
+
function usageMetricIndex(name) {
|
|
18633
|
+
const index = USAGE_METRIC_NAMES.indexOf(name);
|
|
18634
|
+
if (index === -1) throw new Error(`Unsupported trusted trace-aggregate token metric: ${name}`);
|
|
18635
|
+
return index;
|
|
18636
|
+
}
|
|
18637
|
+
/**
|
|
18638
|
+
* Builds `usage`: one row per candidate trace that has at least one token metric row, holding
|
|
18639
|
+
* per-name token sums (`t<i>`, indexed by `TRACE_AGGREGATE_USAGE_METRIC_NAMES`) and the trace's
|
|
18640
|
+
* pricing state. Metric rows are matched by traceId, usage metric name, tenant scope, and
|
|
18641
|
+
* `timestamp >= from` only: a trace that starts in the window can emit metrics after `to`, and
|
|
18642
|
+
* the candidates semi-join already bounds the scan.
|
|
18643
|
+
*
|
|
18644
|
+
* Rows are deduplicated on `metricId` alone. The primary key is (`metricId`, `timestamp`)
|
|
18645
|
+
* because the table is partitioned by timestamp, so retried copies with different timestamps
|
|
18646
|
+
* are both stored.
|
|
18647
|
+
*/
|
|
18648
|
+
function compileUsageCtes(schema, plan, param) {
|
|
18649
|
+
const scopeConditions = plan.scope ? [`m."organizationId" = ${param(plan.scope.organizationId)}`, ...plan.scope.resourceId === void 0 ? [] : [`m."resourceId" = ${param(plan.scope.resourceId)}`]] : [];
|
|
18650
|
+
const rowConditions = [
|
|
18651
|
+
`m."traceId" IN (SELECT "traceId" FROM candidates)`,
|
|
18652
|
+
`m."name" = ANY(${param(USAGE_METRIC_NAMES)}::text[])`,
|
|
18653
|
+
`m."timestamp" >= ${param(plan.timeRange.from)}::timestamptz`,
|
|
18654
|
+
...scopeConditions
|
|
18655
|
+
];
|
|
18656
|
+
const costRow = `"name" = ANY(${param(_mastra_core_storage.TRACE_AGGREGATE_COST_METRIC_NAMES)}::text[])`;
|
|
18657
|
+
const priced = `${costRow} AND "estimatedCost" IS NOT NULL AND "costUnit" IS NOT NULL AND NOT "hasError"`;
|
|
18658
|
+
const failed = `${costRow} AND ("hasError" OR ("estimatedCost" IS NOT NULL AND "costUnit" IS NULL))`;
|
|
18659
|
+
const tokenColumns = USAGE_METRIC_NAMES.map((name, index) => `SUM("value") FILTER (WHERE "name" = ${param(name)}) AS "t${index}"`);
|
|
18660
|
+
return [`usage_rows AS (
|
|
18661
|
+
SELECT DISTINCT ON (m."metricId") m."traceId", m."name", m."value", m."estimatedCost", m."costUnit",
|
|
18662
|
+
COALESCE(jsonb_typeof(m."costMetadata" -> 'error'), 'null') <> 'null' AS "hasError"
|
|
18663
|
+
FROM ${qualifiedTable(schema, TABLE_METRIC_EVENTS)} m
|
|
18664
|
+
WHERE ${rowConditions.join("\n AND ")}
|
|
18665
|
+
ORDER BY m."metricId", m."timestamp"
|
|
18666
|
+
)`, `usage AS (
|
|
18667
|
+
SELECT "traceId",
|
|
18668
|
+
${tokenColumns.join(",\n ")},
|
|
18669
|
+
SUM("estimatedCost") FILTER (WHERE ${priced}) AS "cost",
|
|
18670
|
+
bool_or(${priced}) AS "priced",
|
|
18671
|
+
bool_or(${failed}) AS "pricingFailure",
|
|
18672
|
+
MIN("costUnit" COLLATE "C") FILTER (WHERE ${priced}) AS "unitMin",
|
|
18673
|
+
MAX("costUnit" COLLATE "C") FILTER (WHERE ${priced}) AS "unitMax"
|
|
18674
|
+
FROM usage_rows
|
|
18675
|
+
GROUP BY "traceId"
|
|
18676
|
+
)`];
|
|
18677
|
+
}
|
|
18678
|
+
function nullableNumber(value) {
|
|
18679
|
+
return value === null || value === void 0 ? null : Number(value);
|
|
18680
|
+
}
|
|
18439
18681
|
function toIsoTimestamp(value) {
|
|
18440
18682
|
return value instanceof Date ? value.toISOString() : new Date(value).toISOString();
|
|
18441
18683
|
}
|
|
@@ -18453,7 +18695,11 @@ async function aggregateTraces(client, schema, plan, timeoutMs) {
|
|
|
18453
18695
|
}
|
|
18454
18696
|
return {
|
|
18455
18697
|
rows: resultRows.map((row) => {
|
|
18456
|
-
const shaped = { measures: Object.fromEntries(plan.measures.map((measure, index) => [measure.name,
|
|
18698
|
+
const shaped = { measures: Object.fromEntries(plan.measures.map((measure, index) => [measure.name, nullableNumber(row[`m${index}`])])) };
|
|
18699
|
+
if ("costCoverage" in row) shaped.cost = {
|
|
18700
|
+
coverage: nullableNumber(row.costCoverage),
|
|
18701
|
+
unit: row.costUnit ?? null
|
|
18702
|
+
};
|
|
18457
18703
|
if (plan.dimensions.length > 0) shaped.dimensions = Object.fromEntries(plan.dimensions.map((dimension, index) => [dimension, row[`d${index}`] ?? null]));
|
|
18458
18704
|
if (plan.interval !== void 0) shaped.bucket = toIsoTimestamp(row.bucket);
|
|
18459
18705
|
return shaped;
|
|
@@ -19175,6 +19421,7 @@ async function dangerouslyClearTracing(client, schema) {
|
|
|
19175
19421
|
* application database — observability writes will degrade app performance.
|
|
19176
19422
|
* Use it through `MastraCompositeStore` with a dedicated Postgres connection.
|
|
19177
19423
|
*/
|
|
19424
|
+
const spanQueryFeatures = typeof _mastra_core_storage.planSpanQuery === "function" ? ["span-query"] : [];
|
|
19178
19425
|
function wrapError(op, error, details) {
|
|
19179
19426
|
if (error instanceof _mastra_core_error.MastraError || error instanceof _mastra_core_storage.TraceQueryCursorError || error instanceof _mastra_core_storage.TraceQueryExecutionError || error instanceof _mastra_core_storage.TraceQueryResourceLimitError) throw error;
|
|
19180
19427
|
throw new _mastra_core_error.MastraError({
|
|
@@ -19364,6 +19611,7 @@ var ObservabilityStoragePostgresVNext = class ObservabilityStoragePostgresVNext
|
|
|
19364
19611
|
"metric-discovery",
|
|
19365
19612
|
"trace-query",
|
|
19366
19613
|
"trace-aggregate",
|
|
19614
|
+
...spanQueryFeatures,
|
|
19367
19615
|
"trace-query-root-duration",
|
|
19368
19616
|
"trace-query-discovery",
|
|
19369
19617
|
"thread-query",
|
|
@@ -19383,6 +19631,7 @@ var ObservabilityStoragePostgresVNext = class ObservabilityStoragePostgresVNext
|
|
|
19383
19631
|
"delta-polling",
|
|
19384
19632
|
"trace-query",
|
|
19385
19633
|
"trace-aggregate",
|
|
19634
|
+
...spanQueryFeatures,
|
|
19386
19635
|
"trace-query-root-duration",
|
|
19387
19636
|
"trace-query-discovery",
|
|
19388
19637
|
"thread-query",
|
|
@@ -19431,6 +19680,9 @@ var ObservabilityStoragePostgresVNext = class ObservabilityStoragePostgresVNext
|
|
|
19431
19680
|
async listTraces(args) {
|
|
19432
19681
|
return this.#run("LIST_TRACES", () => listTraces(this.#readClient, this.#schema, args));
|
|
19433
19682
|
}
|
|
19683
|
+
async querySpans(plan) {
|
|
19684
|
+
return this.#run("QUERY_SPANS", () => querySpans(this.#readClient, this.#schema, plan, this.#traceQueryTimeoutMs));
|
|
19685
|
+
}
|
|
19434
19686
|
async queryTraces(plan) {
|
|
19435
19687
|
return this.#run("QUERY_TRACES", () => queryTraces(this.#readClient, this.#schema, plan, this.#traceQueryTimeoutMs));
|
|
19436
19688
|
}
|