Code refactoring for bpa operator
[icn.git] / cmd / bpa-operator / vendor / golang.org / x / net / trace / trace.go
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 /*
6 Package trace implements tracing of requests and long-lived objects.
7 It exports HTTP interfaces on /debug/requests and /debug/events.
8
9 A trace.Trace provides tracing for short-lived objects, usually requests.
10 A 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
24 The /debug/requests HTTP endpoint organizes the traces by family,
25 errors, and duration.  It also provides histogram of request duration
26 for each family.
27
28 A trace.EventLog provides tracing for long-lived objects, such as RPC
29 connections.
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
59 The /debug/events HTTP endpoint organizes the event logs by family and
60 by time since the last error.  The expanded view displays recent log
61 entries and the log's call stack.
62 */
63 package trace // import "golang.org/x/net/trace"
64
65 import (
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.
87 var DebugUseAfterFinish = false
88
89 // HTTP ServeMux paths.
90 const (
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].
105 var 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
120 func 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.
136 func 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.
141 func 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.
151 func 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.
166 func 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.
180 func 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
288 func 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
304 func 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
312 type contextKeyT string
313
314 var contextKey = contextKeyT("golang.org/x/net/trace.Trace")
315
316 // Trace represents an active request.
317 type 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
351 type lazySprintf struct {
352         format string
353         a      []interface{}
354 }
355
356 func (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.
361 func 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
397 func (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
433 const (
434         bucketsPerFamily    = 9
435         tracesPerBucket     = 10
436         maxActiveTraces     = 20 // Maximum number of active traces to show.
437         maxEventsPerTrace   = 10
438         numHistogramBuckets = 38
439 )
440
441 var (
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
451 type 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
462 func (ts *traceSet) Len() int {
463         ts.mu.RLock()
464         defer ts.mu.RUnlock()
465         return len(ts.m)
466 }
467
468 func (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
477 func (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.
484 func (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
532 func 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
542 func 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
552 func 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.
564 type 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
573 func 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.
592 type 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
602 func (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.
630 func (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
649 func (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.
656 type cond interface {
657         match(t *trace) bool
658         String() string
659 }
660
661 type minCond time.Duration
662
663 func (m minCond) match(t *trace) bool { return t.Elapsed >= time.Duration(m) }
664 func (m minCond) String() string      { return fmt.Sprintf("≥%gs", time.Duration(m).Seconds()) }
665
666 type errorCond struct{}
667
668 func (e errorCond) match(t *trace) bool { return t.IsError }
669 func (e errorCond) String() string      { return "errors" }
670
671 type traceList []*trace
672
673 // Free calls unref on each element of the list.
674 func (trl traceList) Free() {
675         for _, t := range trl {
676                 t.unref()
677         }
678 }
679
680 // traceList may be sorted in reverse chronological order.
681 func (trl traceList) Len() int           { return len(trl) }
682 func (trl traceList) Less(i, j int) bool { return trl[i].Start.After(trl[j].Start) }
683 func (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.
686 type 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.
697 func (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.
706 type discarded int
707
708 func (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.
714 type 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
741 func (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
768 func (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
776 func (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
829 func (tr *trace) LazyLog(x fmt.Stringer, sensitive bool) {
830         tr.addEvent(x, true, sensitive)
831 }
832
833 func (tr *trace) LazyPrintf(format string, a ...interface{}) {
834         tr.addEvent(&lazySprintf{format, a}, false, false)
835 }
836
837 func (tr *trace) SetError() {
838         tr.mu.Lock()
839         tr.IsError = true
840         tr.mu.Unlock()
841 }
842
843 func (tr *trace) SetRecycler(f func(interface{})) {
844         tr.mu.Lock()
845         tr.recycler = f
846         tr.mu.Unlock()
847 }
848
849 func (tr *trace) SetTraceInfo(traceID, spanID uint64) {
850         tr.mu.Lock()
851         tr.traceID, tr.spanID = traceID, spanID
852         tr.mu.Unlock()
853 }
854
855 func (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
864 func (tr *trace) ref() {
865         atomic.AddInt32(&tr.refs, 1)
866 }
867
868 func (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
887 func (tr *trace) When() string {
888         return tr.Start.Format("2006/01/02 15:04:05.000000")
889 }
890
891 func (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
903 func (tr *trace) Events() []event {
904         tr.mu.RLock()
905         defer tr.mu.RUnlock()
906         return tr.events
907 }
908
909 var traceFreeList = make(chan *trace, 1000) // TODO(dsymonds): Use sync.Pool?
910
911 // newTrace returns a trace ready to use.
912 func 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.
923 func 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
934 func 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
956 var pageTmplCache *template.Template
957 var pageTmplOnce sync.Once
958
959 func 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
969 const 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 `