Mesurer pour mieux comprendre : introduction aux métriques
Montons ensemble à bord d’un beau voilier trois-mâts, en route vers un pays plein de promesses. La destination est lointaine et le voyage semé d’incertitudes !
Depuis des siècles, les marins cherchent à réduire cette incertitude en s’aidant de différents instruments : boussole, cartes, baromètre… Chacun met des chiffres sur une réalité parfois difficile à apprécier : la vitesse, le cap, la profondeur. Pris séparément, ces instruments donnent une information limitée ; ensemble, ils aident l’équipage à comprendre la situation et à corriger sa trajectoire si nécessaire.

Le nom de Cabestan Technologies fait référence au vocabulaire de la marine. Mais l’expertise que je vous propose aujourd’hui concerne un autre domaine qui, lui aussi, a besoin de garder le cap : le backend. Quand un service ralentit ou renvoie des erreurs, les utilisateurs peuvent nous le signaler — parfois trop tard. En instrumentant le service, on peut suivre son comportement et repérer plus tôt les évolutions qui méritent notre attention.
Dans cet article, nous verrons à quoi servent les métriques backend et comment en exposer quelques-unes dans un service Go. Nous regarderons ensuite comment les consulter dans Grafana, à travers un tableau de bord. Je ne détaillerai pas la mise en place de l’infrastructure nécessaire afin de garder l’article centré sur les métriques.
Une métrique, c’est quoi ?¶
Une métrique est une mesure chiffrée du fonctionnement d’un service. En la suivant dans le temps, on voit si la situation évolue. Par exemple, on peut compter les requêtes reçues, mesurer leur durée ou suivre la mémoire utilisée.
Quelques notions utiles pour lire ces mesures :
- Métrique : une valeur mesurée, comme le nombre de requêtes reçues.
- KPI (Key Performance Indicator, ou indicateur clé de performance) : une mesure choisie pour suivre un objectif. Le temps de réponse est une métrique ; la proportion de requêtes terminées en moins de 300 millisecondes peut servir de KPI pour suivre l’expérience des utilisateurs.
- Label : une information qui permet de distinguer les mesures, comme la méthode HTTP (
GET,POST) ou le code de réponse (200,500). Les labels doivent avoir un nombre limité de valeurs. Un identifiant utilisateur ou un identifiant de requête créerait presque autant de séries que de requêtes, ce qui alourdirait leur stockage.
Toutes les métriques ne sont pas des KPI. Pour choisir celles à suivre, partons des questions auxquelles on veut répondre : le service est-il disponible ? Les réponses ralentissent-elles ? Les erreurs augmentent-elles ?
À noter : en production, les métriques aident à suivre l’évolution d’un service et à repérer un changement inhabituel. Lors d’un incident, voir la latence et les erreurs augmenter en même temps donne une piste pour orienter l’enquête.
Elles ne suffisent toutefois pas toujours à trouver la cause : une hausse de la latence ne dit pas si les requêtes attendent la base de données, un service distant ou un traitement interne. Les logs et le tracing peuvent aider à examiner ces détails. Il faut aussi interpréter les courbes dans leur contexte : un pic de trafic, par exemple, n’est pas forcément anormal.
Voyons maintenant les principaux types de métriques et ce qu’ils permettent de mesurer.
Les principaux types de métriques¶
Pour suivre le fonctionnement d’un service, trois types de métriques sont particulièrement utiles : les compteurs, les jauges et les histogrammes. Le choix dépend de la question à laquelle on veut répondre.
Counter : compter ce qui s’est produit¶
Un compteur (Counter) additionne les événements au fil du temps : chaque requête reçue le fait augmenter. Sa valeur brute ne diminue pas pendant que le service fonctionne. Si le service redémarre, elle repart de zéro.
Dans un tableau de bord, on affiche souvent le débit calculé à partir du compteur — par exemple le nombre de requêtes par seconde — plutôt que son total brut. Ce calcul tient compte des remises à zéro : le débit ne chute pas artificiellement au redémarrage.

