-
Notifications
You must be signed in to change notification settings - Fork 0
/
sampler.go
128 lines (103 loc) · 3.17 KB
/
sampler.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package opentelemetry
import (
"fmt"
"strings"
tracesdk "go.opentelemetry.io/otel/sdk/trace"
"go.opentelemetry.io/otel/trace"
"flamingo.me/flamingo/v3/framework/config"
)
type configuredURLPrefixSampler struct {
allowlist []string
blocklist []string
}
// alwaysSampleSpanKindClient enforces sampling of outgoing http requests (client)
type alwaysSampleSpanKindClient struct {
base tracesdk.Sampler
}
var _ tracesdk.Sampler = (*configuredURLPrefixSampler)(nil)
var _ tracesdk.Sampler = (*alwaysSampleSpanKindClient)(nil)
// Inject dependencies
func (c *configuredURLPrefixSampler) Inject(
cfg *struct {
Allowlist config.Slice `inject:"config:flamingo.opentelemetry.tracing.sampler.allowlist,optional"`
Blocklist config.Slice `inject:"config:flamingo.opentelemetry.tracing.sampler.blocklist,optional"`
},
) *configuredURLPrefixSampler {
if cfg != nil {
var allowed, blocked []string
err := cfg.Allowlist.MapInto(&allowed)
if err != nil {
panic(fmt.Errorf("failed to map flamingo.opentelemetry.tracing.sampler.allowlist: %w", err))
}
err = cfg.Blocklist.MapInto(&blocked)
if err != nil {
panic(fmt.Errorf("failed to map flamingo.opentelemetry.tracing.sampler.blocklist: %w", err))
}
c.allowlist = allowed
c.blocklist = blocked
}
return c
}
func (c *configuredURLPrefixSampler) ShouldSample(params tracesdk.SamplingParameters) tracesdk.SamplingResult {
psc := trace.SpanContextFromContext(params.ParentContext)
path := ""
for _, attr := range params.Attributes {
if attr.Key == "http.target" {
path = attr.Value.AsString()
}
}
// if this is not an incoming request, we decide by parent span
if path == "" {
decision := tracesdk.Drop
if psc.IsSampled() {
decision = tracesdk.RecordAndSample
}
return tracesdk.SamplingResult{
Decision: decision,
Tracestate: psc.TraceState(),
}
}
// empty allowed means all
sample := len(c.allowlist) == 0
// decide if we should sample based on allow list
for _, p := range c.allowlist {
if strings.HasPrefix(path, p) {
sample = true
break
}
}
// we do not sample, unless the parent is sampled
if !sample {
return tracesdk.SamplingResult{
Decision: tracesdk.Drop,
Tracestate: psc.TraceState(),
}
}
// check sampling decision against blocked
for _, p := range c.blocklist {
if strings.HasPrefix(path, p) {
return tracesdk.SamplingResult{
Decision: tracesdk.Drop,
Tracestate: psc.TraceState(),
}
}
}
return tracesdk.SamplingResult{
Decision: tracesdk.RecordAndSample,
Tracestate: psc.TraceState(),
}
}
func (c *configuredURLPrefixSampler) Description() string {
allowlist := strings.Join(c.allowlist, ",")
blocklist := strings.Join(c.blocklist, ",")
return fmt.Sprintf("ConfiguredURLPrefixSampler{allowlist:%s,blocklist:%s}", allowlist, blocklist)
}
func (s *alwaysSampleSpanKindClient) ShouldSample(parameters tracesdk.SamplingParameters) tracesdk.SamplingResult {
if parameters.Kind == trace.SpanKindClient {
return tracesdk.AlwaysSample().ShouldSample(parameters)
}
return s.base.ShouldSample(parameters)
}
func (s *alwaysSampleSpanKindClient) Description() string {
return fmt.Sprintf("SpanKindBasedSampler{base:%s}", s.base.Description())
}