github.com/waldiirawan/apm-agent-go/v2@v2.2.2/sampler.go (about) 1 // Licensed to Elasticsearch B.V. under one or more contributor 2 // license agreements. See the NOTICE file distributed with 3 // this work for additional information regarding copyright 4 // ownership. Elasticsearch B.V. licenses this file to you under 5 // the Apache License, Version 2.0 (the "License"); you may 6 // not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, 12 // software distributed under the License is distributed on an 13 // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 // KIND, either express or implied. See the License for the 15 // specific language governing permissions and limitations 16 // under the License. 17 18 package apm // import "github.com/waldiirawan/apm-agent-go/v2" 19 20 import ( 21 "encoding/binary" 22 "math" 23 "math/big" 24 25 "github.com/pkg/errors" 26 ) 27 28 // Sampler provides a means of sampling transactions. 29 type Sampler interface { 30 // Sample indicates whether or not a transaction 31 // should be sampled, and the sampling rate in 32 // effect at the time.This method will be invoked 33 // by calls to Tracer.StartTransaction for the root 34 // of a trace, so it must be goroutine-safe, and 35 // should avoid synchronization as far as possible. 36 Sample(SampleParams) SampleResult 37 } 38 39 // SampleParams holds parameters for Sampler.Sample. 40 type SampleParams struct { 41 // TraceContext holds the newly-generated TraceContext 42 // for the root transaction which is being sampled. 43 TraceContext TraceContext 44 } 45 46 // SampleResult holds information about a sampling decision. 47 type SampleResult struct { 48 // Sampled holds the sampling decision. 49 Sampled bool 50 51 // SampleRate holds the sample rate in effect at the 52 // time of the sampling decision. This is used for 53 // propagating the value downstream, and for inclusion 54 // in events sent to APM Server. 55 // 56 // The sample rate will be rounded to 4 decimal places 57 // half away from zero, except if it is in the interval 58 // (0, 0.0001], in which case it is set to 0.0001. The 59 // Sampler implementation should also internally apply 60 // this logic to ensure consistency. 61 SampleRate float64 62 } 63 64 // NewRatioSampler returns a new Sampler with the given ratio 65 // 66 // A ratio of 1.0 samples 100% of transactions, a ratio of 0.5 67 // samples ~50%, and so on. If the ratio provided does not lie 68 // within the range [0,1.0], NewRatioSampler will panic. 69 // 70 // Sampling rate is rounded to 4 digits half away from zero, 71 // except if it is in the interval (0, 0.0001], in which case 72 // is set to 0.0001. 73 // 74 // The returned Sampler bases its decision on the value of the 75 // transaction ID, so there is no synchronization involved. 76 func NewRatioSampler(r float64) Sampler { 77 if r < 0 || r > 1.0 { 78 panic(errors.Errorf("ratio %v out of range [0,1.0]", r)) 79 } 80 r = roundSampleRate(r) 81 var x big.Float 82 x.SetUint64(math.MaxUint64) 83 x.Mul(&x, big.NewFloat(r)) 84 ceil, _ := x.Uint64() 85 return ratioSampler{r, ceil} 86 } 87 88 type ratioSampler struct { 89 ratio float64 90 ceil uint64 91 } 92 93 // Sample samples the transaction according to the configured 94 // ratio and pseudo-random source. 95 func (s ratioSampler) Sample(args SampleParams) SampleResult { 96 v := binary.BigEndian.Uint64(args.TraceContext.Span[:]) 97 result := SampleResult{ 98 Sampled: v > 0 && v-1 < s.ceil, 99 SampleRate: s.ratio, 100 } 101 return result 102 } 103 104 // roundSampleRate rounds r to 4 decimal places half away from zero, 105 // with the exception of values > 0 and < 0.0001, which are set to 0.0001. 106 func roundSampleRate(r float64) float64 { 107 if r > 0 && r < 0.0001 { 108 r = 0.0001 109 } 110 return math.Round(r*10000) / 10000 111 }