Construire l'application
Prérequis
- Vous disposez d'un client Git. Les exemples de cette section utilisent un client Git en ligne de commande, mais vous pouvez utiliser n'importe quel client.
Vous allez créer un serveur Golang avec quelques points de terminaison pour simuler une application du monde réel. Ensuite, vous exposerez les métriques du serveur à l'aide de Prometheus.
Obtenir l'application d'exemple
Clonez l'application d'exemple à utiliser avec ce guide. Ouvrez un terminal, changez de répertoire pour un répertoire dans lequel vous souhaitez travailler, et exécutez la commande suivante pour cloner le dépôt :
$ git clone https://github.com/dockersamples/go-prometheus-monitoring.git
Une fois que vous avez cloné, vous verrez la structure de contenu suivante à l'intérieur du répertoire go-prometheus-monitoring
,
go-prometheus-monitoring
├── CONTRIBUTING.md
├── Docker
│ ├── grafana.yml
│ └── prometheus.yml
├── dashboard.json
├── Dockerfile
├── LICENSE
├── README.md
├── compose.yaml
├── go.mod
├── go.sum
└── main.go
- main.go - Le point d'entrée de l'application.
- go.mod et go.sum - Fichiers de module Go.
- Dockerfile - Dockerfile utilisé pour construire l'application.
- Docker/ - Contient les fichiers de configuration Docker Compose pour Grafana et Prometheus.
- compose.yaml - Fichier Compose pour tout lancer (application Golang, Prometheus et Grafana).
- dashboard.json - Fichier de configuration du tableau de bord Grafana.
- Dockerfile - Dockerfile utilisé pour construire l'application Golang.
- compose.yaml - Fichier Docker Compose pour tout lancer (application Golang, Prometheus et Grafana).
- Les autres fichiers sont à des fins de licence et de documentation.
Comprendre l'application
Voici la logique complète de l'application que vous trouverez dans main.go
.
package main
import (
"strconv"
"github.com/gin-gonic/gin"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
// Définir les métriques
var (
HttpRequestTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
Name: "api_http_request_total",
Help: "Nombre total de requêtes traitées par l'API",
}, []string{"path", "status"})
HttpRequestErrorTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
Name: "api_http_request_error_total",
Help: "Nombre total d'erreurs retournées par l'API",
}, []string{"path", "status"})
)
// Registre personnalisé (sans les métriques Go par défaut)
var customRegistry = prometheus.NewRegistry()
// Enregistrer les métriques avec le registre personnalisé
func init() {
customRegistry.MustRegister(HttpRequestTotal, HttpRequestErrorTotal)
}
func main() {
router := gin.Default()
// Enregistrer /metrics avant le middleware
router.GET("/metrics", PrometheusHandler())
router.Use(RequestMetricsMiddleware())
router.GET("/health", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "Up and running!",
})
})
router.GET("/v1/users", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "Hello from /v1/users",
})
})
router.Run(":8000")
}
// Gestionnaire de métriques personnalisé avec registre personnalisé
func PrometheusHandler() gin.HandlerFunc {
h := promhttp.HandlerFor(customRegistry, promhttp.HandlerOpts{})
return func(c *gin.Context) {
h.ServeHTTP(c.Writer, c.Request)
}
}
// Middleware pour enregistrer les métriques des requêtes entrantes
func RequestMetricsMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
path := c.Request.URL.Path
c.Next()
status := c.Writer.Status()
if status < 400 {
HttpRequestTotal.WithLabelValues(path, strconv.Itoa(status)).Inc()
} else {
HttpRequestErrorTotal.WithLabelValues(path, strconv.Itoa(status)).Inc()
}
}
}
Dans cette partie du code, vous avez importé les paquets requis gin
, prometheus
et promhttp
. Ensuite, vous avez défini quelques variables, HttpRequestTotal
et HttpRequestErrorTotal
sont des métriques de compteur Prometheus, et customRegistry
est un registre personnalisé qui sera utilisé pour enregistrer ces métriques. Le nom de la métrique est une chaîne que vous pouvez utiliser pour identifier la métrique. La chaîne d'aide est une chaîne qui sera affichée lorsque vous interrogerez le point de terminaison /metrics
pour comprendre la métrique. La raison pour laquelle vous utilisez le registre personnalisé est d'éviter les métriques Go par défaut qui sont enregistrées par défaut par le client Prometheus. Ensuite, à l'aide de la fonction init
, vous enregistrez les métriques avec le registre personnalisé.
import (
"strconv"
"github.com/gin-gonic/gin"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
// Définir les métriques
var (
HttpRequestTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
Name: "api_http_request_total",
Help: "Nombre total de requêtes traitées par l'API",
}, []string{"path", "status"})
HttpRequestErrorTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
Name: "api_http_request_error_total",
Help: "Nombre total d'erreurs retournées par l'API",
}, []string{"path", "status"})
)
// Registre personnalisé (sans les métriques Go par défaut)
var customRegistry = prometheus.NewRegistry()
// Enregistrer les métriques avec le registre personnalisé
func init() {
customRegistry.MustRegister(HttpRequestTotal, HttpRequestErrorTotal)
}
Dans la fonction main
, vous avez créé une nouvelle instance du framework gin
et créé trois routes. Vous pouvez voir le point de terminaison de santé qui se trouve sur le chemin /health
qui retournera un JSON avec {"message": "Up and running!"}
et le point de terminaison /v1/users
qui retournera un JSON avec {"message": "Hello from /v1/users"}
. La troisième route est pour le point de terminaison /metrics
qui retournera les métriques au format Prometheus. Ensuite, vous avez le middleware RequestMetricsMiddleware
, il sera appelé pour chaque requête faite à l'API. Il enregistrera les métriques des requêtes entrantes comme les codes d'état et les chemins. Enfin, vous exécutez l'application gin sur le port 8000.
func main() {
router := gin.Default()
// Enregistrer /metrics avant le middleware
router.GET("/metrics", PrometheusHandler())
router.Use(RequestMetricsMiddleware())
router.GET("/health", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "Up and running!",
})
})
router.GET("/v1/users", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "Hello from /v1/users",
})
})
router.Run(":8000")
}
Vient maintenant la fonction middleware RequestMetricsMiddleware
. Cette fonction est appelée pour chaque requête faite à l'API. Elle incrémente le compteur HttpRequestTotal
(compteur différent pour différents chemins et codes d'état) si le code d'état est inférieur ou égal à 400. Si le code d'état est supérieur à 400, elle incrémente le compteur HttpRequestErrorTotal
(compteur différent pour différents chemins et codes d'état). La fonction PrometheusHandler
est le gestionnaire personnalisé qui sera appelé pour le point de terminaison /metrics
. Il retournera les métriques au format Prometheus.
// Gestionnaire de métriques personnalisé avec registre personnalisé
func PrometheusHandler() gin.HandlerFunc {
h := promhttp.HandlerFor(customRegistry, promhttp.HandlerOpts{})
return func(c *gin.Context) {
h.ServeHTTP(c.Writer, c.Request)
}
}
// Middleware pour enregistrer les métriques des requêtes entrantes
func RequestMetricsMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
path := c.Request.URL.Path
c.Next()
status := c.Writer.Status()
if status < 400 {
HttpRequestTotal.WithLabelValues(path, strconv.Itoa(status)).Inc()
} else {
HttpRequestErrorTotal.WithLabelValues(path, strconv.Itoa(status)).Inc()
}
}
}
C'est tout, c'était l'essentiel de l'application. Il est maintenant temps d'exécuter et de tester si l'application enregistre correctement les métriques.
Exécuter l'application
Assurez-vous que vous êtes toujours dans le répertoire go-prometheus-monitoring
dans le terminal, et exécutez la commande suivante. Installez les dépendances en exécutant go mod tidy
, puis construisez et exécutez l'application en exécutant go run main.go
. Ensuite, visitez http://localhost:8000/health
ou http://localhost:8000/v1/users
. Vous devriez voir la sortie {"message": "Up and running!"}
ou {"message": "Hello from /v1/users"}
. Si vous pouvez voir cela, votre application est démarrée et fonctionne avec succès.
Maintenant, vérifiez les métriques de votre application en accédant au point de terminaison /metrics
.
Ouvrez http://localhost:8000/metrics
dans votre navigateur. Vous devriez voir une sortie similaire à la suivante.
# HELP api_http_request_error_total Nombre total d'erreurs retournées par l'API
# TYPE api_http_request_error_total counter
api_http_request_error_total{path="/",status="404"} 1
api_http_request_error_total{path="//v1/users",status="404"} 1
api_http_request_error_total{path="/favicon.ico",status="404"} 1
# HELP api_http_request_total Nombre total de requêtes traitées par l'API
# TYPE api_http_request_total counter
api_http_request_total{path="/health",status="200"} 2
api_http_request_total{path="/v1/users",status="200"} 1
Dans le terminal, appuyez sur ctrl
+ c
pour arrêter l'application.
NoteSi vous ne voulez pas exécuter l'application localement, et que vous voulez l'exécuter dans un conteneur Docker, passez à la page suivante où vous créerez un Dockerfile et conteneuriserez l'application.
Résumé
Dans cette section, vous avez appris à créer une application Golang pour enregistrer des métriques avec Prometheus. En implémentant des fonctions middleware, vous avez pu incrémenter les compteurs en fonction du chemin de la requête et des codes d'état.
Prochaines étapes
Dans la section suivante, vous apprendrez à conteneuriser votre application.