Цели

  • Создание пользовательских метрик Prometheus в Go.
  • Визуализация пользовательских метрик в Grafana.
  • Создать веб-хук Slack.
  • Создать оповещение в Grafana.
  • Отправить в Slack сообщение с оповещением.

Создание пользовательских метрик Prometheus

  • prometheus.go:
package metrics

import (
"github.com/prometheus/client_golang/prometheus"
)

var (
HttpRequestCountWithPath = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "http_requests_total_with_path",
Help: "Number of HTTP requests by path.",
},
[]string{"url"},
)

// PROMQL => rate(http_request_duration_seconds_sum{}[5m]) / rate(http_request_duration_seconds_count{}[5m])
HttpRequestDuration = prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: "http_request_duration_seconds",
Help: "Response time of HTTP request.",
},
[]string{"path"},
)
)

func init() {
prometheus.MustRegister(HttpRequestCountWithPath)
prometheus.MustRegister(HttpRequestDuration)
}

HttpRequestCountWithPath: этой метрикой показывается, сколько HTTP-запросов отправляется по одному и тому же пути.

HttpRequestDuration: этой метрикой показывается время ответа HTTP-запроса.

prometheus.MustRegister() вызывается для регистрации метрик с Prometheus. Регистрация необходима для извлечения этих метрик с помощью Prometheus.

Использование метрик в промежуточном ПО

  • middleware.go:
/*
Регистрируем на New Relic все HTTP-запросы и ответы.
Генерируется пользовательская метрика счетчика для Prometheus. Используются путь HTTP-запроса и HTTP-метод.
*/
func (m middleware) LogMiddleware(ctx *gin.Context) {
reqMethodAndPath := fmt.Sprintf("[%s] %s", ctx.Request.Method, ctx.FullPath())

// Длительность ответа на HTTP-запрос
timer := prometheus.NewTimer(metrics.HttpRequestDuration.WithLabelValues(reqMethodAndPath))
defer timer.ObserveDuration()

var responseBody = logging.HandleResponseBody(ctx.Writer)
var requestBody = logging.HandleRequestBody(ctx.Request)
requestId := uuid.NewString()

if hub := sentrygin.GetHubFromContext(ctx); hub != nil {
hub.Scope().SetTag("requestId", requestId)
ctx.Writer = responseBody
}
ctx.Next()

statusCode := ctx.Writer.Status()
// Тот же счетчик пути HTTP-запроса
metrics.HttpRequestCountWithPath.With(prometheus.Labels{"url": reqMethodAndPath}).Inc()
logMessage := logging.FormatRequestAndResponse(statusCode, ctx.Request, responseBody.Body.String(), requestId, requestBody)

if logMessage != "" {
if isSuccessStatusCode(statusCode) {
m.logger.Info(logMessage)
} else {
m.logger.Error(logMessage)
}
}
}

func isSuccessStatusCode(statusCode int) bool {
switch statusCode {
case http.StatusOK, http.StatusCreated, http.StatusAccepted, http.StatusNoContent:
return true
default:
return false
}
}

Пользовательские метрики в Grafana

PromQl => my_http_requests_total_with_path

PromQl =>

rate(http_request_duration_seconds_sum{}[5m]) 

rate(http_request_duration_seconds_count{}[5m])

Разделив показатель суммы на показатель счетчика, получаем среднюю продолжительность каждого запроса за последние пять минут.

Создание веб-хука Slack

У меня уже имеются бот и веб-хук Slack, которым на канал #random в Slack отправляется сообщение.

Создание оповещения в Grafana

По этой ссылке создаем контактную точку оповещения с URL-адресом веб-хука Slack:

Если среднее время ответа на HTTP-запрос больше 0,3 мс, на канал Slack отправляется сообщение с оповещением, это последние пять минут в этом запросе.

Сохраним правило и обратим внимание на состояние работоспособности:

Похоже, работоспособность в норме.

Отправка HTTP-запроса со временем ожидания

Этой строкой время отклика задерживается.

В конечную точку GetUserById отправлено слишком много запросов.

  • Время отклика  —  более 0,5 мс.
  • Среднее время отклика увеличилось.
  • Появляется тег запуска.
  • Похоже, метрика нерабочая.
  • Оповещение активировалось, и на канал Slack отправлено сообщение.

Сообщение с оповещением настраивается добавлением аннотаций или указанием пользователей.

Вот репозиторий на GitHub.

Читайте также:

Читайте нас в Telegram, VK и Дзен


Перевод статьи Mert ÇAKMAK: Creating Custom Prometheus Metrics in Golang and Sending Alerts to Slack (with Grafana)

Предыдущая статьяОбзор курса “Полное введение в React” от Frontend Masters
Следующая статьяВозможности контроля в JavaScript: методы AbortSignal.timeout() и AbortSignal.any()