Skip to content

Instantly share code, notes, and snippets.

@MrDOS
Last active February 4, 2022 09:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save MrDOS/ebdc448a795643b447750b213add38d2 to your computer and use it in GitHub Desktop.
Save MrDOS/ebdc448a795643b447750b213add38d2 to your computer and use it in GitHub Desktop.
package config
import (
"net/http"
"regexp"
"strings"
)
// idPatterns describes patterns of IDs in URLs. These patterns are matched
// against an entire URL. These patterns are used as given without any
// additional prefix or suffix, so to match against only one element of a path
// (e.g., only “bar” in “https://foo/bar/baz”), the patterns must include its
// own checks for path separators and the end of the URL.
var idPatterns = []struct {
pattern *regexp.Regexp
placeholder []byte
}{
// Strictly numeric IDs (e.g., “/123”).
{
regexp.MustCompile(`/\d+(/|$)`),
[]byte("/id$1"),
},
// UUIDs (e.g., “00000000-0000-0000-0000-000000000000”).
{
regexp.MustCompile(`/\w{8}-\w{4}-\w{4}-\w{4}-\w{12}(/|$)`),
[]byte("/uuid$1"),
},
}
// IDReplacer attempts to generate the resource name for an HTTP request by
// replacing portions which look like IDs with generic placeholders. Because we
// don't have access to the actual route pattern, we'll synthesize it by
// replacing anything in the URL which looks like a numeric ID or a UUID with a
// placeholder token (“id” or “uuid”, respectively). E.g., a GET request for:
//
// /api/foo/f9849b8d-455b-41fc-bec5-a45bc822023d/bar/42
//
// will be transformed into:
//
// GET /api/foo/uuid/bar/id
//
// This may differ from the actual route definition; for example:
//
// /api/foo/:fooID/bar/:barID
//
// ...but it's close enough for tracing.
func IDReplacer(req *http.Request) string {
resource := req.URL.Path
for _, idPattern := range idPatterns {
resource = string(idPattern.pattern.ReplaceAll(
[]byte(resource),
idPattern.placeholder))
}
// Route normalization: remove any trailing slashes so traces for
// extension-less routes are combined regardless of whether the request had
// a trailing slash (e.g., “/foo vs. “/foo/”).
if resource != "/" {
resource = strings.TrimRight(resource, "/")
}
return req.Method + " " + resource
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment