193 lines
4.5 KiB
Go
193 lines
4.5 KiB
Go
package metrics
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
|
)
|
|
|
|
var (
|
|
// Default metrics
|
|
requestDuration = prometheus.NewHistogramVec(
|
|
prometheus.HistogramOpts{
|
|
Name: "http_request_duration_seconds",
|
|
Help: "Duration of HTTP requests in seconds",
|
|
Buckets: prometheus.DefBuckets,
|
|
},
|
|
[]string{"method", "path", "status"},
|
|
)
|
|
|
|
requestTotal = prometheus.NewCounterVec(
|
|
prometheus.CounterOpts{
|
|
Name: "http_requests_total",
|
|
Help: "Total number of HTTP requests",
|
|
},
|
|
[]string{"method", "path", "status"},
|
|
)
|
|
|
|
otpGenerationTotal = prometheus.NewCounterVec(
|
|
prometheus.CounterOpts{
|
|
Name: "otp_generation_total",
|
|
Help: "Total number of OTP generations",
|
|
},
|
|
[]string{"user_id", "otp_id"},
|
|
)
|
|
|
|
otpVerificationTotal = prometheus.NewCounterVec(
|
|
prometheus.CounterOpts{
|
|
Name: "otp_verification_total",
|
|
Help: "Total number of OTP verifications",
|
|
},
|
|
[]string{"user_id", "otp_id", "success"},
|
|
)
|
|
|
|
activeUsers = prometheus.NewGauge(
|
|
prometheus.GaugeOpts{
|
|
Name: "active_users",
|
|
Help: "Number of active users",
|
|
},
|
|
)
|
|
|
|
cacheHits = prometheus.NewCounterVec(
|
|
prometheus.CounterOpts{
|
|
Name: "cache_hits_total",
|
|
Help: "Total number of cache hits",
|
|
},
|
|
[]string{"cache"},
|
|
)
|
|
|
|
cacheMisses = prometheus.NewCounterVec(
|
|
prometheus.CounterOpts{
|
|
Name: "cache_misses_total",
|
|
Help: "Total number of cache misses",
|
|
},
|
|
[]string{"cache"},
|
|
)
|
|
)
|
|
|
|
func init() {
|
|
// Register metrics with prometheus
|
|
prometheus.MustRegister(
|
|
requestDuration,
|
|
requestTotal,
|
|
otpGenerationTotal,
|
|
otpVerificationTotal,
|
|
activeUsers,
|
|
cacheHits,
|
|
cacheMisses,
|
|
)
|
|
}
|
|
|
|
// MetricsService provides metrics functionality
|
|
type MetricsService struct {
|
|
activeUsersMutex sync.RWMutex
|
|
activeUserIDs map[string]bool
|
|
}
|
|
|
|
// NewMetricsService creates a new MetricsService
|
|
func NewMetricsService() *MetricsService {
|
|
return &MetricsService{
|
|
activeUserIDs: make(map[string]bool),
|
|
}
|
|
}
|
|
|
|
// Handler returns an HTTP handler for metrics
|
|
func (s *MetricsService) Handler() http.Handler {
|
|
return promhttp.Handler()
|
|
}
|
|
|
|
// RecordRequest records metrics for an HTTP request
|
|
func (s *MetricsService) RecordRequest(method, path string, status int, duration time.Duration) {
|
|
labels := prometheus.Labels{
|
|
"method": method,
|
|
"path": path,
|
|
"status": fmt.Sprintf("%d", status),
|
|
}
|
|
|
|
requestDuration.With(labels).Observe(duration.Seconds())
|
|
requestTotal.With(labels).Inc()
|
|
}
|
|
|
|
// RecordOTPGeneration records metrics for OTP generation
|
|
func (s *MetricsService) RecordOTPGeneration(userID, otpID string) {
|
|
otpGenerationTotal.With(prometheus.Labels{
|
|
"user_id": userID,
|
|
"otp_id": otpID,
|
|
}).Inc()
|
|
}
|
|
|
|
// RecordOTPVerification records metrics for OTP verification
|
|
func (s *MetricsService) RecordOTPVerification(userID, otpID string, success bool) {
|
|
otpVerificationTotal.With(prometheus.Labels{
|
|
"user_id": userID,
|
|
"otp_id": otpID,
|
|
"success": fmt.Sprintf("%t", success),
|
|
}).Inc()
|
|
}
|
|
|
|
// RecordUserActivity records user activity
|
|
func (s *MetricsService) RecordUserActivity(userID string) {
|
|
s.activeUsersMutex.Lock()
|
|
defer s.activeUsersMutex.Unlock()
|
|
|
|
if !s.activeUserIDs[userID] {
|
|
s.activeUserIDs[userID] = true
|
|
activeUsers.Inc()
|
|
}
|
|
}
|
|
|
|
// RecordUserInactivity records user inactivity
|
|
func (s *MetricsService) RecordUserInactivity(userID string) {
|
|
s.activeUsersMutex.Lock()
|
|
defer s.activeUsersMutex.Unlock()
|
|
|
|
if s.activeUserIDs[userID] {
|
|
delete(s.activeUserIDs, userID)
|
|
activeUsers.Dec()
|
|
}
|
|
}
|
|
|
|
// RecordCacheHit records a cache hit
|
|
func (s *MetricsService) RecordCacheHit(cache string) {
|
|
cacheHits.With(prometheus.Labels{
|
|
"cache": cache,
|
|
}).Inc()
|
|
}
|
|
|
|
// RecordCacheMiss records a cache miss
|
|
func (s *MetricsService) RecordCacheMiss(cache string) {
|
|
cacheMisses.With(prometheus.Labels{
|
|
"cache": cache,
|
|
}).Inc()
|
|
}
|
|
|
|
// Middleware creates a middleware that records request metrics
|
|
func (s *MetricsService) Middleware(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
start := time.Now()
|
|
|
|
// Create response writer that captures status code
|
|
rw := &responseWriter{ResponseWriter: w, status: http.StatusOK}
|
|
|
|
// Call next handler
|
|
next.ServeHTTP(rw, r)
|
|
|
|
// Record metrics
|
|
s.RecordRequest(r.Method, r.URL.Path, rw.status, time.Since(start))
|
|
})
|
|
}
|
|
|
|
// responseWriter wraps http.ResponseWriter to capture status code
|
|
type responseWriter struct {
|
|
http.ResponseWriter
|
|
status int
|
|
}
|
|
|
|
func (rw *responseWriter) WriteHeader(code int) {
|
|
rw.status = code
|
|
rw.ResponseWriter.WriteHeader(code)
|
|
}
|