diff options
Diffstat (limited to 'vendor/go.opencensus.io/trace/spanstore.go')
-rw-r--r-- | vendor/go.opencensus.io/trace/spanstore.go | 306 |
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 | |||
15 | package trace | ||
16 | |||
17 | import ( | ||
18 | "sync" | ||
19 | "time" | ||
20 | |||
21 | "go.opencensus.io/internal" | ||
22 | ) | ||
23 | |||
24 | const ( | ||
25 | maxBucketSize = 100000 | ||
26 | defaultBucketSize = 10 | ||
27 | ) | ||
28 | |||
29 | var ( | ||
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. | ||
35 | type internalOnly struct{} | ||
36 | |||
37 | func init() { | ||
38 | //TODO(#412): remove | ||
39 | internal.Trace = &internalOnly{} | ||
40 | } | ||
41 | |||
42 | // ReportActiveSpans returns the active spans for the given name. | ||
43 | func (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. | ||
60 | func (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. | ||
92 | func (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. | ||
113 | func (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. | ||
146 | func (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. | ||
186 | type 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. | ||
195 | func 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. | ||
210 | func 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. | ||
221 | func 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. | ||
242 | func 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 | |||
261 | func (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. | ||
274 | func (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. | ||
282 | func (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 | } | ||