madipo2611 e58bbb71be
All checks were successful
continuous-integration/drone/push Build is passing
v0.0.24 Добавлены метрики в messages_resolvers
2025-08-22 23:01:49 +03:00

253 lines
6.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package middleware
import (
"net/http"
"strconv"
"time"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
)
var (
// HTTP метрики
httpRequestsTotal = promauto.NewCounterVec(
prometheus.CounterOpts{
Name: "http_requests_total",
Help: "Total number of HTTP requests",
},
[]string{"method", "path", "status", "handler"},
)
httpRequestDuration = promauto.NewHistogramVec(
prometheus.HistogramOpts{
Name: "http_request_duration_seconds",
Help: "Duration of HTTP requests",
Buckets: []float64{0.01, 0.05, 0.1, 0.5, 1, 2.5, 5, 10},
},
[]string{"method", "path", "handler"},
)
// GraphQL специфичные метрики
gqlOperationsTotal = promauto.NewCounterVec(
prometheus.CounterOpts{
Name: "graphql_operations_total",
Help: "Total number of GraphQL operations",
},
[]string{"operation", "type", "name", "success"},
)
gqlOperationDuration = promauto.NewHistogramVec(
prometheus.HistogramOpts{
Name: "graphql_operation_duration_seconds",
Help: "Duration of GraphQL operations",
Buckets: []float64{0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1, 2, 5},
},
[]string{"operation", "type", "name"},
)
// Бизнес метрики
usersTotal = promauto.NewGauge(
prometheus.GaugeOpts{
Name: "users_total",
Help: "Total number of registered users",
},
)
postsTotal = promauto.NewGauge(
prometheus.GaugeOpts{
Name: "posts_total",
Help: "Total number of posts",
},
)
commentsTotal = promauto.NewGauge(
prometheus.GaugeOpts{
Name: "comments_total",
Help: "Total number of comments",
},
)
messagesTotal = promauto.NewGauge(
prometheus.GaugeOpts{
Name: "messages_total",
Help: "Total number of messages",
},
)
activeWebsockets = promauto.NewGauge(
prometheus.GaugeOpts{
Name: "websocket_connections_active",
Help: "Number of active WebSocket connections",
},
)
websocketMessagesTotal = promauto.NewCounterVec(
prometheus.CounterOpts{
Name: "websocket_messages_total",
Help: "Total number of WebSocket messages",
},
[]string{"direction", "type"},
)
// Метрики ошибок
errorsTotal = promauto.NewCounterVec(
prometheus.CounterOpts{
Name: "errors_total",
Help: "Total number of errors by type",
},
[]string{"type", "source", "severity"},
)
// Метрики базы данных
dbQueriesTotal = promauto.NewCounterVec(
prometheus.CounterOpts{
Name: "db_queries_total",
Help: "Total number of database queries",
},
[]string{"operation", "table", "success"},
)
dbQueryDuration = promauto.NewHistogramVec(
prometheus.HistogramOpts{
Name: "db_query_duration_seconds",
Help: "Duration of database queries",
Buckets: []float64{0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1, 2},
},
[]string{"operation", "table"},
)
// Метрики кэша
cacheHitsTotal = promauto.NewCounterVec(
prometheus.CounterOpts{
Name: "cache_hits_total",
Help: "Total number of cache hits",
},
[]string{"type", "name"},
)
cacheMissesTotal = promauto.NewCounterVec(
prometheus.CounterOpts{
Name: "cache_misses_total",
Help: "Total number of cache misses",
},
[]string{"type", "name"},
)
)
// MetricsMiddleware собирает метрики для Prometheus
func MetricsMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
rw := &responseWriter{w, http.StatusOK, 0}
next.ServeHTTP(rw, r)
duration := time.Since(start).Seconds()
status := strconv.Itoa(rw.status)
// Определяем handler type
handlerType := "http"
if r.URL.Path == "/query" {
handlerType = "graphql"
} else if r.URL.Path == "/ws" {
handlerType = "websocket"
}
httpRequestsTotal.WithLabelValues(
r.Method,
r.URL.Path,
status,
handlerType,
).Inc()
httpRequestDuration.WithLabelValues(
r.Method,
r.URL.Path,
handlerType,
).Observe(duration)
})
}
// GraphQLMetricsMiddleware для отслеживания GraphQL операций
func GraphQLMetricsMiddleware() func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/query" {
next.ServeHTTP(w, r)
return
}
// Здесь можно парсить GraphQL запрос и извлекать информацию об операции
// Для простоты пока пропускаем
next.ServeHTTP(w, r)
})
}
}
// Вспомогательные функции для обновления метрик
func IncGQLOperation(operationType, operationName string, success bool, duration time.Duration) {
status := "false"
if success {
status = "true"
}
gqlOperationsTotal.WithLabelValues(
operationType,
operationName,
status,
).Inc()
gqlOperationDuration.WithLabelValues(
operationType,
operationName,
).Observe(duration.Seconds())
}
func IncWebSocketMessage(direction, messageType string) {
websocketMessagesTotal.WithLabelValues(direction, messageType).Inc()
}
func SetActiveWebsockets(count int) {
activeWebsockets.Set(float64(count))
}
func IncError(errorType, source, severity string) {
errorsTotal.WithLabelValues(errorType, source, severity).Inc()
}
func IncDBQuery(operation, table string, success bool, duration time.Duration) {
status := "false"
if success {
status = "true"
}
dbQueriesTotal.WithLabelValues(operation, table, status).Inc()
dbQueryDuration.WithLabelValues(operation, table).Observe(duration.Seconds())
}
func IncCacheHit(cacheType, cacheName string) {
cacheHitsTotal.WithLabelValues(cacheType, cacheName).Inc()
}
func IncCacheMiss(cacheType, cacheName string) {
cacheMissesTotal.WithLabelValues(cacheType, cacheName).Inc()
}
func SetUsersCount(count int) {
usersTotal.Set(float64(count))
}
func SetPostsCount(count int) {
postsTotal.Set(float64(count))
}
func SetCommentsCount(count int) {
commentsTotal.Set(float64(count))
}
func SetMessagesCount(count int) {
messagesTotal.Set(float64(count))
}