@mastra/clickhouse 1.26.0 → 1.27.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/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/index.cjs +234 -32
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +234 -32
- package/dist/index.js.map +1 -1
- package/dist/storage/domains/observability/v-next/ddl.d.ts.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 +34 -1
- package/dist/storage/domains/observability/v-next/span-query.d.ts.map +1 -1
- package/dist/storage/domains/observability/v-next/trace-aggregate.d.ts +7 -1
- 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 +1 -1
- package/dist/storage/domains/observability/v-next/trace-query.d.ts.map +1 -1
- package/package.json +6 -6
package/dist/docs/SKILL.md
CHANGED
|
@@ -3,7 +3,7 @@ name: mastra-clickhouse
|
|
|
3
3
|
description: Documentation for @mastra/clickhouse. Use when working with @mastra/clickhouse APIs, configuration, or implementation.
|
|
4
4
|
metadata:
|
|
5
5
|
package: "@mastra/clickhouse"
|
|
6
|
-
version: "1.
|
|
6
|
+
version: "1.27.0-alpha.0"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
## When to use
|
package/dist/index.cjs
CHANGED
|
@@ -3671,6 +3671,9 @@ const ALL_MIGRATIONS = [
|
|
|
3671
3671
|
addColumn(TABLE_SPAN_EVENTS, "inputPreview", "Nullable(String)"),
|
|
3672
3672
|
addColumn(TABLE_SPAN_EVENTS, "outputPreview", "Nullable(String)"),
|
|
3673
3673
|
addColumn(TABLE_SPAN_EVENTS, "errorPreview", "Nullable(String)"),
|
|
3674
|
+
addColumn(TABLE_TRACE_BRANCHES, "entityVersionId", "Nullable(String)"),
|
|
3675
|
+
addColumn(TABLE_TRACE_BRANCHES, "parentEntityVersionId", "Nullable(String)"),
|
|
3676
|
+
addColumn(TABLE_TRACE_BRANCHES, "rootEntityVersionId", "Nullable(String)"),
|
|
3674
3677
|
addColumn(TABLE_SPAN_EVENTS, "entityVersionId", "Nullable(String)"),
|
|
3675
3678
|
addColumn(TABLE_SPAN_EVENTS, "parentEntityVersionId", "Nullable(String)"),
|
|
3676
3679
|
addColumn(TABLE_SPAN_EVENTS, "rootEntityVersionId", "Nullable(String)"),
|
|
@@ -8012,8 +8015,7 @@ async function queryThreads(client, plan, timeoutMs) {
|
|
|
8012
8015
|
});
|
|
8013
8016
|
}
|
|
8014
8017
|
/** Compile a direct span-query filter using its dedicated field mapping. */
|
|
8015
|
-
function compileSpanQueryPredicate(predicate) {
|
|
8016
|
-
const parameters = new ParameterBuilder();
|
|
8018
|
+
function compileSpanQueryPredicate(predicate, parameters = new ParameterBuilder()) {
|
|
8017
8019
|
return {
|
|
8018
8020
|
sql: compileScalarPredicate(predicate, SPAN_QUERY_FIELDS, parameters),
|
|
8019
8021
|
params: parameters.params
|
|
@@ -8174,6 +8176,131 @@ function compileClickHouseSpanQuery(plan) {
|
|
|
8174
8176
|
}
|
|
8175
8177
|
};
|
|
8176
8178
|
}
|
|
8179
|
+
const branchSpanTypes = new Set(BRANCH_SPAN_TYPE_VALUES);
|
|
8180
|
+
const sameColumn = (field) => [field];
|
|
8181
|
+
/**
|
|
8182
|
+
* Span fields `trace_branches` can serve, as the `trace_branches` columns each one reads. The two
|
|
8183
|
+
* tables are expected to diverge, so this list is explicit: a selection whose fields are not all
|
|
8184
|
+
* listed reads `span_events`. A new span-query field has to be classified here deliberately, and a
|
|
8185
|
+
* missing column then costs speed, not correctness.
|
|
8186
|
+
*/
|
|
8187
|
+
const TRACE_BRANCHES_SPAN_FIELD_COLUMNS = {
|
|
8188
|
+
...Object.fromEntries([
|
|
8189
|
+
"organizationId",
|
|
8190
|
+
"resourceId",
|
|
8191
|
+
"traceId",
|
|
8192
|
+
"spanId",
|
|
8193
|
+
"parentSpanId",
|
|
8194
|
+
"name",
|
|
8195
|
+
"spanType",
|
|
8196
|
+
"startedAt",
|
|
8197
|
+
"endedAt",
|
|
8198
|
+
"timeToFirstChunkMs",
|
|
8199
|
+
"threadId",
|
|
8200
|
+
"runId",
|
|
8201
|
+
"sessionId",
|
|
8202
|
+
"userId",
|
|
8203
|
+
"requestId",
|
|
8204
|
+
"serviceName",
|
|
8205
|
+
"experimentId",
|
|
8206
|
+
"environment",
|
|
8207
|
+
"executionSource",
|
|
8208
|
+
"entityType",
|
|
8209
|
+
"entityId",
|
|
8210
|
+
"entityName",
|
|
8211
|
+
"entityVersionId",
|
|
8212
|
+
"parentEntityType",
|
|
8213
|
+
"parentEntityId",
|
|
8214
|
+
"parentEntityName",
|
|
8215
|
+
"parentEntityVersionId",
|
|
8216
|
+
"rootEntityType",
|
|
8217
|
+
"rootEntityId",
|
|
8218
|
+
"rootEntityName",
|
|
8219
|
+
"rootEntityVersionId"
|
|
8220
|
+
].map((field) => [field, sameColumn(field)])),
|
|
8221
|
+
status: ["error"],
|
|
8222
|
+
error: ["error"],
|
|
8223
|
+
durationMs: ["startedAt", "endedAt"]
|
|
8224
|
+
};
|
|
8225
|
+
/**
|
|
8226
|
+
* Whether a span selection reads `trace_branches`: `where` must restrict `spanType` to branch
|
|
8227
|
+
* types, and `trace_branches` must serve every selected field (`served`, for tests).
|
|
8228
|
+
*/
|
|
8229
|
+
function readsTraceBranches(where, fields, served = TRACE_BRANCHES_SPAN_FIELD_COLUMNS) {
|
|
8230
|
+
return positiveSpanConjuncts(where).some(({ field, values }) => field === "spanType" && values.length > 0 && values.every((value) => branchSpanTypes.has(String(value)))) && [...fields].every((field) => Object.hasOwn(served, field));
|
|
8231
|
+
}
|
|
8232
|
+
/**
|
|
8233
|
+
* Top-level `spanType` / `name` equality or `in` conditions. Every span the predicate can match
|
|
8234
|
+
* satisfies them, and copies of a span never differ in either field, so they can be applied
|
|
8235
|
+
* before collapsing copies.
|
|
8236
|
+
*/
|
|
8237
|
+
function positiveSpanConjuncts(where) {
|
|
8238
|
+
return (where?.type === "boolean" && where.operator === "and" ? where.args : where ? [where] : []).flatMap((conjunct) => {
|
|
8239
|
+
if (conjunct.type !== "comparison" && conjunct.type !== "membership") return [];
|
|
8240
|
+
if (conjunct.field !== "spanType" && conjunct.field !== "name") return [];
|
|
8241
|
+
if (conjunct.type === "comparison" && conjunct.operator === "eq") return [{
|
|
8242
|
+
field: conjunct.field,
|
|
8243
|
+
values: [conjunct.value]
|
|
8244
|
+
}];
|
|
8245
|
+
if (conjunct.type === "membership" && conjunct.operator === "in") return [{
|
|
8246
|
+
field: conjunct.field,
|
|
8247
|
+
values: conjunct.values
|
|
8248
|
+
}];
|
|
8249
|
+
return [];
|
|
8250
|
+
});
|
|
8251
|
+
}
|
|
8252
|
+
/**
|
|
8253
|
+
* The spans `querySpans()` selects, as CTEs ending in `selected` (alias each row as you like):
|
|
8254
|
+
* one row per current completed span with `startedAt` in the window, matching `where`, carrying
|
|
8255
|
+
* the identity, `startedAt`, `endedAt`, `status`, and `fields`.
|
|
8256
|
+
*
|
|
8257
|
+
* Copies of a span collapse to the copy with the latest `endedAt`. When `where` requires branch
|
|
8258
|
+
* span types (agent and workflow runs, tool calls, …) and `trace_branches` serves every selected
|
|
8259
|
+
* field, the spans are read from `trace_branches`, whose sort key starts with `spanType`, instead of
|
|
8260
|
+
* every span in the window. That path can differ from `querySpans()` in two ways:
|
|
8261
|
+
* - `trace_branches` is filled only by its materialized view, with no backfill, so an install that
|
|
8262
|
+
* upgraded from @mastra/clickhouse 1.4–1.6 has no branch rows for spans written before then.
|
|
8263
|
+
* - It is a `ReplacingMergeTree` without a version column, so once a background merge collapses a
|
|
8264
|
+
* retried span's copies it keeps the last-inserted copy, not the one with the latest `endedAt`.
|
|
8265
|
+
* Counts are unaffected; `status` and duration of an out-of-order retry can differ.
|
|
8266
|
+
*
|
|
8267
|
+
* Like `querySpans()`, the read has no upper bound on `endedAt` (`PREWHERE endedAt >= from` only,
|
|
8268
|
+
* since a span that starts in the window can end any time later), so a historical window reads
|
|
8269
|
+
* every span that ended since `from`.
|
|
8270
|
+
*/
|
|
8271
|
+
function compileClickHouseSpanSelection(plan, fields, parameters) {
|
|
8272
|
+
const from = parameters.add(plan.timeRange.from, "DateTime64(3, 'UTC')");
|
|
8273
|
+
const to = parameters.add(plan.timeRange.to, "DateTime64(3, 'UTC')");
|
|
8274
|
+
const prefilter = positiveSpanConjuncts(plan.where).map(({ field, values }) => values.length ? `\n AND e.${field} IN (${values.map((value) => parameters.add(String(value), "String")).join(", ")})` : "\n AND 0").join("");
|
|
8275
|
+
const predicate = plan.where ? compileSpanQueryPredicate(plan.where, parameters).sql : "1";
|
|
8276
|
+
let tenant = "";
|
|
8277
|
+
if (plan.scope) {
|
|
8278
|
+
tenant += `\n AND e.organizationId = ${parameters.add(plan.scope.organizationId, "String")}`;
|
|
8279
|
+
if (plan.scope.resourceId !== void 0) tenant += `\n AND e.resourceId = ${parameters.add(plan.scope.resourceId, "String")}`;
|
|
8280
|
+
}
|
|
8281
|
+
const selectionFields = [.../* @__PURE__ */ new Set([
|
|
8282
|
+
"startedAt",
|
|
8283
|
+
"endedAt",
|
|
8284
|
+
"status",
|
|
8285
|
+
...fields,
|
|
8286
|
+
...predicateFields$1(plan.where)
|
|
8287
|
+
])].filter((field) => !new Set(identityFields).has(field));
|
|
8288
|
+
const branches = readsTraceBranches(plan.where, selectionFields);
|
|
8289
|
+
const scan = `FROM ${branches ? TABLE_TRACE_BRANCHES : TABLE_SPAN_EVENTS} e
|
|
8290
|
+
PREWHERE e.endedAt >= ${from}
|
|
8291
|
+
WHERE e.startedAt >= ${from} AND e.startedAt < ${to}${tenant}${prefilter}`;
|
|
8292
|
+
return [`span_candidates AS (
|
|
8293
|
+
${branches ? `SELECT ${identityFields.map((field) => `e.${field} AS ${field}`).join(", ")}, ${selectionFields.map((field) => field === "endedAt" ? "max(e.endedAt) AS endedAt" : `argMax(tuple(${fieldExpression(field)}), e.endedAt).1 AS ${field}`).join(", ")}
|
|
8294
|
+
${scan}
|
|
8295
|
+
GROUP BY ${identityFields.map((field) => `e.${field}`).join(", ")}` : `SELECT ${identities}, ${selectionFields.map((field) => `${fieldExpression(field)} AS ${field}`).join(", ")}
|
|
8296
|
+
${scan}
|
|
8297
|
+
ORDER BY ${identities}, e.endedAt DESC
|
|
8298
|
+
LIMIT 1 BY ${identities}`}
|
|
8299
|
+
)`, `selected AS (
|
|
8300
|
+
SELECT * FROM span_candidates s
|
|
8301
|
+
WHERE s.startedAt >= ${from} AND s.startedAt < ${to} AND (${predicate})
|
|
8302
|
+
)`];
|
|
8303
|
+
}
|
|
8177
8304
|
const LEGACY_PAYLOAD_BATCH_ROWS = 32;
|
|
8178
8305
|
function iso$1(value) {
|
|
8179
8306
|
return new Date(value.includes("T") ? value : `${value.replace(" ", "T")}Z`).toISOString();
|
|
@@ -8577,6 +8704,28 @@ const DIMENSION_SQL = {
|
|
|
8577
8704
|
organizationId: "r.organizationId",
|
|
8578
8705
|
experimentId: "r.experimentId"
|
|
8579
8706
|
};
|
|
8707
|
+
/** Span column expressions (alias `r`, a `selected` span row) for each groupable span dimension. */
|
|
8708
|
+
const SPAN_DIMENSION_SQL = Object.fromEntries([
|
|
8709
|
+
"name",
|
|
8710
|
+
"spanType",
|
|
8711
|
+
"entityType",
|
|
8712
|
+
"entityId",
|
|
8713
|
+
"entityName",
|
|
8714
|
+
"parentEntityType",
|
|
8715
|
+
"parentEntityName",
|
|
8716
|
+
"rootEntityType",
|
|
8717
|
+
"rootEntityName",
|
|
8718
|
+
"environment",
|
|
8719
|
+
"status",
|
|
8720
|
+
"serviceName",
|
|
8721
|
+
"executionSource",
|
|
8722
|
+
"threadId",
|
|
8723
|
+
"resourceId",
|
|
8724
|
+
"userId",
|
|
8725
|
+
"sessionId",
|
|
8726
|
+
"organizationId",
|
|
8727
|
+
"experimentId"
|
|
8728
|
+
].map((field) => [field, `r.${field}`]));
|
|
8580
8729
|
const PERCENTILES = {
|
|
8581
8730
|
"duration.p50": .5,
|
|
8582
8731
|
"duration.p90": .9,
|
|
@@ -8603,13 +8752,41 @@ const COMPARISON_SQL = {
|
|
|
8603
8752
|
*/
|
|
8604
8753
|
function compileClickHouseTraceAggregate(plan) {
|
|
8605
8754
|
const parameters = new ParameterBuilder();
|
|
8606
|
-
|
|
8607
|
-
|
|
8608
|
-
|
|
8609
|
-
|
|
8610
|
-
|
|
8611
|
-
|
|
8612
|
-
|
|
8755
|
+
return compileClickHouseAggregate(plan, parameters, {
|
|
8756
|
+
ctes: compileClickHouseTraceCandidates(plan, "*", parameters, { oneRootPerTrace: true }),
|
|
8757
|
+
from: "candidates",
|
|
8758
|
+
dimensionSql: (field) => {
|
|
8759
|
+
if (field.startsWith("metadata.")) return traceMetadataValueSql(parameters.add(field.slice(9), "String"));
|
|
8760
|
+
return lookupDimensionSql(DIMENSION_SQL, field);
|
|
8761
|
+
},
|
|
8762
|
+
isErrorSql: "isNotNull(r.error)",
|
|
8763
|
+
usageKey: ["traceId"],
|
|
8764
|
+
usageBound: "traceId IN (SELECT traceId FROM candidates)"
|
|
8765
|
+
});
|
|
8766
|
+
}
|
|
8767
|
+
/**
|
|
8768
|
+
* Compiles a trusted span aggregate plan over the spans `querySpans()` selects. Usage is
|
|
8769
|
+
* attributed by `(traceId, spanId)`, so only the span that recorded a metric row carries it.
|
|
8770
|
+
*/
|
|
8771
|
+
function compileClickHouseSpanAggregate(plan) {
|
|
8772
|
+
const parameters = new ParameterBuilder();
|
|
8773
|
+
return compileClickHouseAggregate(plan, parameters, {
|
|
8774
|
+
ctes: compileClickHouseSpanSelection(plan, [...plan.dimensions, ...plan.measures.flatMap((measure) => measure.type === "countDistinct" && measure.field !== "traceId" ? [measure.field] : [])], parameters),
|
|
8775
|
+
from: "selected",
|
|
8776
|
+
dimensionSql: (field) => lookupDimensionSql(SPAN_DIMENSION_SQL, field),
|
|
8777
|
+
isErrorSql: "r.status = 'error'",
|
|
8778
|
+
usageKey: ["traceId", "spanId"],
|
|
8779
|
+
usageBound: "isNotNull(spanId)"
|
|
8780
|
+
});
|
|
8781
|
+
}
|
|
8782
|
+
function lookupDimensionSql(columns, field) {
|
|
8783
|
+
const sql = Object.hasOwn(columns, field) ? columns[field] : void 0;
|
|
8784
|
+
if (sql === void 0) throw new Error(`Unsupported trusted aggregate field: ${field}`);
|
|
8785
|
+
return sql;
|
|
8786
|
+
}
|
|
8787
|
+
function compileClickHouseAggregate(plan, parameters, source) {
|
|
8788
|
+
const { ctes } = source;
|
|
8789
|
+
const dimensionSql = source.dimensionSql;
|
|
8613
8790
|
const distinctSql = (field) => field === "traceId" ? "r.traceId" : dimensionSql(field);
|
|
8614
8791
|
const dimensionColumns = plan.dimensions.map((_, index) => `d${index}`);
|
|
8615
8792
|
const distinctColumns = /* @__PURE__ */ new Map();
|
|
@@ -8620,7 +8797,7 @@ function compileClickHouseTraceAggregate(plan) {
|
|
|
8620
8797
|
distinctColumns.set(measure.field, column);
|
|
8621
8798
|
factColumns.push(`CAST(${distinctSql(measure.field)} AS Nullable(String)) AS ${column}`);
|
|
8622
8799
|
}
|
|
8623
|
-
factColumns.push(`toFloat64(${durationMsSql("r.startedAt", "r.endedAt")}) AS durationMs`,
|
|
8800
|
+
factColumns.push(`toFloat64(${durationMsSql("r.startedAt", "r.endedAt")}) AS durationMs`, `${source.isErrorSql} AS isError`, `cityHash64(${source.usageKey.map((column) => `r.${column}`).join(", ")}) AS traceSeed`);
|
|
8624
8801
|
if (plan.interval !== void 0) {
|
|
8625
8802
|
const intervalMs = _mastra_core_storage.TRACE_AGGREGATE_INTERVAL_MS[plan.interval];
|
|
8626
8803
|
if (intervalMs === void 0) throw new Error(`Unsupported trusted trace-aggregate interval: ${plan.interval}`);
|
|
@@ -8630,14 +8807,14 @@ function compileClickHouseTraceAggregate(plan) {
|
|
|
8630
8807
|
const hasCost = measureKinds.has("cost");
|
|
8631
8808
|
let usageJoin = "";
|
|
8632
8809
|
if (hasCost || measureKinds.has("tokens")) {
|
|
8633
|
-
ctes.push(compileUsageCte(plan, parameters));
|
|
8634
|
-
usageJoin =
|
|
8810
|
+
ctes.push(compileUsageCte(plan, parameters, source));
|
|
8811
|
+
usageJoin = `\n LEFT JOIN usage u ON ${source.usageKey.map((column) => `u.${column} = r.${column}`).join(" AND ")}`;
|
|
8635
8812
|
USAGE_METRIC_NAMES.forEach((_, index) => factColumns.push(`if(u.hasUsage = 1, u.t${index}, NULL) AS t${index}`));
|
|
8636
8813
|
factColumns.push(`u.hasUsage = 1 AS usageBearing`, `if(u.hasUsage = 1 AND u.priced = 1, u.cost, NULL) AS traceCost`, `u.hasUsage = 1 AND u.priced = 1 AND u.pricingFailure = 0 AS covered`, `if(u.hasUsage = 1 AND u.priced = 1, u.unitMin, NULL) AS unitMin`, `if(u.hasUsage = 1 AND u.priced = 1, u.unitMax, NULL) AS unitMax`);
|
|
8637
8814
|
}
|
|
8638
8815
|
ctes.push(`facts AS (
|
|
8639
8816
|
SELECT ${factColumns.join(",\n ")}
|
|
8640
|
-
FROM
|
|
8817
|
+
FROM ${source.from} r${usageJoin}
|
|
8641
8818
|
)`);
|
|
8642
8819
|
const mixedUnitsSql = "minOrNull(unitMin) != maxOrNull(unitMax)";
|
|
8643
8820
|
const measureSql = (name) => {
|
|
@@ -8752,26 +8929,28 @@ function usageMetricIndex(name) {
|
|
|
8752
8929
|
return index;
|
|
8753
8930
|
}
|
|
8754
8931
|
/**
|
|
8755
|
-
* Builds `usage`: one row per
|
|
8756
|
-
* per-name token sums (`t<i>`, indexed by `TRACE_AGGREGATE_USAGE_METRIC_NAMES`) and
|
|
8757
|
-
* pricing state. Metric rows are matched by
|
|
8758
|
-
* `timestamp >= from` only: a trace that starts in the window can emit
|
|
8759
|
-
* the
|
|
8932
|
+
* Builds `usage`: one row per usage key (a trace, or a span) that has at least one token metric
|
|
8933
|
+
* row, holding per-name token sums (`t<i>`, indexed by `TRACE_AGGREGATE_USAGE_METRIC_NAMES`) and
|
|
8934
|
+
* its pricing state. Metric rows are matched by the source's usage bound, usage metric name,
|
|
8935
|
+
* tenant scope, and `timestamp >= from` only: a trace or span that starts in the window can emit
|
|
8936
|
+
* metrics after `to`. For spans that makes the read cost grow with the age of `from` (see
|
|
8937
|
+
* `usageBound`).
|
|
8760
8938
|
*
|
|
8761
8939
|
* Rows are deduplicated with `LIMIT 1 BY metricId` at query time. `ReplacingMergeTree` only
|
|
8762
8940
|
* collapses rows with equal sort keys `(name, timestamp, metricId)`, so retried copies with
|
|
8763
8941
|
* different timestamps never merge, and copies with equal keys stay separate until a background
|
|
8764
8942
|
* merge runs.
|
|
8765
8943
|
*/
|
|
8766
|
-
function compileUsageCte(plan, parameters) {
|
|
8944
|
+
function compileUsageCte(plan, parameters, source) {
|
|
8945
|
+
const key = source.usageKey.join(", ");
|
|
8767
8946
|
const names = USAGE_METRIC_NAMES.map((name) => parameters.add(name, "String"));
|
|
8768
8947
|
const costRow = `name IN (${_mastra_core_storage.TRACE_AGGREGATE_COST_METRIC_NAMES.map((name) => names[usageMetricIndex(name)]).join(", ")})`;
|
|
8769
8948
|
const from = parameters.add(plan.timeRange.from, "DateTime64(3, 'UTC')");
|
|
8770
8949
|
const tenant = compileTenantScope(plan.scope, parameters);
|
|
8771
|
-
const priced = `${costRow} AND isNotNull(estimatedCost) AND isNotNull(costUnit) AND NOT hasError`;
|
|
8950
|
+
const priced = `${costRow} AND isNotNull(estimatedCost) AND isNotNull(costUnit) AND (NOT hasError OR partialCost)`;
|
|
8772
8951
|
const failed = `${costRow} AND (hasError OR (isNotNull(estimatedCost) AND isNull(costUnit)))`;
|
|
8773
8952
|
return `usage AS (
|
|
8774
|
-
SELECT
|
|
8953
|
+
SELECT ${key},
|
|
8775
8954
|
toUInt8(1) AS hasUsage,
|
|
8776
8955
|
${names.map((name, index) => `sumIf(value, name = ${name}) AS t${index}`).join(",\n ")},
|
|
8777
8956
|
sumIf(assumeNotNull(estimatedCost), ${priced}) AS cost,
|
|
@@ -8780,34 +8959,42 @@ function compileUsageCte(plan, parameters) {
|
|
|
8780
8959
|
minIf(assumeNotNull(costUnit), ${priced}) AS unitMin,
|
|
8781
8960
|
maxIf(assumeNotNull(costUnit), ${priced}) AS unitMax
|
|
8782
8961
|
FROM (
|
|
8783
|
-
SELECT
|
|
8962
|
+
SELECT ${key},
|
|
8784
8963
|
latest.1 AS name,
|
|
8785
8964
|
latest.2 AS value,
|
|
8786
8965
|
latest.3 AS estimatedCost,
|
|
8787
8966
|
latest.4 AS costUnit,
|
|
8788
|
-
latest.5 AS hasError
|
|
8967
|
+
latest.5 AS hasError,
|
|
8968
|
+
latest.6 AS partialCost
|
|
8789
8969
|
FROM (
|
|
8790
|
-
SELECT
|
|
8791
|
-
argMax(tuple(name, value, estimatedCost, costUnit, hasError), timestamp) AS latest
|
|
8970
|
+
SELECT ${key},
|
|
8971
|
+
argMax(tuple(name, value, estimatedCost, costUnit, hasError, partialCost), timestamp) AS latest
|
|
8792
8972
|
FROM (
|
|
8793
|
-
SELECT
|
|
8794
|
-
if(${costRow}, ifNull(JSONHas(costMetadata, 'error') AND JSONType(costMetadata, 'error') != 'Null', 0), 0) AS hasError
|
|
8973
|
+
SELECT ${key}, metricId, timestamp, name, value, estimatedCost, costUnit,
|
|
8974
|
+
if(${costRow}, ifNull(JSONHas(costMetadata, 'error') AND JSONType(costMetadata, 'error') != 'Null', 0), 0) AS hasError,
|
|
8975
|
+
if(${costRow}, ifNull(JSONExtractString(costMetadata, 'error') = 'partial_cost', 0), 0) AS partialCost
|
|
8795
8976
|
FROM ${TABLE_METRIC_EVENTS}
|
|
8796
|
-
WHERE
|
|
8977
|
+
WHERE ${source.usageBound}
|
|
8797
8978
|
AND name IN (${names.join(", ")})
|
|
8798
8979
|
AND timestamp >= ${from}${tenant}
|
|
8799
8980
|
)
|
|
8800
|
-
GROUP BY
|
|
8981
|
+
GROUP BY ${key}, metricId
|
|
8801
8982
|
)
|
|
8802
8983
|
)
|
|
8803
|
-
GROUP BY
|
|
8984
|
+
GROUP BY ${key}
|
|
8804
8985
|
)`;
|
|
8805
8986
|
}
|
|
8806
8987
|
function nullableNumber(value) {
|
|
8807
8988
|
return value === null || value === void 0 ? null : Number(value);
|
|
8808
8989
|
}
|
|
8809
|
-
|
|
8810
|
-
|
|
8990
|
+
function aggregateTraces(client, plan, timeoutMs) {
|
|
8991
|
+
return runAggregate(client, plan, compileClickHouseTraceAggregate(plan), timeoutMs);
|
|
8992
|
+
}
|
|
8993
|
+
async function aggregateSpans(client, plan, timeoutMs) {
|
|
8994
|
+
return await runAggregate(client, plan, compileClickHouseSpanAggregate(plan), timeoutMs);
|
|
8995
|
+
}
|
|
8996
|
+
async function runAggregate(client, plan, compiled, timeoutMs) {
|
|
8997
|
+
const result = await runWithClickHouseTraceQueryTimeout(client, { timeoutMs }, compiled);
|
|
8811
8998
|
let truncated;
|
|
8812
8999
|
let resultRows;
|
|
8813
9000
|
if (plan.interval === void 0) {
|
|
@@ -9703,6 +9890,7 @@ function buildBranchCursor(row) {
|
|
|
9703
9890
|
//#endregion
|
|
9704
9891
|
//#region src/storage/domains/observability/v-next/index.ts
|
|
9705
9892
|
const spanQueryFeatures = typeof _mastra_core_storage.planSpanQuery === "function" ? ["span-query", "span-query-context-fields"] : [];
|
|
9893
|
+
const spanAggregateFeatures = typeof _mastra_core_storage.planSpanAggregate === "function" ? ["span-aggregate"] : [];
|
|
9706
9894
|
const threadQueryFeatures = typeof _mastra_core_storage.planThreadRowsQuery === "function" ? ["thread-query-rows"] : [];
|
|
9707
9895
|
function buildSignalMigrationRequiredMessage(args) {
|
|
9708
9896
|
const tableList = args.tables.map((table) => ` - ${table.table} (${table.engine})`).join("\n");
|
|
@@ -10146,6 +10334,7 @@ var ObservabilityStorageClickhouseVNext = class extends _mastra_core_storage.Obs
|
|
|
10146
10334
|
"trace-query-root-entity-id",
|
|
10147
10335
|
"trace-aggregate",
|
|
10148
10336
|
...spanQueryFeatures,
|
|
10337
|
+
...spanAggregateFeatures,
|
|
10149
10338
|
...threadQueryFeatures
|
|
10150
10339
|
];
|
|
10151
10340
|
return [
|
|
@@ -10170,6 +10359,7 @@ var ObservabilityStorageClickhouseVNext = class extends _mastra_core_storage.Obs
|
|
|
10170
10359
|
"trace-query-root-entity-id",
|
|
10171
10360
|
"trace-aggregate",
|
|
10172
10361
|
...spanQueryFeatures,
|
|
10362
|
+
...spanAggregateFeatures,
|
|
10173
10363
|
...threadQueryFeatures
|
|
10174
10364
|
];
|
|
10175
10365
|
}
|
|
@@ -10321,6 +10511,18 @@ var ObservabilityStorageClickhouseVNext = class extends _mastra_core_storage.Obs
|
|
|
10321
10511
|
}, error);
|
|
10322
10512
|
}
|
|
10323
10513
|
}
|
|
10514
|
+
async aggregateSpans(plan) {
|
|
10515
|
+
try {
|
|
10516
|
+
return await aggregateSpans(this.#client, plan, this.#traceQueryTimeoutMs);
|
|
10517
|
+
} catch (error) {
|
|
10518
|
+
if (error instanceof _mastra_core_error.MastraError || error instanceof _mastra_core_storage.TraceQueryExecutionError || error instanceof _mastra_core_storage.TraceQueryResourceLimitError) throw error;
|
|
10519
|
+
throw new _mastra_core_error.MastraError({
|
|
10520
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("CLICKHOUSE", "AGGREGATE_SPANS", "FAILED"),
|
|
10521
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
10522
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY
|
|
10523
|
+
}, error);
|
|
10524
|
+
}
|
|
10525
|
+
}
|
|
10324
10526
|
async getTraceQueryObservedFields(plan) {
|
|
10325
10527
|
try {
|
|
10326
10528
|
return await getTraceQueryObservedFields(this.#client, plan, this.#traceQueryDiscoveryLimits);
|