Code refactoring for bpa operator
[icn.git] / cmd / bpa-operator / vendor / github.com / Azure / go-autorest / tracing / tracing.go
1 package tracing
2
3 // Copyright 2018 Microsoft Corporation
4 //
5 //  Licensed under the Apache License, Version 2.0 (the "License");
6 //  you may not use this file except in compliance with the License.
7 //  You may obtain a copy of the License at
8 //
9 //      http://www.apache.org/licenses/LICENSE-2.0
10 //
11 //  Unless required by applicable law or agreed to in writing, software
12 //  distributed under the License is distributed on an "AS IS" BASIS,
13 //  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 //  See the License for the specific language governing permissions and
15 //  limitations under the License.
16
17 import (
18         "context"
19         "fmt"
20         "net/http"
21         "os"
22
23         "contrib.go.opencensus.io/exporter/ocagent"
24         "go.opencensus.io/plugin/ochttp"
25         "go.opencensus.io/plugin/ochttp/propagation/tracecontext"
26         "go.opencensus.io/stats/view"
27         "go.opencensus.io/trace"
28 )
29
30 var (
31         // Transport is the default tracing RoundTripper. The custom options setter will control
32         // if traces are being emitted or not.
33         Transport = &ochttp.Transport{
34                 Propagation:     &tracecontext.HTTPFormat{},
35                 GetStartOptions: getStartOptions,
36         }
37
38         // enabled is the flag for marking if tracing is enabled.
39         enabled = false
40
41         // Sampler is the tracing sampler. If tracing is disabled it will never sample. Otherwise
42         // it will be using the parent sampler or the default.
43         sampler = trace.NeverSample()
44
45         // Views for metric instrumentation.
46         views = map[string]*view.View{}
47
48         // the trace exporter
49         traceExporter trace.Exporter
50 )
51
52 func init() {
53         enableFromEnv()
54 }
55
56 func enableFromEnv() {
57         _, ok := os.LookupEnv("AZURE_SDK_TRACING_ENABLED")
58         _, legacyOk := os.LookupEnv("AZURE_SDK_TRACING_ENABELD")
59         if ok || legacyOk {
60                 agentEndpoint, ok := os.LookupEnv("OCAGENT_TRACE_EXPORTER_ENDPOINT")
61
62                 if ok {
63                         EnableWithAIForwarding(agentEndpoint)
64                 } else {
65                         Enable()
66                 }
67         }
68 }
69
70 // IsEnabled returns true if monitoring is enabled for the sdk.
71 func IsEnabled() bool {
72         return enabled
73 }
74
75 // Enable will start instrumentation for metrics and traces.
76 func Enable() error {
77         enabled = true
78         sampler = nil
79
80         err := initStats()
81         return err
82 }
83
84 // Disable will disable instrumentation for metrics and traces.
85 func Disable() {
86         disableStats()
87         sampler = trace.NeverSample()
88         if traceExporter != nil {
89                 trace.UnregisterExporter(traceExporter)
90         }
91         enabled = false
92 }
93
94 // EnableWithAIForwarding will start instrumentation and will connect to app insights forwarder
95 // exporter making the metrics and traces available in app insights.
96 func EnableWithAIForwarding(agentEndpoint string) (err error) {
97         err = Enable()
98         if err != nil {
99                 return err
100         }
101
102         traceExporter, err := ocagent.NewExporter(ocagent.WithInsecure(), ocagent.WithAddress(agentEndpoint))
103         if err != nil {
104                 return err
105         }
106         trace.RegisterExporter(traceExporter)
107         return
108 }
109
110 // getStartOptions is the custom options setter for the ochttp package.
111 func getStartOptions(*http.Request) trace.StartOptions {
112         return trace.StartOptions{
113                 Sampler: sampler,
114         }
115 }
116
117 // initStats registers the views for the http metrics
118 func initStats() (err error) {
119         clientViews := []*view.View{
120                 ochttp.ClientCompletedCount,
121                 ochttp.ClientRoundtripLatencyDistribution,
122                 ochttp.ClientReceivedBytesDistribution,
123                 ochttp.ClientSentBytesDistribution,
124         }
125         for _, cv := range clientViews {
126                 vn := fmt.Sprintf("Azure/go-autorest/tracing-%s", cv.Name)
127                 views[vn] = cv.WithName(vn)
128                 err = view.Register(views[vn])
129                 if err != nil {
130                         return err
131                 }
132         }
133         return
134 }
135
136 // disableStats will unregister the previously registered metrics
137 func disableStats() {
138         for _, v := range views {
139                 view.Unregister(v)
140         }
141 }
142
143 // StartSpan starts a trace span
144 func StartSpan(ctx context.Context, name string) context.Context {
145         ctx, _ = trace.StartSpan(ctx, name, trace.WithSampler(sampler))
146         return ctx
147 }
148
149 // EndSpan ends a previously started span stored in the context
150 func EndSpan(ctx context.Context, httpStatusCode int, err error) {
151         span := trace.FromContext(ctx)
152
153         if span == nil {
154                 return
155         }
156
157         if err != nil {
158                 span.SetStatus(trace.Status{Message: err.Error(), Code: toTraceStatusCode(httpStatusCode)})
159         }
160         span.End()
161 }
162
163 // toTraceStatusCode converts HTTP Codes to OpenCensus codes as defined
164 // at https://github.com/census-instrumentation/opencensus-specs/blob/master/trace/HTTP.md#status
165 func toTraceStatusCode(httpStatusCode int) int32 {
166         switch {
167         case http.StatusOK <= httpStatusCode && httpStatusCode < http.StatusBadRequest:
168                 return trace.StatusCodeOK
169         case httpStatusCode == http.StatusBadRequest:
170                 return trace.StatusCodeInvalidArgument
171         case httpStatusCode == http.StatusUnauthorized: // 401 is actually unauthenticated.
172                 return trace.StatusCodeUnauthenticated
173         case httpStatusCode == http.StatusForbidden:
174                 return trace.StatusCodePermissionDenied
175         case httpStatusCode == http.StatusNotFound:
176                 return trace.StatusCodeNotFound
177         case httpStatusCode == http.StatusTooManyRequests:
178                 return trace.StatusCodeResourceExhausted
179         case httpStatusCode == 499:
180                 return trace.StatusCodeCancelled
181         case httpStatusCode == http.StatusNotImplemented:
182                 return trace.StatusCodeUnimplemented
183         case httpStatusCode == http.StatusServiceUnavailable:
184                 return trace.StatusCodeUnavailable
185         case httpStatusCode == http.StatusGatewayTimeout:
186                 return trace.StatusCodeDeadlineExceeded
187         default:
188                 return trace.StatusCodeUnknown
189         }
190 }