Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

contrib: store http.route in span tags for ASM backend WAF #1342

Merged
merged 10 commits into from Jun 16, 2022
1 change: 1 addition & 0 deletions contrib/gin-gonic/gin/gintrace.go
Expand Up @@ -39,6 +39,7 @@ func Middleware(service string, opts ...Option) gin.HandlerFunc {
if !math.IsNaN(cfg.analyticsRate) {
opts = append(opts, tracer.Tag(ext.EventSampleRate, cfg.analyticsRate))
}
opts = append(opts, tracer.Tag(ext.HTTPRoute, getRoute(c)))
span, ctx := httptrace.StartRequestSpan(c.Request, opts...)
defer func() {
httptrace.FinishRequestSpan(span, c.Writer.Status())
Expand Down
13 changes: 13 additions & 0 deletions contrib/gin-gonic/gin/option.go
Expand Up @@ -96,3 +96,16 @@ func defaultResourceNamer(c *gin.Context) string {
}
return getName(c.Request, c)
}
func getRoute(c *gin.Context) string {
// getFullPath uses the same trick as getName above to make sure we don't break pre v1.4.0 builds for which
// gin.Context.GetFullPath() does not exist
getFullPath := func(req *http.Request, c interface{}) string {
if fp, ok := c.(interface {
FullPath() string
}); ok {
return fp.FullPath()
}
return ""
}
return getFullPath(c.Request, c)
}
knusbaum marked this conversation as resolved.
Show resolved Hide resolved
1 change: 1 addition & 0 deletions contrib/go-chi/chi.v5/chi.go
Expand Up @@ -66,6 +66,7 @@ func Middleware(opts ...Option) func(next http.Handler) http.Handler {

// set the resource name as we get it only once the handler is executed
resourceName := chi.RouteContext(r.Context()).RoutePattern()
span.SetTag(ext.HTTPRoute, resourceName)
if resourceName == "" {
resourceName = "unknown"
}
Expand Down
1 change: 1 addition & 0 deletions contrib/go-chi/chi/chi.go
Expand Up @@ -66,6 +66,7 @@ func Middleware(opts ...Option) func(next http.Handler) http.Handler {

// set the resource name as we get it only once the handler is executed
resourceName := chi.RouteContext(r.Context()).RoutePattern()
span.SetTag(ext.HTTPRoute, resourceName)
if resourceName == "" {
resourceName = "unknown"
}
Expand Down
3 changes: 3 additions & 0 deletions contrib/gorilla/mux/mux.go
Expand Up @@ -89,12 +89,14 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
var (
match mux.RouteMatch
spanopts []ddtrace.StartSpanOption
route string
)
// get the resource associated to this request
if r.Match(req, &match) && match.Route != nil {
if h, err := match.Route.GetHostTemplate(); err == nil {
spanopts = append(spanopts, tracer.Tag("mux.host", h))
}
route, _ = match.Route.GetPathTemplate()
}
spanopts = append(spanopts, r.config.spanOpts...)
if r.config.headerTags {
Expand All @@ -108,6 +110,7 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
SpanOpts: spanopts,
QueryParams: r.config.queryParams,
RouteParams: match.Vars,
Route: route,
})
}

Expand Down
5 changes: 3 additions & 2 deletions contrib/labstack/echo.v4/echotrace.go
Expand Up @@ -34,8 +34,9 @@ func Middleware(opts ...Option) echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
request := c.Request()
resource := request.Method + " " + c.Path()
opts := append(spanOpts, tracer.ResourceName(resource))
route := c.Path()
resource := request.Method + " " + route
opts := append(spanOpts, tracer.ResourceName(resource), tracer.Tag(ext.HTTPRoute, route))

if !math.IsNaN(cfg.analyticsRate) {
opts = append(opts, tracer.Tag(ext.EventSampleRate, cfg.analyticsRate))
Expand Down
2 changes: 2 additions & 0 deletions contrib/net/http/http.go
Expand Up @@ -49,6 +49,7 @@ func (mux *ServeMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
Service: mux.cfg.serviceName,
Resource: resource,
SpanOpts: mux.cfg.spanOpts,
Route: route,
})
}

Expand All @@ -74,6 +75,7 @@ func WrapHandler(h http.Handler, service, resource string, opts ...Option) http.
Resource: resource,
FinishOpts: cfg.finishOpts,
SpanOpts: cfg.spanOpts,
Route: req.URL.EscapedPath(),
})
})
}
3 changes: 3 additions & 0 deletions contrib/net/http/trace.go
Expand Up @@ -27,6 +27,8 @@ type ServeConfig struct {
Resource string
// QueryParams should be true in order to append the URL query values to the "http.url" tag.
QueryParams bool
// Route is the request matched route if any, or is empty otherwise
Route string
// RouteParams specifies framework-specific route parameters (e.g. for route /user/:id coming
// in as /user/123 we'll have {"id": "123"}). This field is optional and is used for monitoring
// by AppSec. It is only taken into account when AppSec is enabled.
Expand All @@ -47,6 +49,7 @@ func TraceAndServe(h http.Handler, w http.ResponseWriter, r *http.Request, cfg *
if cfg.QueryParams {
opts = append(opts, tracer.Tag(ext.HTTPURL, r.URL.Path+"?"+r.URL.RawQuery))
}
opts = append(opts, tracer.Tag(ext.HTTPRoute, cfg.Route))
span, ctx := httptrace.StartRequestSpan(r, opts...)
rw, ddrw := wrapResponseWriter(w)
defer func() {
Expand Down
3 changes: 3 additions & 0 deletions ddtrace/ext/tags.go
Expand Up @@ -30,6 +30,9 @@ const (
// HTTPCode sets the HTTP status code as a tag.
HTTPCode = "http.status_code"

// HTTPRoute is the route value of the HTTP request.
HTTPRoute = "http.route"

// HTTPURL sets the HTTP URL for a span.
HTTPURL = "http.url"

Expand Down