Gauge : suivre une valeur qui monte et descend¶
Une jauge (Gauge) indique une valeur à un instant donné, qui peut monter ou descendre. Elle peut, par exemple, mesurer le nombre de requêtes en cours, la mémoire utilisée ou les connexions ouvertes. Si cette valeur augmente sans redescendre, cela peut signaler une accumulation. Après un redémarrage, l’ancienne valeur n’est pas automatiquement conservée : l’application publie celle qu’elle mesure ou initialise à ce moment-là.

Histogram : observer une distribution¶
Un histogramme (Histogram) regroupe les observations par tranches. Pour les requêtes HTTP, il répartit leurs durées dans différentes plages de temps. On peut ainsi estimer, par exemple, sous quelle durée se terminent 95 % des requêtes.
Les tranches doivent correspondre aux durées que l’on veut observer. L’histogramme ne conserve pas chaque durée individuellement : il en donne une répartition, à partir de laquelle les percentiles sont estimés.

En pratique, un compteur peut suivre le nombre de requêtes, une jauge le nombre d’utilisateurs connectés, et un histogramme la durée des requêtes. Ensemble, ces mesures donnent déjà plusieurs angles de vue sur un serveur HTTP. Il restera à choisir les labels qui permettent de les distinguer utilement, sans multiplier inutilement les séries.
De l’application au tableau de bord : les outils¶
Il existe plusieurs façons de collecter, stocker et afficher des métriques. Je m’appuie sur Prometheus et Grafana , la stack avec laquelle je travaille habituellement. D’autres outils et combinaisons existent ; le principe général reste le même.
Le parcours des métriques tient en trois étapes :
- Le service backend mesure son activité et expose les valeurs sur un endpoint HTTP, souvent
/metrics. - Prometheus interroge régulièrement cet endpoint — c’est le scraping —, conserve les mesures dans le temps et permet de les consulter avec PromQL.
- Grafana se connecte à Prometheus pour transformer ces mesures en courbes et en tableaux de bord.
Je vous présente ici une collecte en pull, c’est-à-dire que Prometheus interroge régulièrement le service. Un mode push est également possible : le service est alors responsable de l’envoi de ses métriques, généralement à un intermédiaire comme le Pushgateway . C’est particulièrement utile pour les tâches très courtes, qui s’arrêtent avant que Prometheus puisse les interroger ou qui n’exposent pas de serveur HTTP.
Dans le cas de NuCorder , j’utilise VictoriaMetrics à la place de Prometheus pour collecter et stocker les métriques. Il s’intègre à l’écosystème Prometheus, et Grafana peut l’interroger comme source de données. Le parcours reste le même : le service expose les métriques, VictoriaMetrics les collecte et Grafana les affiche.
Quelles métriques choisir pour un service HTTP ?¶
Pour commencer, inutile de mesurer tout ce que fait le service. Je partirais de quelques questions concrètes :
- Combien de requêtes arrivent ? On peut suivre leur nombre et, si utile, les distinguer par méthode HTTP ou par route.
- Combien échouent ? Le code de réponse permet de repérer les erreurs, par exemple les réponses 5xx.
- Combien de temps prennent les réponses ? Suivre leur durée aide à voir si les requêtes ralentissent, notamment les plus lentes.
Ces trois mesures donnent une première vue de l’état du service. Si le débit reste stable alors que les réponses ralentissent, une dépendance ou le service lui-même peut être en difficulté. Si les erreurs augmentent après un déploiement, cela peut signaler une régression.
À partir de ces premiers résultats, on peut ajouter des métriques métier pour examiner une question plus précise. Par exemple, compter les tentatives de connexion et distinguer celles qui réussissent de celles qui échouent permet de suivre l’évolution des échecs de connexion.
À noter : les labels permettent de filtrer les mesures par méthode, code de réponse ou route. Il faut toutefois éviter les valeurs qui changent à chaque requête : utilisez le pattern de route /users/{id} plutôt que le chemin contenant l’identifiant réel, et n’ajoutez pas d’identifiant utilisateur, d’adresse email ou de paramètre de recherche. Chaque valeur différente crée une nouvelle série et peut vite en multiplier le nombre.
Instrumenter un endpoint HTTP en Go¶
Go est le langage que j’utilise au quotidien, c’est donc celui que j’utiliserai dans cet exemple. Pour instrumenter le service, j’utilise le client Go officiel de Prometheus , qui fournit les types de métriques et les outils pour les exposer en HTTP.
Des clients Prometheus dans d’autres langages¶
Le même principe peut s’appliquer dans d’autres langages, avec une bibliothèque adaptée :
- Java : client_java
- Node.js : client_js
- Python : client_python
- Rust : client_rust
La documentation Prometheus recense d’autres bibliothèques clientes.
Voici un exemple volontairement réduit. Un middleware placé autour du handler relève le code de réponse et la durée après son exécution, puis compte les requêtes par méthode, route et code :
package main
import (
"fmt"
"log"
"net/http"
"strconv"
"time"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
type responseRecorder struct {
http.ResponseWriter
status int
wroteHeader bool
}
// responseRecorder mémorise le code renvoyé par le handler.
func (r *responseRecorder) WriteHeader(status int) {
if r.wroteHeader {
return
}
r.status = status
r.wroteHeader = true
r.ResponseWriter.WriteHeader(status)
}
func (r *responseRecorder) Write(p []byte) (int, error) {
if !r.wroteHeader {
r.WriteHeader(http.StatusOK)
}
return r.ResponseWriter.Write(p)
}
func instrumentHTTP(requests *prometheus.CounterVec, duration *prometheus.HistogramVec, next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
rec := &responseRecorder{ResponseWriter: w, status: http.StatusOK}
next.ServeHTTP(rec, r)
// ServeMux fournit un pattern stable, contrairement à l'URL
// avec ses identifiants.
route := r.Pattern
code := strconv.Itoa(rec.status)
requests.WithLabelValues(r.Method, route, code).Inc()
duration.WithLabelValues(r.Method, route).Observe(time.Since(start).Seconds())
})
}
func main() {
requests := prometheus.NewCounterVec(prometheus.CounterOpts{
Name: "http_requests_total",
Help: "Nombre total de requêtes HTTP.",
}, []string{"method", "route", "code"})
duration := prometheus.NewHistogramVec(prometheus.HistogramOpts{
Name: "http_request_duration_seconds",
Help: "Durée des requêtes HTTP en secondes.",
Buckets: prometheus.DefBuckets,
}, []string{"method", "route"})
// Important : pensez à déclarer vos métriques avant
// de les utiliser
prometheus.MustRegister(requests, duration)
app := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Bonjour !")
})
mux := http.NewServeMux()
mux.Handle("/hello", instrumentHTTP(requests, duration, app))
// /metrics reste hors middleware pour ne pas compter les requêtes
// de scraping.
mux.Handle("/metrics", promhttp.Handler())
log.Println("Écoute sur http://localhost:8080")
log.Fatal(http.ListenAndServe(":8080", mux))
}Pour essayer l’exemple, ajoutez la dépendance github.com/prometheus/client_golang, lancez le serveur et ouvrez /hello. Les mesures sont ensuite consultables sur /metrics, dans un format que Prometheus peut lire.
Les mesures exposées sont :
http_requests_totalcompte les requêtes par méthode, pattern de route et code de réponse.http_request_duration_secondssuit leur durée par méthode et pattern de route.- Le pattern de route — par exemple
/users/{id}— regroupe les requêtes visant des utilisateurs différents, contrairement à l’adresse complète.
À noter : récupérer le pattern de route avec r.Pattern nécessite Go 1.22 ou plus.
Consulter les métriques dans Grafana¶
Pour visualiser les métriques, on ajoute Prometheus comme source de données dans Grafana. On peut ensuite créer un tableau de bord avec trois graphiques : le débit de requêtes, le taux d’erreur et la latence au 95e percentile.

Débit de requêtes¶
Pour afficher le nombre de requêtes par seconde, on calcule le taux d’augmentation du compteur sur une fenêtre de temps, puis on additionne les séries :
sum(rate(http_requests_total[$__rate_interval]))Le résultat donne le débit global. Pour le ventiler par code HTTP, on peut regrouper les séries par label code :
sum by (code) (rate(http_requests_total[$__rate_interval]))Taux d’erreur¶
On peut comparer le débit des réponses 5xx au débit total :
sum(rate(http_requests_total{code=~"5.."}[$__rate_interval]))
/
sum(rate(http_requests_total[$__rate_interval]))Le résultat est une proportion, que l’on peut afficher en pourcentage dans Grafana. Si aucune requête n’a été reçue pendant la période, le taux d’erreur n’est pas défini.
Latence au 95e percentile¶
L’histogramme fournit des comptes cumulés par tranche de durée. On peut les agréger puis demander une estimation du 95e percentile :
histogram_quantile(
0.95,
sum by (le) (rate(http_request_duration_seconds_bucket[$__rate_interval]))
)Le p95, qu’est-ce que c’est ? Pour un point de la courbe, si le p95 vaut 300 millisecondes, cela signifie qu’environ 95 % des requêtes de la période de calcul ont répondu en moins de 300 millisecondes. Les 5 % restantes ont pris plus de temps.
Le p95 complète la moyenne, qui peut masquer un ralentissement touchant seulement les requêtes les plus lentes.
Ces trois courbes aident à repérer quand le comportement du service change ; il reste à en chercher la cause.
Ce que les métriques ne montrent pas à elles seules¶
Les métriques donnent une vue d’ensemble du service sur une période. Elles aident à suivre les tendances et à repérer une anomalie, mais ne décrivent pas nécessairement ce qui est arrivé à une requête précise.
Un tableau de bord peut montrer que le p95 a augmenté et que les réponses 5xx sont plus nombreuses, mais il ne dira pas automatiquement quelle requête a échoué ni quelle opération interne a pris du temps. Les logs apportent des événements détaillés et contextualisés ; le tracing suit le parcours d’une requête entre les composants ; le profiling aide à examiner le travail réalisé à l’intérieur d’un processus. Ces outils répondent à des questions différentes et peuvent se compléter lors d’un diagnostic.
On peut aussi définir des alertes à partir des métriques, par exemple lorsqu’un taux d’erreur reste élevé ou qu’une latence dépasse un seuil pendant plusieurs minutes. Une alerte doit correspondre à une situation qui demande réellement une action : multiplier les seuils trop sensibles peut produire du bruit et rendre les notifications moins utiles. La définition des règles et de leur acheminement dépend de l’environnement ; elle dépasse le périmètre de cet article.
Ce que j’en retiens¶
Les métriques backend donnent des repères concrets sur le trafic, les erreurs, la latence et les ressources d’un service. Avec Prometheus — ou VictoriaMetrics dans mon cas — et Grafana, quelques mesures bien choisies et présentées avec leur unité et leur contexte suffisent pour suivre son évolution et repérer un changement. En instrumentant quelques handlers Go, on passe d’une impression « l’API semble lente » à des questions précises : depuis quand, sur quelle proportion de requêtes, et où chercher ensuite ? Les métriques ne pilotent pas le service à notre place, mais elles aident à savoir quand corriger le cap.
Besoin d’aide pour mieux suivre votre backend ?¶
Si vous souhaitez choisir les métriques utiles à votre service ou mettre en place un premier tableau de bord, n’hésitez pas à me contacter.