サーバサイドの処理のプロファイリングをChromeのDevtool
で可視化するライブラリです。
go-server-timing
そもそも論として
HTTPプロトコルヘッダーには、Server-Timing
というものがあります。ここにサーバ側で計測した値をセットして、HTTPレスポンスに一緒に仕込んでブラウザに返せば、Chrome Devtool
がいい感じに可視化してくれるわけです。
こんな感じに。
コードサンプル
実行したソースコードです。(README.mdからママ)
package main
import (
"fmt"
"math/rand"
"net/http"
"sync"
"time"
servertiming "github.com/mitchellh/go-server-timing"
)
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
}
コードの説明
41行目の
defer timing.NewMetric(name).Start().Stop()
でプロファイラを仕込んでいます。
Goのdeferで、関数をチェインした場合、最後の.Stop()
のみdeferされ、.Start()
は即時実行されることに注意してください。
また、deferのスコープは関数になります。38行目のgo func