|  | // Copyright 2017 Google Inc. All Rights Reserved. | 
|  | // | 
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | // you may not use this file except in compliance with the License. | 
|  | // You may obtain a copy of the License at | 
|  | // | 
|  | //      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | // | 
|  | // Unless required by applicable law or agreed to in writing, software | 
|  | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | // See the License for the specific language governing permissions and | 
|  | // limitations under the License. | 
|  |  | 
|  | // +build go1.7 | 
|  |  | 
|  | package trace | 
|  |  | 
|  | import "net/http" | 
|  |  | 
|  | type tracerTransport struct { | 
|  | base http.RoundTripper | 
|  | } | 
|  |  | 
|  | func (tt *tracerTransport) RoundTrip(req *http.Request) (*http.Response, error) { | 
|  | span := FromContext(req.Context()).NewRemoteChild(req) | 
|  | resp, err := tt.base.RoundTrip(req) | 
|  |  | 
|  | // TODO(jbd): Is it possible to defer the span.Finish? | 
|  | // In cases where RoundTrip panics, we still can finish the span. | 
|  | span.Finish(WithResponse(resp)) | 
|  | return resp, err | 
|  | } | 
|  |  | 
|  | // HTTPClient is an HTTP client that enhances http.Client | 
|  | // with automatic tracing support. | 
|  | type HTTPClient struct { | 
|  | http.Client | 
|  | traceClient *Client | 
|  | } | 
|  |  | 
|  | // Do behaves like (*http.Client).Do but automatically traces | 
|  | // outgoing requests if tracing is enabled for the current request. | 
|  | // | 
|  | // If req.Context() contains a traced *Span, the outgoing request | 
|  | // is traced with the existing span. If not, the request is not traced. | 
|  | func (c *HTTPClient) Do(req *http.Request) (*http.Response, error) { | 
|  | return c.Client.Do(req) | 
|  | } | 
|  |  | 
|  | // NewHTTPClient creates a new HTTPClient that will trace the outgoing | 
|  | // requests using tc. The attributes of this client are inherited from the | 
|  | // given http.Client. If orig is nil, http.DefaultClient is used. | 
|  | func (c *Client) NewHTTPClient(orig *http.Client) *HTTPClient { | 
|  | if orig == nil { | 
|  | orig = http.DefaultClient | 
|  | } | 
|  | rt := orig.Transport | 
|  | if rt == nil { | 
|  | rt = http.DefaultTransport | 
|  | } | 
|  | client := http.Client{ | 
|  | Transport:     &tracerTransport{base: rt}, | 
|  | CheckRedirect: orig.CheckRedirect, | 
|  | Jar:           orig.Jar, | 
|  | Timeout:       orig.Timeout, | 
|  | } | 
|  | return &HTTPClient{ | 
|  | Client:      client, | 
|  | traceClient: c, | 
|  | } | 
|  | } | 
|  |  | 
|  | // HTTPHandler returns a http.Handler from the given handler | 
|  | // that is aware of the incoming request's span. | 
|  | // The span can be extracted from the incoming request in handler | 
|  | // functions from incoming request's context: | 
|  | // | 
|  | //    span := trace.FromContext(r.Context()) | 
|  | // | 
|  | // The span will be auto finished by the handler. | 
|  | func (c *Client) HTTPHandler(h http.Handler) http.Handler { | 
|  | return &handler{traceClient: c, handler: h} | 
|  | } | 
|  |  | 
|  | type handler struct { | 
|  | traceClient *Client | 
|  | handler     http.Handler | 
|  | } | 
|  |  | 
|  | func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { | 
|  | span := h.traceClient.SpanFromRequest(r) | 
|  | defer span.Finish() | 
|  |  | 
|  | r = r.WithContext(NewContext(r.Context(), span)) | 
|  | h.handler.ServeHTTP(w, r) | 
|  | } |