github.com/instana/go-sensor@v1.62.2-0.20240520081010-4919868049e1/docs/roundtripper.md (about) 1 ## Tracing HTTP Outgoing Requests 2 3 The tracer is able to collect data from the Go standard library for outgoing HTTP requests. 4 That is, when one creates an [http.Client](https://pkg.go.dev/net/http@go1.21.3#Client) instance to make calls to HTTP servers. 5 6 To achieve this data collection we provide a [RoundTripper](https://pkg.go.dev/net/http@go1.21.3#RoundTripper) wrapper to be used as the http.Client Transport. 7 Additionally, as HTTP outgoing requests are exit spans, the HTTP request must be attached to a context containing a entry span. 8 9 ### Usage 10 11 Let's assume the following code snippet as an example to be traced: 12 13 ```go 14 client := &http.Client{} 15 16 req, err := http.NewRequest(http.MethodGet, "https://www.instana.com", nil) 17 18 _, err = client.Do(req) 19 20 ``` 21 22 The first thing we need is to add the collector to the project: 23 24 ```go 25 col := instana.InitCollector(&instana.Options{ 26 Service: "my-http-client", 27 }) 28 ``` 29 30 Then, we need to wrap the current Transport (if any) with `instana.RoundTripper`. 31 If no Transport is provided, simply pass `nil` as the second argument. 32 The `instana.RoundTripper` wrapper will intercept the relevant information from the HTTP request, such as URL, methods and so on. It will then collect them and send to the Agent periodically. 33 34 ```go 35 // Wrap the original http.Client transport with instana.RoundTripper(). 36 // The http.DefaultTransport will be used if there was no transport provided. 37 client := &http.Client{ 38 Transport: instana.RoundTripper(col, nil), 39 } 40 ``` 41 42 Usually, your application will have an entry span already, received via HTTP or other type of incoming request. 43 This span should be contained into the context, which needs to be passed ahead to your client HTTP request. 44 Also, make sure to finish the span in order to send it to the Agent. 45 46 ```go 47 // Inject the parent span into request context 48 ctx := instana.ContextWithSpan(context.Background(), entrySpan) 49 50 // Use your instrumented http.Client to propagate tracing context with the request 51 _, err = client.Do(req.WithContext(ctx)) 52 ``` 53 54 If you do not have an entry span as explained above or you are not sure, it's possible to manually create an entry span and attach it to a context to be passed forward to your HTTP client: 55 56 ```go 57 // Every call should start with an entry span: 58 // https://www.ibm.com/docs/en/instana-observability/current?topic=tracing-best-practices#start-new-traces-with-entry-spans 59 // Normally this would be your HTTP/GRPC/message queue request span, but here we need to create it explicitly, 60 // since an HTTP client call is an exit span. And all exit spans must have a parent entry span. 61 entrySpan := col.Tracer().StartSpan("client-call") 62 entrySpan.SetTag(string(ext.SpanKind), "entry") 63 64 ... 65 66 // Inject the parent span into request context 67 ctx := instana.ContextWithSpan(context.Background(), entrySpan) 68 69 // Use your instrumented http.Client to propagate tracing context with the request 70 _, err = client.Do(req.WithContext(ctx)) 71 72 ... 73 74 // Remember to always finish spans that were created manually to make sure it's propagated to the Agent. 75 // In this case, we want to make sure that the entry span is finished after the HTTP request is completed. 76 // Optionally, we could use defer right after the span is created. 77 entrySpan.Finish() 78 ``` 79 You can learn more about manually instrumenting your code [here](). 80 81 #### Complete Example 82 83 ```go 84 package main 85 86 import ( 87 "context" 88 "log" 89 "net/http" 90 91 instana "github.com/instana/go-sensor" 92 "github.com/opentracing/opentracing-go/ext" 93 ) 94 95 func main() { 96 col := instana.InitCollector(&instana.Options{ 97 Service: "my-http-client", 98 }) 99 100 client := &http.Client{ 101 Transport: instana.RoundTripper(col, nil), 102 } 103 104 entrySpan := col.Tracer().StartSpan("client-call") 105 entrySpan.SetTag(string(ext.SpanKind), "entry") 106 107 req, err := http.NewRequest(http.MethodGet, "https://www.instana.com", nil) 108 if err != nil { 109 log.Fatalf("failed to create request: %s", err) 110 } 111 112 ctx := instana.ContextWithSpan(context.Background(), entrySpan) 113 114 _, err = client.Do(req.WithContext(ctx)) 115 if err != nil { 116 log.Fatalf("failed to GET https://www.instana.com: %s", err) 117 } 118 119 entrySpan.Finish() 120 } 121 ``` 122 123 ----- 124 [README](../README.md) | 125 [Tracer Options](options.md) | 126 [Tracing SQL Driver Databases](sql.md) | 127 [Tracing Other Go Packages](other_packages.md) | 128 [Instrumenting Code Manually](manual_instrumentation.md)