feat(metrics): integrate Prometheus metrics into router and main

- /metrics endpoint via promhttp.Handler
- actionHandler: request counter, bytes counter, latency histogram, errors
- Gauge updater: queues/messages count per tenant every 15s
- All metrics labeled by tenant and/or operation
This commit is contained in:
Naeel
2026-04-12 12:04:54 +03:00
parent 3d59b5500c
commit a4c910a099
2 changed files with 24 additions and 1 deletions
+4
View File
@@ -16,6 +16,7 @@ import (
"shared-sqs/app/billing"
"shared-sqs/app/conf"
"shared-sqs/app/gosqs"
"shared-sqs/app/metrics"
"shared-sqs/app/models"
"shared-sqs/app/persistence"
"shared-sqs/app/router"
@@ -136,6 +137,9 @@ func main() {
quit := make(chan bool)
go gosqs.PeriodicTasks(1*time.Second, quit)
// Metrics: gauge updater — пересчёт очередей/сообщений per tenant каждые 15 секунд
metrics.StartGaugeUpdater(15*time.Second, quit)
// HTTP сервер с таймаутами
srv := &http.Server{
Addr: "0.0.0.0:" + port,
+20 -1
View File
@@ -11,15 +11,19 @@ import (
"net/http"
"strings"
"time"
"shared-sqs/app/admin"
"shared-sqs/app/auth"
"shared-sqs/app/billing"
sqs "shared-sqs/app/gosqs"
"shared-sqs/app/interfaces"
"shared-sqs/app/metrics"
"shared-sqs/app/tenant"
"shared-sqs/app/ui"
"github.com/gorilla/mux"
"github.com/prometheus/client_golang/prometheus/promhttp"
log "github.com/sirupsen/logrus"
)
@@ -34,6 +38,9 @@ func New(tenantStore *tenant.TenantStore, adminToken string) http.Handler {
// /health — публичный, без auth
r.HandleFunc("/health", health).Methods("GET")
// /metrics — Prometheus endpoint для Victoria Metrics scrape
r.Handle("/metrics", promhttp.Handler()).Methods("GET")
// Admin API — Bearer token auth, регистрируется через AdminHandler
adminHandler := admin.NewHandler(tenantStore, adminToken)
adminHandler.RegisterRoutes(r)
@@ -124,6 +131,7 @@ func health(w http.ResponseWriter, req *http.Request) {
func actionHandler(w http.ResponseWriter, req *http.Request) {
action := extractAction(req)
start := time.Now()
log.WithFields(log.Fields{
"action": action,
"url": req.URL,
@@ -132,7 +140,11 @@ func actionHandler(w http.ResponseWriter, req *http.Request) {
if ok {
statusCode, responseBody := jsonFn(req)
encodeResponse(w, req, statusCode, responseBody)
// Billing: записываем каждую успешную SQS-операцию (async, no-op если billing выключен)
// Metrics: latency гистограмма для каждой операции
duration := time.Since(start).Seconds()
metrics.RequestDuration.WithLabelValues(action).Observe(duration)
if statusCode < 400 {
if t, _ := req.Context().Value(auth.TenantContextKey).(*tenant.Tenant); t != nil {
msgBytes := req.ContentLength
@@ -144,8 +156,15 @@ func actionHandler(w http.ResponseWriter, req *http.Request) {
if queueName == "" {
queueName = req.FormValue("QueueName")
}
// Billing: запись в PostgreSQL (async, no-op если billing выключен)
billing.RecordUsage(t.ID, action, queueName, 1, msgBytes)
// Prometheus counters: requests + bytes
metrics.RequestsTotal.WithLabelValues(t.ID, action).Inc()
metrics.RequestBytesTotal.WithLabelValues(t.ID, action).Add(float64(msgBytes))
}
} else {
// Prometheus: счётчик ошибок
metrics.ErrorsTotal.WithLabelValues(action).Inc()
}
return
}