Merge pull request 'Ajout métrique prometheus de latence des proxies.' (#53) from response-time-histo into master
All checks were successful
Cadoles/bouncer/pipeline/head This commit looks good

Reviewed-on: #53
This commit is contained in:
2025-08-25 12:17:40 +02:00
3 changed files with 63 additions and 15 deletions

View File

@ -1,6 +1,6 @@
# Métriques # Métriques
Bouncer expose un certain nombre de métriques Prometheus sur le serveur proxy ainsi que sur le serveur d'administration. Ces métriques sont par défaut accessibles sur `/.bouncer/metrics`. Bouncer expose un certain nombre de métriques Prometheus sur le serveur proxy ainsi que sur le serveur d'administration. Ces métriques sont par défaut accessibles sur `/.bouncer/metrics`.
Il est possible de configurer le point d'entrée de ces métriques ainsi que d'ajouter une authentification de type `Basic Auth` [via la configuration](../../../misc/packaging/common/config.yml) (voir les clés `admin.metrics` et `proxy.metrics`). Il est possible de configurer le point d'entrée de ces métriques ainsi que d'ajouter une authentification de type `Basic Auth` [via la configuration](../../../misc/packaging/common/config.yml) (voir les clés `admin.metrics` et `proxy.metrics`).
@ -15,15 +15,40 @@ Chaque layer associé à un proxy peut également ses propres métriques spécif
#### `bouncer_proxy_director_proxy_requests_total{proxy=<proxyName>}` #### `bouncer_proxy_director_proxy_requests_total{proxy=<proxyName>}`
- **Type:** `counter` - **Type:** `counter`
- **Description**: Nombre total de requêtes ayant transité par le proxy - **Description**: Nombre total de requêtes ayant transité par le proxy
- **Exemple** - **Exemple**
``` ```
# HELP bouncer_proxy_director_proxy_requests_total Bouncer proxy total requests # HELP bouncer_proxy_director_proxy_requests_total Bouncer proxy total requests
# TYPE bouncer_proxy_director_proxy_requests_total counter # TYPE bouncer_proxy_director_proxy_requests_total counter
bouncer_proxy_director_proxy_requests_total{proxy="cadoles"} 64 bouncer_proxy_director_proxy_requests_total{proxy="cadoles"} 64
``` ```
#### `bouncer_proxy_director_proxy_responses_duration_seconds{proxy=<proxyName>}`
- **Type:** `histogram`
- **Description**: Histogramme du temps de traitement du cycle requête/réponse par proxy
- **Exemple**
```
# HELP bouncer_proxy_director_proxy_responses_duration_seconds Bouncer proxy responses duration
# TYPE bouncer_proxy_director_proxy_responses_duration_seconds histogram
bouncer_proxy_director_proxy_responses_duration_seconds_bucket{proxy="dummy",le="0.005"} 13
bouncer_proxy_director_proxy_responses_duration_seconds_bucket{proxy="dummy",le="0.01"} 13
bouncer_proxy_director_proxy_responses_duration_seconds_bucket{proxy="dummy",le="0.025"} 13
bouncer_proxy_director_proxy_responses_duration_seconds_bucket{proxy="dummy",le="0.05"} 13
bouncer_proxy_director_proxy_responses_duration_seconds_bucket{proxy="dummy",le="0.1"} 13
bouncer_proxy_director_proxy_responses_duration_seconds_bucket{proxy="dummy",le="0.25"} 13
bouncer_proxy_director_proxy_responses_duration_seconds_bucket{proxy="dummy",le="0.5"} 13
bouncer_proxy_director_proxy_responses_duration_seconds_bucket{proxy="dummy",le="1"} 13
bouncer_proxy_director_proxy_responses_duration_seconds_bucket{proxy="dummy",le="2.5"} 13
bouncer_proxy_director_proxy_responses_duration_seconds_bucket{proxy="dummy",le="5"} 13
bouncer_proxy_director_proxy_responses_duration_seconds_bucket{proxy="dummy",le="10"} 13
bouncer_proxy_director_proxy_responses_duration_seconds_bucket{proxy="dummy",le="+Inf"} 13
bouncer_proxy_director_proxy_responses_duration_seconds_sum{proxy="dummy"} 0.009556884
bouncer_proxy_director_proxy_responses_duration_seconds_count{proxy="dummy"} 13
```
### Serveur d'administration ### Serveur d'administration
_Pas de métrique supplémentaire._ _Pas de métrique supplémentaire._

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"net/http" "net/http"
"sort" "sort"
"time"
"forge.cadoles.com/Cadoles/go-proxy" "forge.cadoles.com/Cadoles/go-proxy"
"forge.cadoles.com/Cadoles/go-proxy/wildcard" "forge.cadoles.com/Cadoles/go-proxy/wildcard"
@ -28,12 +29,12 @@ type Director struct {
const proxiesCacheKey = "proxies" const proxiesCacheKey = "proxies"
func (d *Director) rewriteRequest(r *http.Request) (*http.Request, error) { func (d *Director) rewriteRequest(r *http.Request) (*http.Request, []store.ProxyName, error) {
ctx := r.Context() ctx := r.Context()
proxies, _, err := d.cachedProxies.Get(ctx, proxiesCacheKey) proxies, _, err := d.cachedProxies.Get(ctx, proxiesCacheKey)
if err != nil { if err != nil {
return r, errors.WithStack(err) return r, nil, errors.WithStack(err)
} }
url := getRequestURL(r) url := getRequestURL(r)
@ -42,12 +43,16 @@ func (d *Director) rewriteRequest(r *http.Request) (*http.Request, error) {
layers := make([]*store.Layer, 0) layers := make([]*store.Layer, 0)
matchingProxies := make([]store.ProxyName, 0)
for _, p := range proxies { for _, p := range proxies {
for _, from := range p.From { for _, from := range p.From {
if matches := wildcard.Match(url.String(), from); !matches { if matches := wildcard.Match(url.String(), from); !matches {
continue continue
} }
matchingProxies = append(matchingProxies, p.Name)
proxyCtx := logger.With(ctx, proxyCtx := logger.With(ctx,
logger.F("proxy", p.Name), logger.F("proxy", p.Name),
logger.F("host", r.Host), logger.F("host", r.Host),
@ -58,7 +63,7 @@ func (d *Director) rewriteRequest(r *http.Request) (*http.Request, error) {
proxyLayers, _, err := d.cachedLayers.Get(proxyCtx, string(p.Name)) proxyLayers, _, err := d.cachedLayers.Get(proxyCtx, string(p.Name))
if err != nil { if err != nil {
return r, errors.WithStack(err) return r, nil, errors.WithStack(err)
} }
layers = append(layers, proxyLayers...) layers = append(layers, proxyLayers...)
@ -69,7 +74,7 @@ func (d *Director) rewriteRequest(r *http.Request) (*http.Request, error) {
toURL, err := url.Parse(p.To) toURL, err := url.Parse(p.To)
if err != nil { if err != nil {
return r, errors.WithStack(err) return r, nil, errors.WithStack(err)
} }
r.URL.Host = toURL.Host r.URL.Host = toURL.Host
@ -87,14 +92,14 @@ func (d *Director) rewriteRequest(r *http.Request) (*http.Request, error) {
}) })
} }
return r, nil return r, matchingProxies, nil
} }
} }
ctx = withLayers(ctx, layers) ctx = withLayers(ctx, layers)
r = r.WithContext(ctx) r = r.WithContext(ctx)
return r, nil return r, matchingProxies, nil
} }
func (d *Director) getProxies(ctx context.Context, key string) ([]*store.Proxy, error) { func (d *Director) getProxies(ctx context.Context, key string) ([]*store.Proxy, error) {
@ -215,17 +220,26 @@ func (d *Director) ResponseTransformer() proxy.ResponseTransformer {
func (d *Director) Middleware() proxy.Middleware { func (d *Director) Middleware() proxy.Middleware {
return func(next http.Handler) http.Handler { return func(next http.Handler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) { fn := func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
sentry.ConfigureScope(func(scope *sentry.Scope) { sentry.ConfigureScope(func(scope *sentry.Scope) {
ctx := withHandleError(r.Context(), d.handleError) ctx := withHandleError(r.Context(), d.handleError)
ctx = withSentryScope(ctx, scope) ctx = withSentryScope(ctx, scope)
r = r.WithContext(ctx) r = r.WithContext(ctx)
r, err := d.rewriteRequest(r) r, matched, err := d.rewriteRequest(r)
if err != nil { if err != nil {
HandleError(ctx, w, r, http.StatusInternalServerError, errors.Wrap(err, "could not rewrite request")) HandleError(ctx, w, r, http.StatusInternalServerError, errors.Wrap(err, "could not rewrite request"))
return return
} }
defer func() {
elapsed := time.Since(start)
for _, p := range matched {
metricProxyResponsesDurationSeconds.WithLabelValues(string(p)).Observe(elapsed.Seconds())
}
}()
ctx = r.Context() ctx = r.Context()
layers, err := ctxLayers(ctx) layers, err := ctxLayers(ctx)

View File

@ -18,3 +18,12 @@ var metricProxyRequestsTotal = promauto.NewCounterVec(
}, },
[]string{metricLabelProxy}, []string{metricLabelProxy},
) )
var metricProxyResponsesDurationSeconds = promauto.NewHistogramVec(
prometheus.HistogramOpts{
Name: "proxy_responses_duration_seconds",
Help: "Bouncer proxy responses duration",
Namespace: metricNamespace,
},
[]string{metricLabelProxy},
)