Files
renovate-sh-app[bot]GitHubrenovate-sh-app[bot] <219655108+renovate-sh-app[bot]@users.noreply.github.com>A. Stoewer
92ce383d0e fix(deps): update github.com/grafana/dskit digest to 10fce42 (#5749)
* fix(deps): update github.com/grafana/dskit digest to 10fce42

Signed-off-by: renovate-sh-app[bot] <219655108+renovate-sh-app[bot]@users.noreply.github.com>

* make generate-manifest

---------

Signed-off-by: renovate-sh-app[bot] <219655108+renovate-sh-app[bot]@users.noreply.github.com>
Co-authored-by: renovate-sh-app[bot] <219655108+renovate-sh-app[bot]@users.noreply.github.com>
Co-authored-by: A. Stoewer <[email protected]>
2025-10-28 08:29:23 +10:00

98 lines
2.4 KiB
Go

// SPDX-License-Identifier: Apache-2.0
package middleware
import (
"context"
"net/http"
"regexp"
"strings"
"github.com/gorilla/mux"
)
// RouteInjector is a middleware that injects the route name for the current request into the request context.
//
// The route name can be retrieved by calling ExtractRouteName.
type RouteInjector struct {
RouteMatcher RouteMatcher
}
func (i RouteInjector) Wrap(handler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
routeName := getRouteName(i.RouteMatcher, r)
handler.ServeHTTP(w, WithRouteName(r, routeName))
})
}
// WithRouteName annotates r's context with the provided route name.
//
// The provided value must be suitable to use as a Prometheus label value.
//
// This method should generally only be used in tests: in production code, use RouteInjector instead.
func WithRouteName(r *http.Request, routeName string) *http.Request {
ctx := context.WithValue(r.Context(), contextKeyRouteName, routeName)
return r.WithContext(ctx)
}
// ExtractRouteName returns the route name associated with this request that was previously injected by the
// RouteInjector middleware or WithRouteName.
//
// This is the same route name used for trace and metric names, and is already suitable for use as a Prometheus label
// value.
func ExtractRouteName(ctx context.Context) string {
routeName, ok := ctx.Value(contextKeyRouteName).(string)
if !ok {
return ""
}
return routeName
}
func getRouteName(routeMatcher RouteMatcher, r *http.Request) string {
var routeMatch mux.RouteMatch
if routeMatcher == nil || !routeMatcher.Match(r, &routeMatch) {
return ""
}
if routeMatch.MatchErr == mux.ErrNotFound {
return "notfound"
}
if routeMatch.Route == nil {
return ""
}
if name := routeMatch.Route.GetName(); name != "" {
return name
}
tmpl, err := routeMatch.Route.GetPathTemplate()
if err == nil {
return MakeLabelValue(tmpl)
}
return ""
}
var invalidChars = regexp.MustCompile(`[^a-zA-Z0-9]+`)
// MakeLabelValue converts a Gorilla mux path to a string suitable for use in
// a Prometheus label value.
func MakeLabelValue(path string) string {
// Convert non-alnums to underscores.
result := invalidChars.ReplaceAllString(path, "_")
// Trim leading and trailing underscores.
result = strings.Trim(result, "_")
// Make it all lowercase
result = strings.ToLower(result)
// Special case.
if result == "" {
result = "root"
}
return result
}