golang-prometheus-metrics/

В рамках поста Устанавливаем связку из Prometheus и Grafana мы познакомились с Prometheus и разобрались с его настройкой. Теперь давайте выясним, как отправить в него каких-нибудь метрик из нашего собственного приложения. Писать будем на языке Go , но я почти уверен, что для других языков существуют аналогичные библиотеки.

Объем демонстрационного кода составил всего лишь 80 строк, так что просто рассмотрим его целиком:

package main

import (
«log»
«flag»
«math/rand»
«net/http»
«time»

«github.com/prometheus/client_golang/prometheus»
«github.com/prometheus/client_golang/prometheus/promhttp»
)

var addr = flag . String ( «listen-address» , «:8080» ,
«The address to listen on for HTTP requests.» )

func main () {
flag . Parse ()

usersRegistered := prometheus . NewCounter (
prometheus . CounterOpts {
Name : «users_registered» ,
})
prometheus . MustRegister ( usersRegistered )

usersOnline := prometheus . NewGauge (
prometheus . GaugeOpts {
Name : «users_online» ,
})
prometheus . MustRegister ( usersOnline )

requestProcessingTimeSummaryMs := prometheus . NewSummary (
prometheus . SummaryOpts {
Name : «request_processing_time_summary_ms» ,
Objectives : map [ float64 ] float64 { 0 . 5 : 0 . 05 , 0 . 9 : 0 . 01 , 0 . 99 : 0 . 001 },
})
prometheus . MustRegister ( requestProcessingTimeSummaryMs )

requestProcessingTimeHistogramMs := prometheus . NewHistogram (
prometheus . HistogramOpts {
Name : «request_processing_time_histogram_ms» ,
Buckets : prometheus . LinearBuckets ( 0 , 10 , 20 ),
})
prometheus . MustRegister ( requestProcessingTimeHistogramMs )

go func () {
for {
usersRegistered . Inc () // or: Add(5)
time . Sleep ( 1000 * time . Millisecond )
}
}()

go func () {
for {
for i := 0 ; i < 10000 ; i ++ {
usersOnline . Set ( float64 ( i )) // or: Inc(), Dec(), Add(5), Dec(5)
time . Sleep ( 10 * time . Millisecond )
}
}
}()

go func (){
src := rand . NewSource ( time . Now () . UnixNano ())
rnd := rand . New ( src )
for {
obs := float64 ( 100 + rnd . Intn ( 30 ))
requestProcessingTimeSummaryMs . Observe ( obs )
requestProcessingTimeHistogramMs . Observe ( obs )
time . Sleep ( 10 * time . Millisecond )
}
}()

http . Handle ( «/metrics» , promhttp . Handler ())

log . Printf ( «Starting web server at %s n » , * addr )
err := http . ListenAndServe ( * addr , nil )
if err != nil {
log . Printf ( «http.ListenAndServer: %v n » , err )
}
}

Библиотека автоматически экспортирует метрики рантайма языка Go, такие, как количество работающих горутин, время сборки мусора, и так далее. То есть, для получения этих метрик особо ничего делать не нужно.

Кроме того, мы можем создавать собственные метрики следующих типов:

  • Counter, как несложно угадать по названию, представляет собой простой счетчик. Не самый полезный тип метрики, поскольку счетчик этот является неубывающим. То есть, подходит он для отображения только чего-то вроде суммарного числа учетных записей в системе, да и то лишь при условии, что учетные записи являются неудаляемыми.
  • Gauge, здесь используется в значении «мера». Gauge похож на Counter, но в отличие от него может не только возрастать, но и убывать. Этот тип отлично подходит для отображения текущего значения чего-то — температуры, давления, числа пользователей онлайн, и так далее.
  • Histogram представляет собой гистограмму. Этот тип метрики хранит число раз, которое измеряемая величина попала в заданный интервал значений (бакет). Гистограммы может быть трудновато использовать, если интервал допустимых значений величины заранее неизвестен. В Grafana по гистограмме можно примерно посчитать процентили, используя функцию histogram_quantile .
  • Summary честно считает заданные процентили. Идеально подходит для измерения времени ответа или чего-то такого. Минус Summary заключается в том, что его дорого считать. Поэтому часто обходятся гистограммами и примерными значениями процентилей.
  • Наконец, существуют типы HistogramVec, SummaryVec и так далее. Они представляют собой словарь (map) из описанных выше типов. То есть, это как бы метрики со строковыми метками, или создаваемые на лету метрики. Отлично подходят в случаях, когда вам нужно измерить время ответа сервера в зависимости от запроса, или вроде того. Примеры использования этих типов метрик вы найдете на godoc.org .

Ну вот и все. Остается только дописать адрес нашего приложения в prometheus.yml, как ранее мы это делали для Node Exporter, сказать:

sudo systemctl restart prometheus

…, и метрики начнут собираться.

Метрики, к сожалению, не являются панацеей от всего. Допустим, у одного конкретного пользователя почему-то тормозит один конкретный запрос. А запрос этот на самом деле распадается на множество подзапросов к разным микросервисам. В такой ситуации метрики не помогут отследить, где и почему тормозит этот один запрос. Тем не менее, метрики довольно полезны, когда требуется оценить состояние системы в целом.

Дополнение: Вас также могут заинтересовать посты про агрегацию логов с Loki и распределенную трассировку при помощи Jaeger .

EnglishRussianUkrainian