Documentation ¶
Overview ¶
Package httptrace implements support for tracing HTTP applications.
This package exposes a HTTP middleware usable for generating traces for measuring the performance and debugging distributed HTTP applications using appdash.
The middleware is Negroni-compliant, and can thus be used with Negroni easily or with a pure net/http (i.e. stdlib-only) application with ease.
Trace Collection Server ¶
Trace collection occurs anywhere (on this HTTP server, remotely on another, etc). It is independent from this package. One approach is to run a local collection server (on the HTTP server itself) that keeps the last 20s of appdash events in-memory, like so:
// Create a recent in-memory store, evicting data after 20s. store := &appdash.RecentStore{ MinEvictAge: 20 * time.Second, DeleteStore: appdash.NewMemoryStore(), } // Listen on port 7701. ln, err := net.Listen("tcp", ":7701") if err != nil { // handle error } // Create an appdash server, listen and serve in a separate goroutine. cs := appdash.NewServer(ln, appdash.NewLocalCollector(store)) go cs.Start()
Note that the above server exposes the traces in plain-text (i.e. insecurely) over the given port. Allowing access to that port outside your network allows others to potentially see API keys and other information about HTTP requests going through your network.
If you intend to make appdash available outside your network, use a secure appdash server instead (see the appdash package for details).
Server Init ¶
Whether you plan to use Negroni, or just net/http, you'll first need to make a collector. For example, by connecting to the appdash server that we made earlier:
// Connect to a remote collection server. collector := appdash.NewRemoteCollector(":7701")
And a basic middleware:
// Create a httptrace middleware. tracemw := httptrace.Middleware(collector, &httptrace.MiddlewareConfig{})
With Negroni ¶
Negroni is a idiomatic web middleware package for Go, and the middleware exposed by this package is fully compliant with it's requirements -- which makes using it a breeze:
// Create app handler: mux := http.NewServeMux() mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { fmt.Fprintf(w, "Hello world!") }) // Setup Negroni for our app: n := negroni.Classic() n.Use(negroni.HandlerFunc(tracemw)) // Register appdash's HTTP middleware. n.UseHandler(mux) n.Run(":3000")
With The http Package ¶
The HTTP middleware can also be used without Negroni, although slightly more verbose. Say for example that you have a net/http handler for your app:
func appHandler(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello World!") }
Simply create a middleware and pass each HTTP request through it, continuing with your application handler:
// Let all requests pass through the middleware, and then go on to let our // app handler serve the request. http.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { tracemw(w, r, appHandler) })
Other details such as outbound client requests, displaying the trace ID in the webpage e.g. to let users give you their trace ID for troubleshooting, and much more are covered in the example application provided at cmd/appdash/example_app.go.
Index ¶
- Constants
- Variables
- func GetSpanID(h http.Header) (*appdash.SpanID, error)
- func Middleware(c appdash.Collector, conf *MiddlewareConfig) func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)
- func SetSpanIDHeader(h http.Header, e appdash.SpanID)
- type ClientEvent
- type MiddlewareConfig
- type RequestInfo
- type ResponseInfo
- type ServerEvent
- type Transport
Constants ¶
const ( // HeaderSpanID is the name of the HTTP header by which the trace // and span IDs are passed along. HeaderSpanID = "Span-ID" // HeaderParentSpanID is the name of the HTTP header by which the // parent trace and span IDs are passed along. It should only be // set by clients that are incapable of creating their own span // IDs (e.g., JavaScript API clients in a web page, which can // easily pass along an existing parent span ID but not create a // new child span ID). HeaderParentSpanID = "Parent-Span-ID" )
Variables ¶
var ( // RedactedHeaders is a slice of header names whose values should be // entirely redacted from logs. RedactedHeaders = []string{"Authorization"} )
Functions ¶
func GetSpanID ¶
GetSpanID returns the SpanID for the current request, based on the values in the HTTP headers. If a Span-ID header is provided, it is parsed; if a Parent-Span-ID header is provided, a new child span is created and it is returned; otherwise a new root SpanID is created.
func Middleware ¶
func Middleware(c appdash.Collector, conf *MiddlewareConfig) func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)
Middleware creates a new http.Handler middleware (negroni-compliant) that records incoming HTTP requests to the collector c as "HTTPServer"-schema events.
Types ¶
type ClientEvent ¶
type ClientEvent struct { Request RequestInfo `trace:"Client.Request"` Response ResponseInfo `trace:"Client.Response"` ClientSend time.Time `trace:"Client.Send"` ClientRecv time.Time `trace:"Client.Recv"` }
ClientEvent records an HTTP client request event.
func NewClientEvent ¶
func NewClientEvent(r *http.Request) *ClientEvent
NewClientEvent returns an event which records various aspects of an HTTP request. The returned value is incomplete, and should have the response status, size, and the ClientSend/ClientRecv times set before being logged.
func (ClientEvent) End ¶
func (e ClientEvent) End() time.Time
End implements the appdash TimespanEvent interface.
func (ClientEvent) Important ¶
func (ClientEvent) Important() []string
Important implements the appdash ImportantEvent.
func (ClientEvent) Schema ¶
func (ClientEvent) Schema() string
Schema returns the constant "HTTPClient".
func (ClientEvent) Start ¶
func (e ClientEvent) Start() time.Time
Start implements the appdash TimespanEvent interface.
type MiddlewareConfig ¶
type MiddlewareConfig struct { // RouteName, if non-nil, is called to get the current route's // name. This name is used as the span's name. RouteName func(*http.Request) string // CurrentUser, if non-nil, is called to get the current user ID // (which may be a login or a numeric ID). CurrentUser func(*http.Request) string // SetContextSpan, if non-nil, is called to set the span (which is // either taken from the client request header or created anew) in // the HTTP request context, so it may be used by other parts of // the handling process. SetContextSpan func(*http.Request, appdash.SpanID) }
MiddlewareConfig configures the HTTP tracing middleware.
type RequestInfo ¶
type RequestInfo struct { Method string URI string Proto string Headers map[string]string Host string RemoteAddr string ContentLength int64 }
RequestInfo describes an HTTP request.
type ResponseInfo ¶
ResponseInfo describes an HTTP response.
type ServerEvent ¶
type ServerEvent struct { Request RequestInfo `trace:"Server.Request"` Response ResponseInfo `trace:"Server.Response"` Route string `trace:"Server.Route"` User string `trace:"Server.User"` ServerRecv time.Time `trace:"Server.Recv"` ServerSend time.Time `trace:"Server.Send"` }
ServerEvent records an HTTP server request handling event.
func NewServerEvent ¶
func NewServerEvent(r *http.Request) *ServerEvent
NewServerEvent returns an event which records various aspects of an HTTP response. It takes an HTTP request, not response, as input because the information it records is derived from the request, and HTTP handlers don't have access to the response struct (only http.ResponseWriter, which requires wrapping or buffering to introspect).
The returned value is incomplete and should have its Response and ServerRecv/ServerSend values set before being logged.
func (ServerEvent) End ¶
func (e ServerEvent) End() time.Time
End implements the appdash TimespanEvent interface.
func (ServerEvent) Important ¶
func (ServerEvent) Important() []string
Important implements the appdash ImportantEvent.
func (ServerEvent) Schema ¶
func (ServerEvent) Schema() string
Schema returns the constant "HTTPServer".
func (ServerEvent) Start ¶
func (e ServerEvent) Start() time.Time
Start implements the appdash TimespanEvent interface.
type Transport ¶
type Transport struct { // Recorder is the current span's recorder. A new child Recorder // (with a new child SpanID) is created for each HTTP roundtrip. *appdash.Recorder // Transport is the underlying HTTP transport to use when making // requests. It will default to http.DefaultTransport if nil. Transport http.RoundTripper SetName bool // contains filtered or unexported fields }
Transport is an HTTP transport that adds appdash span ID headers to requests so that downstream operations are associated with the same trace.
func (*Transport) CancelRequest ¶
CancelRequest cancels an in-flight request by closing its connection.