Skip to content

BufSpanProcessor sometimes triggers a panic #2285

Description

@RebeccaMahany

Stack trace:

runtime error: invalid memory address or nil pointer dereference
github.com/kolide/launcher/ee/gowrapper.GoWithRecoveryAction.func1.1
	/Users/runner/work/launcher/launcher/ee/gowrapper/goroutine.go:31
runtime.gopanic
	/Users/runner/hostedtoolcache/go/1.23.0/x64/src/runtime/panic.go:785
runtime.panicmem
	/Users/runner/hostedtoolcache/go/1.23.0/x64/src/runtime/panic.go:262
runtime.sigpanic
	/Users/runner/hostedtoolcache/go/1.23.0/x64/src/runtime/signal_unix.go:900
go.opentelemetry.io/otel/sdk/trace.(*batchSpanProcessor).enqueueDrop
	/Users/runner/go/pkg/mod/go.opentelemetry.io/otel/sdk@v1.35.0/trace/batch_span_processor.go:389
go.opentelemetry.io/otel/sdk/trace.(*batchSpanProcessor).enqueue
	/Users/runner/go/pkg/mod/go.opentelemetry.io/otel/sdk@v1.35.0/trace/batch_span_processor.go:371
go.opentelemetry.io/otel/sdk/trace.(*batchSpanProcessor).OnEnd
	/Users/runner/go/pkg/mod/go.opentelemetry.io/otel/sdk@v1.35.0/trace/batch_span_processor.go:138
github.com/kolide/launcher/ee/observability/bufspanprocessor.(*BufSpanProcessor).SetChildProcessor
	/Users/runner/work/launcher/launcher/ee/observability/bufspanprocessor/bufspanprocessor.go:41
github.com/kolide/launcher/ee/observability/exporter.(*TelemetryExporter).setNewGlobalTracerProvider
	/Users/runner/work/launcher/launcher/ee/observability/exporter/exporter.go:317
github.com/kolide/launcher/ee/observability/exporter.(*TelemetryExporter).setNewGlobalProvider
	/Users/runner/work/launcher/launcher/ee/observability/exporter/exporter.go:248
github.com/kolide/launcher/ee/observability/exporter.(*TelemetryExporter).Execute
	/Users/runner/work/launcher/launcher/ee/observability/exporter/exporter.go:369
github.com/kolide/launcher/pkg/rungroup.(*Group).Run.func1
	/Users/runner/work/launcher/launcher/pkg/rungroup/rungroup.go:76
github.com/kolide/launcher/ee/gowrapper.GoWithRecoveryAction.func1
	/Users/runner/work/launcher/launcher/ee/gowrapper/goroutine.go:39
runtime.goexit
	/Users/runner/hostedtoolcache/go/1.23.0/x64/src/runtime/asm_arm64.s:1223

Relevant otel code with line number annotations:

OnEnd:

// OnEnd method enqueues a ReadOnlySpan for later processing.
func (bsp *batchSpanProcessor) OnEnd(s ReadOnlySpan) {
	// Do not enqueue spans after Shutdown.
	if bsp.stopped.Load() {
		return
	}

	// Do not enqueue spans if we are just going to drop them.
	if bsp.e == nil {
		return
	}
	bsp.enqueue(s) // batch_span_processor.go:138
}

enqueue:

func (bsp *batchSpanProcessor) enqueue(sd ReadOnlySpan) {
	ctx := context.TODO()
	if bsp.o.BlockOnQueueFull {
		bsp.enqueueBlockOnQueueFull(ctx, sd)
	} else {
		bsp.enqueueDrop(ctx, sd) // batch_span_processor.go:371
	}
}

enqueueDrop:

func (bsp *batchSpanProcessor) enqueueDrop(_ context.Context, sd ReadOnlySpan) bool {
	if !sd.SpanContext().IsSampled() { // batch_span_processor.go:389
		return false
	}

	select {
	case bsp.queue <- sd:
		return true
	default:
		atomic.AddUint32(&bsp.dropped, 1)
	}
	return false
}

My reading is that the span must be nil at this point -- it doesn't seem possible for the span to be non-nil but to have a nil return to SpanContext(). However, I'm not sure how the span could be nil. We could throw in a nil check here https://github.com/kolide/launcher/blob/main/ee/observability/bufspanprocessor/bufspanprocessor.go#L41, but it would be nice to understand how/why the span is nil first.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions