Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/mitchellh/go-server-timing

Go (golang) library for creating and consuming HTTP Server-Timing headers
https://github.com/mitchellh/go-server-timing

Last synced: about 2 months ago
JSON representation

Go (golang) library for creating and consuming HTTP Server-Timing headers

Awesome Lists containing this project

README

        

# HTTP Server-Timing for Go
[![Godoc](https://godoc.org/github.com/mitchellh/go-server-timing?status.svg)](https://godoc.org/github.com/mitchellh/go-server-timing)

This is a library including middleware for using
[HTTP Server-Timing](https://www.w3.org/TR/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:

![Server Timing Example](https://raw.githubusercontent.com/mitchellh/go-server-timing/master/example/screenshot.png)

## 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](https://tools.ietf.org/html/rfc7230#section-4.4) 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.

* Either **Chrome 65 or higher** or **Firefox 71 or higher** is required
to properly display server timings in the devtools.

* 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.

```go
func main() {
// Our handler. In a real application this might be your root router,
// or some subset of your router. Wrapping this ensures that all routes
// handled by this handler have access to the server timing header struct.
var h http.Handler = http.HandlerFunc(handler)

// Wrap our handler with the server timing middleware
h = servertiming.Middleware(h, nil)

// Start!
http.ListenAndServe(":8080", h)
}

func handler(w http.ResponseWriter, r *http.Request) {
// Get our timing header builder from the context
timing := servertiming.FromContext(r.Context())

// Imagine your handler performs some tasks in a goroutine, such as
// accessing some remote service. timing is concurrency safe so we can
// record how long that takes. Let's simulate making 5 concurrent requests
// to various servicse.
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
name := fmt.Sprintf("service-%d", i)
go func(name string) {
// This creats a new metric and starts the timer. The Stop is
// deferred so when the function exits it'll record the duration.
defer timing.NewMetric(name).Start().Stop()
time.Sleep(random(25, 75))
wg.Done()
}(name)
}

// Imagine this is just some blocking code in your main handler such
// as a SQL query. Let's record that.
m := timing.NewMetric("sql").WithDesc("SQL query").Start()
time.Sleep(random(20, 50))
m.Stop()

// Wait for the goroutine to end
wg.Wait()

// You could continue recording more metrics, but let's just return now
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
}
```