查詢指標
Mastra 透過三種介面提供相同的五種 OLAP 查詢(getMetricAggregate、getMetricBreakdown、getMetricTimeSeries、getMetricPercentiles 及探索輔助函式):處理程序內儲存區存取器、執行階段 HTTP API,以及 mastra api metric CLI。三者接受相同且經 Zod 驗證的輸入格式,因此你可以從一次性的 CLI 調查轉移到程式化的儀表板 Tool,而不必重新學習 API。
適用情境「適用情境」的直接連結
- 在 Studio 旁建立自訂儀表板或 KPI 圖塊。
- 建立排程警示,在 token 成本或延遲超過臨界值時觸發。
- 為 Agent 提供能讀取自身效能指標並在聊天中解釋的 Tool。
- 從終端機使用
mastra api metric ...進行一次性調查。
若要設定可觀測性儲存區本身,請參閱指標總覽。若要查看可查詢的指標名稱清單,請參閱自動指標參考。
指標查詢由可觀測性領域提供,因此需要支援 OLAP 的儲存區(本機使用 DuckDB,正式環境使用 ClickHouse)。設定方式請參閱指標總覽。若未設定可觀測性儲存區,getStore('observability') 會回傳 null。
介面「介面」的直接連結
處理程序內「處理程序內」的直接連結
在 Tool、伺服器路由或 Workflow 步驟內,從 Mastra 儲存空間取得可觀測性儲存區:
import { createTool } from '@mastra/core/tools'
import { z } from 'zod'
export const agentLatencyTool = createTool({
id: 'agentLatency',
description: 'Average agent latency over the last hour.',
inputSchema: z.object({}),
execute: async (_input, context) => {
const observability = await context.mastra!.getStorage()!.getStore('observability')
if (!observability) {
throw new Error('Observability domain is not configured (requires DuckDB or ClickHouse)')
}
const result = await observability.getMetricAggregate({
name: ['mastra_agent_duration_ms'],
aggregation: 'avg',
filters: {
timestamp: { start: new Date(Date.now() - 60 * 60 * 1000) },
},
})
return { averageMs: result.value }
},
})
當設定的後端不支援 OLAP 查詢時,getStore('observability') 會回傳 null。
HTTP「HTTP」的直接連結
mastra dev 伺服器(以及任何已部署的 Mastra 執行階段)會在 /api/observability/metrics/* 下提供相同的查詢。彙總、細分、時間序列及百分位數端點會使用 POST 接收 JSON 內文。探索端點則使用帶有查詢參數的 GET。
curl -sS -X POST http://localhost:4111/api/observability/metrics/aggregate \
-H "content-type: application/json" \
-d '{"name":["mastra_agent_duration_ms"],"aggregation":"avg"}'
可用路由:
POST /api/observability/metrics/aggregatePOST /api/observability/metrics/breakdownPOST /api/observability/metrics/timeseriesPOST /api/observability/metrics/percentilesGET /api/observability/metrics(原始資料列、分頁)GET /api/observability/discovery/metric-namesGET /api/observability/discovery/metric-label-keysGET /api/observability/discovery/metric-label-values
@mastra/client-js SDK 將相同路由封裝為 mastraClient.getMetricAggregate(...)、getMetricBreakdown(...) 等方法。
CLI「CLI」的直接連結
mastra api metric ... 以單一 JSON 引數呼叫相同端點,因此 Agent 或 shell 指令碼無須撰寫任何程式碼即可擷取指標:
mastra api metric aggregate \
'{"name":["mastra_agent_duration_ms"],"aggregation":"avg"}' \
--url http://localhost:4111
CLI 預設以託管的 Mastra 可觀測性服務(https://observability.mastra.ai)為目標。傳入 --url http://localhost:4111 即可查詢本機 mastra dev 伺服器。完整命令清單請參閱 mastra api metric aggregate 及其相鄰項目。
查詢「查詢」的直接連結
getMetricAggregate「getmetricaggregate」的直接連結
回傳單一純量,是 KPI 卡片的基礎元件。
輸入:
name:由一或多個指標名稱組成的陣列。aggregation:'sum' | 'avg' | 'min' | 'max' | 'count' | 'count_distinct' | 'last'之一。filters:選用的篩選器物件。comparePeriod:選用的'previous_period' | 'previous_day' | 'previous_week',用於逐期比較。
回應:
value、previousValue、changePercent。- token 指標會包含
estimatedCost、costUnit、previousEstimatedCost、costChangePercent。
const observability = await mastra.getStorage()!.getStore('observability')
const cost = await observability!.getMetricAggregate({
name: ['mastra_model_total_input_tokens', 'mastra_model_total_output_tokens'],
aggregation: 'sum',
comparePeriod: 'previous_day',
})
console.log(cost.value, cost.estimatedCost, cost.costUnit, cost.changePercent)
getMetricBreakdown「getmetricbreakdown」的直接連結
依一或多個維度將資料列分組,並彙總每個群組,是前 N 名表格(例如「各 Agent 的 token 數」)的基礎元件。
輸入:
name:指標名稱陣列。groupBy:作為分組依據的欄位陣列(例如['entityName'])。aggregation:與上述相同的列舉值。limit:伺服器端的前 K 名上限。高基數groupBy必須提供此值。orderDirection:'ASC' | 'DESC'(預設為DESC)。filters:選用。
回應:groups[],每個群組包含 dimensions(群組鍵值的記錄)、value 與 estimatedCost。
const byAgent = await observability!.getMetricBreakdown({
name: ['mastra_model_total_input_tokens'],
groupBy: ['entityName'],
aggregation: 'sum',
limit: 10,
orderDirection: 'DESC',
})
getMetricTimeSeries「getmetrictimeseries」的直接連結
依固定間隔將值分桶,是折線圖及長條圖的基礎元件。
輸入:
name:指標名稱陣列。interval:'1m' | '5m' | '15m' | '1h' | '1d'之一。aggregation:相同的列舉值。groupBy:選用。省略時,多個指標名稱會加總為一個序列。若要分開保留,請為每個指標各呼叫一次。filters:選用。
回應:series[],每個序列包含 name、costUnit,以及由 { timestamp, value, estimatedCost } 組成的 points[]。
const inputTokens = await observability!.getMetricTimeSeries({
name: ['mastra_model_total_input_tokens'],
aggregation: 'sum',
interval: '1h',
filters: {
timestamp: { start: new Date(Date.now() - 24 * 60 * 60 * 1000) },
},
})
getMetricPercentiles「getmetricpercentiles」的直接連結
回傳依時間分桶的百分位數值,是延遲圖表的基礎元件。
輸入:
name:單一指標名稱(字串,而非陣列)。percentiles:介於0與1之間的數字陣列,例如[0.5, 0.95, 0.99]。interval:與getMetricTimeSeries相同的列舉值。filters:選用。
回應:series[],每個序列包含 percentile,以及由 { timestamp, value } 組成的 points[]。
const latency = await observability!.getMetricPercentiles({
name: 'mastra_agent_duration_ms',
percentiles: [0.5, 0.95],
interval: '1h',
})
探索「探索」的直接連結
使用這些端點填入下拉式選單,或向 Agent 提供可用於篩選的值清單。所有探索路由皆為 GET,並位於 /api/observability/discovery/ 下。
指標專用(也以 mastra api metric 子命令提供):
| 方法 | 引數 | 路徑後綴 | CLI |
|---|---|---|---|
getMetricNames | { prefix?, limit? } | metric-names | mastra api metric names |
getMetricLabelKeys | { metricName } | metric-label-keys | mastra api metric label-keys |
getMetricLabelValues | { metricName, labelKey, prefix?, limit? } | metric-label-values | mastra api metric label-values |
與 Trace 及記錄共用(僅限 HTTP,沒有專用 CLI 子命令):
| 方法 | 引數 | 路徑後綴 |
|---|---|---|
getEntityTypes | {} | entity-types |
getEntityNames | { entityType? } | entity-names |
getServiceNames | {} | service-names |
getEnvironments | {} | environments |
getTags | { entityType? } | tags |
篩選「篩選」的直接連結
每項查詢都接受相同的 filters 物件。最實用的欄位如下:
name:限制為特定指標名稱。(最上層的name已會對彙總、細分及時間序列執行此限制。若要在單一查詢中混合多個指標,請使用filters.name。)timestamp:{ start, end, startExclusive, endExclusive }。兩個邊界皆為選用。省略end代表「直到現在」。provider、model、costUnit:適用於 token 與成本指標。labels:精確比對指標標籤的鍵值,例如期間指標可使用{ status: 'error' }。- 關聯欄位:
entityType、entityName、parentEntityName、rootEntityName、userId、organizationId、resourceId、runId、sessionId、threadId、requestId、executionSource、environment、serviceName、experimentId、tags。
相同的 filters 格式適用於全部三種介面:
// In-process
await observability!.getMetricAggregate({
name: ['mastra_tool_duration_ms'],
aggregation: 'avg',
filters: { entityName: 'weatherTool', labels: { status: 'error' } },
})
# CLI
mastra api metric aggregate \
'{"name":["mastra_tool_duration_ms"],"aggregation":"avg","filters":{"entityName":"weatherTool","labels":{"status":"error"}}}' \
--url http://localhost:4111
# HTTP
curl -sS -X POST http://localhost:4111/api/observability/metrics/aggregate \
-H "content-type: application/json" \
-d '{"name":["mastra_tool_duration_ms"],"aggregation":"avg","filters":{"entityName":"weatherTool","labels":{"status":"error"}}}'
一律提供時間範圍「一律提供時間範圍」的直接連結
filters.timestamp 是選用欄位,但對正式環境儲存區執行的任何查詢,都應將它視為必填欄位。可觀測性資料表通常依事件時間分割(TimescaleDB 則會分塊)。提供 timestamp.start(理想情況下也提供 end)時,後端可排除不與範圍重疊的分割區,通常只需存取一或兩個分割區。若未提供時間範圍,規劃器就必須掃描每個分割區;保留一年的資料可能產生數百個區段,這也是由 Postgres 支援的儲存區中,OLAP 查詢緩慢最常見的原因。
臨時查詢可安全地預設為過去 24 小時;警示與儀表板則應符合實際的評估時間範圍:
await observability!.getMetricAggregate({
name: ['mastra_agent_duration_ms'],
aggregation: 'p95',
filters: {
timestamp: { start: new Date(Date.now() - 24 * 60 * 60 * 1000) },
},
})
此指引適用於所有後端(ClickHouse、Postgres v-next、DuckDB),但對 Postgres v-next 最為重要,因為每缺少一個時間邊界,就會直接多掃描一個分割區。
範例:建立自訂 KPI 圖塊「範例:建立自訂 KPI 圖塊」的直接連結
以下 Tool 會回傳過去一小時的輸入 token 數量與預估成本。Agent 或儀表板可透過 structuredContent 呼叫它,而不必重新實作查詢。
import { createTool } from '@mastra/core/tools'
import { z } from 'zod'
export const tokenKpiTool = createTool({
id: 'tokenKpi',
description: 'Returns input-token volume and estimated cost for the last hour.',
inputSchema: z.object({}),
outputSchema: z.object({
inputTokens: z.number().nullable(),
estimatedCost: z.number().nullable(),
costUnit: z.string().nullable(),
changePercent: z.number().nullable(),
}),
execute: async (_input, context) => {
const observability = await context.mastra!.getStorage()!.getStore('observability')
if (!observability) {
throw new Error('Observability domain is not configured (requires DuckDB or ClickHouse)')
}
const result = await observability.getMetricAggregate({
name: ['mastra_model_total_input_tokens'],
aggregation: 'sum',
filters: {
timestamp: { start: new Date(Date.now() - 60 * 60 * 1000) },
},
comparePeriod: 'previous_period',
})
return {
inputTokens: result.value,
estimatedCost: result.estimatedCost ?? null,
costUnit: result.costUnit ?? null,
changePercent: result.changePercent ?? null,
}
},
})