diff --git a/CHANGELOG.md b/CHANGELOG.md index 394c01306..ce18bf337 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -52,6 +52,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - OTLP Metric exporter supports Histogram aggregation. (#1209) - The `Code` struct from the `go.opentelemetry.io/otel/codes` package now supports JSON marshaling and unmarshaling as well as implements the `Stringer` interface. (#1214) - A Baggage API to implement the OpenTelemetry specification. (#1217) +- Add Shutdown method to sdk/trace/provider, shutdown processors in the order they were registered. (#1227) ### Changed diff --git a/example/basic/main.go b/example/basic/main.go index 2f615d5f6..f4f094d82 100644 --- a/example/basic/main.go +++ b/example/basic/main.go @@ -46,8 +46,8 @@ func main() { } bsp := sdktrace.NewBatchSpanProcessor(exporter) - defer bsp.Shutdown() tp := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(bsp)) + defer func() { _ = tp.Shutdown(context.Background()) }() pusher := push.New( basic.New( simple.NewWithExactDistribution(), diff --git a/example/namedtracer/main.go b/example/namedtracer/main.go index beb02466f..aacd97d8f 100644 --- a/example/namedtracer/main.go +++ b/example/namedtracer/main.go @@ -35,12 +35,12 @@ var ( var tp *sdktrace.TracerProvider // initTracer creates and registers trace provider instance. -func initTracer() func() { +func initTracer() { var err error exp, err := stdout.NewExporter(stdout.WithPrettyPrint()) if err != nil { log.Panicf("failed to initialize stdout exporter %v\n", err) - return nil + return } bsp := sdktrace.NewBatchSpanProcessor(exp) tp = sdktrace.NewTracerProvider( @@ -52,17 +52,16 @@ func initTracer() func() { sdktrace.WithSpanProcessor(bsp), ) global.SetTracerProvider(tp) - return bsp.Shutdown } func main() { // initialize trace provider. - shutdown := initTracer() - defer shutdown() + initTracer() // Create a named tracer with package path as its name. tracer := tp.Tracer("example/namedtracer/main") ctx := context.Background() + defer func() { _ = tp.Shutdown(ctx) }() ctx = otel.ContextWithBaggageValues(ctx, fooKey.String("foo1"), barKey.String("bar1")) var span otel.Span diff --git a/example/otel-collector/main.go b/example/otel-collector/main.go index 2c96facb1..6fa294f6f 100644 --- a/example/otel-collector/main.go +++ b/example/otel-collector/main.go @@ -80,7 +80,7 @@ func initProvider() func() { pusher.Start() return func() { - bsp.Shutdown() // shutdown the processor + handleErr(tracerProvider.Shutdown(context.Background()), "failed to shutdown provider") handleErr(exp.Shutdown(context.Background()), "failed to stop exporter") pusher.Stop() // pushes any last exports to the receiver } diff --git a/exporters/otlp/otlp_integration_test.go b/exporters/otlp/otlp_integration_test.go index 44fa06da2..7cbe7d649 100644 --- a/exporters/otlp/otlp_integration_test.go +++ b/exporters/otlp/otlp_integration_test.go @@ -492,6 +492,7 @@ func TestNewExporter_withMultipleAttributeTypes(t *testing.T) { sdktrace.WithMaxExportBatchSize(10), ), ) + defer func() { _ = tp.Shutdown(context.Background()) }() tr := tp.Tracer("test-tracer") testKvs := []label.KeyValue{ diff --git a/sdk/trace/provider.go b/sdk/trace/provider.go index afe01eb5d..b4cdcf6bb 100644 --- a/sdk/trace/provider.go +++ b/sdk/trace/provider.go @@ -15,6 +15,7 @@ package trace import ( + "context" "sync" "sync/atomic" @@ -180,6 +181,21 @@ func (p *TracerProvider) ApplyConfig(cfg Config) { p.config.Store(&c) } +// Shutdown shuts down the span processors in the order they were registered +func (p *TracerProvider) Shutdown(ctx context.Context) error { + spss, ok := p.spanProcessors.Load().(spanProcessorStates) + if !ok || len(spss) == 0 { + return nil + } + + for _, sps := range spss { + sps.state.Do(func() { + sps.sp.Shutdown() + }) + } + return nil +} + // WithSyncer registers the exporter with the TracerProvider using a // SimpleSpanProcessor. func WithSyncer(e export.SpanExporter) TracerProviderOption { diff --git a/sdk/trace/provider_test.go b/sdk/trace/provider_test.go new file mode 100644 index 000000000..02c028289 --- /dev/null +++ b/sdk/trace/provider_test.go @@ -0,0 +1,48 @@ +// 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" + "testing" + + export "go.opentelemetry.io/otel/sdk/export/trace" +) + +type basicSpanProcesor struct { + running bool +} + +func (t *basicSpanProcesor) Shutdown() { + t.running = false +} + +func (t *basicSpanProcesor) OnStart(s *export.SpanData) {} +func (t *basicSpanProcesor) OnEnd(s *export.SpanData) {} +func (t *basicSpanProcesor) ForceFlush() {} + +func TestShutdownTraceProvider(t *testing.T) { + stp := NewTracerProvider() + sp := &basicSpanProcesor{} + stp.RegisterSpanProcessor(sp) + + sp.running = true + + _ = stp.Shutdown(context.Background()) + + if sp.running != false { + t.Errorf("Error shutdown basicSpanProcesor\n") + } +}