aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/go.opencensus.io/trace/spanstore.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/go.opencensus.io/trace/spanstore.go')
-rw-r--r--vendor/go.opencensus.io/trace/spanstore.go306
1 files changed, 306 insertions, 0 deletions
diff --git a/vendor/go.opencensus.io/trace/spanstore.go b/vendor/go.opencensus.io/trace/spanstore.go
new file mode 100644
index 0000000..c442d99
--- /dev/null
+++ b/vendor/go.opencensus.io/trace/spanstore.go
@@ -0,0 +1,306 @@
1// Copyright 2017, OpenCensus Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package trace
16
17import (
18 "sync"
19 "time"
20
21 "go.opencensus.io/internal"
22)
23
24const (
25 maxBucketSize = 100000
26 defaultBucketSize = 10
27)
28
29var (
30 ssmu sync.RWMutex // protects spanStores
31 spanStores = make(map[string]*spanStore)
32)
33
34// This exists purely to avoid exposing internal methods used by z-Pages externally.
35type internalOnly struct{}
36
37func init() {
38 //TODO(#412): remove
39 internal.Trace = &internalOnly{}
40}
41
42// ReportActiveSpans returns the active spans for the given name.
43func (i internalOnly) ReportActiveSpans(name string) []*SpanData {
44 s := spanStoreForName(name)
45 if s == nil {
46 return nil
47 }
48 var out []*SpanData
49 s.mu.Lock()
50 defer s.mu.Unlock()
51 for span := range s.active {
52 out = append(out, span.makeSpanData())
53 }
54 return out
55}
56
57// ReportSpansByError returns a sample of error spans.
58//
59// If code is nonzero, only spans with that status code are returned.
60func (i internalOnly) ReportSpansByError(name string, code int32) []*SpanData {
61 s := spanStoreForName(name)
62 if s == nil {
63 return nil
64 }
65 var out []*SpanData
66 s.mu.Lock()
67 defer s.mu.Unlock()
68 if code != 0 {
69 if b, ok := s.errors[code]; ok {
70 for _, sd := range b.buffer {
71 if sd == nil {
72 break
73 }
74 out = append(out, sd)
75 }
76 }
77 } else {
78 for _, b := range s.errors {
79 for _, sd := range b.buffer {
80 if sd == nil {
81 break
82 }
83 out = append(out, sd)
84 }
85 }
86 }
87 return out
88}
89
90// ConfigureBucketSizes sets the number of spans to keep per latency and error
91// bucket for different span names.
92func (i internalOnly) ConfigureBucketSizes(bcs []internal.BucketConfiguration) {
93 for _, bc := range bcs {
94 latencyBucketSize := bc.MaxRequestsSucceeded
95 if latencyBucketSize < 0 {
96 latencyBucketSize = 0
97 }
98 if latencyBucketSize > maxBucketSize {
99 latencyBucketSize = maxBucketSize
100 }
101 errorBucketSize := bc.MaxRequestsErrors
102 if errorBucketSize < 0 {
103 errorBucketSize = 0
104 }
105 if errorBucketSize > maxBucketSize {
106 errorBucketSize = maxBucketSize
107 }
108 spanStoreSetSize(bc.Name, latencyBucketSize, errorBucketSize)
109 }
110}
111
112// ReportSpansPerMethod returns a summary of what spans are being stored for each span name.
113func (i internalOnly) ReportSpansPerMethod() map[string]internal.PerMethodSummary {
114 out := make(map[string]internal.PerMethodSummary)
115 ssmu.RLock()
116 defer ssmu.RUnlock()
117 for name, s := range spanStores {
118 s.mu.Lock()
119 p := internal.PerMethodSummary{
120 Active: len(s.active),
121 }
122 for code, b := range s.errors {
123 p.ErrorBuckets = append(p.ErrorBuckets, internal.ErrorBucketSummary{
124 ErrorCode: code,
125 Size: b.size(),
126 })
127 }
128 for i, b := range s.latency {
129 min, max := latencyBucketBounds(i)
130 p.LatencyBuckets = append(p.LatencyBuckets, internal.LatencyBucketSummary{
131 MinLatency: min,
132 MaxLatency: max,
133 Size: b.size(),
134 })
135 }
136 s.mu.Unlock()
137 out[name] = p
138 }
139 return out
140}
141
142// ReportSpansByLatency returns a sample of successful spans.
143//
144// minLatency is the minimum latency of spans to be returned.
145// maxLatency, if nonzero, is the maximum latency of spans to be returned.
146func (i internalOnly) ReportSpansByLatency(name string, minLatency, maxLatency time.Duration) []*SpanData {
147 s := spanStoreForName(name)
148 if s == nil {
149 return nil
150 }
151 var out []*SpanData
152 s.mu.Lock()
153 defer s.mu.Unlock()
154 for i, b := range s.latency {
155 min, max := latencyBucketBounds(i)
156 if i+1 != len(s.latency) && max <= minLatency {
157 continue
158 }
159 if maxLatency != 0 && maxLatency < min {
160 continue
161 }
162 for _, sd := range b.buffer {
163 if sd == nil {
164 break
165 }
166 if minLatency != 0 || maxLatency != 0 {
167 d := sd.EndTime.Sub(sd.StartTime)
168 if d < minLatency {
169 continue
170 }
171 if maxLatency != 0 && d > maxLatency {
172 continue
173 }
174 }
175 out = append(out, sd)
176 }
177 }
178 return out
179}
180
181// spanStore keeps track of spans stored for a particular span name.
182//
183// It contains all active spans; a sample of spans for failed requests,
184// categorized by error code; and a sample of spans for successful requests,
185// bucketed by latency.
186type spanStore struct {
187 mu sync.Mutex // protects everything below.
188 active map[*Span]struct{}
189 errors map[int32]*bucket
190 latency []bucket
191 maxSpansPerErrorBucket int
192}
193
194// newSpanStore creates a span store.
195func newSpanStore(name string, latencyBucketSize int, errorBucketSize int) *spanStore {
196 s := &spanStore{
197 active: make(map[*Span]struct{}),
198 latency: make([]bucket, len(defaultLatencies)+1),
199 maxSpansPerErrorBucket: errorBucketSize,
200 }
201 for i := range s.latency {
202 s.latency[i] = makeBucket(latencyBucketSize)
203 }
204 return s
205}
206
207// spanStoreForName returns the spanStore for the given name.
208//
209// It returns nil if it doesn't exist.
210func spanStoreForName(name string) *spanStore {
211 var s *spanStore
212 ssmu.RLock()
213 s, _ = spanStores[name]
214 ssmu.RUnlock()
215 return s
216}
217
218// spanStoreForNameCreateIfNew returns the spanStore for the given name.
219//
220// It creates it if it didn't exist.
221func spanStoreForNameCreateIfNew(name string) *spanStore {
222 ssmu.RLock()
223 s, ok := spanStores[name]
224 ssmu.RUnlock()
225 if ok {
226 return s
227 }
228 ssmu.Lock()
229 defer ssmu.Unlock()
230 s, ok = spanStores[name]
231 if ok {
232 return s
233 }
234 s = newSpanStore(name, defaultBucketSize, defaultBucketSize)
235 spanStores[name] = s
236 return s
237}
238
239// spanStoreSetSize resizes the spanStore for the given name.
240//
241// It creates it if it didn't exist.
242func spanStoreSetSize(name string, latencyBucketSize int, errorBucketSize int) {
243 ssmu.RLock()
244 s, ok := spanStores[name]
245 ssmu.RUnlock()
246 if ok {
247 s.resize(latencyBucketSize, errorBucketSize)
248 return
249 }
250 ssmu.Lock()
251 defer ssmu.Unlock()
252 s, ok = spanStores[name]
253 if ok {
254 s.resize(latencyBucketSize, errorBucketSize)
255 return
256 }
257 s = newSpanStore(name, latencyBucketSize, errorBucketSize)
258 spanStores[name] = s
259}
260
261func (s *spanStore) resize(latencyBucketSize int, errorBucketSize int) {
262 s.mu.Lock()
263 for i := range s.latency {
264 s.latency[i].resize(latencyBucketSize)
265 }
266 for _, b := range s.errors {
267 b.resize(errorBucketSize)
268 }
269 s.maxSpansPerErrorBucket = errorBucketSize
270 s.mu.Unlock()
271}
272
273// add adds a span to the active bucket of the spanStore.
274func (s *spanStore) add(span *Span) {
275 s.mu.Lock()
276 s.active[span] = struct{}{}
277 s.mu.Unlock()
278}
279
280// finished removes a span from the active set, and adds a corresponding
281// SpanData to a latency or error bucket.
282func (s *spanStore) finished(span *Span, sd *SpanData) {
283 latency := sd.EndTime.Sub(sd.StartTime)
284 if latency < 0 {
285 latency = 0
286 }
287 code := sd.Status.Code
288
289 s.mu.Lock()
290 delete(s.active, span)
291 if code == 0 {
292 s.latency[latencyBucket(latency)].add(sd)
293 } else {
294 if s.errors == nil {
295 s.errors = make(map[int32]*bucket)
296 }
297 if b := s.errors[code]; b != nil {
298 b.add(sd)
299 } else {
300 b := makeBucket(s.maxSpansPerErrorBucket)
301 s.errors[code] = &b
302 b.add(sd)
303 }
304 }
305 s.mu.Unlock()
306}