github.com/waldiirawan/apm-agent-go/v2@v2.2.2/docs/context-propagation.asciidoc (about) 1 [[custom-instrumentation-propagation]] 2 === Context propagation 3 4 In Go, https://golang.org/pkg/context/[context] is used to propagate request-scoped values along a call 5 chain, potentially crossing between goroutines and between processes. For servers based on `net/http`, 6 each request contains an independent context object, which allows adding values specific to that particular 7 request. 8 9 When you start a transaction, you can add it to a context object using 10 <<apm-context-with-transaction, apm.ContextWithTransaction>>. This context object can be 11 later passed to <<apm-transaction-from-context, apm.TransactionFromContext>> to obtain 12 the transaction, or into <<apm-start-span, apm.StartSpan>> to start a span. 13 14 The simplest way to create and propagate a span is by using <<apm-start-span, apm.StartSpan>>, 15 which takes a context and returns a span. The span will be created as a child of the span most recently 16 added to this context, or a transaction added to the context as described above. If the context contains 17 neither a transaction nor a span, then the span will be dropped (i.e. will not be reported to the APM Server.) 18 19 For example, take a simple CRUD-type web service, which accepts requests over HTTP and then makes 20 corresponding database queries. For each incoming request, a transaction will be started and added to the 21 request context automatically. This context needs to be passed into method calls within the handler manually 22 in order to create spans within that transaction, e.g. to measure the duration of SQL queries. 23 24 [source,go] 25 ---- 26 import ( 27 "net/http" 28 29 "github.com/waldiirawan/apm-agent-go/v2" 30 "github.com/waldiirawan/apm-agent-go/module/apmhttp/v2" 31 "github.com/waldiirawan/apm-agent-go/module/apmsql/v2" 32 _ "github.com/waldiirawan/apm-agent-go/module/apmsql/v2/pq" 33 ) 34 35 var db *sql.DB 36 37 func init() { 38 // apmsql.Open wraps sql.Open, in order 39 // to add tracing to database operations. 40 db, _ = apmsql.Open("postgres", "") 41 } 42 43 func main() { 44 mux := http.NewServeMux() 45 mux.HandleFunc("/", handleList) 46 47 // apmhttp.Wrap instruments an http.Handler, in order 48 // to report any request to this handler as a transaction, 49 // and to store the transaction in the request's context. 50 handler := apmhttp.Wrap(mux) 51 http.ListenAndServe(":8080", handler) 52 } 53 54 func handleList(w http.ResponseWriter, req *http.Request) { 55 // By passing the request context down to getList, getList can add spans to it. 56 ctx := req.Context() 57 getList(ctx) 58 ... 59 } 60 61 func getList(ctx context.Context) ( 62 // When getList is called with a context containing a transaction or span, 63 // StartSpan creates a child span. In this example, getList is always called 64 // with a context containing a transaction for the handler, so we should 65 // expect to see something like: 66 // 67 // Transaction: handleList 68 // Span: getList 69 // Span: SELECT FROM items 70 // 71 span, ctx := apm.StartSpan(ctx, "getList", "custom") 72 defer span.End() 73 74 // NOTE: The context object ctx returned by StartSpan above contains 75 // the current span now, so subsequent calls to StartSpan create new 76 // child spans. 77 78 // db was opened with apmsql, so queries will be reported as 79 // spans when using the context methods. 80 rows, err := db.QueryContext(ctx, "SELECT * FROM items") 81 ... 82 rows.Close() 83 } 84 ---- 85 86 Contexts can have deadlines associated and can be explicitly canceled. In some cases you may 87 wish to propagate the trace context (parent transaction/span) to some code without propagating 88 the cancellation. For example, an HTTP request's context will be canceled when the client's 89 connection closes. You may want to perform some operation in the request handler without it 90 being canceled due to the client connection closing, such as in a fire-and-forget operation. 91 To handle scenarios like this, we provide the function <<apm-detached-context, apm.DetachedContext>>. 92 93 [source,go] 94 ---- 95 func handleRequest(w http.ResponseWriter, req *http.Request) { 96 go fireAndForget(apm.DetachedContext(req.Context())) 97 98 // After handleRequest returns, req.Context() will be canceled, 99 // but the "detached context" passed into fireAndForget will not. 100 // Any spans created by fireAndForget will still be joined to 101 // the handleRequest transaction. 102 } 103 ----