You've already forked opentelemetry-go
mirror of
https://github.com/open-telemetry/opentelemetry-go.git
synced 2026-06-03 18:35:08 +02:00
Comply with W3C Baggage specification limits (#7880)
Updates the baggage implementation to comply with https://www.w3.org/TR/baggage/#limits: - Changed maxMembers from 180 to 64 (the W3C compliance requirement) > The resulting baggage-string contains 64 list-members or less. - Removed maxBytesPerMembers (4096) - this per-member limit was not part of the W3C spec - Added limit checking in extractMultiBaggage for multiple baggage headers: - Checks combined byte size across all headers (max 8192 bytes) - Checks combined member count across all headers (max 64 members) This uses non-deterministic truncation when handling baggage limits.
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package errorhandler provides the global error handler for OpenTelemetry.
|
||||
//
|
||||
// This package has no OTel dependencies, allowing it to be imported by any
|
||||
// package in the module without creating import cycles.
|
||||
package errorhandler // import "go.opentelemetry.io/otel/internal/errorhandler"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// ErrorHandler handles irremediable events.
|
||||
type ErrorHandler interface {
|
||||
// Handle handles any error deemed irremediable by an OpenTelemetry
|
||||
// component.
|
||||
Handle(error)
|
||||
}
|
||||
|
||||
type ErrDelegator struct {
|
||||
delegate atomic.Pointer[ErrorHandler]
|
||||
}
|
||||
|
||||
// Compile-time check that delegator implements ErrorHandler.
|
||||
var _ ErrorHandler = (*ErrDelegator)(nil)
|
||||
|
||||
func (d *ErrDelegator) Handle(err error) {
|
||||
if eh := d.delegate.Load(); eh != nil {
|
||||
(*eh).Handle(err)
|
||||
return
|
||||
}
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
// setDelegate sets the ErrorHandler delegate.
|
||||
func (d *ErrDelegator) setDelegate(eh ErrorHandler) {
|
||||
d.delegate.Store(&eh)
|
||||
}
|
||||
|
||||
type errorHandlerHolder struct {
|
||||
eh ErrorHandler
|
||||
}
|
||||
|
||||
var (
|
||||
globalErrorHandler = defaultErrorHandler()
|
||||
delegateErrorHandlerOnce sync.Once
|
||||
)
|
||||
|
||||
// GetErrorHandler returns the global ErrorHandler instance.
|
||||
//
|
||||
// The default ErrorHandler instance returned will log all errors to STDERR
|
||||
// until an override ErrorHandler is set with SetErrorHandler. All
|
||||
// ErrorHandler returned prior to this will automatically forward errors to
|
||||
// the set instance instead of logging.
|
||||
//
|
||||
// Subsequent calls to SetErrorHandler after the first will not forward errors
|
||||
// to the new ErrorHandler for prior returned instances.
|
||||
func GetErrorHandler() ErrorHandler {
|
||||
return globalErrorHandler.Load().(errorHandlerHolder).eh
|
||||
}
|
||||
|
||||
// SetErrorHandler sets the global ErrorHandler to h.
|
||||
//
|
||||
// The first time this is called all ErrorHandler previously returned from
|
||||
// GetErrorHandler will send errors to h instead of the default logging
|
||||
// ErrorHandler. Subsequent calls will set the global ErrorHandler, but not
|
||||
// delegate errors to h.
|
||||
func SetErrorHandler(h ErrorHandler) {
|
||||
current := GetErrorHandler()
|
||||
|
||||
if _, cOk := current.(*ErrDelegator); cOk {
|
||||
if _, ehOk := h.(*ErrDelegator); ehOk && current == h {
|
||||
// Do not assign to the delegate of the default ErrDelegator to be
|
||||
// itself.
|
||||
log.Print(errors.New("no ErrorHandler delegate configured"), " ErrorHandler remains its current value.")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
delegateErrorHandlerOnce.Do(func() {
|
||||
if def, ok := current.(*ErrDelegator); ok {
|
||||
def.setDelegate(h)
|
||||
}
|
||||
})
|
||||
globalErrorHandler.Store(errorHandlerHolder{eh: h})
|
||||
}
|
||||
|
||||
func defaultErrorHandler() *atomic.Value {
|
||||
v := &atomic.Value{}
|
||||
v.Store(errorHandlerHolder{eh: &ErrDelegator{}})
|
||||
return v
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package errorhandler
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type fnErrHandler func(error)
|
||||
|
||||
func (f fnErrHandler) Handle(err error) { f(err) }
|
||||
|
||||
var noopEH = fnErrHandler(func(error) {})
|
||||
|
||||
type nonComparableErrorHandler struct {
|
||||
ErrorHandler
|
||||
|
||||
nonComparable func() //nolint:unused // This is not called.
|
||||
}
|
||||
|
||||
func resetForTest(t testing.TB) {
|
||||
t.Cleanup(func() {
|
||||
globalErrorHandler = defaultErrorHandler()
|
||||
delegateErrorHandlerOnce = sync.Once{}
|
||||
})
|
||||
}
|
||||
|
||||
func TestErrDelegator(t *testing.T) {
|
||||
buf := new(bytes.Buffer)
|
||||
log.Default().SetOutput(buf)
|
||||
t.Cleanup(func() { log.Default().SetOutput(os.Stderr) })
|
||||
|
||||
e := &ErrDelegator{}
|
||||
|
||||
err := errors.New("testing")
|
||||
e.Handle(err)
|
||||
|
||||
got := buf.String()
|
||||
if !strings.Contains(got, err.Error()) {
|
||||
t.Error("default handler did not log")
|
||||
}
|
||||
buf.Reset()
|
||||
|
||||
var gotErr error
|
||||
e.setDelegate(fnErrHandler(func(e error) { gotErr = e }))
|
||||
e.Handle(err)
|
||||
|
||||
if buf.String() != "" {
|
||||
t.Error("delegate not set")
|
||||
} else if !errors.Is(gotErr, err) {
|
||||
t.Error("error not passed to delegate")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetErrorHandler(t *testing.T) {
|
||||
t.Run("Set With default is a noop", func(t *testing.T) {
|
||||
resetForTest(t)
|
||||
SetErrorHandler(GetErrorHandler())
|
||||
|
||||
eh, ok := GetErrorHandler().(*ErrDelegator)
|
||||
if !ok {
|
||||
t.Fatal("Global ErrorHandler should be the default ErrorHandler")
|
||||
}
|
||||
|
||||
if eh.delegate.Load() != nil {
|
||||
t.Fatal("ErrorHandler should not delegate when setting itself")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("First Set() should replace the delegate", func(t *testing.T) {
|
||||
resetForTest(t)
|
||||
|
||||
SetErrorHandler(noopEH)
|
||||
|
||||
_, ok := GetErrorHandler().(*ErrDelegator)
|
||||
if ok {
|
||||
t.Fatal("Global ErrorHandler was not changed")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Set() should delegate existing ErrorHandlers", func(t *testing.T) {
|
||||
resetForTest(t)
|
||||
|
||||
eh := GetErrorHandler()
|
||||
SetErrorHandler(noopEH)
|
||||
|
||||
errDel, ok := eh.(*ErrDelegator)
|
||||
if !ok {
|
||||
t.Fatal("Wrong ErrorHandler returned")
|
||||
}
|
||||
|
||||
if errDel.delegate.Load() == nil {
|
||||
t.Fatal("The ErrDelegator should have a delegate")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("non-comparable types should not panic", func(t *testing.T) {
|
||||
resetForTest(t)
|
||||
|
||||
eh := nonComparableErrorHandler{}
|
||||
assert.NotPanics(t, func() { SetErrorHandler(eh) }, "delegate")
|
||||
assert.NotPanics(t, func() { SetErrorHandler(eh) }, "replacement")
|
||||
})
|
||||
}
|
||||
@@ -5,33 +5,13 @@
|
||||
package global // import "go.opentelemetry.io/otel/internal/global"
|
||||
|
||||
import (
|
||||
"log"
|
||||
"sync/atomic"
|
||||
"go.opentelemetry.io/otel/internal/errorhandler"
|
||||
)
|
||||
|
||||
// ErrorHandler handles irremediable events.
|
||||
type ErrorHandler interface {
|
||||
// Handle handles any error deemed irremediable by an OpenTelemetry
|
||||
// component.
|
||||
Handle(error)
|
||||
}
|
||||
// ErrorHandler is an alias for errorhandler.ErrorHandler, kept for backward
|
||||
// compatibility with existing callers of internal/global.
|
||||
type ErrorHandler = errorhandler.ErrorHandler
|
||||
|
||||
type ErrDelegator struct {
|
||||
delegate atomic.Pointer[ErrorHandler]
|
||||
}
|
||||
|
||||
// Compile-time check that delegator implements ErrorHandler.
|
||||
var _ ErrorHandler = (*ErrDelegator)(nil)
|
||||
|
||||
func (d *ErrDelegator) Handle(err error) {
|
||||
if eh := d.delegate.Load(); eh != nil {
|
||||
(*eh).Handle(err)
|
||||
return
|
||||
}
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
// setDelegate sets the ErrorHandler delegate.
|
||||
func (d *ErrDelegator) setDelegate(eh ErrorHandler) {
|
||||
d.delegate.Store(&eh)
|
||||
}
|
||||
// ErrDelegator is an alias for errorhandler.ErrDelegator, kept for backward
|
||||
// compatibility with existing callers of internal/global.
|
||||
type ErrDelegator = errorhandler.ErrDelegator
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
// Copyright The OpenTelemetry Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package global
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestErrDelegator(t *testing.T) {
|
||||
buf := new(bytes.Buffer)
|
||||
log.Default().SetOutput(buf)
|
||||
t.Cleanup(func() { log.Default().SetOutput(os.Stderr) })
|
||||
|
||||
e := &ErrDelegator{}
|
||||
|
||||
err := errors.New("testing")
|
||||
e.Handle(err)
|
||||
|
||||
got := buf.String()
|
||||
if !strings.Contains(got, err.Error()) {
|
||||
t.Error("default handler did not log")
|
||||
}
|
||||
buf.Reset()
|
||||
|
||||
var gotErr error
|
||||
e.setDelegate(fnErrHandler(func(e error) { gotErr = e }))
|
||||
e.Handle(err)
|
||||
|
||||
if buf.String() != "" {
|
||||
t.Error("delegate not set")
|
||||
} else if !errors.Is(gotErr, err) {
|
||||
t.Error("error not passed to delegate")
|
||||
}
|
||||
}
|
||||
@@ -8,16 +8,13 @@ import (
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"go.opentelemetry.io/otel/internal/errorhandler"
|
||||
"go.opentelemetry.io/otel/metric"
|
||||
"go.opentelemetry.io/otel/propagation"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
type (
|
||||
errorHandlerHolder struct {
|
||||
eh ErrorHandler
|
||||
}
|
||||
|
||||
tracerProviderHolder struct {
|
||||
tp trace.TracerProvider
|
||||
}
|
||||
@@ -32,12 +29,10 @@ type (
|
||||
)
|
||||
|
||||
var (
|
||||
globalErrorHandler = defaultErrorHandler()
|
||||
globalTracer = defaultTracerValue()
|
||||
globalPropagators = defaultPropagatorsValue()
|
||||
globalMeterProvider = defaultMeterProvider()
|
||||
|
||||
delegateErrorHandlerOnce sync.Once
|
||||
delegateTraceOnce sync.Once
|
||||
delegateTextMapPropagatorOnce sync.Once
|
||||
delegateMeterOnce sync.Once
|
||||
@@ -53,7 +48,7 @@ var (
|
||||
// Subsequent calls to SetErrorHandler after the first will not forward errors
|
||||
// to the new ErrorHandler for prior returned instances.
|
||||
func GetErrorHandler() ErrorHandler {
|
||||
return globalErrorHandler.Load().(errorHandlerHolder).eh
|
||||
return errorhandler.GetErrorHandler()
|
||||
}
|
||||
|
||||
// SetErrorHandler sets the global ErrorHandler to h.
|
||||
@@ -63,26 +58,7 @@ func GetErrorHandler() ErrorHandler {
|
||||
// ErrorHandler. Subsequent calls will set the global ErrorHandler, but not
|
||||
// delegate errors to h.
|
||||
func SetErrorHandler(h ErrorHandler) {
|
||||
current := GetErrorHandler()
|
||||
|
||||
if _, cOk := current.(*ErrDelegator); cOk {
|
||||
if _, ehOk := h.(*ErrDelegator); ehOk && current == h {
|
||||
// Do not assign to the delegate of the default ErrDelegator to be
|
||||
// itself.
|
||||
Error(
|
||||
errors.New("no ErrorHandler delegate configured"),
|
||||
"ErrorHandler remains its current value.",
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
delegateErrorHandlerOnce.Do(func() {
|
||||
if def, ok := current.(*ErrDelegator); ok {
|
||||
def.setDelegate(h)
|
||||
}
|
||||
})
|
||||
globalErrorHandler.Store(errorHandlerHolder{eh: h})
|
||||
errorhandler.SetErrorHandler(h)
|
||||
}
|
||||
|
||||
// TracerProvider is the internal implementation for global.TracerProvider.
|
||||
@@ -174,12 +150,6 @@ func SetMeterProvider(mp metric.MeterProvider) {
|
||||
globalMeterProvider.Store(meterProviderHolder{mp: mp})
|
||||
}
|
||||
|
||||
func defaultErrorHandler() *atomic.Value {
|
||||
v := &atomic.Value{}
|
||||
v.Store(errorHandlerHolder{eh: &ErrDelegator{}})
|
||||
return v
|
||||
}
|
||||
|
||||
func defaultTracerValue() *atomic.Value {
|
||||
v := &atomic.Value{}
|
||||
v.Store(tracerProviderHolder{tp: &tracerProvider{}})
|
||||
|
||||
@@ -15,12 +15,6 @@ import (
|
||||
tracenoop "go.opentelemetry.io/otel/trace/noop"
|
||||
)
|
||||
|
||||
type nonComparableErrorHandler struct {
|
||||
ErrorHandler
|
||||
|
||||
nonComparable func() //nolint:unused // This is not called.
|
||||
}
|
||||
|
||||
type nonComparableTracerProvider struct {
|
||||
trace.TracerProvider
|
||||
|
||||
@@ -33,63 +27,6 @@ type nonComparableMeterProvider struct {
|
||||
nonComparable func() //nolint:unused // This is not called.
|
||||
}
|
||||
|
||||
type fnErrHandler func(error)
|
||||
|
||||
func (f fnErrHandler) Handle(err error) { f(err) }
|
||||
|
||||
var noopEH = fnErrHandler(func(error) {})
|
||||
|
||||
func TestSetErrorHandler(t *testing.T) {
|
||||
t.Run("Set With default is a noop", func(t *testing.T) {
|
||||
ResetForTest(t)
|
||||
SetErrorHandler(GetErrorHandler())
|
||||
|
||||
eh, ok := GetErrorHandler().(*ErrDelegator)
|
||||
if !ok {
|
||||
t.Fatal("Global ErrorHandler should be the default ErrorHandler")
|
||||
}
|
||||
|
||||
if eh.delegate.Load() != nil {
|
||||
t.Fatal("ErrorHandler should not delegate when setting itself")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("First Set() should replace the delegate", func(t *testing.T) {
|
||||
ResetForTest(t)
|
||||
|
||||
SetErrorHandler(noopEH)
|
||||
|
||||
_, ok := GetErrorHandler().(*ErrDelegator)
|
||||
if ok {
|
||||
t.Fatal("Global ErrorHandler was not changed")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Set() should delegate existing ErrorHandlers", func(t *testing.T) {
|
||||
ResetForTest(t)
|
||||
|
||||
eh := GetErrorHandler()
|
||||
SetErrorHandler(noopEH)
|
||||
|
||||
errDel, ok := eh.(*ErrDelegator)
|
||||
if !ok {
|
||||
t.Fatal("Wrong ErrorHandler returned")
|
||||
}
|
||||
|
||||
if errDel.delegate.Load() == nil {
|
||||
t.Fatal("The ErrDelegator should have a delegate")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("non-comparable types should not panic", func(t *testing.T) {
|
||||
ResetForTest(t)
|
||||
|
||||
eh := nonComparableErrorHandler{}
|
||||
assert.NotPanics(t, func() { SetErrorHandler(eh) }, "delegate")
|
||||
assert.NotPanics(t, func() { SetErrorHandler(eh) }, "replacement")
|
||||
})
|
||||
}
|
||||
|
||||
func TestSetTracerProvider(t *testing.T) {
|
||||
t.Run("Set With default is a noop", func(t *testing.T) {
|
||||
ResetForTest(t)
|
||||
|
||||
@@ -12,11 +12,9 @@ import (
|
||||
// its Cleanup step.
|
||||
func ResetForTest(t testing.TB) {
|
||||
t.Cleanup(func() {
|
||||
globalErrorHandler = defaultErrorHandler()
|
||||
globalTracer = defaultTracerValue()
|
||||
globalPropagators = defaultPropagatorsValue()
|
||||
globalMeterProvider = defaultMeterProvider()
|
||||
delegateErrorHandlerOnce = sync.Once{}
|
||||
delegateTraceOnce = sync.Once{}
|
||||
delegateTextMapPropagatorOnce = sync.Once{}
|
||||
delegateMeterOnce = sync.Once{}
|
||||
|
||||
Reference in New Issue
Block a user