Un client Prometheus pour Node.js qui prend en charge l'histogramme, les résumés, les jauges et les compteurs.
Voir le dossier d'exemple pour un exemple d'utilisation. La bibliothèque ne regroupe aucun framework Web. Pour exposer les métriques, répondez aux requêtes scrape de Prometheus avec le résultat de await registry.metrics()
.
cluster
de Node.js Le module cluster
de Node.js génère plusieurs processus et transmet les connexions socket à ces travailleurs. Le renvoi des mesures du registre local d'un travailleur ne révélera que les mesures de ce travailleur individuel, ce qui n'est généralement pas souhaitable. Pour résoudre ce problème, vous pouvez regrouper toutes les mesures des travailleurs dans le processus principal. Voir example/cluster.js
pour un exemple.
Les métriques par défaut utilisent des méthodes d'agrégation judicieuses. (Notez cependant que la moyenne du retard de la boucle d'événement et les percentiles sont calculés en moyenne, ce qui n'est pas parfaitement précis.) Les métriques personnalisées sont additionnées par défaut pour tous les nœuds de calcul. Pour utiliser une méthode d'agrégation différente, définissez la propriété aggregator
dans la configuration des métriques sur l'une des valeurs suivantes : "sum", "first", "min", "max", "average" ou "omit". (Voir lib/metrics/version.js
pour un exemple.)
Si vous devez exposer des métriques sur un travailleur individuel, vous pouvez inclure une valeur unique au travailleur (telle que l'ID du travailleur ou l'ID du processus) dans une étiquette. (Voir example/server.js
pour un exemple utilisant worker_${cluster.worker.id}
comme valeur d'étiquette.)
Les métriques sont regroupées par défaut à partir du registre global. Pour utiliser un autre registre, appelez client.AggregatorRegistry.setRegistries(registryOrArrayOfRegistries)
à partir des processus de travail.
Certaines métriques par défaut sont recommandées par Prometheus lui-même. Pour les collecter, appelez collectDefaultMetrics
. De plus, certaines métriques spécifiques à Node.js sont incluses, telles que le décalage de boucle d'événement, les descripteurs actifs, la version GC et Node.js. Voir lib/metrics pour une liste de toutes les métriques.
REMARQUE : Certaines métriques, concernant les descripteurs de fichiers et la mémoire, ne sont disponibles que sous Linux.
collectDefaultMetrics
accepte éventuellement un objet de configuration avec les entrées suivantes :
prefix
un préfixe facultatif pour les noms de métriques. Par défaut : pas de préfixe.register
dans quel registre les métriques doivent être enregistrées. Par défaut : le registre global par défaut.gcDurationBuckets
avec des compartiments personnalisés pour l'histogramme de durée GC. Les tranches par défaut de l'histogramme de durée GC sont [0.001, 0.01, 0.1, 1, 2, 5]
(en secondes).eventLoopMonitoringPrecision
avec taux d'échantillonnage en millisecondes. Doit être supérieur à zéro. Par défaut : 10. Pour enregistrer des métriques dans un autre registre, transmettez-les en tant que register
:
const client = require ( 'prom-client' ) ;
const collectDefaultMetrics = client . collectDefaultMetrics ;
const Registry = client . Registry ;
const register = new Registry ( ) ;
collectDefaultMetrics ( { register } ) ;
Pour utiliser des compartiments personnalisés pour l'histogramme de durée GC, transmettez-le sous la forme gcDurationBuckets
:
const client = require ( 'prom-client' ) ;
const collectDefaultMetrics = client . collectDefaultMetrics ;
collectDefaultMetrics ( { gcDurationBuckets : [ 0.1 , 0.2 , 0.3 ] } ) ;
Pour préfixer les noms de métriques avec votre propre chaîne arbitraire, transmettez un prefix
:
const client = require ( 'prom-client' ) ;
const collectDefaultMetrics = client . collectDefaultMetrics ;
const prefix = 'my_application_' ;
collectDefaultMetrics ( { prefix } ) ;
Pour appliquer des étiquettes génériques à toutes les métriques par défaut, transmettez un objet à la propriété labels
(utile si vous travaillez dans un environnement clusterisé) :
const client = require ( 'prom-client' ) ;
const collectDefaultMetrics = client . collectDefaultMetrics ;
collectDefaultMetrics ( {
labels : { NODE_APP_INSTANCE : process . env . NODE_APP_INSTANCE } ,
} ) ;
Vous pouvez obtenir la liste complète des métriques en inspectant client.collectDefaultMetrics.metricsList
.
Les métriques par défaut sont collectées lors du scraping du point de terminaison des métriques, et non selon un intervalle.
const client = require ( 'prom-client' ) ;
const collectDefaultMetrics = client . collectDefaultMetrics ;
collectDefaultMetrics ( ) ;
Tous les types de métriques ont deux paramètres obligatoires : name
et help
. Reportez-vous à https://prometheus.io/docs/practices/naming/ pour obtenir des conseils sur la dénomination des métriques.
Pour les métriques basées sur des observations ponctuelles (par exemple, l'utilisation actuelle de la mémoire, par opposition aux durées des requêtes HTTP observées en continu dans un histogramme), vous devez fournir une fonction collect()
, qui sera invoquée lorsque Prometheus récupère le point de terminaison de vos métriques. collect()
peut être synchrone ou renvoyer une promesse. Voir Jauge ci-dessous pour un exemple. (Notez que vous ne devez pas mettre à jour les valeurs des métriques dans un rappel setInterval
; faites-le plutôt dans cette fonction collect
.)
Voir Étiquettes pour plus d'informations sur la configuration des étiquettes pour tous les types de métriques.
Les compteurs augmentent et se réinitialisent lorsque le processus redémarre.
const client = require ( 'prom-client' ) ;
const counter = new client . Counter ( {
name : 'metric_name' ,
help : 'metric_help' ,
} ) ;
counter . inc ( ) ; // Increment by 1
counter . inc ( 10 ) ; // Increment by 10
Les jauges sont similaires aux compteurs mais la valeur d'une jauge peut être diminuée.
const client = require ( 'prom-client' ) ;
const gauge = new client . Gauge ( { name : 'metric_name' , help : 'metric_help' } ) ;
gauge . set ( 10 ) ; // Set to 10
gauge . inc ( ) ; // Increment 1
gauge . inc ( 10 ) ; // Increment 10
gauge . dec ( ) ; // Decrement by 1
gauge . dec ( 10 ) ; // Decrement by 10
Si la jauge est utilisée pour une observation ponctuelle, vous devez fournir une fonction collect
:
const client = require ( 'prom-client' ) ;
new client . Gauge ( {
name : 'metric_name' ,
help : 'metric_help' ,
collect ( ) {
// Invoked when the registry collects its metrics' values.
// This can be synchronous or it can return a promise/be an async function.
this . set ( /* the current value */ ) ;
} ,
} ) ;
// Async version:
const client = require ( 'prom-client' ) ;
new client . Gauge ( {
name : 'metric_name' ,
help : 'metric_help' ,
async collect ( ) {
// Invoked when the registry collects its metrics' values.
const currentValue = await somethingAsync ( ) ;
this . set ( currentValue ) ;
} ,
} ) ;
Notez que vous ne devez pas utiliser de fonctions fléchées pour collect
car les fonctions fléchées n'auront pas la valeur correcte pour this
.
// Set value to current time in seconds:
gauge . setToCurrentTime ( ) ;
// Record durations:
const end = gauge . startTimer ( ) ;
http . get ( 'url' , res => {
end ( ) ;
} ) ;
Les histogrammes suivent la taille et la fréquence des événements.
Les compartiments par défaut sont destinés à couvrir les requêtes Web/RPC habituelles, mais ils peuvent être remplacés. (Voir aussi Générateurs de godets .)
const client = require ( 'prom-client' ) ;
new client . Histogram ( {
name : 'metric_name' ,
help : 'metric_help' ,
buckets : [ 0.1 , 5 , 15 , 50 , 100 , 500 ] ,
} ) ;
const client = require ( 'prom-client' ) ;
const histogram = new client . Histogram ( {
name : 'metric_name' ,
help : 'metric_help' ,
} ) ;
histogram . observe ( 10 ) ; // Observe value in histogram
const end = histogram . startTimer ( ) ;
xhrRequest ( function ( err , res ) {
const seconds = end ( ) ; // Observes and returns the value to xhrRequests duration in seconds
} ) ;
Les résumés calculent les percentiles des valeurs observées.
Les percentiles par défaut sont : 0,01, 0,05, 0,5, 0,9, 0,95, 0,99, 0,999. Mais ils peuvent être remplacés en spécifiant un tableau percentiles
. (Voir aussi Générateurs de godets .)
const client = require ( 'prom-client' ) ;
new client . Summary ( {
name : 'metric_name' ,
help : 'metric_help' ,
percentiles : [ 0.01 , 0.1 , 0.9 , 0.99 ] ,
} ) ;
Pour activer la fonctionnalité de fenêtre coulissante pour les résumés, vous devez ajouter maxAgeSeconds
et ageBuckets
à la configuration comme ceci :
const client = require ( 'prom-client' ) ;
new client . Summary ( {
name : 'metric_name' ,
help : 'metric_help' ,
maxAgeSeconds : 600 ,
ageBuckets : 5 ,
pruneAgedBuckets : false ,
} ) ;
maxAgeSeconds
indiquera l'âge d'un bucket avant sa réinitialisation et ageBuckets
configure le nombre de buckets que nous aurons dans notre fenêtre coulissante pour le résumé. Si pruneAgedBuckets
est false
(par défaut), la valeur de la métrique sera toujours présente, même lorsqu'elle est vide (ses valeurs centiles seront 0
). Définissez pruneAgedBuckets
sur true
si vous ne souhaitez pas l'exporter lorsqu'il est vide.
const client = require ( 'prom-client' ) ;
const summary = new client . Summary ( {
name : 'metric_name' ,
help : 'metric_help' ,
} ) ;
summary . observe ( 10 ) ;
const end = summary . startTimer ( ) ;
xhrRequest ( function ( err , res ) {
end ( ) ; // Observes the value to xhrRequests duration in seconds
} ) ;
Toutes les métriques peuvent prendre une propriété labelNames
dans l'objet de configuration. Tous les noms d’étiquettes que la prise en charge des métriques doit être déclarés ici. Il existe deux manières d'ajouter des valeurs aux étiquettes :
const client = require ( 'prom-client' ) ;
const gauge = new client . Gauge ( {
name : 'metric_name' ,
help : 'metric_help' ,
labelNames : [ 'method' , 'statusCode' ] ,
} ) ;
// 1st version: Set value to 100 with "method" set to "GET" and "statusCode" to "200"
gauge . set ( { method : 'GET' , statusCode : '200' } , 100 ) ;
// 2nd version: Same effect as above
gauge . labels ( { method : 'GET' , statusCode : '200' } ) . set ( 100 ) ;
// 3rd version: And again the same effect as above
gauge . labels ( 'GET' , '200' ) . set ( 100 ) ;
Il est également possible d'utiliser des timers avec des étiquettes, avant et après la création du timer :
const end = startTimer ( { method : 'GET' } ) ; // Set method to GET, we don't know statusCode yet
xhrRequest ( function ( err , res ) {
if ( err ) {
end ( { statusCode : '500' } ) ; // Sets value to xhrRequest duration in seconds with statusCode 500
} else {
end ( { statusCode : '200' } ) ; // Sets value to xhrRequest duration in seconds with statusCode 200
}
} ) ;
Les métriques avec des étiquettes ne peuvent pas être exportées avant d'avoir été observées au moins une fois, car les valeurs d'étiquette possibles ne sont pas connues avant d'être observées.
Pour les histogrammes, cela peut être résolu en mettant explicitement à zéro toutes les valeurs d'étiquette attendues :
const histogram = new client . Histogram ( {
name : 'metric_name' ,
help : 'metric_help' ,
buckets : [ 0.1 , 5 , 15 , 50 , 100 , 500 ] ,
labels : [ 'method' ] ,
} ) ;
histogram . zero ( { method : 'GET' } ) ;
histogram . zero ( { method : 'POST' } ) ;
Typescript peut également appliquer les noms d'étiquettes en utilisant as const
import * as client from 'prom-client' ;
const counter = new client . Counter ( {
name : 'metric_name' ,
help : 'metric_help' ,
// add `as const` here to enforce label names
labelNames : [ 'method' ] as const ,
} ) ;
// Ok
counter . inc ( { method : 1 } ) ;
// this is an error since `'methods'` is not a valid `labelName`
// @ts-expect-error
counter . inc ( { methods : 1 } ) ;
Des étiquettes statiques peuvent être appliquées à chaque métrique émise par un registre :
const client = require ( 'prom-client' ) ;
const defaultLabels = { serviceName : 'api-v1' } ;
client . register . setDefaultLabels ( defaultLabels ) ;
Cela affichera les métriques de la manière suivante :
# HELP process_resident_memory_bytes Resident memory size in bytes.
# TYPE process_resident_memory_bytes gauge
process_resident_memory_bytes{serviceName="api-v1"} 33853440 1498510040309
Les étiquettes par défaut seront remplacées en cas de conflit de noms.
register.clear()
effacera les étiquettes par défaut.
Les exemples définis dans la spécification OpenMetrics peuvent être activés sur les types de métriques Compteur et Histogramme. Les métriques par défaut prennent en charge OpenTelemetry, elles rempliront les exemplaires avec les étiquettes {traceId, spanId}
et leurs valeurs correspondantes.
Le format des appels inc()
et observe()
est différent si les exemplaires sont activés. Ils obtiennent un seul objet au format {labels, value, exemplarLabels}
.
Lors de l'utilisation d'exemples, le registre utilisé pour les métriques doit être défini sur le type OpenMetrics (y compris le registre global ou par défaut si aucun registre n'est spécifié).
La bibliothèque prend en charge à la fois l'ancien format Prometheus et le format OpenMetrics. Le format peut être défini par registre. Pour les métriques par défaut :
const Prometheus = require ( 'prom-client' ) ;
Prometheus . register . setContentType (
Prometheus . Registry . OPENMETRICS_CONTENT_TYPE ,
) ;
Les types de registre actuellement disponibles sont définis par les types de contenu :
PROMETHEUS_CONTENT_TYPE - version 0.0.4 des métriques Prometheus d'origine, il s'agit actuellement du type de registre par défaut.
OPENMETRICS_CONTENT_TYPE - par défaut la version 1.0.0 de la norme OpenMetrics.
La chaîne HTTP Content-Type pour chaque type de registre est exposée à la fois au niveau du module ( prometheusContentType
et openMetricsContentType
) et en tant que propriétés statiques sur l'objet Registry
.
La constante contentType
exposée par le module renvoie le type de contenu par défaut lors de la création d'un nouveau registre, actuellement par défaut le type Prometheus.
Par défaut, les métriques sont automatiquement enregistrées dans le registre global (situé dans require('prom-client').register
). Vous pouvez éviter cela en spécifiant registers: []
dans la configuration du constructeur de métriques.
L'utilisation de registres non globaux nécessite la création d'une instance de registre et sa transmission dans registers
de l'objet de configuration de métrique. Vous pouvez également transmettre un tableau registers
vide et l'enregistrer manuellement.
Le registre dispose d'une fonction merge
qui vous permet d'exposer plusieurs registres sur le même point de terminaison. Si le même nom de métrique existe dans les deux registres, une erreur sera générée.
La fusion de registres de différents types n'est pas définie. L'utilisateur doit s'assurer que tous les registres utilisés ont le même type (versions Prometheus ou OpenMetrics).
const client = require ( 'prom-client' ) ;
const registry = new client . Registry ( ) ;
const counter = new client . Counter ( {
name : 'metric_name' ,
help : 'metric_help' ,
registers : [ registry ] , // specify a non-default registry
} ) ;
const histogram = new client . Histogram ( {
name : 'metric_name' ,
help : 'metric_help' ,
registers : [ ] , // don't automatically register this metric
} ) ;
registry . registerMetric ( histogram ) ; // register metric manually
counter . inc ( ) ;
const mergedRegistries = client . Registry . merge ( [ registry , client . register ] ) ;
Si vous souhaitez utiliser plusieurs registres ou non par défaut avec le module cluster
Node.js, vous devrez configurer le(s) registre(s) pour qu'ils s'agrègent à partir de :
const AggregatorRegistry = client . AggregatorRegistry ;
AggregatorRegistry . setRegistries ( registry ) ;
// or for multiple registries:
AggregatorRegistry . setRegistries ( [ registry1 , registry2 ] ) ;
Vous pouvez obtenir toutes les métriques en exécutant await register.metrics()
, qui renverra une chaîne au format d'exposition Prometheus.
Si vous devez générer une seule métrique au format d'exposition Prometheus, vous pouvez utiliser await register.getSingleMetricAsString(*name of metric*)
, qui renverra une chaîne que Prometheus pourra consommer.
Si vous avez besoin d'obtenir une référence à une métrique précédemment enregistrée, vous pouvez utiliser register.getSingleMetric(*name of metric*)
.
Vous pouvez supprimer toutes les métriques en appelant register.clear()
. Vous pouvez également supprimer une seule métrique en appelant register.removeSingleMetric(*name of metric*)
.
Si vous devez réinitialiser toutes les métriques, vous pouvez utiliser register.resetMetrics()
. Les métriques resteront présentes dans le registre et pourront être utilisées sans qu'il soit nécessaire de les instancier à nouveau, comme vous auriez besoin de le faire après register.clear()
.
Vous pouvez obtenir des métriques agrégées pour tous les nœuds de calcul d'un cluster Node.js avec await register.clusterMetrics()
. Cette méthode renvoie une promesse qui se résout avec une chaîne de métriques adaptée à la consommation de Prometheus.
const metrics = await register . clusterMetrics ( ) ;
// - or -
register
. clusterMetrics ( )
. then ( metrics => {
/* ... */
} )
. catch ( err => {
/* ... */
} ) ;
Il est possible de pousser des métriques via un Pushgateway.
const client = require ( 'prom-client' ) ;
let gateway = new client . Pushgateway ( 'http://127.0.0.1:9091' ) ;
gateway . pushAdd ( { jobName : 'test' } )
. then ( ( { resp , body } ) => {
/* ... */
} )
. catch ( err => {
/* ... */
} ) ) ; //Add metric and overwrite old ones
gateway . push ( { jobName : 'test' } )
. then ( ( { resp , body } ) => {
/* ... */
} )
. catch ( err => {
/* ... */
} ) ) ; //Overwrite all metrics (use PUT)
gateway . delete ( { jobName : 'test' } )
. then ( ( { resp , body } ) => {
/* ... */
} )
. catch ( err => {
/* ... */
} ) ) ; //Delete all metrics for jobName
//All gateway requests can have groupings on it
gateway . pushAdd ( { jobName : 'test' , groupings : { key : 'value' } } )
. then ( ( { resp , body } ) => {
/* ... */
} )
. catch ( err => {
/* ... */
} ) )