github.com/Andyfoo/golang/x/net@v0.0.0-20190901054642-57c1bf301704/trace/trace.go (about)

     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 "github.com/Andyfoo/golang/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  	"github.com/Andyfoo/golang/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  			"github.com/Andyfoo/golang/x/net/trace in your binary, trying to maintain separate state. This may " +
   125  			"involve a vendored copy of github.com/Andyfoo/golang/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("github.com/Andyfoo/golang/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  `