RousselTMLEARNING

Observabilité

TraceQL : le langage de requête des traces

Maîtriser TraceQL : sélecteurs de spans, attributs de ressource et de span, opérateurs, comparaisons de durée, opérateurs structurels, agrégations et select.

1. Les sélecteurs de spans #

Les accolades vides sont valides, mais coûteuses.

Attributs et portées #

Structure d'une requête TraceQL
On compose les niveaux de gauche à droite.
{ resource.service.name = "checkout" }                       # attribut de ressource
{ span.http.status_code = 500 }                                   # attribut de span
{ .http.status_code = 500 }                                       # portée implicite (span puis ressource)
{ name = "POST /payer" }                                          # nom du span
{ status = error }                                                # statut : error | ok | unset
{ kind = server }                                                 # kind : server, client, producer...
{ duration > 2s }                                                 # durée du span
{ traceDuration > 5s }                                            # durée de la trace complète
{ resource.service.name =~ "api-.*" && span.http.method != "GET" }  # regex, &&, ||
Bonne Pratique : Utilisez les noms d'attributs qualifiés (span. / resource.) : la recherche est plus rapide et sans ambiguïté.

2. Opérateurs structurels #

Relier des spans entre eux.

Parent, enfant et descendant #

# Appels de paiement en erreur sous le service checkout (descendant)
{ resource.service.name = "checkout" } >> { resource.service.name = "payment" && status = error }

# Enfant direct
{ resource.service.name = "frontend" } > { resource.service.name = "checkout" }

# Spans frères (sibling)
{ span.db.system = "postgresql" } ~ { span.db.system = "redis" }

# Remontée : trouver l'ancêtre d'un span lent
{ duration > 1s } << { resource.service.name = "gateway" }
OpérateurSignification
>>A est un ancêtre de B
>A est le parent direct de B
~A et B sont frères
<< / <Versions inversées

3. Agrégations et sélection #

Analyser le résultat.

Pipeline TraceQL #

# Traces avec plus de 10 requêtes SQL (problème N+1 probable)
{ span.db.system = "postgresql" } | count() > 10

# Traces dont la durée moyenne des spans HTTP dépasse 500 ms
{ span.http.method != "" } | avg(duration) > 500ms

# Afficher uniquement certains attributs dans les résultats
{ status = error } | select(span.http.url, resource.service.name, span.exception.message)

# Regrouper
{ resource.service.name = "api" } | by(span.http.route) | count() > 5

Via l'API et Tempo CLI #

curl -G -s http://localhost:3200/api/search \
  --data-urlencode 'q={ resource.service.name = "checkout" && status = error }' \
  --data-urlencode 'limit=20' --data-urlencode 'start='$(date -d '1 hour ago' +%s) --data-urlencode 'end='$(date +%s) | jq '.traces[].traceID'

curl -s http://localhost:3200/api/search/tags | jq                 # attributs disponibles
curl -s http://localhost:3200/api/search/tag/service.name/values | jq

4. Requêtes de diagnostic prêtes à l'emploi #

Un petit catalogue.

Catalogue #

ObjectifRequête TraceQL
Erreurs récentes d'un service{ resource.service.name = "checkout" && status = error }
Requêtes lentes (> 2 s){ kind = server && duration > 2s }
Appels HTTP 5xx sortants{ kind = client && span.http.status_code >= 500 }
Retries excessifs{ name = "http.retry" } | count() > 3
Une trace par utilisateur{ span.user.id = "42" }

Pour aller plus loin