aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/go.opencensus.io/plugin/ochttp/client.go
blob: da815b2a734519e3d3f19aad1752386584fa058d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
// Copyright 2018, OpenCensus Authors
//
// 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 ochttp

import (
    "net/http"
    "net/http/httptrace"

    "go.opencensus.io/trace"
    "go.opencensus.io/trace/propagation"
)

// Transport is an http.RoundTripper that instruments all outgoing requests with
// OpenCensus stats and tracing.
//
// The zero value is intended to be a useful default, but for
// now it's recommended that you explicitly set Propagation, since the default
// for this may change.
type Transport struct {
    // Base may be set to wrap another http.RoundTripper that does the actual
    // requests. By default http.DefaultTransport is used.
    //
    // If base HTTP roundtripper implements CancelRequest,
    // the returned round tripper will be cancelable.
    Base http.RoundTripper

    // Propagation defines how traces are propagated. If unspecified, a default
    // (currently B3 format) will be used.
    Propagation propagation.HTTPFormat

    // StartOptions are applied to the span started by this Transport around each
    // request.
    //
    // StartOptions.SpanKind will always be set to trace.SpanKindClient
    // for spans started by this transport.
    StartOptions trace.StartOptions

    // GetStartOptions allows to set start options per request. If set,
    // StartOptions is going to be ignored.
    GetStartOptions func(*http.Request) trace.StartOptions

    // NameFromRequest holds the function to use for generating the span name
    // from the information found in the outgoing HTTP Request. By default the
    // name equals the URL Path.
    FormatSpanName func(*http.Request) string

    // NewClientTrace may be set to a function allowing the current *trace.Span
    // to be annotated with HTTP request event information emitted by the
    // httptrace package.
    NewClientTrace func(*http.Request, *trace.Span) *httptrace.ClientTrace

    // TODO: Implement tag propagation for HTTP.
}

// RoundTrip implements http.RoundTripper, delegating to Base and recording stats and traces for the request.
func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
    rt := t.base()
    if isHealthEndpoint(req.URL.Path) {
        return rt.RoundTrip(req)
    }
    // TODO: remove excessive nesting of http.RoundTrippers here.
    format := t.Propagation
    if format == nil {
        format = defaultFormat
    }
    spanNameFormatter := t.FormatSpanName
    if spanNameFormatter == nil {
        spanNameFormatter = spanNameFromURL
    }

    startOpts := t.StartOptions
    if t.GetStartOptions != nil {
        startOpts = t.GetStartOptions(req)
    }

    rt = &traceTransport{
        base:   rt,
        format: format,
        startOptions: trace.StartOptions{
            Sampler:  startOpts.Sampler,
            SpanKind: trace.SpanKindClient,
        },
        formatSpanName: spanNameFormatter,
        newClientTrace: t.NewClientTrace,
    }
    rt = statsTransport{base: rt}
    return rt.RoundTrip(req)
}

func (t *Transport) base() http.RoundTripper {
    if t.Base != nil {
        return t.Base
    }
    return http.DefaultTransport
}

// CancelRequest cancels an in-flight request by closing its connection.
func (t *Transport) CancelRequest(req *http.Request) {
    type canceler interface {
        CancelRequest(*http.Request)
    }
    if cr, ok := t.base().(canceler); ok {
        cr.CancelRequest(req)
    }
}