-
-
Save pierrre/d6f86351ce384a30b548c8ef2ecb6ebf to your computer and use it in GitHub Desktop.
DataDog HTTP tracing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Package mux provides tracing functions for tracing the gorilla/mux package (https://github.com/gorilla/mux). | |
package mux | |
import ( | |
"net/http" | |
tracing_net_http "github.com/xxx/yyy/tracing/net/http" | |
"github.com/gorilla/mux" | |
) | |
// Router registers routes to be matched and dispatches a handler. | |
type Router struct { | |
*mux.Router | |
service string | |
} | |
// NewRouterWithServiceName returns a new router instance which traces under the given service | |
// name. | |
// | |
// TODO(gbbr): Remove tracer parameter once we switch to OpenTracing. | |
func NewRouterWithServiceName(service string) *Router { | |
return &Router{ | |
Router: mux.NewRouter(), | |
service: service, | |
} | |
} | |
// ServeHTTP dispatches the request to the handler | |
// whose pattern most closely matches the request URL. | |
// We only need to rewrite this function to be able to trace | |
// all the incoming requests to the underlying multiplexer | |
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { | |
var ( | |
match mux.RouteMatch | |
route string | |
err error | |
) | |
// get the resource associated to this request | |
if r.Match(req, &match) { | |
route, err = match.Route.GetPathTemplate() | |
if err != nil { | |
route = "unknown" | |
} | |
} else { | |
route = "unknown" | |
} | |
resource := req.Method + " " + route | |
tracing_net_http.TraceAndServe(r.Router, w, req, r.service, resource) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Package http provides functions to trace the net/http package (https://golang.org/pkg/net/http). | |
package http | |
import ( | |
"net/http" | |
) | |
// ServeMux is an HTTP request multiplexer that traces all the incoming requests. | |
type ServeMux struct { | |
*http.ServeMux | |
service string | |
} | |
// NewServeMuxWithServiceName creates a new http.ServeMux that is traced using | |
// the given service name. | |
// | |
// TODO(gbbr): Remove this once we switch to OpenTracing. | |
func NewServeMuxWithServiceName(service string) *ServeMux { | |
return &ServeMux{ | |
ServeMux: http.NewServeMux(), | |
service: service, | |
} | |
} | |
// ServeHTTP dispatches the request to the handler | |
// whose pattern most closely matches the request URL. | |
// We only need to rewrite this function to be able to trace | |
// all the incoming requests to the underlying multiplexer | |
func (mux *ServeMux) ServeHTTP(w http.ResponseWriter, r *http.Request) { | |
// get the resource associated to this request | |
_, route := mux.Handler(r) | |
resource := r.Method + " " + route | |
TraceAndServe(mux.ServeMux, w, r, mux.service, resource) | |
} | |
// WrapHandler wraps an http.Handler with the default tracer using the | |
// specified service and resource. | |
func WrapHandler(h http.Handler, service, resource string) http.Handler { | |
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { | |
TraceAndServe(h, w, req, service, resource) | |
}) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package http | |
import ( | |
"net/http" | |
"strconv" | |
ddtrace_opentracing "github.com/DataDog/dd-trace-go/opentracing" | |
ddtrace_tracer_ext "github.com/DataDog/dd-trace-go/tracer/ext" | |
"github.com/opentracing/opentracing-go" | |
) | |
// TraceAndServe will apply tracing to the given http.Handler using the passed tracer under the given service and resource. | |
func TraceAndServe(h http.Handler, w http.ResponseWriter, r *http.Request, service, resource string) { | |
span, ctx := opentracing.StartSpanFromContext(r.Context(), "http.request") | |
defer span.Finish() | |
span.SetTag(ddtrace_opentracing.SpanType, ddtrace_tracer_ext.HTTPType) | |
span.SetTag(ddtrace_opentracing.ServiceName, service) | |
span.SetTag(ddtrace_opentracing.ResourceName, resource) | |
span.SetTag(ddtrace_tracer_ext.HTTPMethod, r.Method) | |
span.SetTag(ddtrace_tracer_ext.HTTPURL, r.URL.Path) | |
traceRequest := r.WithContext(ctx) | |
traceWriter := NewResponseWriter(w, span) | |
h.ServeHTTP(traceWriter, traceRequest) | |
} | |
// ResponseWriter is a small wrapper around an http response writer that will | |
// intercept and store the status of a request. | |
// It implements the ResponseWriter interface. | |
type ResponseWriter struct { | |
http.ResponseWriter | |
span opentracing.Span | |
status int | |
} | |
// NewResponseWriter allocateds and returns a new ResponseWriter. | |
func NewResponseWriter(w http.ResponseWriter, span opentracing.Span) *ResponseWriter { | |
return &ResponseWriter{w, span, 0} | |
} | |
// Write writes the data to the connection as part of an HTTP reply. | |
// We explicitly call WriteHeader with the 200 status code | |
// in order to get it reported into the span. | |
func (w *ResponseWriter) Write(b []byte) (int, error) { | |
if w.status == 0 { | |
w.WriteHeader(http.StatusOK) | |
} | |
return w.ResponseWriter.Write(b) | |
} | |
// WriteHeader sends an HTTP response header with status code. | |
// It also sets the status code to the span. | |
func (w *ResponseWriter) WriteHeader(status int) { | |
w.ResponseWriter.WriteHeader(status) | |
w.status = status | |
w.span.SetTag(ddtrace_tracer_ext.HTTPCode, strconv.Itoa(status)) | |
if status >= 500 && status < 600 { | |
if span, ok := w.span.(*ddtrace_opentracing.Span); ok { | |
span.Error = 1 | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment