1// Copyright The OpenTelemetry 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	"context"
19	"time"
20
21	export "go.opentelemetry.io/otel/sdk/export/trace"
22	"go.opentelemetry.io/otel/sdk/export/trace/tracetest"
23)
24
25// DurationFilter is a SpanProcessor that filters spans that have lifetimes
26// outside of a defined range.
27type DurationFilter struct {
28	// Next is the next SpanProcessor in the chain.
29	Next SpanProcessor
30
31	// Min is the duration under which spans are dropped.
32	Min time.Duration
33	// Max is the duration over which spans are dropped.
34	Max time.Duration
35}
36
37func (f DurationFilter) OnStart(parent context.Context, sd *export.SpanData) {
38	f.Next.OnStart(parent, sd)
39}
40func (f DurationFilter) Shutdown(ctx context.Context) error { return f.Next.Shutdown(ctx) }
41func (f DurationFilter) ForceFlush()                        { f.Next.ForceFlush() }
42func (f DurationFilter) OnEnd(sd *export.SpanData) {
43	if f.Min > 0 && sd.EndTime.Sub(sd.StartTime) < f.Min {
44		// Drop short lived spans.
45		return
46	}
47	if f.Max > 0 && sd.EndTime.Sub(sd.StartTime) > f.Max {
48		// Drop long lived spans.
49		return
50	}
51	f.Next.OnEnd(sd)
52}
53
54// InstrumentationBlacklist is a SpanProcessor that drops all spans from
55// certain instrumentation.
56type InstrumentationBlacklist struct {
57	// Next is the next SpanProcessor in the chain.
58	Next SpanProcessor
59
60	// Blacklist is the set of instrumentation names for which spans will be
61	// dropped.
62	Blacklist map[string]bool
63}
64
65func (f InstrumentationBlacklist) OnStart(parent context.Context, sd *export.SpanData) {
66	f.Next.OnStart(parent, sd)
67}
68func (f InstrumentationBlacklist) Shutdown(ctx context.Context) error { return f.Next.Shutdown(ctx) }
69func (f InstrumentationBlacklist) ForceFlush()                        { f.Next.ForceFlush() }
70func (f InstrumentationBlacklist) OnEnd(sd *export.SpanData) {
71	if f.Blacklist != nil && f.Blacklist[sd.InstrumentationLibrary.Name] {
72		// Drop spans from this instrumentation
73		return
74	}
75	f.Next.OnEnd(sd)
76}
77
78func ExampleSpanProcessor() {
79	exportSP := NewSimpleSpanProcessor(tracetest.NewNoopExporter())
80
81	// Build a SpanProcessor chain to filter out all spans from the pernicious
82	// "naughty-instrumentation" dependency and only allow spans shorter than
83	// an minute and longer than a second to be exported with the exportSP.
84	filter := DurationFilter{
85		Next: InstrumentationBlacklist{
86			Next: exportSP,
87			Blacklist: map[string]bool{
88				"naughty-instrumentation": true,
89			},
90		},
91		Min: time.Second,
92		Max: time.Minute,
93	}
94
95	_ = NewTracerProvider(WithSpanProcessor(filter))
96	// ...
97}
98