HTTP Server-Timing for Go

This is a library including middleware for using
HTTP Server-Timing with Go. This header
allows a server to send timing information from the backend, such as database
access time, file reads, etc. The timing information can be then be inspected
in the standard browser developer tools:

Features
-
Middleware for injecting the server timing struct into the request Context
and writing the Server-Timing
header.
-
Concurrency-safe structures for easily recording timings of multiple
concurrency tasks.
-
Parse Server-Timing
headers as a client.
-
Note: No browser properly supports sending the Server-Timing header as
an HTTP Trailer so
the Middleware only supports a normal header currently.
Browser Support
Browser support is required to view server timings easily. Because server
timings are sent as an HTTP header, there is no negative impact to sending
the header to unsupported browsers.
-
Chrome 65 or higher is required to properly display server timings
in the devtools.
-
Firefox is pending with an open bug report (ID 1403051)
-
IE, Opera, and others are unknown at this time.
Usage
Example usage is shown below. A fully runnable example is available in
the example/
directory.
func main() {
var h http.Handler = http.HandlerFunc(handler)
h = servertiming.Middleware(h, nil)
http.ListenAndServe(":8080", h)
}
func handler(w http.ResponseWriter, r *http.Request) {
timing := servertiming.FromContext(r.Context())
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
name := fmt.Sprintf("service-%d", i)
go func(name string) {
defer timing.NewMetric(name).Start().Stop()
time.Sleep(random(25, 75))
wg.Done()
}(name)
}
m := timing.NewMetric("sql").WithDesc("SQL query").Start()
time.Sleep(random(20, 50))
m.Stop()
wg.Wait()
w.WriteHeader(200)
w.Write([]byte("Done. Check your browser inspector timing details."))
}
func random(min, max int) time.Duration {
return (time.Duration(rand.Intn(max-min) + min)) * time.Millisecond
}