Aller au contenu principal

Interroger les métriques

Mastra expose les cinq mêmes requêtes OLAP (getMetricAggregate, getMetricBreakdown, getMetricTimeSeries, getMetricPercentiles et les utilitaires de découverte) via trois interfaces : un accesseur de magasin dans le processus, l'API HTTP du runtime et la CLI mastra api metric. Toutes trois acceptent les mêmes structures d'entrée validées par Zod. Vous pouvez ainsi passer d'une investigation ponctuelle avec la CLI à un outil de tableau de bord programmatique sans avoir à réapprendre l'API.

Quand utiliser cette fonctionnalité
Lien direct vers Quand utiliser cette fonctionnalité

  • Créer un tableau de bord ou une tuile d'indicateur clé de performance (KPI) personnalisé en complément de Studio.
  • Alimenter une alerte planifiée qui se déclenche lorsque le coût des tokens ou la latence dépasse un seuil.
  • Fournir à un agent un outil qui lit ses propres métriques de performance et les explique dans une conversation.
  • Effectuer des investigations ponctuelles depuis un terminal avec mastra api metric ....

Pour configurer le magasin d'observabilité lui-même, consultez la présentation des métriques. Pour connaître la liste des noms de métriques que vous pouvez interroger, consultez la référence des métriques automatiques.

remarque

Les requêtes de métriques sont prises en charge par le domaine d'observabilité, qui nécessite un magasin compatible OLAP (DuckDB en local, ClickHouse en production). Consultez la présentation des métriques pour la configuration. Si le magasin d'observabilité n'est pas configuré, getStore('observability') renvoie null.

Interfaces
Lien direct vers Interfaces

Dans le processus
Lien direct vers Dans le processus

Dans un outil, une route de serveur ou une étape de workflow, récupérez le magasin d'observabilité depuis le stockage Mastra :

src/mastra/tools/agent-latency-tool.ts
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 }
},
})

getStore('observability') renvoie null lorsque le backend configuré ne prend pas en charge les requêtes OLAP.

HTTP
Lien direct vers HTTP

Le serveur mastra dev (comme tout runtime Mastra déployé) expose les mêmes requêtes sous /api/observability/metrics/*. Les endpoints d'agrégation, de répartition, de séries temporelles et de percentiles acceptent un corps JSON avec POST. Les endpoints de découverte utilisent GET avec des paramètres de requête.

curl -sS -X POST http://localhost:4111/api/observability/metrics/aggregate \
-H "content-type: application/json" \
-d '{"name":["mastra_agent_duration_ms"],"aggregation":"avg"}'

Routes disponibles :

  • POST /api/observability/metrics/aggregate
  • POST /api/observability/metrics/breakdown
  • POST /api/observability/metrics/timeseries
  • POST /api/observability/metrics/percentiles
  • GET /api/observability/metrics (lignes brutes, paginées)
  • GET /api/observability/discovery/metric-names
  • GET /api/observability/discovery/metric-label-keys
  • GET /api/observability/discovery/metric-label-values

Le SDK @mastra/client-js encapsule ces mêmes routes avec mastraClient.getMetricAggregate(...), getMetricBreakdown(...), etc.

CLI
Lien direct vers CLI

mastra api metric ... appelle les mêmes endpoints avec un seul argument JSON, ce qui permet à un agent ou à un script shell de récupérer des métriques sans écrire de code :

mastra api metric aggregate \
'{"name":["mastra_agent_duration_ms"],"aggregation":"avg"}' \
--url http://localhost:4111

Par défaut, la CLI cible l'observabilité Mastra hébergée (https://observability.mastra.ai). Transmettez --url http://localhost:4111 pour interroger un serveur mastra dev local. Consultez mastra api metric aggregate et les entrées voisines pour obtenir la liste complète des commandes.

Requêtes
Lien direct vers Requêtes

getMetricAggregate
Lien direct vers getmetricaggregate

Renvoie une valeur scalaire unique, qui constitue la brique de base des cartes de KPI.

Entrées :

  • name : tableau contenant un ou plusieurs noms de métriques.
  • aggregation : l'une des valeurs 'sum' | 'avg' | 'min' | 'max' | 'count' | 'count_distinct' | 'last'.
  • filters : objet de filtrage facultatif.
  • comparePeriod : valeur facultative parmi 'previous_period' | 'previous_day' | 'previous_week' pour effectuer une comparaison d'une période à l'autre.

Réponse :

  • value, previousValue, changePercent.
  • estimatedCost, costUnit, previousEstimatedCost, costChangePercent pour les métriques de tokens.
src/mastra/tools/token-cost-tool.ts
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
Lien direct vers getmetricbreakdown

Regroupe les lignes selon une ou plusieurs dimensions et agrège chaque groupe. Il s'agit de la brique de base des tableaux des N premiers résultats (par exemple, « tokens par agent »).

Entrées :

  • name : tableau de noms de métriques.
  • groupBy : tableau de champs utilisés pour le regroupement (par exemple ['entityName']).
  • aggregation : même énumération que ci-dessus.
  • limit : limite des K premiers résultats côté serveur. Obligatoire pour une propriété groupBy à forte cardinalité.
  • orderDirection : 'ASC' | 'DESC' (valeur par défaut : DESC).
  • filters : facultatif.

Réponse : groups[], dont chaque élément contient dimensions (un enregistrement associant les clés de groupe à leurs valeurs), value et estimatedCost.

const byAgent = await observability!.getMetricBreakdown({
name: ['mastra_model_total_input_tokens'],
groupBy: ['entityName'],
aggregation: 'sum',
limit: 10,
orderDirection: 'DESC',
})

getMetricTimeSeries
Lien direct vers getmetrictimeseries

Regroupe les valeurs dans des intervalles fixes, ce qui constitue la brique de base des graphiques en courbes et en barres.

Entrées :

  • name : tableau de noms de métriques.
  • interval : l'une des valeurs '1m' | '5m' | '15m' | '1h' | '1d'.
  • aggregation : même énumération.
  • groupBy : facultatif. Lorsqu'il est omis, les valeurs de plusieurs métriques sont additionnées dans une seule série. Effectuez un appel par métrique pour les conserver séparément.
  • filters : facultatif.

Réponse : series[], dont chaque élément contient name, costUnit et un tableau points[] d'objets { timestamp, value, estimatedCost }.

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
Lien direct vers getmetricpercentiles

Renvoie les valeurs des percentiles regroupées par intervalle de temps, ce qui constitue la brique de base des graphiques de latence.

Entrées :

  • name : nom d'une seule métrique (une chaîne, pas un tableau).
  • percentiles : tableau de nombres compris entre 0 et 1, par exemple [0.5, 0.95, 0.99].
  • interval : même énumération que getMetricTimeSeries.
  • filters : facultatif.

Réponse : series[], dont chaque élément contient percentile et un tableau points[] d'objets { timestamp, value }.

const latency = await observability!.getMetricPercentiles({
name: 'mastra_agent_duration_ms',
percentiles: [0.5, 0.95],
interval: '1h',
})

Découverte
Lien direct vers Découverte

Utilisez ces endpoints pour alimenter des listes déroulantes ou pour fournir à un agent le menu des valeurs qu'il peut utiliser pour filtrer. Toutes les routes de découverte utilisent GET et se trouvent sous /api/observability/discovery/.

Propres aux métriques (également exposées comme sous-commandes de mastra api metric) :

MéthodeArgumentsSuffixe du cheminCLI
getMetricNames{ prefix?, limit? }metric-namesmastra api metric names
getMetricLabelKeys{ metricName }metric-label-keysmastra api metric label-keys
getMetricLabelValues{ metricName, labelKey, prefix?, limit? }metric-label-valuesmastra api metric label-values

Partagées avec les traces et les journaux (HTTP uniquement, sans sous-commande CLI dédiée) :

MéthodeArgumentsSuffixe du chemin
getEntityTypes{}entity-types
getEntityNames{ entityType? }entity-names
getServiceNames{}service-names
getEnvironments{}environments
getTags{ entityType? }tags

Filtrage
Lien direct vers Filtrage

Toutes les requêtes acceptent le même objet filters. Les champs les plus utiles sont les suivants :

  • name : limite la recherche à des noms de métriques précis. (La propriété name de premier niveau remplit déjà cette fonction pour les agrégations, les répartitions et les séries temporelles. Utilisez filters.name pour combiner plusieurs métriques dans une même requête.)
  • timestamp : { start, end, startExclusive, endExclusive }. Les deux bornes sont facultatives. Omettez end pour inclure les données « jusqu'à maintenant ».
  • provider, model, costUnit : pour les métriques de tokens et de coût.
  • labels : correspondance clé-valeur exacte avec les labels des métriques, par exemple { status: 'error' } pour les métriques de durée.
  • Champs de corrélation : entityType, entityName, parentEntityName, rootEntityName, userId, organizationId, resourceId, runId, sessionId, threadId, requestId, executionSource, environment, serviceName, experimentId, tags.

La même structure filters fonctionne avec les trois interfaces :

// 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"}}}'

Toujours fournir une plage temporelle
Lien direct vers Toujours fournir une plage temporelle

filters.timestamp est facultatif, mais vous devriez le considérer comme obligatoire pour toute requête exécutée sur un magasin de production. Les tables d'observabilité sont généralement partitionnées (ou découpées en chunks avec TimescaleDB) selon l'heure de l'événement. Lorsque vous fournissez timestamp.start (et, idéalement, end), le backend peut limiter le traitement aux partitions qui chevauchent la plage, généralement une ou deux. Sans plage temporelle, le planificateur doit analyser toutes les partitions, soit potentiellement des centaines de segments sur une année de rétention. C'est la cause la plus fréquente de lenteur des requêtes OLAP sur les magasins basés sur Postgres.

Une valeur par défaut sûre pour les requêtes ponctuelles consiste à utiliser les dernières 24 heures. Les alertes et les tableaux de bord doivent correspondre à leur fenêtre d'évaluation réelle :

await observability!.getMetricAggregate({
name: ['mastra_agent_duration_ms'],
aggregation: 'p95',
filters: {
timestamp: { start: new Date(Date.now() - 24 * 60 * 60 * 1000) },
},
})

Cette recommandation s'applique à tous les backends (ClickHouse, Postgres v-next et DuckDB), mais elle est particulièrement importante pour Postgres v-next, où chaque borne temporelle manquante entraîne directement l'analyse d'une partition supplémentaire.

Exemple : créer une tuile de KPI personnalisée
Lien direct vers Exemple : créer une tuile de KPI personnalisée

L'outil suivant renvoie le volume de tokens d'entrée et le coût estimé pour la dernière heure. Un agent ou un tableau de bord peut l'appeler comme structuredContent sans réimplémenter la requête.

src/mastra/tools/token-kpi-tool.ts
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,
}
},
})