1// Copyright 2015 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5/*
6Package trace implements tracing of requests and long-lived objects.
7It exports HTTP interfaces on /debug/requests and /debug/events.
8
9A trace.Trace provides tracing for short-lived objects, usually requests.
10A request handler might be implemented like this:
11
12	func fooHandler(w http.ResponseWriter, req *http.Request) {
13		tr := trace.New("mypkg.Foo", req.URL.Path)
14		defer tr.Finish()
15		...
16		tr.LazyPrintf("some event %q happened", str)
17		...
18		if err := somethingImportant(); err != nil {
19			tr.LazyPrintf("somethingImportant failed: %v", err)
20			tr.SetError()
21		}
22	}
23
24The /debug/requests HTTP endpoint organizes the traces by family,
25errors, and duration.  It also provides histogram of request duration
26for each family.
27
28A trace.EventLog provides tracing for long-lived objects, such as RPC
29connections.
30
31	// A Fetcher fetches URL paths for a single domain.
32	type Fetcher struct {
33		domain string
34		events trace.EventLog
35	}
36
37	func NewFetcher(domain string) *Fetcher {
38		return &Fetcher{
39			domain,
40			trace.NewEventLog("mypkg.Fetcher", domain),
41		}
42	}
43
44	func (f *Fetcher) Fetch(path string) (string, error) {
45		resp, err := http.Get("http://" + f.domain + "/" + path)
46		if err != nil {
47			f.events.Errorf("Get(%q) = %v", path, err)
48			return "", err
49		}
50		f.events.Printf("Get(%q) = %s", path, resp.Status)
51		...
52	}
53
54	func (f *Fetcher) Close() error {
55		f.events.Finish()
56		return nil
57	}
58
59The /debug/events HTTP endpoint organizes the event logs by family and
60by time since the last error.  The expanded view displays recent log
61entries and the log's call stack.
62*/
63package trace // import "golang.org/x/net/trace"
64
65import (
66	"bytes"
67	"context"
68	"fmt"
69	"html/template"
70	"io"
71	"log"
72	"net"
73	"net/http"
74	"net/url"
75	"runtime"
76	"sort"
77	"strconv"
78	"sync"
79	"sync/atomic"
80	"time"
81
82	"golang.org/x/net/internal/timeseries"
83)
84
85// DebugUseAfterFinish controls whether to debug uses of Trace values after finishing.
86// FOR DEBUGGING ONLY. This will slow down the program.
87var DebugUseAfterFinish = false
88
89// HTTP ServeMux paths.
90const (
91	debugRequestsPath = "/debug/requests"
92	debugEventsPath   = "/debug/events"
93)
94
95// AuthRequest determines whether a specific request is permitted to load the
96// /debug/requests or /debug/events pages.
97//
98// It returns two bools; the first indicates whether the page may be viewed at all,
99// and the second indicates whether sensitive events will be shown.
100//
101// AuthRequest may be replaced by a program to customize its authorization requirements.
102//
103// The default AuthRequest function returns (true, true) if and only if the request
104// comes from localhost/127.0.0.1/[::1].
105var AuthRequest = func(req *http.Request) (any, sensitive bool) {
106	// RemoteAddr is commonly in the form "IP" or "IP:port".
107	// If it is in the form "IP:port", split off the port.
108	host, _, err := net.SplitHostPort(req.RemoteAddr)
109	if err != nil {
110		host = req.RemoteAddr
111	}
112	switch host {
113	case "localhost", "127.0.0.1", "::1":
114		return true, true
115	default:
116		return false, false
117	}
118}
119
120func init() {
121	_, pat := http.DefaultServeMux.Handler(&http.Request{URL: &url.URL{Path: debugRequestsPath}})
122	if pat == debugRequestsPath {
123		panic("/debug/requests is already registered. You may have two independent copies of " +
124			"golang.org/x/net/trace in your binary, trying to maintain separate state. This may " +
125			"involve a vendored copy of golang.org/x/net/trace.")
126	}
127
128	// TODO(jbd): Serve Traces from /debug/traces in the future?
129	// There is no requirement for a request to be present to have traces.
130	http.HandleFunc(debugRequestsPath, Traces)
131	http.HandleFunc(debugEventsPath, Events)
132}
133
134// NewContext returns a copy of the parent context
135// and associates it with a Trace.
136func NewContext(ctx context.Context, tr Trace) context.Context {
137	return context.WithValue(ctx, contextKey, tr)
138}
139
140// FromContext returns the Trace bound to the context, if any.
141func FromContext(ctx context.Context) (tr Trace, ok bool) {
142	tr, ok = ctx.Value(contextKey).(Trace)
143	return
144}
145
146// Traces responds with traces from the program.
147// The package initialization registers it in http.DefaultServeMux
148// at /debug/requests.
149//
150// It performs authorization by running AuthRequest.
151func Traces(w http.ResponseWriter, req *http.Request) {
152	any, sensitive := AuthRequest(req)
153	if !any {
154		http.Error(w, "not allowed", http.StatusUnauthorized)
155		return
156	}
157	w.Header().Set("Content-Type", "text/html; charset=utf-8")
158	Render(w, req, sensitive)
159}
160
161// Events responds with a page of events collected by EventLogs.
162// The package initialization registers it in http.DefaultServeMux
163// at /debug/events.
164//
165// It performs authorization by running AuthRequest.
166func Events(w http.ResponseWriter, req *http.Request) {
167	any, sensitive := AuthRequest(req)
168	if !any {
169		http.Error(w, "not allowed", http.StatusUnauthorized)
170		return
171	}
172	w.Header().Set("Content-Type", "text/html; charset=utf-8")
173	RenderEvents(w, req, sensitive)
174}
175
176// Render renders the HTML page typically served at /debug/requests.
177// It does not do any auth checking. The request may be nil.
178//
179// Most users will use the Traces handler.
180func Render(w io.Writer, req *http.Request, sensitive bool) {
181	data := &struct {
182		Families         []string
183		ActiveTraceCount map[string]int
184		CompletedTraces  map[string]*family
185
186		// Set when a bucket has been selected.
187		Traces        traceList
188		Family        string
189		Bucket        int
190		Expanded      bool
191		Traced        bool
192		Active        bool
193		ShowSensitive bool // whether to show sensitive events
194
195		Histogram       template.HTML
196		HistogramWindow string // e.g. "last minute", "last hour", "all time"
197
198		// If non-zero, the set of traces is a partial set,
199		// and this is the total number.
200		Total int
201	}{
202		CompletedTraces: completedTraces,
203	}
204
205	data.ShowSensitive = sensitive
206	if req != nil {
207		// Allow show_sensitive=0 to force hiding of sensitive data for testing.
208		// This only goes one way; you can't use show_sensitive=1 to see things.
209		if req.FormValue("show_sensitive") == "0" {
210			data.ShowSensitive = false
211		}
212
213		if exp, err := strconv.ParseBool(req.FormValue("exp")); err == nil {
214			data.Expanded = exp
215		}
216		if exp, err := strconv.ParseBool(req.FormValue("rtraced")); err == nil {
217			data.Traced = exp
218		}
219	}
220
221	completedMu.RLock()
222	data.Families = make([]string, 0, len(completedTraces))
223	for fam := range completedTraces {
224		data.Families = append(data.Families, fam)
225	}
226	completedMu.RUnlock()
227	sort.Strings(data.Families)
228
229	// We are careful here to minimize the time spent locking activeMu,
230	// since that lock is required every time an RPC starts and finishes.
231	data.ActiveTraceCount = make(map[string]int, len(data.Families))
232	activeMu.RLock()
233	for fam, s := range activeTraces {
234		data.ActiveTraceCount[fam] = s.Len()
235	}
236	activeMu.RUnlock()
237
238	var ok bool
239	data.Family, data.Bucket, ok = parseArgs(req)
240	switch {
241	case !ok:
242		// No-op
243	case data.Bucket == -1:
244		data.Active = true
245		n := data.ActiveTraceCount[data.Family]
246		data.Traces = getActiveTraces(data.Family)
247		if len(data.Traces) < n {
248			data.Total = n
249		}
250	case data.Bucket < bucketsPerFamily:
251		if b := lookupBucket(data.Family, data.Bucket); b != nil {
252			data.Traces = b.Copy(data.Traced)
253		}
254	default:
255		if f := getFamily(data.Family, false); f != nil {
256			var obs timeseries.Observable
257			f.LatencyMu.RLock()
258			switch o := data.Bucket - bucketsPerFamily; o {
259			case 0:
260				obs = f.Latency.Minute()
261				data.HistogramWindow = "last minute"
262			case 1:
263				obs = f.Latency.Hour()
264				data.HistogramWindow = "last hour"
265			case 2:
266				obs = f.Latency.Total()
267				data.HistogramWindow = "all time"
268			}
269			f.LatencyMu.RUnlock()
270			if obs != nil {
271				data.Histogram = obs.(*histogram).html()
272			}
273		}
274	}
275
276	if data.Traces != nil {
277		defer data.Traces.Free()
278		sort.Sort(data.Traces)
279	}
280
281	completedMu.RLock()
282	defer completedMu.RUnlock()
283	if err := pageTmpl().ExecuteTemplate(w, "Page", data); err != nil {
284		log.Printf("net/trace: Failed executing template: %v", err)
285	}
286}
287
288func parseArgs(req *http.Request) (fam string, b int, ok bool) {
289	if req == nil {
290		return "", 0, false
291	}
292	fam, bStr := req.FormValue("fam"), req.FormValue("b")
293	if fam == "" || bStr == "" {
294		return "", 0, false
295	}
296	b, err := strconv.Atoi(bStr)
297	if err != nil || b < -1 {
298		return "", 0, false
299	}
300
301	return fam, b, true
302}
303
304func lookupBucket(fam string, b int) *traceBucket {
305	f := getFamily(fam, false)
306	if f == nil || b < 0 || b >= len(f.Buckets) {
307		return nil
308	}
309	return f.Buckets[b]
310}
311
312type contextKeyT string
313
314var contextKey = contextKeyT("golang.org/x/net/trace.Trace")
315
316// Trace represents an active request.
317type Trace interface {
318	// LazyLog adds x to the event log. It will be evaluated each time the
319	// /debug/requests page is rendered. Any memory referenced by x will be
320	// pinned until the trace is finished and later discarded.
321	LazyLog(x fmt.Stringer, sensitive bool)
322
323	// LazyPrintf evaluates its arguments with fmt.Sprintf each time the
324	// /debug/requests page is rendered. Any memory referenced by a will be
325	// pinned until the trace is finished and later discarded.
326	LazyPrintf(format string, a ...interface{})
327
328	// SetError declares that this trace resulted in an error.
329	SetError()
330
331	// SetRecycler sets a recycler for the trace.
332	// f will be called for each event passed to LazyLog at a time when
333	// it is no longer required, whether while the trace is still active
334	// and the event is discarded, or when a completed trace is discarded.
335	SetRecycler(f func(interface{}))
336
337	// SetTraceInfo sets the trace info for the trace.
338	// This is currently unused.
339	SetTraceInfo(traceID, spanID uint64)
340
341	// SetMaxEvents sets the maximum number of events that will be stored
342	// in the trace. This has no effect if any events have already been
343	// added to the trace.
344	SetMaxEvents(m int)
345
346	// Finish declares that this trace is complete.
347	// The trace should not be used after calling this method.
348	Finish()
349}
350
351type lazySprintf struct {
352	format string
353	a      []interface{}
354}
355
356func (l *lazySprintf) String() string {
357	return fmt.Sprintf(l.format, l.a...)
358}
359
360// New returns a new Trace with the specified family and title.
361func New(family, title string) Trace {
362	tr := newTrace()
363	tr.ref()
364	tr.Family, tr.Title = family, title
365	tr.Start = time.Now()
366	tr.maxEvents = maxEventsPerTrace
367	tr.events = tr.eventsBuf[:0]
368
369	activeMu.RLock()
370	s := activeTraces[tr.Family]
371	activeMu.RUnlock()
372	if s == nil {
373		activeMu.Lock()
374		s = activeTraces[tr.Family] // check again
375		if s == nil {
376			s = new(traceSet)
377			activeTraces[tr.Family] = s
378		}
379		activeMu.Unlock()
380	}
381	s.Add(tr)
382
383	// Trigger allocation of the completed trace structure for this family.
384	// This will cause the family to be present in the request page during
385	// the first trace of this family. We don't care about the return value,
386	// nor is there any need for this to run inline, so we execute it in its
387	// own goroutine, but only if the family isn't allocated yet.
388	completedMu.RLock()
389	if _, ok := completedTraces[tr.Family]; !ok {
390		go allocFamily(tr.Family)
391	}
392	completedMu.RUnlock()
393
394	return tr
395}
396
397func (tr *trace) Finish() {
398	elapsed := time.Now().Sub(tr.Start)
399	tr.mu.Lock()
400	tr.Elapsed = elapsed
401	tr.mu.Unlock()
402
403	if DebugUseAfterFinish {
404		buf := make([]byte, 4<<10) // 4 KB should be enough
405		n := runtime.Stack(buf, false)
406		tr.finishStack = buf[:n]
407	}
408
409	activeMu.RLock()
410	m := activeTraces[tr.Family]
411	activeMu.RUnlock()
412	m.Remove(tr)
413
414	f := getFamily(tr.Family, true)
415	tr.mu.RLock() // protects tr fields in Cond.match calls
416	for _, b := range f.Buckets {
417		if b.Cond.match(tr) {
418			b.Add(tr)
419		}
420	}
421	tr.mu.RUnlock()
422
423	// Add a sample of elapsed time as microseconds to the family's timeseries
424	h := new(histogram)
425	h.addMeasurement(elapsed.Nanoseconds() / 1e3)
426	f.LatencyMu.Lock()
427	f.Latency.Add(h)
428	f.LatencyMu.Unlock()
429
430	tr.unref() // matches ref in New
431}
432
433const (
434	bucketsPerFamily    = 9
435	tracesPerBucket     = 10
436	maxActiveTraces     = 20 // Maximum number of active traces to show.
437	maxEventsPerTrace   = 10
438	numHistogramBuckets = 38
439)
440
441var (
442	// The active traces.
443	activeMu     sync.RWMutex
444	activeTraces = make(map[string]*traceSet) // family -> traces
445
446	// Families of completed traces.
447	completedMu     sync.RWMutex
448	completedTraces = make(map[string]*family) // family -> traces
449)
450
451type traceSet struct {
452	mu sync.RWMutex
453	m  map[*trace]bool
454
455	// We could avoid the entire map scan in FirstN by having a slice of all the traces
456	// ordered by start time, and an index into that from the trace struct, with a periodic
457	// repack of the slice after enough traces finish; we could also use a skip list or similar.
458	// However, that would shift some of the expense from /debug/requests time to RPC time,
459	// which is probably the wrong trade-off.
460}
461
462func (ts *traceSet) Len() int {
463	ts.mu.RLock()
464	defer ts.mu.RUnlock()
465	return len(ts.m)
466}
467
468func (ts *traceSet) Add(tr *trace) {
469	ts.mu.Lock()
470	if ts.m == nil {
471		ts.m = make(map[*trace]bool)
472	}
473	ts.m[tr] = true
474	ts.mu.Unlock()
475}
476
477func (ts *traceSet) Remove(tr *trace) {
478	ts.mu.Lock()
479	delete(ts.m, tr)
480	ts.mu.Unlock()
481}
482
483// FirstN returns the first n traces ordered by time.
484func (ts *traceSet) FirstN(n int) traceList {
485	ts.mu.RLock()
486	defer ts.mu.RUnlock()
487
488	if n > len(ts.m) {
489		n = len(ts.m)
490	}
491	trl := make(traceList, 0, n)
492
493	// Fast path for when no selectivity is needed.
494	if n == len(ts.m) {
495		for tr := range ts.m {
496			tr.ref()
497			trl = append(trl, tr)
498		}
499		sort.Sort(trl)
500		return trl
501	}
502
503	// Pick the oldest n traces.
504	// This is inefficient. See the comment in the traceSet struct.
505	for tr := range ts.m {
506		// Put the first n traces into trl in the order they occur.
507		// When we have n, sort trl, and thereafter maintain its order.
508		if len(trl) < n {
509			tr.ref()
510			trl = append(trl, tr)
511			if len(trl) == n {
512				// This is guaranteed to happen exactly once during this loop.
513				sort.Sort(trl)
514			}
515			continue
516		}
517		if tr.Start.After(trl[n-1].Start) {
518			continue
519		}
520
521		// Find where to insert this one.
522		tr.ref()
523		i := sort.Search(n, func(i int) bool { return trl[i].Start.After(tr.Start) })
524		trl[n-1].unref()
525		copy(trl[i+1:], trl[i:])
526		trl[i] = tr
527	}
528
529	return trl
530}
531
532func getActiveTraces(fam string) traceList {
533	activeMu.RLock()
534	s := activeTraces[fam]
535	activeMu.RUnlock()
536	if s == nil {
537		return nil
538	}
539	return s.FirstN(maxActiveTraces)
540}
541
542func getFamily(fam string, allocNew bool) *family {
543	completedMu.RLock()
544	f := completedTraces[fam]
545	completedMu.RUnlock()
546	if f == nil && allocNew {
547		f = allocFamily(fam)
548	}
549	return f
550}
551
552func allocFamily(fam string) *family {
553	completedMu.Lock()
554	defer completedMu.Unlock()
555	f := completedTraces[fam]
556	if f == nil {
557		f = newFamily()
558		completedTraces[fam] = f
559	}
560	return f
561}
562
563// family represents a set of trace buckets and associated latency information.
564type family struct {
565	// traces may occur in multiple buckets.
566	Buckets [bucketsPerFamily]*traceBucket
567
568	// latency time series
569	LatencyMu sync.RWMutex
570	Latency   *timeseries.MinuteHourSeries
571}
572
573func newFamily() *family {
574	return &family{
575		Buckets: [bucketsPerFamily]*traceBucket{
576			{Cond: minCond(0)},
577			{Cond: minCond(50 * time.Millisecond)},
578			{Cond: minCond(100 * time.Millisecond)},
579			{Cond: minCond(200 * time.Millisecond)},
580			{Cond: minCond(500 * time.Millisecond)},
581			{Cond: minCond(1 * time.Second)},
582			{Cond: minCond(10 * time.Second)},
583			{Cond: minCond(100 * time.Second)},
584			{Cond: errorCond{}},
585		},
586		Latency: timeseries.NewMinuteHourSeries(func() timeseries.Observable { return new(histogram) }),
587	}
588}
589
590// traceBucket represents a size-capped bucket of historic traces,
591// along with a condition for a trace to belong to the bucket.
592type traceBucket struct {
593	Cond cond
594
595	// Ring buffer implementation of a fixed-size FIFO queue.
596	mu     sync.RWMutex
597	buf    [tracesPerBucket]*trace
598	start  int // < tracesPerBucket
599	length int // <= tracesPerBucket
600}
601
602func (b *traceBucket) Add(tr *trace) {
603	b.mu.Lock()
604	defer b.mu.Unlock()
605
606	i := b.start + b.length
607	if i >= tracesPerBucket {
608		i -= tracesPerBucket
609	}
610	if b.length == tracesPerBucket {
611		// "Remove" an element from the bucket.
612		b.buf[i].unref()
613		b.start++
614		if b.start == tracesPerBucket {
615			b.start = 0
616		}
617	}
618	b.buf[i] = tr
619	if b.length < tracesPerBucket {
620		b.length++
621	}
622	tr.ref()
623}
624
625// Copy returns a copy of the traces in the bucket.
626// If tracedOnly is true, only the traces with trace information will be returned.
627// The logs will be ref'd before returning; the caller should call
628// the Free method when it is done with them.
629// TODO(dsymonds): keep track of traced requests in separate buckets.
630func (b *traceBucket) Copy(tracedOnly bool) traceList {
631	b.mu.RLock()
632	defer b.mu.RUnlock()
633
634	trl := make(traceList, 0, b.length)
635	for i, x := 0, b.start; i < b.length; i++ {
636		tr := b.buf[x]
637		if !tracedOnly || tr.spanID != 0 {
638			tr.ref()
639			trl = append(trl, tr)
640		}
641		x++
642		if x == b.length {
643			x = 0
644		}
645	}
646	return trl
647}
648
649func (b *traceBucket) Empty() bool {
650	b.mu.RLock()
651	defer b.mu.RUnlock()
652	return b.length == 0
653}
654
655// cond represents a condition on a trace.
656type cond interface {
657	match(t *trace) bool
658	String() string
659}
660
661type minCond time.Duration
662
663func (m minCond) match(t *trace) bool { return t.Elapsed >= time.Duration(m) }
664func (m minCond) String() string      { return fmt.Sprintf("≥%gs", time.Duration(m).Seconds()) }
665
666type errorCond struct{}
667
668func (e errorCond) match(t *trace) bool { return t.IsError }
669func (e errorCond) String() string      { return "errors" }
670
671type traceList []*trace
672
673// Free calls unref on each element of the list.
674func (trl traceList) Free() {
675	for _, t := range trl {
676		t.unref()
677	}
678}
679
680// traceList may be sorted in reverse chronological order.
681func (trl traceList) Len() int           { return len(trl) }
682func (trl traceList) Less(i, j int) bool { return trl[i].Start.After(trl[j].Start) }
683func (trl traceList) Swap(i, j int)      { trl[i], trl[j] = trl[j], trl[i] }
684
685// An event is a timestamped log entry in a trace.
686type event struct {
687	When       time.Time
688	Elapsed    time.Duration // since previous event in trace
689	NewDay     bool          // whether this event is on a different day to the previous event
690	Recyclable bool          // whether this event was passed via LazyLog
691	Sensitive  bool          // whether this event contains sensitive information
692	What       interface{}   // string or fmt.Stringer
693}
694
695// WhenString returns a string representation of the elapsed time of the event.
696// It will include the date if midnight was crossed.
697func (e event) WhenString() string {
698	if e.NewDay {
699		return e.When.Format("2006/01/02 15:04:05.000000")
700	}
701	return e.When.Format("15:04:05.000000")
702}
703
704// discarded represents a number of discarded events.
705// It is stored as *discarded to make it easier to update in-place.
706type discarded int
707
708func (d *discarded) String() string {
709	return fmt.Sprintf("(%d events discarded)", int(*d))
710}
711
712// trace represents an active or complete request,
713// either sent or received by this program.
714type trace struct {
715	// Family is the top-level grouping of traces to which this belongs.
716	Family string
717
718	// Title is the title of this trace.
719	Title string
720
721	// Start time of the this trace.
722	Start time.Time
723
724	mu        sync.RWMutex
725	events    []event // Append-only sequence of events (modulo discards).
726	maxEvents int
727	recycler  func(interface{})
728	IsError   bool          // Whether this trace resulted in an error.
729	Elapsed   time.Duration // Elapsed time for this trace, zero while active.
730	traceID   uint64        // Trace information if non-zero.
731	spanID    uint64
732
733	refs int32     // how many buckets this is in
734	disc discarded // scratch space to avoid allocation
735
736	finishStack []byte // where finish was called, if DebugUseAfterFinish is set
737
738	eventsBuf [4]event // preallocated buffer in case we only log a few events
739}
740
741func (tr *trace) reset() {
742	// Clear all but the mutex. Mutexes may not be copied, even when unlocked.
743	tr.Family = ""
744	tr.Title = ""
745	tr.Start = time.Time{}
746
747	tr.mu.Lock()
748	tr.Elapsed = 0
749	tr.traceID = 0
750	tr.spanID = 0
751	tr.IsError = false
752	tr.maxEvents = 0
753	tr.events = nil
754	tr.recycler = nil
755	tr.mu.Unlock()
756
757	tr.refs = 0
758	tr.disc = 0
759	tr.finishStack = nil
760	for i := range tr.eventsBuf {
761		tr.eventsBuf[i] = event{}
762	}
763}
764
765// delta returns the elapsed time since the last event or the trace start,
766// and whether it spans midnight.
767// L >= tr.mu
768func (tr *trace) delta(t time.Time) (time.Duration, bool) {
769	if len(tr.events) == 0 {
770		return t.Sub(tr.Start), false
771	}
772	prev := tr.events[len(tr.events)-1].When
773	return t.Sub(prev), prev.Day() != t.Day()
774}
775
776func (tr *trace) addEvent(x interface{}, recyclable, sensitive bool) {
777	if DebugUseAfterFinish && tr.finishStack != nil {
778		buf := make([]byte, 4<<10) // 4 KB should be enough
779		n := runtime.Stack(buf, false)
780		log.Printf("net/trace: trace used after finish:\nFinished at:\n%s\nUsed at:\n%s", tr.finishStack, buf[:n])
781	}
782
783	/*
784		NOTE TO DEBUGGERS
785
786		If you are here because your program panicked in this code,
787		it is almost definitely the fault of code using this package,
788		and very unlikely to be the fault of this code.
789
790		The most likely scenario is that some code elsewhere is using
791		a trace.Trace after its Finish method is called.
792		You can temporarily set the DebugUseAfterFinish var
793		to help discover where that is; do not leave that var set,
794		since it makes this package much less efficient.
795	*/
796
797	e := event{When: time.Now(), What: x, Recyclable: recyclable, Sensitive: sensitive}
798	tr.mu.Lock()
799	e.Elapsed, e.NewDay = tr.delta(e.When)
800	if len(tr.events) < tr.maxEvents {
801		tr.events = append(tr.events, e)
802	} else {
803		// Discard the middle events.
804		di := int((tr.maxEvents - 1) / 2)
805		if d, ok := tr.events[di].What.(*discarded); ok {
806			(*d)++
807		} else {
808			// disc starts at two to count for the event it is replacing,
809			// plus the next one that we are about to drop.
810			tr.disc = 2
811			if tr.recycler != nil && tr.events[di].Recyclable {
812				go tr.recycler(tr.events[di].What)
813			}
814			tr.events[di].What = &tr.disc
815		}
816		// The timestamp of the discarded meta-event should be
817		// the time of the last event it is representing.
818		tr.events[di].When = tr.events[di+1].When
819
820		if tr.recycler != nil && tr.events[di+1].Recyclable {
821			go tr.recycler(tr.events[di+1].What)
822		}
823		copy(tr.events[di+1:], tr.events[di+2:])
824		tr.events[tr.maxEvents-1] = e
825	}
826	tr.mu.Unlock()
827}
828
829func (tr *trace) LazyLog(x fmt.Stringer, sensitive bool) {
830	tr.addEvent(x, true, sensitive)
831}
832
833func (tr *trace) LazyPrintf(format string, a ...interface{}) {
834	tr.addEvent(&lazySprintf{format, a}, false, false)
835}
836
837func (tr *trace) SetError() {
838	tr.mu.Lock()
839	tr.IsError = true
840	tr.mu.Unlock()
841}
842
843func (tr *trace) SetRecycler(f func(interface{})) {
844	tr.mu.Lock()
845	tr.recycler = f
846	tr.mu.Unlock()
847}
848
849func (tr *trace) SetTraceInfo(traceID, spanID uint64) {
850	tr.mu.Lock()
851	tr.traceID, tr.spanID = traceID, spanID
852	tr.mu.Unlock()
853}
854
855func (tr *trace) SetMaxEvents(m int) {
856	tr.mu.Lock()
857	// Always keep at least three events: first, discarded count, last.
858	if len(tr.events) == 0 && m > 3 {
859		tr.maxEvents = m
860	}
861	tr.mu.Unlock()
862}
863
864func (tr *trace) ref() {
865	atomic.AddInt32(&tr.refs, 1)
866}
867
868func (tr *trace) unref() {
869	if atomic.AddInt32(&tr.refs, -1) == 0 {
870		tr.mu.RLock()
871		if tr.recycler != nil {
872			// freeTrace clears tr, so we hold tr.recycler and tr.events here.
873			go func(f func(interface{}), es []event) {
874				for _, e := range es {
875					if e.Recyclable {
876						f(e.What)
877					}
878				}
879			}(tr.recycler, tr.events)
880		}
881		tr.mu.RUnlock()
882
883		freeTrace(tr)
884	}
885}
886
887func (tr *trace) When() string {
888	return tr.Start.Format("2006/01/02 15:04:05.000000")
889}
890
891func (tr *trace) ElapsedTime() string {
892	tr.mu.RLock()
893	t := tr.Elapsed
894	tr.mu.RUnlock()
895
896	if t == 0 {
897		// Active trace.
898		t = time.Since(tr.Start)
899	}
900	return fmt.Sprintf("%.6f", t.Seconds())
901}
902
903func (tr *trace) Events() []event {
904	tr.mu.RLock()
905	defer tr.mu.RUnlock()
906	return tr.events
907}
908
909var traceFreeList = make(chan *trace, 1000) // TODO(dsymonds): Use sync.Pool?
910
911// newTrace returns a trace ready to use.
912func newTrace() *trace {
913	select {
914	case tr := <-traceFreeList:
915		return tr
916	default:
917		return new(trace)
918	}
919}
920
921// freeTrace adds tr to traceFreeList if there's room.
922// This is non-blocking.
923func freeTrace(tr *trace) {
924	if DebugUseAfterFinish {
925		return // never reuse
926	}
927	tr.reset()
928	select {
929	case traceFreeList <- tr:
930	default:
931	}
932}
933
934func elapsed(d time.Duration) string {
935	b := []byte(fmt.Sprintf("%.6f", d.Seconds()))
936
937	// For subsecond durations, blank all zeros before decimal point,
938	// and all zeros between the decimal point and the first non-zero digit.
939	if d < time.Second {
940		dot := bytes.IndexByte(b, '.')
941		for i := 0; i < dot; i++ {
942			b[i] = ' '
943		}
944		for i := dot + 1; i < len(b); i++ {
945			if b[i] == '0' {
946				b[i] = ' '
947			} else {
948				break
949			}
950		}
951	}
952
953	return string(b)
954}
955
956var pageTmplCache *template.Template
957var pageTmplOnce sync.Once
958
959func pageTmpl() *template.Template {
960	pageTmplOnce.Do(func() {
961		pageTmplCache = template.Must(template.New("Page").Funcs(template.FuncMap{
962			"elapsed": elapsed,
963			"add":     func(a, b int) int { return a + b },
964		}).Parse(pageHTML))
965	})
966	return pageTmplCache
967}
968
969const pageHTML = `
970{{template "Prolog" .}}
971{{template "StatusTable" .}}
972{{template "Epilog" .}}
973
974{{define "Prolog"}}
975<html>
976	<head>
977	<title>/debug/requests</title>
978	<style type="text/css">
979		body {
980			font-family: sans-serif;
981		}
982		table#tr-status td.family {
983			padding-right: 2em;
984		}
985		table#tr-status td.active {
986			padding-right: 1em;
987		}
988		table#tr-status td.latency-first {
989			padding-left: 1em;
990		}
991		table#tr-status td.empty {
992			color: #aaa;
993		}
994		table#reqs {
995			margin-top: 1em;
996		}
997		table#reqs tr.first {
998			{{if $.Expanded}}font-weight: bold;{{end}}
999		}
1000		table#reqs td {
1001			font-family: monospace;
1002		}
1003		table#reqs td.when {
1004			text-align: right;
1005			white-space: nowrap;
1006		}
1007		table#reqs td.elapsed {
1008			padding: 0 0.5em;
1009			text-align: right;
1010			white-space: pre;
1011			width: 10em;
1012		}
1013		address {
1014			font-size: smaller;
1015			margin-top: 5em;
1016		}
1017	</style>
1018	</head>
1019	<body>
1020
1021<h1>/debug/requests</h1>
1022{{end}} {{/* end of Prolog */}}
1023
1024{{define "StatusTable"}}
1025<table id="tr-status">
1026	{{range $fam := .Families}}
1027	<tr>
1028		<td class="family">{{$fam}}</td>
1029
1030		{{$n := index $.ActiveTraceCount $fam}}
1031		<td class="active {{if not $n}}empty{{end}}">
1032			{{if $n}}<a href="?fam={{$fam}}&b=-1{{if $.Expanded}}&exp=1{{end}}">{{end}}
1033			[{{$n}} active]
1034			{{if $n}}</a>{{end}}
1035		</td>
1036
1037		{{$f := index $.CompletedTraces $fam}}
1038		{{range $i, $b := $f.Buckets}}
1039		{{$empty := $b.Empty}}
1040		<td {{if $empty}}class="empty"{{end}}>
1041		{{if not $empty}}<a href="?fam={{$fam}}&b={{$i}}{{if $.Expanded}}&exp=1{{end}}">{{end}}
1042		[{{.Cond}}]
1043		{{if not $empty}}</a>{{end}}
1044		</td>
1045		{{end}}
1046
1047		{{$nb := len $f.Buckets}}
1048		<td class="latency-first">
1049		<a href="?fam={{$fam}}&b={{$nb}}">[minute]</a>
1050		</td>
1051		<td>
1052		<a href="?fam={{$fam}}&b={{add $nb 1}}">[hour]</a>
1053		</td>
1054		<td>
1055		<a href="?fam={{$fam}}&b={{add $nb 2}}">[total]</a>
1056		</td>
1057
1058	</tr>
1059	{{end}}
1060</table>
1061{{end}} {{/* end of StatusTable */}}
1062
1063{{define "Epilog"}}
1064{{if $.Traces}}
1065<hr />
1066<h3>Family: {{$.Family}}</h3>
1067
1068{{if or $.Expanded $.Traced}}
1069  <a href="?fam={{$.Family}}&b={{$.Bucket}}">[Normal/Summary]</a>
1070{{else}}
1071  [Normal/Summary]
1072{{end}}
1073
1074{{if or (not $.Expanded) $.Traced}}
1075  <a href="?fam={{$.Family}}&b={{$.Bucket}}&exp=1">[Normal/Expanded]</a>
1076{{else}}
1077  [Normal/Expanded]
1078{{end}}
1079
1080{{if not $.Active}}
1081	{{if or $.Expanded (not $.Traced)}}
1082	<a href="?fam={{$.Family}}&b={{$.Bucket}}&rtraced=1">[Traced/Summary]</a>
1083	{{else}}
1084	[Traced/Summary]
1085	{{end}}
1086	{{if or (not $.Expanded) (not $.Traced)}}
1087	<a href="?fam={{$.Family}}&b={{$.Bucket}}&exp=1&rtraced=1">[Traced/Expanded]</a>
1088        {{else}}
1089	[Traced/Expanded]
1090	{{end}}
1091{{end}}
1092
1093{{if $.Total}}
1094<p><em>Showing <b>{{len $.Traces}}</b> of <b>{{$.Total}}</b> traces.</em></p>
1095{{end}}
1096
1097<table id="reqs">
1098	<caption>
1099		{{if $.Active}}Active{{else}}Completed{{end}} Requests
1100	</caption>
1101	<tr><th>When</th><th>Elapsed&nbsp;(s)</th></tr>
1102	{{range $tr := $.Traces}}
1103	<tr class="first">
1104		<td class="when">{{$tr.When}}</td>
1105		<td class="elapsed">{{$tr.ElapsedTime}}</td>
1106		<td>{{$tr.Title}}</td>
1107		{{/* TODO: include traceID/spanID */}}
1108	</tr>
1109	{{if $.Expanded}}
1110	{{range $tr.Events}}
1111	<tr>
1112		<td class="when">{{.WhenString}}</td>
1113		<td class="elapsed">{{elapsed .Elapsed}}</td>
1114		<td>{{if or $.ShowSensitive (not .Sensitive)}}... {{.What}}{{else}}<em>[redacted]</em>{{end}}</td>
1115	</tr>
1116	{{end}}
1117	{{end}}
1118	{{end}}
1119</table>
1120{{end}} {{/* if $.Traces */}}
1121
1122{{if $.Histogram}}
1123<h4>Latency (&micro;s) of {{$.Family}} over {{$.HistogramWindow}}</h4>
1124{{$.Histogram}}
1125{{end}} {{/* if $.Histogram */}}
1126
1127	</body>
1128</html>
1129{{end}} {{/* end of Epilog */}}
1130`
1131