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 // Package trace contains facilities for programs to generate traces 6 // for the Go execution tracer. 7 // 8 // Tracing runtime activities 9 // 10 // The execution trace captures a wide range of execution events such as 11 // goroutine creation/blocking/unblocking, syscall enter/exit/block, 12 // GC-related events, changes of heap size, processor start/stop, etc. 13 // A precise nanosecond-precision timestamp and a stack trace is 14 // captured for most events. The generated trace can be interpreted 15 // using `go tool trace`. 16 // 17 // Support for tracing tests and benchmarks built with the standard 18 // testing package is built into `go test`. For example, the following 19 // command runs the test in the current directory and writes the trace 20 // file (trace.out). 21 // 22 // go test -trace=trace.out 23 // 24 // This runtime/trace package provides APIs to add equivalent tracing 25 // support to a standalone program. See the Example that demonstrates 26 // how to use this API to enable tracing. 27 // 28 // There is also a standard HTTP interface to trace data. Adding the 29 // following line will install a handler under the /debug/pprof/trace URL 30 // to download a live trace: 31 // 32 // import _ "net/http/pprof" 33 // 34 // See the net/http/pprof package for more details about all of the 35 // debug endpoints installed by this import. 36 // 37 // User annotation 38 // 39 // Package trace provides user annotation APIs that can be used to 40 // log interesting events during execution. 41 // 42 // There are three types of user annotations: log messages, regions, 43 // and tasks. 44 // 45 // Log emits a timestamped message to the execution trace along with 46 // additional information such as the category of the message and 47 // which goroutine called Log. The execution tracer provides UIs to filter 48 // and group goroutines using the log category and the message supplied 49 // in Log. 50 // 51 // A region is for logging a time interval during a goroutine's execution. 52 // By definition, a region starts and ends in the same goroutine. 53 // Regions can be nested to represent subintervals. 54 // For example, the following code records four regions in the execution 55 // trace to trace the durations of sequential steps in a cappuccino making 56 // operation. 57 // 58 // trace.WithRegion(ctx, "makeCappuccino", func() { 59 // 60 // // orderID allows to identify a specific order 61 // // among many cappuccino order region records. 62 // trace.Log(ctx, "orderID", orderID) 63 // 64 // trace.WithRegion(ctx, "steamMilk", steamMilk) 65 // trace.WithRegion(ctx, "extractCoffee", extractCoffee) 66 // trace.WithRegion(ctx, "mixMilkCoffee", mixMilkCoffee) 67 // }) 68 // 69 // A task is a higher-level component that aids tracing of logical 70 // operations such as an RPC request, an HTTP request, or an 71 // interesting local operation which may require multiple goroutines 72 // working together. Since tasks can involve multiple goroutines, 73 // they are tracked via a context.Context object. NewTask creates 74 // a new task and embeds it in the returned context.Context object. 75 // Log messages and regions are attached to the task, if any, in the 76 // Context passed to Log and WithRegion. 77 // 78 // For example, assume that we decided to froth milk, extract coffee, 79 // and mix milk and coffee in separate goroutines. With a task, 80 // the trace tool can identify the goroutines involved in a specific 81 // cappuccino order. 82 // 83 // ctx, task := trace.NewTask(ctx, "makeCappuccino") 84 // trace.Log(ctx, "orderID", orderID) 85 // 86 // milk := make(chan bool) 87 // espresso := make(chan bool) 88 // 89 // go func() { 90 // trace.WithRegion(ctx, "steamMilk", steamMilk) 91 // milk <- true 92 // }() 93 // go func() { 94 // trace.WithRegion(ctx, "extractCoffee", extractCoffee) 95 // espresso <- true 96 // }() 97 // go func() { 98 // defer task.End() // When assemble is done, the order is complete. 99 // <-espresso 100 // <-milk 101 // trace.WithRegion(ctx, "mixMilkCoffee", mixMilkCoffee) 102 // }() 103 // 104 // 105 // The trace tool computes the latency of a task by measuring the 106 // time between the task creation and the task end and provides 107 // latency distributions for each task type found in the trace. 108 package trace 109 110 import ( 111 "io" 112 "runtime" 113 "sync" 114 "sync/atomic" 115 ) 116 117 // Start enables tracing for the current program. 118 // While tracing, the trace will be buffered and written to w. 119 // Start returns an error if tracing is already enabled. 120 func Start(w io.Writer) error { 121 tracing.Lock() 122 defer tracing.Unlock() 123 124 if err := runtime.StartTrace(); err != nil { 125 return err 126 } 127 go func() { 128 for { 129 data := runtime.ReadTrace() 130 if data == nil { 131 break 132 } 133 w.Write(data) 134 } 135 }() 136 atomic.StoreInt32(&tracing.enabled, 1) 137 return nil 138 } 139 140 // Stop stops the current tracing, if any. 141 // Stop only returns after all the writes for the trace have completed. 142 func Stop() { 143 tracing.Lock() 144 defer tracing.Unlock() 145 atomic.StoreInt32(&tracing.enabled, 0) 146 147 runtime.StopTrace() 148 } 149 150 var tracing struct { 151 sync.Mutex // gate mutators (Start, Stop) 152 enabled int32 // accessed via atomic 153 } 154