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:
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user