Surveillance en temps réel de Watermill à l'aide de Prometheus
Métriques
Watermill peut être surveillé en utilisant des décorateurs pour les éditeurs/abonnés et des intergiciels pour les gestionnaires. Nous fournissons une implémentation par défaut en utilisant la bibliothèque officielle client Prometheus pour Go.
Le package components/metrics
exporte PrometheusMetricsBuilder
, qui fournit des fonctions pratiques pour envelopper les éditeurs, les abonnés et les gestionnaires afin de mettre à jour le registre Prometheus pertinent :
Code source complet : github.com/ThreeDotsLabs/watermill/components/metrics/builder.go
// ...
// PrometheusMetricsBuilder fournit des méthodes pour décorer les éditeurs, les abonnés et les gestionnaires.
type PrometheusMetricsBuilder struct {
// PrometheusRegistry peut remplir un registre Prometheus existant ou être vide pour utiliser le registre par défaut.
PrometheusRegistry prometheus.Registerer
Namespace string
Subsystem string
}
// AddPrometheusRouterMetrics est une fonction pratique pour ajouter un intergiciel de métriques à tous les gestionnaires sur le routeur de messages. Il décore également les éditeurs et les abonnés des gestionnaires.
func (b PrometheusMetricsBuilder) AddPrometheusRouterMetrics(r *message.Router) {
// ...
Envelopper les éditeurs, les abonnés et les gestionnaires
Si vous utilisez le routeur de Watermill (ce qui est recommandé dans la plupart des cas), vous pouvez utiliser la fonction pratique AddPrometheusRouterMetrics
pour vous assurer que tous les gestionnaires ajoutés à ce routeur sont enveloppés pour mettre à jour le registre Prometheus, ainsi que leurs éditeurs et abonnés :
Code source complet : github.com/ThreeDotsLabs/watermill/components/metrics/builder.go
// ...
// AddPrometheusRouterMetrics est une fonction pratique pour ajouter un intergiciel de métriques à tous les gestionnaires sur le routeur de messages. Il décore également les éditeurs et les abonnés des gestionnaires.
func (b PrometheusMetricsBuilder) AddPrometheusRouterMetrics(r *message.Router) {
r.AddPublisherDecorators(b.DecoratePublisher)
r.AddSubscriberDecorators(b.DecorateSubscriber)
r.AddMiddleware(b.NewRouterMiddleware().Middleware)
}
// ...
Exemple d'utilisation de AddPrometheusRouterMetrics
:
Code source complet : github.com/ThreeDotsLabs/watermill/_examples/basic/4-metrics/main.go
// ...
// Nous laissons les paramètres d'espace de noms et de sous-système vides
metricsBuilder := metrics.NewPrometheusMetricsBuilder(registrePrometheus, "", "")
metricsBuilder.AddPrometheusRouterMetrics(router)
// ...
Dans l'extrait de code ci-dessus, nous laissons les paramètres namespace
et subsystem
vides. La bibliothèque cliente Prometheus utilise ces paramètres pour préfixer les noms des métriques. Vous pouvez vouloir utiliser l'espace de noms ou le sous-système, mais veuillez noter que cela affectera les noms des métriques, vous devrez donc ajuster le tableau de bord Grafana en conséquence.
Les éditeurs et abonnés indépendants peuvent également être décorés en utilisant des méthodes dédiées de PrometheusMetricsBuilder
:
Code source complet : github.com/ThreeDotsLabs/watermill/_examples/basic/4-metrics/main.go
// ...
subAvecMetriques, err := metricsBuilder.DecorateSubscriber(pubSub)
if err != nil {
panic(err)
}
pubAvecMetriques, err := metricsBuilder.DecoratePublisher(pub)
if err != nil {
panic(err)
}
// ...
Exposer le point de terminaison /metrics
Selon le principe de fonctionnement de Prometheus, un service doit exposer un point de terminaison HTTP pour le raclage des données. Conventionnellement, il s'agit d'un point de terminaison GET, et le chemin est généralement /metrics
.
Pour fournir ce point de terminaison, il existe deux fonctions pratiques disponibles, l'une utilisant le registre Prometheus précédemment créé et l'autre créant simultanément un nouveau Registre :
Code source complet : github.com/ThreeDotsLabs/watermill/components/metrics/http.go
// ...
// CreateRegistryAndServeHTTP établit un serveur HTTP à l'adresse donnée pour exposer le point de terminaison /metrics à Prometheus.
// Il renvoie un nouveau Registre Prometheus (pour l'enregistrement des métriques) et une fonction d'annulation pour arrêter le serveur.
func CreateRegistryAndServeHTTP(addr string) (registry *prometheus.Registry, cancel func()) {
registry = prometheus.NewRegistry()
return registry, ServeHTTP(addr, registry)
}
// ServeHTTP établit un serveur HTTP à l'adresse donnée pour exposer le point de terminaison /metrics à Prometheus.
// Il accepte un Registre Prometheus existant et renvoie une fonction d'annulation pour arrêter le serveur.
func ServeHTTP(addr string, registry *prometheus.Registry) (cancel func()) {
// ...
Voici un exemple d'utilisation :
Code source complet : github.com/ThreeDotsLabs/watermill/_examples/basic/4-metrics/main.go
// ...
registrePrometheus, fermerServeurMetrics := metrics.CreateRegistryAndServeHTTP(*metricsAddr)
defer fermerServeurMetrics()
// Nous laissons l'espace de noms et le sous-système vides
metricsBuilder := metrics.NewPrometheusMetricsBuilder(registrePrometheus, "", "")
metricsBuilder.AddPrometheusRouterMetrics(router)
// ...
Exemple d'Application
Pour comprendre le fonctionnement du tableau de bord en pratique, vous pouvez vous référer à l'exemple de métriques.
Suivez les instructions dans le README de l'exemple pour l'exécuter et ajouter la source de données Prometheus à Grafana.
Tableau de bord Grafana
Nous avons préparé un tableau de bord Grafana à utiliser avec la mise en oeuvre des métriques mentionnées. Il fournit des informations de base sur le débit, le taux d'échec et la durée de publication/traitement.
Si vous souhaitez consulter ce tableau de bord localement, vous pouvez utiliser l'application exemple.
Pour plus d'informations sur les métriques exportées vers Prometheus, voir Métriques exportées.
Importation du Tableau de bord
Pour importer le tableau de bord Grafana, sélectionnez Dashboard/Gérer dans le menu de gauche, puis cliquez sur +Import
.
Entrez l'URL du tableau de bord https://grafana.com/dashboards/9777 (ou simplement l'identifiant, 9777), puis cliquez sur Charger.
Ensuite, sélectionnez la source de données Prometheus utilisée pour racler le point de terminaison /metrics
. Cliquez sur Importer
et le tour est joué !
Métriques exportées
Ce qui suit énumère toutes les métriques enregistrées dans le registre Prometheus par PrometheusMetricsBuilder
.
Pour plus d'informations sur les types de métriques Prometheus, veuillez vous référer à la documentation de Prometheus.
Objet | Métrique | Description | Libellés/Valeurs |
---|---|---|---|
Abonné | subscriber_messages_received_total |
Un compteur Prometheus. Compte le nombre de messages reçus par un abonné. | acked est "acked" ou "nacked". |
Si l'abonné opère dans un gestionnaire, définir handler_name ; sinon, " |
|||
subscriber_name identifie l'abonné. S'il implémente l'interface fmt.Stringer , c'est le résultat de String() ; sinon, c'est package.structName . |
|||
Gestionnaire | handler_execution_time_seconds |
Un histogramme Prometheus. Enregistre le temps d'exécution de la fonction de gestionnaire enveloppée par le middleware. | handler_name est le nom du gestionnaire. |
success est "true" ou "false", selon que la fonction de gestionnaire enveloppée renvoie une erreur ou non. |
|||
Éditeur | publish_time_seconds |
Un histogramme Prometheus. Enregistre le temps d'exécution de la fonction de publication décorée de l'éditeur. | success est "true" ou "false", selon que l'éditeur décoré renvoie une erreur ou non. |
Si l'éditeur opère dans un gestionnaire, définir handler_name ; sinon, " |
|||
publisher_name identifie l'éditeur. S'il implémente l'interface fmt.Stringer , c'est le résultat de String() ; sinon, c'est package.structName . |
De plus, chaque métrique a un libellé node
fourni par Prometheus, avec sa valeur correspondant à l'instance de la source de la métrique, et un libellé job
spécifié comme nom du travail dans le fichier de configuration de Prometheus.
Remarque : Comme mentionné ci-dessus, l'utilisation d'un namespace
ou subsystem
non vide entraînera un préfixe de nom de métrique. Vous devrez peut-être apporter des ajustements correspondants, comme dans la définition de panneau d'un tableau de bord Grafana.
Personnalisation
Si vous estimez qu'une certaine métrique a été négligée, vous pouvez facilement étendre cette implémentation de base. La meilleure façon est d'utiliser le registre Prometheus utilisé avec la méthode ServeHTTP
et d'enregistrer les métriques selon la documentation du client Prometheus ici.
Une méthode concise pour mettre à jour ces métriques consiste à utiliser des décorateurs. Le code source complet peut être trouvé à l'adresse github.com/ThreeDotsLabs/watermill/message/decorator.go.
// ...
// MessageTransformSubscriberDecorator crée un décorateur d'abonné qui appelle la fonction de transformation sur chaque message passée par l'abonné.
func MessageTransformSubscriberDecorator(transform func(*Message)) SubscriberDecorator {
if transform == nil {
panic("la fonction de transformation est nulle")
}
return func(sub Subscriber) (Subscriber, error) {
return &messageTransformSubscriberDecorator{
sub: sub,
transform: transform,
}, nil
}
}
// MessageTransformPublisherDecorator crée un décorateur d'éditeur qui appelle la fonction de transformation sur chaque message passée par l'éditeur.
func MessageTransformPublisherDecorator(transform func(*Message)) PublisherDecorator {
if transform == nil {
panic("la fonction de transformation est nulle")
}
return func(pub Publisher) (Publisher, error) {
return &messageTransformPublisherDecorator{
Publisher: pub,
transform: transform,
}, nil
}
}
type messageTransformSubscriberDecorator struct {
// ...
Et/ou des middleware dans les routeurs.
Une méthode plus simple consiste à mettre à jour les métriques requises uniquement dans les fonctions de gestionnaire.