Um cliente prometheus para Node.js que oferece suporte a histogramas, resumos, medidores e contadores.
Veja a pasta de exemplo para um exemplo de uso. A biblioteca não inclui nenhuma estrutura da web. Para expor as métricas, responda às solicitações de raspagem do Prometheus com o resultado de await registry.metrics()
.
cluster
do Node.js O módulo cluster
do Node.js gera vários processos e transfere conexões de soquete para esses trabalhadores. O retorno de métricas do registro local de um trabalhador revelará apenas as métricas desse trabalhador individual, o que geralmente é indesejável. Para resolver isso, você pode agregar todas as métricas dos trabalhadores no processo mestre. Veja example/cluster.js
para ver um exemplo.
As métricas padrão usam métodos de agregação sensatos. (Observe, no entanto, que a média e os percentis do atraso do loop de eventos são calculados, o que não é perfeitamente preciso.) As métricas personalizadas são somadas entre os trabalhadores por padrão. Para usar um método de agregação diferente, defina a propriedade aggregator
na configuração da métrica como 'sum', 'first', 'min', 'max', 'average' ou 'omit'. (Veja lib/metrics/version.js
para ver um exemplo.)
Se precisar expor métricas sobre um trabalhador individual, você poderá incluir um valor exclusivo para o trabalhador (como o ID do trabalhador ou o ID do processo) em um rótulo. (Veja example/server.js
para ver um exemplo usando worker_${cluster.worker.id}
como um valor de rótulo.)
As métricas são agregadas do registro global por padrão. Para usar um registro diferente, chame client.AggregatorRegistry.setRegistries(registryOrArrayOfRegistries)
dos processos de trabalho.
Existem algumas métricas padrão recomendadas pelo próprio Prometheus. Para coletá-los, chame collectDefaultMetrics
. Além disso, algumas métricas específicas do Node.js estão incluídas, como atraso do loop de eventos, identificadores ativos, GC e versão do Node.js. Consulte lib/metrics para obter uma lista de todas as métricas.
NOTA: Algumas das métricas relativas aos descritores de arquivos e memória estão disponíveis apenas no Linux.
collectDefaultMetrics
aceita opcionalmente um objeto de configuração com as seguintes entradas:
prefix
um prefixo opcional para nomes de métricas. Padrão: sem prefixo.register
em qual registro as métricas devem ser registradas. Padrão: o registro padrão global.gcDurationBuckets
com intervalos personalizados para histograma de duração do GC. Os intervalos padrão do histograma de duração do GC são [0.001, 0.01, 0.1, 1, 2, 5]
(em segundos).eventLoopMonitoringPrecision
com taxa de amostragem em milissegundos. Deve ser maior que zero. Padrão: 10. Para registrar métricas em outro registro, passe-o como register
:
const client = require ( 'prom-client' ) ;
const collectDefaultMetrics = client . collectDefaultMetrics ;
const Registry = client . Registry ;
const register = new Registry ( ) ;
collectDefaultMetrics ( { register } ) ;
Para usar intervalos personalizados para o histograma de duração do GC, passe-o como gcDurationBuckets
:
const client = require ( 'prom-client' ) ;
const collectDefaultMetrics = client . collectDefaultMetrics ;
collectDefaultMetrics ( { gcDurationBuckets : [ 0.1 , 0.2 , 0.3 ] } ) ;
Para prefixar nomes de métricas com sua própria string arbitrária, passe um prefix
:
const client = require ( 'prom-client' ) ;
const collectDefaultMetrics = client . collectDefaultMetrics ;
const prefix = 'my_application_' ;
collectDefaultMetrics ( { prefix } ) ;
Para aplicar rótulos genéricos a todas as métricas padrão, passe um objeto para a propriedade labels
(útil se você estiver trabalhando em um ambiente clusterizado):
const client = require ( 'prom-client' ) ;
const collectDefaultMetrics = client . collectDefaultMetrics ;
collectDefaultMetrics ( {
labels : { NODE_APP_INSTANCE : process . env . NODE_APP_INSTANCE } ,
} ) ;
Você pode obter a lista completa de métricas inspecionando client.collectDefaultMetrics.metricsList
.
As métricas padrão são coletadas na coleta do endpoint de métricas, não em um intervalo.
const client = require ( 'prom-client' ) ;
const collectDefaultMetrics = client . collectDefaultMetrics ;
collectDefaultMetrics ( ) ;
Todos os tipos de métricas possuem dois parâmetros obrigatórios: name
e help
. Consulte https://prometheus.io/docs/practices/naming/ para obter orientação sobre como nomear métricas.
Para métricas baseadas em observações pontuais (por exemplo, uso atual de memória, em oposição às durações de solicitação HTTP observadas continuamente em um histograma), você deve fornecer uma função collect()
, que será invocada quando o Prometheus raspar o endpoint de suas métricas. collect()
pode ser síncrono ou retornar uma promessa. Veja o medidor abaixo para ver um exemplo. (Observe que você não deve atualizar valores de métrica em um retorno de chamada setInterval
; em vez disso, faça isso nesta função collect
.)
Consulte Rótulos para obter informações sobre como configurar rótulos para todos os tipos de métricas.
Os contadores aumentam e são redefinidos quando o processo é reiniciado.
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
Os medidores são semelhantes aos contadores, mas o valor de um medidor pode ser diminuído.
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
Se o medidor for usado para uma observação pontual, você deverá fornecer uma função 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 ) ;
} ,
} ) ;
Observe que você não deve usar funções de seta para collect
porque as funções de seta não terão o valor correto para this
.
// Set value to current time in seconds:
gauge . setToCurrentTime ( ) ;
// Record durations:
const end = gauge . startTimer ( ) ;
http . get ( 'url' , res => {
end ( ) ;
} ) ;
Os histogramas rastreiam os tamanhos e a frequência dos eventos.
Os buckets padrão destinam-se a cobrir solicitações usuais da Web/RPC, mas podem ser substituídos. (Veja também Geradores de balde .)
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
} ) ;
Os resumos calculam percentis dos valores observados.
Os percentis padrão são: 0,01, 0,05, 0,5, 0,9, 0,95, 0,99, 0,999. Mas eles podem ser substituídos especificando uma matriz percentiles
. (Veja também Geradores de balde .)
const client = require ( 'prom-client' ) ;
new client . Summary ( {
name : 'metric_name' ,
help : 'metric_help' ,
percentiles : [ 0.01 , 0.1 , 0.9 , 0.99 ] ,
} ) ;
Para ativar a funcionalidade de janela deslizante para resumos, você precisa adicionar maxAgeSeconds
e ageBuckets
à configuração assim:
const client = require ( 'prom-client' ) ;
new client . Summary ( {
name : 'metric_name' ,
help : 'metric_help' ,
maxAgeSeconds : 600 ,
ageBuckets : 5 ,
pruneAgedBuckets : false ,
} ) ;
O maxAgeSeconds
dirá quantos anos um bucket pode ter antes de ser redefinido e ageBuckets
configura quantos buckets teremos em nossa janela deslizante para o resumo. Se pruneAgedBuckets
for false
(padrão), o valor da métrica sempre estará presente, mesmo quando vazio (seus valores percentuais serão 0
). Defina pruneAgedBuckets
como true
se não quiser exportá-lo quando estiver vazio.
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
} ) ;
Todas as métricas podem receber uma propriedade labelNames
no objeto de configuração. Todos os nomes de rótulos que a métrica suporta precisam ser declarados aqui. Existem duas maneiras de adicionar valores aos rótulos:
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 ) ;
Também é possível usar temporizadores com rótulos, antes e depois da criação do temporizador:
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
}
} ) ;
As métricas com rótulos não podem ser exportadas antes de serem observadas pelo menos uma vez, pois os possíveis valores dos rótulos não são conhecidos antes de serem observados.
Para histogramas, isso pode ser resolvido zerando explicitamente todos os valores de rótulo esperados:
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' } ) ;
O Typescript também pode impor nomes de rótulos usando 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 } ) ;
Rótulos estáticos podem ser aplicados a todas as métricas emitidas por um registro:
const client = require ( 'prom-client' ) ;
const defaultLabels = { serviceName : 'api-v1' } ;
client . register . setDefaultLabels ( defaultLabels ) ;
Isso gerará métricas da seguinte maneira:
# 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
Os rótulos padrão serão substituídos se houver conflito de nomes.
register.clear()
limpará os rótulos padrão.
Os exemplares definidos na especificação OpenMetrics podem ser habilitados nos tipos de métricas Contador e Histograma. As métricas padrão têm suporte para OpenTelemetry, elas preencherão os exemplares com os rótulos {traceId, spanId}
e seus valores correspondentes.
O formato para chamadas inc()
e observe()
será diferente se os exemplares estiverem habilitados. Eles obtêm um único objeto com o formato {labels, value, exemplarLabels}
.
Ao usar exemplares, o registro usado para métricas deve ser definido como o tipo OpenMetrics (incluindo o registro global ou padrão se nenhum registro for especificado).
A biblioteca oferece suporte ao antigo formato Prometheus e ao formato OpenMetrics. O formato pode ser definido por registro. Para métricas padrão:
const Prometheus = require ( 'prom-client' ) ;
Prometheus . register . setContentType (
Prometheus . Registry . OPENMETRICS_CONTENT_TYPE ,
) ;
Os tipos de registro disponíveis atualmente são definidos pelos tipos de conteúdo:
PROMETHEUS_CONTENT_TYPE - versão 0.0.4 das métricas originais do Prometheus, atualmente é o tipo de registro padrão.
OPENMETRICS_CONTENT_TYPE - o padrão é a versão 1.0.0 do padrão OpenMetrics.
A cadeia de caracteres HTTP Content-Type para cada tipo de registro é exposta no nível do módulo ( prometheusContentType
e openMetricsContentType
) e como propriedades estáticas no objeto Registry
.
A constante contentType
exposta pelo módulo retorna o tipo de conteúdo padrão ao criar um novo registro, atualmente o padrão é o tipo Prometheus.
Por padrão, as métricas são registradas automaticamente no registro global (localizado em require('prom-client').register
). Você pode evitar isso especificando registers: []
na configuração do construtor de métrica.
O uso de registros não globais requer a criação de uma instância do Registro e sua transmissão dentro registers
no objeto de configuração de métrica. Alternativamente, você pode passar um array registers
vazio e registrá-lo manualmente.
O registro possui uma função merge
que permite expor vários registros no mesmo terminal. Se o mesmo nome de métrica existir em ambos os registros, será gerado um erro.
A mesclagem de registros de tipos diferentes é indefinida. O usuário precisa garantir que todos os registros usados sejam do mesmo tipo (versões 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 ] ) ;
Se quiser usar registros múltiplos ou não padrão com o módulo cluster
Node.js, você precisará definir os registros/registros para agregar de:
const AggregatorRegistry = client . AggregatorRegistry ;
AggregatorRegistry . setRegistries ( registry ) ;
// or for multiple registries:
AggregatorRegistry . setRegistries ( [ registry1 , registry2 ] ) ;
Você pode obter todas as métricas executando await register.metrics()
, que retornará uma string no formato de exposição do Prometheus.
Se você precisar gerar uma única métrica no formato de exposição do Prometheus, poderá usar await register.getSingleMetricAsString(*name of metric*)
, que retornará uma string para o Prometheus consumir.
Se precisar obter uma referência a uma métrica registrada anteriormente, você pode usar register.getSingleMetric(*name of metric*)
.
Você pode remover todas as métricas chamando register.clear()
. Você também pode remover uma única métrica chamando register.removeSingleMetric(*name of metric*)
.
Se precisar redefinir todas as métricas, você pode usar register.resetMetrics()
. As métricas permanecerão presentes no registrador e poderão ser utilizadas sem a necessidade de instanciá-las novamente, como seria necessário fazer após register.clear()
.
Você pode obter métricas agregadas para todos os trabalhadores em um cluster Node.js com await register.clusterMetrics()
. Este método retorna uma promessa que é resolvida com uma string de métricas adequada para o Prometheus consumir.
const metrics = await register . clusterMetrics ( ) ;
// - or -
register
. clusterMetrics ( )
. then ( metrics => {
/* ... */
} )
. catch ( err => {
/* ... */
} ) ;
É possível enviar métricas por meio de um 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 => {
/* ... */
} ) )