feat: add metrics
This commit is contained in:
67
internal/prometheus.go
Normal file
67
internal/prometheus.go
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2024 Jonas Kaninda
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type PrometheusRoute struct {
|
||||
name string
|
||||
path string
|
||||
}
|
||||
|
||||
var totalRequests = prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Name: "http_requests_total",
|
||||
Help: "Number of get requests.",
|
||||
},
|
||||
[]string{"path"},
|
||||
)
|
||||
|
||||
var responseStatus = prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Name: "response_status",
|
||||
Help: "Status of HTTP response",
|
||||
},
|
||||
[]string{"status"},
|
||||
)
|
||||
|
||||
var httpDuration = promauto.NewHistogramVec(prometheus.HistogramOpts{
|
||||
Name: "http_response_time_seconds",
|
||||
Help: "Duration of HTTP requests.",
|
||||
}, []string{"path"})
|
||||
|
||||
func prometheusMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
route := mux.CurrentRoute(r)
|
||||
path, _ := route.GetPathTemplate()
|
||||
timer := prometheus.NewTimer(httpDuration.WithLabelValues(path))
|
||||
|
||||
responseStatus.WithLabelValues(strconv.Itoa(http.StatusOK)).Inc()
|
||||
totalRequests.WithLabelValues(path).Inc()
|
||||
|
||||
timer.ObserveDuration()
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
|
||||
}
|
||||
@@ -29,7 +29,7 @@ import (
|
||||
// ProxyHandler proxies requests to the backend
|
||||
func (proxyRoute ProxyRoute) ProxyHandler() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
logger.Info("%s %s %s %s", r.Method, getRealIP(r), r.URL, r.UserAgent())
|
||||
logger.Info("%s %s %s %s", r.Method, getRealIP(r), r.URL.Path, r.UserAgent())
|
||||
// Check Method if is allowed
|
||||
if len(proxyRoute.methods) > 0 {
|
||||
if !slices.Contains(proxyRoute.methods, r.Method) {
|
||||
|
||||
@@ -20,9 +20,17 @@ import (
|
||||
"github.com/jkaninda/goma-gateway/internal/middleware"
|
||||
"github.com/jkaninda/goma-gateway/pkg/logger"
|
||||
"github.com/jkaninda/goma-gateway/util"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"time"
|
||||
)
|
||||
|
||||
func init() {
|
||||
_ = prometheus.Register(totalRequests)
|
||||
_ = prometheus.Register(responseStatus)
|
||||
_ = prometheus.Register(httpDuration)
|
||||
}
|
||||
|
||||
// Initialize the routes
|
||||
func (gatewayServer GatewayServer) Initialize() *mux.Router {
|
||||
gateway := gatewayServer.gateway
|
||||
@@ -32,11 +40,18 @@ func (gatewayServer GatewayServer) Initialize() *mux.Router {
|
||||
DisableRouteHealthCheckError: gateway.DisableRouteHealthCheckError,
|
||||
Routes: gateway.Routes,
|
||||
}
|
||||
if gateway.EnableMetrics {
|
||||
// Prometheus endpoint
|
||||
r.Path("/metrics").Handler(promhttp.Handler())
|
||||
r.Use(prometheusMiddleware)
|
||||
}
|
||||
|
||||
// Routes health check
|
||||
if !gateway.DisableHealthCheckStatus {
|
||||
r.HandleFunc("/healthz", heath.HealthCheckHandler).Methods("GET")
|
||||
r.HandleFunc("/health/routes", heath.HealthCheckHandler).Methods("GET")
|
||||
}
|
||||
|
||||
// Health check
|
||||
r.HandleFunc("/health/live", heath.HealthReadyHandler).Methods("GET")
|
||||
r.HandleFunc("/readyz", heath.HealthReadyHandler).Methods("GET")
|
||||
@@ -223,6 +238,7 @@ func (gatewayServer GatewayServer) Initialize() *mux.Router {
|
||||
} else {
|
||||
router.PathPrefix("").Handler(proxyRoute.ProxyHandler())
|
||||
}
|
||||
|
||||
} else {
|
||||
logger.Error("Error, path is empty in route %s", route.Name)
|
||||
logger.Error("Route path ignored: %s", route.Path)
|
||||
|
||||
@@ -196,6 +196,7 @@ type Gateway struct {
|
||||
DisableDisplayRouteOnStart bool `yaml:"disableDisplayRouteOnStart"`
|
||||
// DisableKeepAlive allows enabling and disabling KeepALive server
|
||||
DisableKeepAlive bool `yaml:"disableKeepAlive"`
|
||||
EnableMetrics bool `yaml:"enableMetrics"`
|
||||
// InterceptErrors holds the status codes to intercept the error from backend
|
||||
InterceptErrors []int `yaml:"interceptErrors"`
|
||||
// Cors holds proxy global cors
|
||||
|
||||
Reference in New Issue
Block a user