1 // Copyright 2017, OpenCensus Authors
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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.
21 "go.opencensus.io/internal"
25 maxBucketSize = 100000
26 defaultBucketSize = 10
30 ssmu sync.RWMutex // protects spanStores
31 spanStores = make(map[string]*spanStore)
34 // This exists purely to avoid exposing internal methods used by z-Pages externally.
35 type internalOnly struct{}
39 internal.Trace = &internalOnly{}
42 // ReportActiveSpans returns the active spans for the given name.
43 func (i internalOnly) ReportActiveSpans(name string) []*SpanData {
44 s := spanStoreForName(name)
51 for span := range s.active {
52 out = append(out, span.makeSpanData())
57 // ReportSpansByError returns a sample of error spans.
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)
69 if b, ok := s.errors[code]; ok {
70 for _, sd := range b.buffer {
78 for _, b := range s.errors {
79 for _, sd := range b.buffer {
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 {
98 if latencyBucketSize > maxBucketSize {
99 latencyBucketSize = maxBucketSize
101 errorBucketSize := bc.MaxRequestsErrors
102 if errorBucketSize < 0 {
105 if errorBucketSize > maxBucketSize {
106 errorBucketSize = maxBucketSize
108 spanStoreSetSize(bc.Name, latencyBucketSize, errorBucketSize)
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)
117 for name, s := range spanStores {
119 p := internal.PerMethodSummary{
120 Active: len(s.active),
122 for code, b := range s.errors {
123 p.ErrorBuckets = append(p.ErrorBuckets, internal.ErrorBucketSummary{
128 for i, b := range s.latency {
129 min, max := latencyBucketBounds(i)
130 p.LatencyBuckets = append(p.LatencyBuckets, internal.LatencyBucketSummary{
142 // ReportSpansByLatency returns a sample of successful spans.
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)
154 for i, b := range s.latency {
155 min, max := latencyBucketBounds(i)
156 if i+1 != len(s.latency) && max <= minLatency {
159 if maxLatency != 0 && maxLatency < min {
162 for _, sd := range b.buffer {
166 if minLatency != 0 || maxLatency != 0 {
167 d := sd.EndTime.Sub(sd.StartTime)
171 if maxLatency != 0 && d > maxLatency {
175 out = append(out, sd)
181 // spanStore keeps track of spans stored for a particular span name.
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
191 maxSpansPerErrorBucket int
194 // newSpanStore creates a span store.
195 func newSpanStore(name string, latencyBucketSize int, errorBucketSize int) *spanStore {
197 active: make(map[*Span]struct{}),
198 latency: make([]bucket, len(defaultLatencies)+1),
199 maxSpansPerErrorBucket: errorBucketSize,
201 for i := range s.latency {
202 s.latency[i] = makeBucket(latencyBucketSize)
207 // spanStoreForName returns the spanStore for the given name.
209 // It returns nil if it doesn't exist.
210 func spanStoreForName(name string) *spanStore {
213 s, _ = spanStores[name]
218 // spanStoreForNameCreateIfNew returns the spanStore for the given name.
220 // It creates it if it didn't exist.
221 func spanStoreForNameCreateIfNew(name string) *spanStore {
223 s, ok := spanStores[name]
230 s, ok = spanStores[name]
234 s = newSpanStore(name, defaultBucketSize, defaultBucketSize)
239 // spanStoreSetSize resizes the spanStore for the given name.
241 // It creates it if it didn't exist.
242 func spanStoreSetSize(name string, latencyBucketSize int, errorBucketSize int) {
244 s, ok := spanStores[name]
247 s.resize(latencyBucketSize, errorBucketSize)
252 s, ok = spanStores[name]
254 s.resize(latencyBucketSize, errorBucketSize)
257 s = newSpanStore(name, latencyBucketSize, errorBucketSize)
261 func (s *spanStore) resize(latencyBucketSize int, errorBucketSize int) {
263 for i := range s.latency {
264 s.latency[i].resize(latencyBucketSize)
266 for _, b := range s.errors {
267 b.resize(errorBucketSize)
269 s.maxSpansPerErrorBucket = errorBucketSize
273 // add adds a span to the active bucket of the spanStore.
274 func (s *spanStore) add(span *Span) {
276 s.active[span] = struct{}{}
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)
287 code := sd.Status.Code
290 delete(s.active, span)
292 s.latency[latencyBucket(latency)].add(sd)
295 s.errors = make(map[int32]*bucket)
297 if b := s.errors[code]; b != nil {
300 b := makeBucket(s.maxSpansPerErrorBucket)