...

Source file src/go.opencensus.io/trace/spanbucket.go

Documentation: go.opencensus.io/trace

     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  	"time"
    19  )
    20  
    21  // samplePeriod is the minimum time between accepting spans in a single bucket.
    22  const samplePeriod = time.Second
    23  
    24  // defaultLatencies contains the default latency bucket bounds.
    25  // TODO: consider defaults, make configurable
    26  var defaultLatencies = [...]time.Duration{
    27  	10 * time.Microsecond,
    28  	100 * time.Microsecond,
    29  	time.Millisecond,
    30  	10 * time.Millisecond,
    31  	100 * time.Millisecond,
    32  	time.Second,
    33  	10 * time.Second,
    34  	time.Minute,
    35  }
    36  
    37  // bucket is a container for a set of spans for a particular error code or latency range.
    38  type bucket struct {
    39  	nextTime  time.Time   // next time we can accept a span
    40  	buffer    []*SpanData // circular buffer of spans
    41  	nextIndex int         // location next SpanData should be placed in buffer
    42  	overflow  bool        // whether the circular buffer has wrapped around
    43  }
    44  
    45  func makeBucket(bufferSize int) bucket {
    46  	return bucket{
    47  		buffer: make([]*SpanData, bufferSize),
    48  	}
    49  }
    50  
    51  // add adds a span to the bucket, if nextTime has been reached.
    52  func (b *bucket) add(s *SpanData) {
    53  	if s.EndTime.Before(b.nextTime) {
    54  		return
    55  	}
    56  	if len(b.buffer) == 0 {
    57  		return
    58  	}
    59  	b.nextTime = s.EndTime.Add(samplePeriod)
    60  	b.buffer[b.nextIndex] = s
    61  	b.nextIndex++
    62  	if b.nextIndex == len(b.buffer) {
    63  		b.nextIndex = 0
    64  		b.overflow = true
    65  	}
    66  }
    67  
    68  // size returns the number of spans in the bucket.
    69  func (b *bucket) size() int {
    70  	if b.overflow {
    71  		return len(b.buffer)
    72  	}
    73  	return b.nextIndex
    74  }
    75  
    76  // span returns the ith span in the bucket.
    77  func (b *bucket) span(i int) *SpanData {
    78  	if !b.overflow {
    79  		return b.buffer[i]
    80  	}
    81  	if i < len(b.buffer)-b.nextIndex {
    82  		return b.buffer[b.nextIndex+i]
    83  	}
    84  	return b.buffer[b.nextIndex+i-len(b.buffer)]
    85  }
    86  
    87  // resize changes the size of the bucket to n, keeping up to n existing spans.
    88  func (b *bucket) resize(n int) {
    89  	cur := b.size()
    90  	newBuffer := make([]*SpanData, n)
    91  	if cur < n {
    92  		for i := 0; i < cur; i++ {
    93  			newBuffer[i] = b.span(i)
    94  		}
    95  		b.buffer = newBuffer
    96  		b.nextIndex = cur
    97  		b.overflow = false
    98  		return
    99  	}
   100  	for i := 0; i < n; i++ {
   101  		newBuffer[i] = b.span(i + cur - n)
   102  	}
   103  	b.buffer = newBuffer
   104  	b.nextIndex = 0
   105  	b.overflow = true
   106  }
   107  
   108  // latencyBucket returns the appropriate bucket number for a given latency.
   109  func latencyBucket(latency time.Duration) int {
   110  	i := 0
   111  	for i < len(defaultLatencies) && latency >= defaultLatencies[i] {
   112  		i++
   113  	}
   114  	return i
   115  }
   116  
   117  // latencyBucketBounds returns the lower and upper bounds for a latency bucket
   118  // number.
   119  //
   120  // The lower bound is inclusive, the upper bound is exclusive (except for the
   121  // last bucket.)
   122  func latencyBucketBounds(index int) (lower time.Duration, upper time.Duration) {
   123  	if index == 0 {
   124  		return 0, defaultLatencies[index]
   125  	}
   126  	if index == len(defaultLatencies) {
   127  		return defaultLatencies[index-1], 1<<63 - 1
   128  	}
   129  	return defaultLatencies[index-1], defaultLatencies[index]
   130  }
   131  

View as plain text