// Copyright 2017 Google LLC // // 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. package trace import ( "net/http" ) // Transport is an http.RoundTripper that traces the outgoing requests. // // Transport is safe for concurrent usage. // // Deprecated: see https://cloud.google.com/trace/docs/setup/go. type Transport struct { // Base is the base http.RoundTripper to be used to do the actual request. // // Optional. If nil, http.DefaultTransport is used. Base http.RoundTripper } // RoundTrip creates a trace.Span and inserts it into the outgoing request's headers. // The created span can follow a parent span, if a parent is presented in // the request's context. // // Deprecated: see https://cloud.google.com/trace/docs/setup/go. func (t Transport) RoundTrip(req *http.Request) (*http.Response, error) { span := FromContext(req.Context()).NewRemoteChild(req) resp, err := t.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 } // CancelRequest cancels an in-flight request by closing its connection. // // Deprecated: see https://cloud.google.com/trace/docs/setup/go. func (t Transport) CancelRequest(req *http.Request) { type canceler interface { CancelRequest(*http.Request) } if cr, ok := t.base().(canceler); ok { cr.CancelRequest(req) } } func (t Transport) base() http.RoundTripper { if t.Base != nil { return t.Base } return http.DefaultTransport } // 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. // // Deprecated: see https://cloud.google.com/trace/docs/setup/go. func (c *Client) HTTPHandler(h http.Handler) http.Handler { if c == nil { return h } return &handler{traceClient: c, handler: h} } type handler struct { traceClient *Client handler http.Handler } // Deprecated: see https://cloud.google.com/trace/docs/setup/go. func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { traceID, parentSpanID, options, optionsOk, ok := traceInfoFromHeader(r.Header.Get(httpHeader)) if !ok { traceID = nextTraceID() } t := &trace{ traceID: traceID, client: h.traceClient, globalOptions: options, localOptions: options, } span := startNewChildWithRequest(r, t, parentSpanID) span.span.Kind = spanKindServer span.rootSpan = true configureSpanFromPolicy(span, h.traceClient.policy, ok) defer span.Finish() r = r.WithContext(NewContext(r.Context(), span)) if ok && !optionsOk { // Inject the trace context back to the response with the sampling options. // TODO(jbd): Remove when there is a better way to report the client's sampling. w.Header().Set(httpHeader, spanHeader(traceID, parentSpanID, span.trace.localOptions)) } h.handler.ServeHTTP(w, r) }