1// Package timer adds HTTP request and response timing information to a
2// context.
3package timer
4
5import (
6	"fmt"
7	"time"
8
9	"golang.org/x/net/context"
10)
11
12// Timer collects request and response timing information
13type Timer struct {
14	// When the request headers have been received - earliest timing point can get
15	// right now.
16	tsRequestHeaders int64
17	// When the response headers have been received
18	tsResponseHeaders int64
19	// When the response is completely written
20	tsResponseDone int64
21}
22
23func (t Timer) String() string {
24	if t.tsRequestHeaders == 0 {
25		return "timer"
26	}
27	return fmt.Sprintf(
28		"%.2fms total, %.2fms to response headers, %.2fms sending response body",
29		float64(t.tsResponseDone-t.tsRequestHeaders)/1000000.0,
30		float64(t.tsResponseHeaders-t.tsRequestHeaders)/1000000.0,
31		float64(t.tsResponseDone-t.tsResponseHeaders)/1000000.0,
32	)
33}
34
35// RequestHeaders sets the time at which request headers were received
36func (t *Timer) RequestHeaders() {
37	t.tsRequestHeaders = time.Now().UnixNano()
38}
39
40// ResponseHeaders sets the time at which request headers were received
41func (t *Timer) ResponseHeaders() {
42	t.tsResponseHeaders = time.Now().UnixNano()
43}
44
45// ResponseDone sets the time at which request headers were received
46func (t *Timer) ResponseDone() {
47	t.tsResponseDone = time.Now().UnixNano()
48}
49
50// NewContext creates a new context with the timer included
51func (t *Timer) NewContext(ctx context.Context) context.Context {
52	return context.WithValue(ctx, "timer", t)
53}
54
55// FromContext creates a new context with the timer included
56func FromContext(ctx context.Context) *Timer {
57	timer, ok := ctx.Value("timer").(*Timer)
58	if !ok {
59		// Return a dummy timer
60		return &Timer{}
61	}
62	return timer
63}
64