package main import ( "net/http" "strconv" "strings" "time" "github.com/gin-gonic/gin" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" ) var ( // HTTP request metrics httpRequestsTotal = prometheus.NewCounterVec( prometheus.CounterOpts{ Name: "http_requests_total", Help: "Total number of HTTP requests", }, []string{"method", "endpoint", "status_code"}, ) // HTTP request duration metrics httpRequestDuration = prometheus.NewHistogramVec( prometheus.HistogramOpts{ Name: "http_request_duration_seconds", Help: "HTTP request duration in seconds", Buckets: prometheus.DefBuckets, }, []string{"method", "endpoint"}, ) // API endpoint specific metrics apiRequestsTotal = prometheus.NewCounterVec( prometheus.CounterOpts{ Name: "api_requests_total", Help: "Total number of API requests by endpoint", }, []string{"endpoint", "method"}, ) // Database operation metrics dbOperationsTotal = prometheus.NewCounterVec( prometheus.CounterOpts{ Name: "db_operations_total", Help: "Total number of database operations", }, []string{"operation", "table"}, ) // Authentication metrics authAttemptsTotal = prometheus.NewCounterVec( prometheus.CounterOpts{ Name: "auth_attempts_total", Help: "Total number of authentication attempts", }, []string{"type", "status"}, ) ) // InitMetrics initializes Prometheus metrics func InitMetrics() { // Register all metrics prometheus.MustRegister(httpRequestsTotal) prometheus.MustRegister(httpRequestDuration) prometheus.MustRegister(apiRequestsTotal) prometheus.MustRegister(dbOperationsTotal) prometheus.MustRegister(authAttemptsTotal) } // StartMetricsServer starts the metrics server on a separate port func StartMetricsServer(port string) { // Create a new HTTP server for metrics metricsMux := http.NewServeMux() metricsMux.Handle("/metrics", promhttp.Handler()) // Add health check for metrics server metricsMux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) w.Write([]byte("Metrics server is healthy")) }) server := &http.Server{ Addr: "localhost:" + port, Handler: metricsMux, ReadTimeout: 5 * time.Second, WriteTimeout: 10 * time.Second, } go func() { Logger.Printf("📈 Metrics server starting on http://localhost:%s/metrics", port) if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed { Logger.Printf("❌ Metrics server failed to start: %v", err) } }() } // MetricsMiddleware is a Gin middleware to collect HTTP metrics func MetricsMiddleware() gin.HandlerFunc { return func(c *gin.Context) { start := time.Now() path := c.FullPath() method := c.Request.Method // Process request c.Next() // Calculate duration duration := time.Since(start).Seconds() statusCode := strconv.Itoa(c.Writer.Status()) // Record metrics httpRequestsTotal.WithLabelValues(method, path, statusCode).Inc() httpRequestDuration.WithLabelValues(method, path).Observe(duration) // Record API-specific metrics for API routes if strings.HasPrefix(c.Request.URL.Path, "/api") { apiRequestsTotal.WithLabelValues(path, method).Inc() } } } // RecordAPICall records a specific API endpoint call func RecordAPICall(endpoint, method string) { apiRequestsTotal.WithLabelValues(endpoint, method).Inc() } // RecordDBOperation records a database operation func RecordDBOperation(operation, table string) { dbOperationsTotal.WithLabelValues(operation, table).Inc() } // RecordAuthAttempt records an authentication attempt func RecordAuthAttempt(authType, status string) { authAttemptsTotal.WithLabelValues(authType, status).Inc() }