From 31ea893b7a99c9d2fb50989870a89014e1728505 Mon Sep 17 00:00:00 2001 From: Tyler Yahn Date: Tue, 22 Sep 2020 14:50:45 -0700 Subject: [PATCH 1/4] Add example test for a custom SpanProcessor --- sdk/trace/span_processor_example_test.go | 83 ++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 sdk/trace/span_processor_example_test.go diff --git a/sdk/trace/span_processor_example_test.go b/sdk/trace/span_processor_example_test.go new file mode 100644 index 00000000000..fd3580fc617 --- /dev/null +++ b/sdk/trace/span_processor_example_test.go @@ -0,0 +1,83 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package trace + +import ( + "context" + "time" + + export "go.opentelemetry.io/otel/sdk/export/trace" +) + +type exporter struct{} + +func (e exporter) ExportSpans(context.Context, []*export.SpanData) error { return nil } +func (e exporter) Shutdown(context.Context) error { return nil } + +// LowPassFilter is a SpanProcessor that drops short lived spans. +type LowPassFilter struct { + // Next is the next SpanProcessor in the chain. + Next SpanProcessor + // Cutoff is the duration under which spans are dropped. + Cutoff time.Duration +} + +func (f LowPassFilter) OnStart(sd *export.SpanData) { f.Next.OnStart(sd) } +func (f LowPassFilter) Shutdown() { f.Next.Shutdown() } +func (f LowPassFilter) ForceFlush() { f.Next.ForceFlush() } +func (f LowPassFilter) OnEnd(sd *export.SpanData) { + if sd.EndTime.Sub(sd.StartTime) < f.Cutoff { + // Drop short lived spans. + return + } + f.Next.OnEnd(sd) +} + +// HighPassFilter is a SpanProcessor that drops long lived spans. +type HighPassFilter struct { + // Next is the next SpanProcessor in the chain. + Next SpanProcessor + // Cutoff is the duration over which spans are dropped. + Cutoff time.Duration +} + +func (f HighPassFilter) OnStart(sd *export.SpanData) { f.Next.OnStart(sd) } +func (f HighPassFilter) Shutdown() { f.Next.Shutdown() } +func (f HighPassFilter) ForceFlush() { f.Next.ForceFlush() } +func (f HighPassFilter) OnEnd(sd *export.SpanData) { + if sd.EndTime.Sub(sd.StartTime) > f.Cutoff { + // Drop long lived spans. + return + } + f.Next.OnEnd(sd) +} + +func ExampleSpanProcessor() { + exportSpanProcessor := NewSimpleSpanProcessor(exporter{}) + + // Build a band-pass filter to only allow spans shorter than an minute and + // longer than a second to be exported with the exportSpanProcessor. + bandPassFilter := LowPassFilter{ + Next: HighPassFilter{ + Next: exportSpanProcessor, + Cutoff: time.Minute, + }, + Cutoff: time.Second, + } + + traceProvider := NewProvider() + traceProvider.RegisterSpanProcessor(bandPassFilter) + // ... +} From 45632e120eb4fdf8d12e3173e63d0b0c00d0acfd Mon Sep 17 00:00:00 2001 From: Tyler Yahn Date: Tue, 22 Sep 2020 14:55:43 -0700 Subject: [PATCH 2/4] Use existing test framework exporter --- sdk/trace/span_processor_example_test.go | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/sdk/trace/span_processor_example_test.go b/sdk/trace/span_processor_example_test.go index fd3580fc617..eea889ef3ed 100644 --- a/sdk/trace/span_processor_example_test.go +++ b/sdk/trace/span_processor_example_test.go @@ -15,17 +15,12 @@ package trace import ( - "context" "time" export "go.opentelemetry.io/otel/sdk/export/trace" + "go.opentelemetry.io/otel/sdk/export/trace/tracetest" ) -type exporter struct{} - -func (e exporter) ExportSpans(context.Context, []*export.SpanData) error { return nil } -func (e exporter) Shutdown(context.Context) error { return nil } - // LowPassFilter is a SpanProcessor that drops short lived spans. type LowPassFilter struct { // Next is the next SpanProcessor in the chain. @@ -65,7 +60,7 @@ func (f HighPassFilter) OnEnd(sd *export.SpanData) { } func ExampleSpanProcessor() { - exportSpanProcessor := NewSimpleSpanProcessor(exporter{}) + exportSpanProcessor := NewSimpleSpanProcessor(tracetest.NewNoopExporter()) // Build a band-pass filter to only allow spans shorter than an minute and // longer than a second to be exported with the exportSpanProcessor. From 22213ed94ea62b343ef49f2f8640a379652dd153 Mon Sep 17 00:00:00 2001 From: Tyler Yahn Date: Thu, 24 Sep 2020 13:58:10 -0700 Subject: [PATCH 3/4] Update example --- sdk/trace/span_processor_example_test.go | 72 ++++++++++++++---------- 1 file changed, 43 insertions(+), 29 deletions(-) diff --git a/sdk/trace/span_processor_example_test.go b/sdk/trace/span_processor_example_test.go index eea889ef3ed..556f550178f 100644 --- a/sdk/trace/span_processor_example_test.go +++ b/sdk/trace/span_processor_example_test.go @@ -21,58 +21,72 @@ import ( "go.opentelemetry.io/otel/sdk/export/trace/tracetest" ) -// LowPassFilter is a SpanProcessor that drops short lived spans. -type LowPassFilter struct { +// DurationFilter is a SpanProcessor that filters spans that have lifetimes +// outside of a defined range. +type DurationFilter struct { // Next is the next SpanProcessor in the chain. Next SpanProcessor - // Cutoff is the duration under which spans are dropped. - Cutoff time.Duration + + // Min is the duration under which spans are dropped. + Min time.Duration + // Max is the duration over which spans are dropped. + Max time.Duration } -func (f LowPassFilter) OnStart(sd *export.SpanData) { f.Next.OnStart(sd) } -func (f LowPassFilter) Shutdown() { f.Next.Shutdown() } -func (f LowPassFilter) ForceFlush() { f.Next.ForceFlush() } -func (f LowPassFilter) OnEnd(sd *export.SpanData) { - if sd.EndTime.Sub(sd.StartTime) < f.Cutoff { +func (f DurationFilter) OnStart(sd *export.SpanData) { f.Next.OnStart(sd) } +func (f DurationFilter) Shutdown() { f.Next.Shutdown() } +func (f DurationFilter) ForceFlush() { f.Next.ForceFlush() } +func (f DurationFilter) OnEnd(sd *export.SpanData) { + if f.Min > 0 && sd.EndTime.Sub(sd.StartTime) < f.Min { // Drop short lived spans. return } + if f.Max > 0 && sd.EndTime.Sub(sd.StartTime) > f.Max { + // Drop long lived spans. + return + } f.Next.OnEnd(sd) } -// HighPassFilter is a SpanProcessor that drops long lived spans. -type HighPassFilter struct { +// InstrumentationBlacklist is a SpanProcessor that drops all spans from +// certain instrumentation. +type InstrumentationBlacklist struct { // Next is the next SpanProcessor in the chain. Next SpanProcessor - // Cutoff is the duration over which spans are dropped. - Cutoff time.Duration + + // Blacklist is the set of instrumentation names for which spans will be + // dropped. + Blacklist map[string]bool } -func (f HighPassFilter) OnStart(sd *export.SpanData) { f.Next.OnStart(sd) } -func (f HighPassFilter) Shutdown() { f.Next.Shutdown() } -func (f HighPassFilter) ForceFlush() { f.Next.ForceFlush() } -func (f HighPassFilter) OnEnd(sd *export.SpanData) { - if sd.EndTime.Sub(sd.StartTime) > f.Cutoff { - // Drop long lived spans. +func (f InstrumentationBlacklist) OnStart(sd *export.SpanData) { f.Next.OnStart(sd) } +func (f InstrumentationBlacklist) Shutdown() { f.Next.Shutdown() } +func (f InstrumentationBlacklist) ForceFlush() { f.Next.ForceFlush() } +func (f InstrumentationBlacklist) OnEnd(sd *export.SpanData) { + if f.Blacklist != nil && f.Blacklist[sd.InstrumentationLibrary.Name] { + // Drop spans from this instrumentation return } f.Next.OnEnd(sd) } func ExampleSpanProcessor() { - exportSpanProcessor := NewSimpleSpanProcessor(tracetest.NewNoopExporter()) + exportSP := NewSimpleSpanProcessor(tracetest.NewNoopExporter()) - // Build a band-pass filter to only allow spans shorter than an minute and - // longer than a second to be exported with the exportSpanProcessor. - bandPassFilter := LowPassFilter{ - Next: HighPassFilter{ - Next: exportSpanProcessor, - Cutoff: time.Minute, + // Build a SpanProcessor chain to filter out all spans from the pernicious + // "naughty-instrumentation" dependency and only allow spans shorter than + // an minute and longer than a second to be exported with the exportSP. + filter := DurationFilter{ + Next: InstrumentationBlacklist{ + Next: exportSP, + Blacklist: map[string]bool{ + "naughty-instrumentation": true, + }, }, - Cutoff: time.Second, + Min: time.Second, + Max: time.Minute, } - traceProvider := NewProvider() - traceProvider.RegisterSpanProcessor(bandPassFilter) + _ = NewProvider(WithSpanProcessor(filter)) // ... } From c3156464c37951f2ac0f3f78137d9ed18d82f158 Mon Sep 17 00:00:00 2001 From: Tyler Yahn Date: Thu, 24 Sep 2020 14:04:35 -0700 Subject: [PATCH 4/4] Add fixes from upstream --- sdk/trace/span_processor_example_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/trace/span_processor_example_test.go b/sdk/trace/span_processor_example_test.go index 556f550178f..5eb41b005cf 100644 --- a/sdk/trace/span_processor_example_test.go +++ b/sdk/trace/span_processor_example_test.go @@ -87,6 +87,6 @@ func ExampleSpanProcessor() { Max: time.Minute, } - _ = NewProvider(WithSpanProcessor(filter)) + _ = NewTracerProvider(WithSpanProcessor(filter)) // ... }