@mastra/clickhouse 1.26.0-alpha.4 → 1.26.0-alpha.5
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 +68 -50
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +68 -50
- package/dist/index.js.map +1 -1
- package/dist/storage/domains/observability/v-next/index.d.ts +1 -1
- package/dist/storage/domains/observability/v-next/index.d.ts.map +1 -1
- package/dist/storage/domains/observability/v-next/thread-query.d.ts.map +1 -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 +41 -15
- package/dist/storage/domains/observability/v-next/trace-query.d.ts.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -6901,6 +6901,10 @@ const TRACE_FIELDS = {
|
|
|
6901
6901
|
sql: "r.timeToFirstChunkMs",
|
|
6902
6902
|
parameterType: "Float64"
|
|
6903
6903
|
},
|
|
6904
|
+
entityId: {
|
|
6905
|
+
sql: "r.entityId",
|
|
6906
|
+
parameterType: "String"
|
|
6907
|
+
},
|
|
6904
6908
|
entityName: {
|
|
6905
6909
|
sql: "r.entityName",
|
|
6906
6910
|
parameterType: "String"
|
|
@@ -7299,6 +7303,28 @@ function compileTenantScope(scope, parameters) {
|
|
|
7299
7303
|
if (scope.resourceId !== void 0) sql += `\n AND resourceId = ${parameters.add(scope.resourceId, "String")}`;
|
|
7300
7304
|
return sql;
|
|
7301
7305
|
}
|
|
7306
|
+
/**
|
|
7307
|
+
* Order of the versions of one root span, current version first. `mastra_trace_roots` has no
|
|
7308
|
+
* version column, so until a background merge runs, every export of a root is its own row with the
|
|
7309
|
+
* same sort key, and merges never meet versions that ended on different days (it is partitioned by
|
|
7310
|
+
* `endedAt`). The version that ended last is current, as a resumed or completed root is exported
|
|
7311
|
+
* again with a later `endedAt`; a pending copy stores `endedAt = startedAt` and can lack `threadId`,
|
|
7312
|
+
* so a copy with a thread wins an equal-time tie. Remaining ties are broken by insertion order, last
|
|
7313
|
+
* insert first: the part's first block number, then the row's offset in the part. Tied versions
|
|
7314
|
+
* share a partition and sort key, so a merge meets them and keeps the last insert too, and reads
|
|
7315
|
+
* pick the same version before and after it. Both are virtual columns, so the order reads nothing
|
|
7316
|
+
* beyond `endedAt` and `threadId`.
|
|
7317
|
+
*
|
|
7318
|
+
* Merges don't follow this order across `endedAt`: within one day's partition a merge keeps the last
|
|
7319
|
+
* insert, not the version that ended last. If an outdated export of a root is redelivered after its
|
|
7320
|
+
* current version, on the same day, reads pick the current version until a merge, and the outdated
|
|
7321
|
+
* one afterwards (last write wins, as in the PG and DuckDB stores). Making merges keep the version
|
|
7322
|
+
* that ended last needs `ReplacingMergeTree(endedAt)`, a schema change.
|
|
7323
|
+
*
|
|
7324
|
+
* Every root collapse uses this order: trace rows, aggregates, thread rows and the discovery reads.
|
|
7325
|
+
*/
|
|
7326
|
+
const ROOT_VERSION_ORDER = `endedAt DESC, isNotNull(threadId) DESC, toUInt64(splitByChar('_', _part)[2]) DESC,
|
|
7327
|
+
_part_offset DESC`;
|
|
7302
7328
|
function compileClickHouseTraceScope(selection, relationCollections, parameters, scope, seedConjuncts = [], options = {}) {
|
|
7303
7329
|
const from = parameters.add(selection.timeRange.from, "DateTime64(3, 'UTC')");
|
|
7304
7330
|
const to = parameters.add(selection.timeRange.to, "DateTime64(3, 'UTC')");
|
|
@@ -7322,7 +7348,15 @@ function compileClickHouseTraceScope(selection, relationCollections, parameters,
|
|
|
7322
7348
|
SELECT *
|
|
7323
7349
|
FROM ${TABLE_TRACE_ROOTS} r
|
|
7324
7350
|
WHERE startedAt >= ${from}
|
|
7325
|
-
AND startedAt < ${to}${tenant}${
|
|
7351
|
+
AND startedAt < ${to}${tenant}${bound}${seedFilter ? `
|
|
7352
|
+
AND traceId IN (
|
|
7353
|
+
SELECT traceId
|
|
7354
|
+
FROM ${TABLE_TRACE_ROOTS} r
|
|
7355
|
+
WHERE startedAt >= ${from}
|
|
7356
|
+
AND startedAt < ${to}${tenant}${seedFilter}
|
|
7357
|
+
)` : ""}
|
|
7358
|
+
ORDER BY startedAt, traceId, spanId, ${ROOT_VERSION_ORDER}
|
|
7359
|
+
LIMIT 1 BY traceId
|
|
7326
7360
|
)`] : [`current_roots AS (
|
|
7327
7361
|
SELECT *
|
|
7328
7362
|
FROM ${TABLE_TRACE_ROOTS}
|
|
@@ -7332,7 +7366,7 @@ function compileClickHouseTraceScope(selection, relationCollections, parameters,
|
|
|
7332
7366
|
WHERE startedAt >= ${from}
|
|
7333
7367
|
AND startedAt < ${to}${tenant}${seedFilter}
|
|
7334
7368
|
)${tenant}
|
|
7335
|
-
ORDER BY traceId,
|
|
7369
|
+
ORDER BY traceId, startedAt, spanId, ${ROOT_VERSION_ORDER}
|
|
7336
7370
|
LIMIT 1 BY traceId
|
|
7337
7371
|
)`, `root_scope AS (
|
|
7338
7372
|
SELECT *
|
|
@@ -7462,11 +7496,7 @@ function traceOrder(plan) {
|
|
|
7462
7496
|
direction: plan.orderBy.direction === "asc" ? "ASC" : "DESC"
|
|
7463
7497
|
};
|
|
7464
7498
|
}
|
|
7465
|
-
/**
|
|
7466
|
-
* Keyset cursor on a trace's sort value. Applied after each trace is reduced to one sort value:
|
|
7467
|
-
* filtering root rows first would let a trace with several roots (or unmerged copies with
|
|
7468
|
-
* different `endedAt`) come back on a later page under a root that sorts after the cursor.
|
|
7469
|
-
*/
|
|
7499
|
+
/** Keyset cursor on a trace's sort value (the current root's), with traceId breaking ties. */
|
|
7470
7500
|
function keysetCursorCondition(plan, order, parameters) {
|
|
7471
7501
|
if (plan.paginationMode !== "keyset" || !plan.cursor) return "";
|
|
7472
7502
|
if (plan.cursor.sortValue === null) return `(isNull(sortValue) AND traceId > ${parameters.add(plan.cursor.traceId, "String")})`;
|
|
@@ -7477,9 +7507,8 @@ function keysetCursorCondition(plan, order, parameters) {
|
|
|
7477
7507
|
}
|
|
7478
7508
|
/**
|
|
7479
7509
|
* First statement of keyset and page mode: the page's traces (after the keyset cursor, `limit + 1`
|
|
7480
|
-
* for keyset mode, `perPage` at the page offset for page mode) as
|
|
7481
|
-
* number of matching traces on every row.
|
|
7482
|
-
* value and the key, so the key always names a row with that sort value. No blob columns are read.
|
|
7510
|
+
* for keyset mode, `perPage` at the page offset for page mode) as keys of their current roots, and
|
|
7511
|
+
* the number of matching traces on every row. No blob columns are read.
|
|
7483
7512
|
*/
|
|
7484
7513
|
function compileClickHouseTraceQueryKeys(plan) {
|
|
7485
7514
|
if (plan.paginationMode === "delta") throw new Error("Delta trace queries have no keys statement");
|
|
@@ -7487,19 +7516,12 @@ function compileClickHouseTraceQueryKeys(plan) {
|
|
|
7487
7516
|
const order = traceOrder(plan);
|
|
7488
7517
|
const ctes = compileClickHouseTraceCandidates(plan, "r.traceId AS traceId, r.dedupeKey AS dedupeKey, r.startedAt AS startedAt, r.endedAt AS endedAt, r.timeToFirstChunkMs AS timeToFirstChunkMs", parameters, QUERY_TRACES_SCOPE);
|
|
7489
7518
|
const cursor = keysetCursorCondition(plan, order, parameters);
|
|
7490
|
-
const pick = order.direction === "DESC" ? "max" : "min";
|
|
7491
|
-
const rootOrder = order.field === "timeToFirstChunkMs" ? `ifNull(${order.field}, ${pick === "max" ? "-inf" : "inf"})` : order.field;
|
|
7492
7519
|
const limit = plan.paginationMode === "page" ? `LIMIT ${parameters.add(plan.perPage, "UInt64")} OFFSET ${parameters.add(plan.page * plan.perPage, "UInt64")}` : `LIMIT ${parameters.add(plan.limit + 1, "UInt64")}`;
|
|
7493
7520
|
return {
|
|
7494
|
-
query: `WITH ${ctes.join(",\n")}
|
|
7495
|
-
|
|
7496
|
-
|
|
7497
|
-
|
|
7498
|
-
FROM candidates
|
|
7499
|
-
GROUP BY traceId${cursor ? `\n HAVING ${cursor}` : ""}
|
|
7500
|
-
)
|
|
7501
|
-
SELECT traceId, root.1 AS dedupeKey, sortValue, root.2 AS rootStartedAt, count() OVER () AS __total
|
|
7502
|
-
FROM per_trace
|
|
7521
|
+
query: `WITH ${ctes.join(",\n")}
|
|
7522
|
+
SELECT traceId, dedupeKey, ${order.field} AS sortValue, startedAt AS rootStartedAt, endedAt AS rootEndedAt,
|
|
7523
|
+
count() OVER () AS __total
|
|
7524
|
+
FROM candidates${cursor ? `\nWHERE ${cursor}` : ""}
|
|
7503
7525
|
ORDER BY sortValue ${order.direction} NULLS LAST, traceId ASC
|
|
7504
7526
|
${limit}`,
|
|
7505
7527
|
query_params: parameters.params,
|
|
@@ -7507,27 +7529,28 @@ ${limit}`,
|
|
|
7507
7529
|
};
|
|
7508
7530
|
}
|
|
7509
7531
|
/**
|
|
7510
|
-
* Second statement of keyset and page mode: the rows of the keyed roots, with `metadata`
|
|
7511
|
-
*
|
|
7512
|
-
*
|
|
7513
|
-
*
|
|
7532
|
+
* Second statement of keyset and page mode: the rows of the keyed roots, with `metadata` and the
|
|
7533
|
+
* stored previews, read by sort key and `endedAt`, so only the keyed version's rows match. Versions
|
|
7534
|
+
* that end at the same instant are ordered as in the keys statement (ROOT_VERSION_ORDER). The
|
|
7535
|
+
* relation-free `where` conjuncts are re-applied, so a version written between the two statements
|
|
7536
|
+
* that doesn't match isn't returned.
|
|
7537
|
+
*
|
|
7538
|
+
* Trade-off of matching on `endedAt`: if a newer version is written between the two statements and
|
|
7539
|
+
* a same-day merge then drops the keyed version, the trace has no row and drops off the page. Without
|
|
7540
|
+
* `endedAt` the lookup would find the replacement, but could also return a version other than the
|
|
7541
|
+
* keyed one whenever both are unmerged. The window is the gap between the two statements.
|
|
7514
7542
|
*/
|
|
7515
7543
|
function compileClickHouseTraceRowsByKey(plan, keys) {
|
|
7516
7544
|
const parameters = new ParameterBuilder();
|
|
7517
7545
|
const order = traceOrder(plan);
|
|
7518
7546
|
const ts = (value) => parameters.add(value, "DateTime64(3, 'UTC')");
|
|
7519
|
-
const
|
|
7520
|
-
const tuples = keys.map((key) => {
|
|
7521
|
-
const started = ts(key.rootStartedAt);
|
|
7522
|
-
const id = `${parameters.add(key.traceId, "String")}, ${parameters.add(key.dedupeKey, "String")}`;
|
|
7523
|
-
return byEnd ? `(${started}, ${id}, ${ts(String(key.sortValue))})` : `(${started}, ${id})`;
|
|
7524
|
-
});
|
|
7547
|
+
const tuples = keys.map((key) => `(${ts(key.rootStartedAt)}, ${parameters.add(key.traceId, "String")}, ${parameters.add(key.dedupeKey, "String")}, ${ts(key.rootEndedAt)})`);
|
|
7525
7548
|
const predicate = (plan.where ? (plan.where.type === "boolean" && plan.where.operator === "and" ? plan.where.args : [plan.where]).filter((conjunct) => collectRelationCollections(conjunct).size === 0) : []).map((conjunct) => `\n AND (${compilePredicate(conjunct, parameters)})`).join("");
|
|
7526
7549
|
return {
|
|
7527
7550
|
query: `SELECT ${TRACE_SELECT}
|
|
7528
7551
|
FROM ${TABLE_TRACE_ROOTS} r
|
|
7529
|
-
WHERE (r.startedAt, r.traceId, r.dedupeKey
|
|
7530
|
-
ORDER BY ${order.field} ${order.direction} NULLS LAST, traceId ASC
|
|
7552
|
+
WHERE (r.startedAt, r.traceId, r.dedupeKey, r.endedAt) IN (${tuples.join(", ")})${compileTenantScope(plan.scope, parameters)}${predicate}
|
|
7553
|
+
ORDER BY ${order.field} ${order.direction} NULLS LAST, traceId ASC, ${ROOT_VERSION_ORDER}
|
|
7531
7554
|
LIMIT 1 BY traceId`,
|
|
7532
7555
|
query_params: parameters.params
|
|
7533
7556
|
};
|
|
@@ -7546,9 +7569,7 @@ FROM candidates`,
|
|
|
7546
7569
|
/**
|
|
7547
7570
|
* The list statement of groups and delta mode (rows without `metadata` and the previews). Keyset
|
|
7548
7571
|
* and page mode list with compileClickHouseTraceQueryKeys and compileClickHouseTraceRowsByKey.
|
|
7549
|
-
*
|
|
7550
|
-
* mode under the row that sorts first in the list order, as in the keys statement; ties go to the
|
|
7551
|
-
* lowest dedupeKey, then the latest endedAt, so every poll picks the same row.
|
|
7572
|
+
* Candidates hold one current root per trace, as in the keys statement.
|
|
7552
7573
|
*/
|
|
7553
7574
|
function compileClickHouseTraceQuery(plan, deltaHead) {
|
|
7554
7575
|
const parameters = new ParameterBuilder();
|
|
@@ -7569,7 +7590,6 @@ LIMIT ${limit}`,
|
|
|
7569
7590
|
};
|
|
7570
7591
|
}
|
|
7571
7592
|
if (plan.paginationMode !== "delta") throw new Error("Keyset and page trace queries use compileClickHouseTraceQueryKeys and compileClickHouseTraceRowsByKey");
|
|
7572
|
-
const order = traceOrder(plan);
|
|
7573
7593
|
const watermark = coreStorage.getTraceQueryDeltaWatermark(plan, "clickhouse");
|
|
7574
7594
|
const after = watermark ? parseDeltaWatermark(watermark) : {
|
|
7575
7595
|
cursorId: "0",
|
|
@@ -7588,8 +7608,7 @@ LIMIT ${limit}`,
|
|
|
7588
7608
|
SELECT c.*, toString(d.latestCursorId) AS __delta_cursor
|
|
7589
7609
|
FROM candidates c
|
|
7590
7610
|
INNER JOIN delta_candidates d ON c.traceId = d.traceId
|
|
7591
|
-
ORDER BY d.latestCursorId ASC, c.traceId ASC
|
|
7592
|
-
LIMIT 1 BY c.traceId
|
|
7611
|
+
ORDER BY d.latestCursorId ASC, c.traceId ASC
|
|
7593
7612
|
LIMIT ${limit}`,
|
|
7594
7613
|
query_params: parameters.params,
|
|
7595
7614
|
sharedSnapshot: true
|
|
@@ -7633,6 +7652,7 @@ function compileClickHouseTraceRootPayloads(keys, scope, columns = "payload") {
|
|
|
7633
7652
|
query: `SELECT traceId, spanId AS rootSpanId, dedupeKey, organizationId, resourceId, ${columns === "payload" ? `metadataRaw AS metadata, ${PREVIEW_COLUMNS.join(", ")}` : "input, output, error"}
|
|
7634
7653
|
FROM ${TABLE_TRACE_ROOTS}
|
|
7635
7654
|
WHERE (startedAt, traceId, dedupeKey, endedAt, ifNull(organizationId, ''), isNull(organizationId), ifNull(resourceId, ''), isNull(resourceId)) IN (${tuples.join(", ")})${compileTenantScope(scope, parameters)}
|
|
7655
|
+
ORDER BY ${ROOT_VERSION_ORDER}
|
|
7636
7656
|
LIMIT 1 BY traceId, dedupeKey, organizationId, resourceId`,
|
|
7637
7657
|
query_params: parameters.params
|
|
7638
7658
|
};
|
|
@@ -7929,7 +7949,8 @@ async function queryTraces(client, plan, timeoutMs, strategy = null) {
|
|
|
7929
7949
|
traceId: String(key.traceId),
|
|
7930
7950
|
dedupeKey: String(key.dedupeKey),
|
|
7931
7951
|
sortValue: sortValue(key.sortValue),
|
|
7932
|
-
rootStartedAt: asIsoTimestamp(key.rootStartedAt)
|
|
7952
|
+
rootStartedAt: asIsoTimestamp(key.rootStartedAt),
|
|
7953
|
+
rootEndedAt: asIsoTimestamp(key.rootEndedAt)
|
|
7933
7954
|
})))) : [];
|
|
7934
7955
|
if (plan.paginationMode === "page") return coreStorage.traceQueryResponseSchema.parse({
|
|
7935
7956
|
traces: await toTraceRecords(rows),
|
|
@@ -8338,7 +8359,7 @@ function compileClickHouseThreadRowsQuery(plan, strategy = "full") {
|
|
|
8338
8359
|
const sortedRoots = `roots AS (
|
|
8339
8360
|
SELECT organizationId, traceId, ${rootDataFields.map((field) => `${rootExpression(field)} AS ${field}`).join(", ")}
|
|
8340
8361
|
FROM ${TABLE_TRACE_ROOTS} ${scope.length || strategy === "candidates" ? `WHERE ${[...scope, ...strategy === "candidates" ? [candidateTracesFilter] : []].join(" AND ")}` : ""}
|
|
8341
|
-
ORDER BY organizationId, traceId, startedAt ASC, spanId,
|
|
8362
|
+
ORDER BY organizationId, traceId, startedAt ASC, spanId, ${ROOT_VERSION_ORDER}
|
|
8342
8363
|
LIMIT 1 BY organizationId, traceId
|
|
8343
8364
|
)`;
|
|
8344
8365
|
return {
|
|
@@ -8440,7 +8461,7 @@ async function queryThreadRows(client, plan, timeoutMs, strategy = "auto") {
|
|
|
8440
8461
|
${contextFields.join(", ")}, if(spanType = 'agent_run', timeToFirstChunkMs, NULL) AS timeToFirstChunkMs,
|
|
8441
8462
|
if(isNull(error), 'success', 'error') AS status, ${PREVIEW_COLUMNS.join(", ")}
|
|
8442
8463
|
FROM ${TABLE_TRACE_ROOTS} WHERE ${rootWhere}
|
|
8443
|
-
ORDER BY
|
|
8464
|
+
ORDER BY ${ROOT_VERSION_ORDER} LIMIT 1 BY organizationId, traceId, spanId`,
|
|
8444
8465
|
query_params: { roots: keys(batch) }
|
|
8445
8466
|
}));
|
|
8446
8467
|
const byRoot = new Map(stored.map((row) => [rootKey(row), row]));
|
|
@@ -8448,7 +8469,7 @@ async function queryThreadRows(client, plan, timeoutMs, strategy = "auto") {
|
|
|
8448
8469
|
for (const batch of batches(missing, 32)) {
|
|
8449
8470
|
const payloads = await run({
|
|
8450
8471
|
query: `SELECT organizationId, traceId, spanId, input, output, error FROM ${TABLE_TRACE_ROOTS}
|
|
8451
|
-
WHERE ${rootWhere} ORDER BY
|
|
8472
|
+
WHERE ${rootWhere} ORDER BY ${ROOT_VERSION_ORDER} LIMIT 1 BY organizationId, traceId, spanId`,
|
|
8452
8473
|
query_params: { roots: keys(batch) }
|
|
8453
8474
|
});
|
|
8454
8475
|
for (const payload of payloads) {
|
|
@@ -8517,6 +8538,7 @@ const DIMENSION_SQL = {
|
|
|
8517
8538
|
entityName: "r.entityName",
|
|
8518
8539
|
name: "r.name",
|
|
8519
8540
|
spanType: "r.spanType",
|
|
8541
|
+
entityId: "r.entityId",
|
|
8520
8542
|
environment: "r.environment",
|
|
8521
8543
|
status: TRACE_STATUS_SQL,
|
|
8522
8544
|
serviceName: "r.serviceName",
|
|
@@ -8555,12 +8577,6 @@ const COMPARISON_SQL = {
|
|
|
8555
8577
|
function compileClickHouseTraceAggregate(plan) {
|
|
8556
8578
|
const parameters = new ParameterBuilder();
|
|
8557
8579
|
const ctes = compileClickHouseTraceCandidates(plan, "*", parameters, { oneRootPerTrace: true });
|
|
8558
|
-
ctes.push(`trace_roots AS (
|
|
8559
|
-
SELECT *
|
|
8560
|
-
FROM candidates
|
|
8561
|
-
ORDER BY traceId, dedupeKey
|
|
8562
|
-
LIMIT 1 BY traceId
|
|
8563
|
-
)`);
|
|
8564
8580
|
const dimensionSql = (field) => {
|
|
8565
8581
|
if (field.startsWith("metadata.")) return traceMetadataValueSql(parameters.add(field.slice(9), "String"));
|
|
8566
8582
|
const sql = Object.hasOwn(DIMENSION_SQL, field) ? DIMENSION_SQL[field] : void 0;
|
|
@@ -8594,7 +8610,7 @@ function compileClickHouseTraceAggregate(plan) {
|
|
|
8594
8610
|
}
|
|
8595
8611
|
ctes.push(`facts AS (
|
|
8596
8612
|
SELECT ${factColumns.join(",\n ")}
|
|
8597
|
-
FROM
|
|
8613
|
+
FROM candidates r${usageJoin}
|
|
8598
8614
|
)`);
|
|
8599
8615
|
const mixedUnitsSql = "minOrNull(unitMin) != maxOrNull(unitMax)";
|
|
8600
8616
|
const measureSql = (name) => {
|
|
@@ -10100,6 +10116,7 @@ var ObservabilityStorageClickhouseVNext = class extends ObservabilityStorage {
|
|
|
10100
10116
|
"trace-query-context-ids",
|
|
10101
10117
|
...timeToFirstChunkFeatures,
|
|
10102
10118
|
"trace-query-root-span-fields",
|
|
10119
|
+
"trace-query-root-entity-id",
|
|
10103
10120
|
"trace-aggregate",
|
|
10104
10121
|
...spanQueryFeatures,
|
|
10105
10122
|
...threadQueryFeatures
|
|
@@ -10123,6 +10140,7 @@ var ObservabilityStorageClickhouseVNext = class extends ObservabilityStorage {
|
|
|
10123
10140
|
"trace-query-context-ids",
|
|
10124
10141
|
...timeToFirstChunkFeatures,
|
|
10125
10142
|
"trace-query-root-span-fields",
|
|
10143
|
+
"trace-query-root-entity-id",
|
|
10126
10144
|
"trace-aggregate",
|
|
10127
10145
|
...spanQueryFeatures,
|
|
10128
10146
|
...threadQueryFeatures
|