podman
308 строк · 7.4 Кб
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 (
25maxBucketSize = 100000
26defaultBucketSize = 10
27)
28
29var (
30ssmu sync.RWMutex // protects spanStores
31spanStores = 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
39internal.Trace = &internalOnly{}
40}
41
42// ReportActiveSpans returns the active spans for the given name.
43func (i internalOnly) ReportActiveSpans(name string) []*SpanData {
44s := spanStoreForName(name)
45if s == nil {
46return nil
47}
48var out []*SpanData
49s.mu.Lock()
50defer s.mu.Unlock()
51for activeSpan := range s.active {
52if s, ok := activeSpan.(*span); ok {
53out = append(out, s.makeSpanData())
54}
55}
56return out
57}
58
59// ReportSpansByError returns a sample of error spans.
60//
61// If code is nonzero, only spans with that status code are returned.
62func (i internalOnly) ReportSpansByError(name string, code int32) []*SpanData {
63s := spanStoreForName(name)
64if s == nil {
65return nil
66}
67var out []*SpanData
68s.mu.Lock()
69defer s.mu.Unlock()
70if code != 0 {
71if b, ok := s.errors[code]; ok {
72for _, sd := range b.buffer {
73if sd == nil {
74break
75}
76out = append(out, sd)
77}
78}
79} else {
80for _, b := range s.errors {
81for _, sd := range b.buffer {
82if sd == nil {
83break
84}
85out = append(out, sd)
86}
87}
88}
89return out
90}
91
92// ConfigureBucketSizes sets the number of spans to keep per latency and error
93// bucket for different span names.
94func (i internalOnly) ConfigureBucketSizes(bcs []internal.BucketConfiguration) {
95for _, bc := range bcs {
96latencyBucketSize := bc.MaxRequestsSucceeded
97if latencyBucketSize < 0 {
98latencyBucketSize = 0
99}
100if latencyBucketSize > maxBucketSize {
101latencyBucketSize = maxBucketSize
102}
103errorBucketSize := bc.MaxRequestsErrors
104if errorBucketSize < 0 {
105errorBucketSize = 0
106}
107if errorBucketSize > maxBucketSize {
108errorBucketSize = maxBucketSize
109}
110spanStoreSetSize(bc.Name, latencyBucketSize, errorBucketSize)
111}
112}
113
114// ReportSpansPerMethod returns a summary of what spans are being stored for each span name.
115func (i internalOnly) ReportSpansPerMethod() map[string]internal.PerMethodSummary {
116out := make(map[string]internal.PerMethodSummary)
117ssmu.RLock()
118defer ssmu.RUnlock()
119for name, s := range spanStores {
120s.mu.Lock()
121p := internal.PerMethodSummary{
122Active: len(s.active),
123}
124for code, b := range s.errors {
125p.ErrorBuckets = append(p.ErrorBuckets, internal.ErrorBucketSummary{
126ErrorCode: code,
127Size: b.size(),
128})
129}
130for i, b := range s.latency {
131min, max := latencyBucketBounds(i)
132p.LatencyBuckets = append(p.LatencyBuckets, internal.LatencyBucketSummary{
133MinLatency: min,
134MaxLatency: max,
135Size: b.size(),
136})
137}
138s.mu.Unlock()
139out[name] = p
140}
141return out
142}
143
144// ReportSpansByLatency returns a sample of successful spans.
145//
146// minLatency is the minimum latency of spans to be returned.
147// maxLatency, if nonzero, is the maximum latency of spans to be returned.
148func (i internalOnly) ReportSpansByLatency(name string, minLatency, maxLatency time.Duration) []*SpanData {
149s := spanStoreForName(name)
150if s == nil {
151return nil
152}
153var out []*SpanData
154s.mu.Lock()
155defer s.mu.Unlock()
156for i, b := range s.latency {
157min, max := latencyBucketBounds(i)
158if i+1 != len(s.latency) && max <= minLatency {
159continue
160}
161if maxLatency != 0 && maxLatency < min {
162continue
163}
164for _, sd := range b.buffer {
165if sd == nil {
166break
167}
168if minLatency != 0 || maxLatency != 0 {
169d := sd.EndTime.Sub(sd.StartTime)
170if d < minLatency {
171continue
172}
173if maxLatency != 0 && d > maxLatency {
174continue
175}
176}
177out = append(out, sd)
178}
179}
180return out
181}
182
183// spanStore keeps track of spans stored for a particular span name.
184//
185// It contains all active spans; a sample of spans for failed requests,
186// categorized by error code; and a sample of spans for successful requests,
187// bucketed by latency.
188type spanStore struct {
189mu sync.Mutex // protects everything below.
190active map[SpanInterface]struct{}
191errors map[int32]*bucket
192latency []bucket
193maxSpansPerErrorBucket int
194}
195
196// newSpanStore creates a span store.
197func newSpanStore(name string, latencyBucketSize int, errorBucketSize int) *spanStore {
198s := &spanStore{
199active: make(map[SpanInterface]struct{}),
200latency: make([]bucket, len(defaultLatencies)+1),
201maxSpansPerErrorBucket: errorBucketSize,
202}
203for i := range s.latency {
204s.latency[i] = makeBucket(latencyBucketSize)
205}
206return s
207}
208
209// spanStoreForName returns the spanStore for the given name.
210//
211// It returns nil if it doesn't exist.
212func spanStoreForName(name string) *spanStore {
213var s *spanStore
214ssmu.RLock()
215s, _ = spanStores[name]
216ssmu.RUnlock()
217return s
218}
219
220// spanStoreForNameCreateIfNew returns the spanStore for the given name.
221//
222// It creates it if it didn't exist.
223func spanStoreForNameCreateIfNew(name string) *spanStore {
224ssmu.RLock()
225s, ok := spanStores[name]
226ssmu.RUnlock()
227if ok {
228return s
229}
230ssmu.Lock()
231defer ssmu.Unlock()
232s, ok = spanStores[name]
233if ok {
234return s
235}
236s = newSpanStore(name, defaultBucketSize, defaultBucketSize)
237spanStores[name] = s
238return s
239}
240
241// spanStoreSetSize resizes the spanStore for the given name.
242//
243// It creates it if it didn't exist.
244func spanStoreSetSize(name string, latencyBucketSize int, errorBucketSize int) {
245ssmu.RLock()
246s, ok := spanStores[name]
247ssmu.RUnlock()
248if ok {
249s.resize(latencyBucketSize, errorBucketSize)
250return
251}
252ssmu.Lock()
253defer ssmu.Unlock()
254s, ok = spanStores[name]
255if ok {
256s.resize(latencyBucketSize, errorBucketSize)
257return
258}
259s = newSpanStore(name, latencyBucketSize, errorBucketSize)
260spanStores[name] = s
261}
262
263func (s *spanStore) resize(latencyBucketSize int, errorBucketSize int) {
264s.mu.Lock()
265for i := range s.latency {
266s.latency[i].resize(latencyBucketSize)
267}
268for _, b := range s.errors {
269b.resize(errorBucketSize)
270}
271s.maxSpansPerErrorBucket = errorBucketSize
272s.mu.Unlock()
273}
274
275// add adds a span to the active bucket of the spanStore.
276func (s *spanStore) add(span SpanInterface) {
277s.mu.Lock()
278s.active[span] = struct{}{}
279s.mu.Unlock()
280}
281
282// finished removes a span from the active set, and adds a corresponding
283// SpanData to a latency or error bucket.
284func (s *spanStore) finished(span SpanInterface, sd *SpanData) {
285latency := sd.EndTime.Sub(sd.StartTime)
286if latency < 0 {
287latency = 0
288}
289code := sd.Status.Code
290
291s.mu.Lock()
292delete(s.active, span)
293if code == 0 {
294s.latency[latencyBucket(latency)].add(sd)
295} else {
296if s.errors == nil {
297s.errors = make(map[int32]*bucket)
298}
299if b := s.errors[code]; b != nil {
300b.add(sd)
301} else {
302b := makeBucket(s.maxSpansPerErrorBucket)
303s.errors[code] = &b
304b.add(sd)
305}
306}
307s.mu.Unlock()
308}
309