Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

baggagetrace: Add baggage key predicate #5619

Merged
merged 24 commits into from
Jun 6, 2024
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
e6a5773
baggagetrace: Add baggage key predicate
MikeGoldsmith May 21, 2024
18a53ab
add changelog entry
MikeGoldsmith May 21, 2024
12662b8
use require instead of assert
MikeGoldsmith Jun 3, 2024
63d85a6
move usage and examples into doc.go
MikeGoldsmith Jun 3, 2024
b1ce53a
Merge branch 'main' into mike/baggage-predicate
MikeGoldsmith Jun 3, 2024
89cb001
Merge branch 'main' into mike/baggage-predicate
codeboten Jun 3, 2024
0960b07
add docs for AllowAllBaggageKeys & typo
MikeGoldsmith Jun 4, 2024
111bf75
move examples to testable examples
MikeGoldsmith Jun 4, 2024
a8fbc83
make AllowAllBaggageKeys work as docs var
MikeGoldsmith Jun 4, 2024
ee48db8
Merge branch 'main' into mike/baggage-predicate
MikeGoldsmith Jun 4, 2024
d496224
add header to examples file
MikeGoldsmith Jun 4, 2024
4f764cc
fix typo in doc file
MikeGoldsmith Jun 4, 2024
aec6728
fix doc lint errors
MikeGoldsmith Jun 4, 2024
b759d50
remove warning in doc
MikeGoldsmith Jun 4, 2024
5b5d274
add test with multiple attributes
MikeGoldsmith Jun 5, 2024
f46ff84
clean-up tests
MikeGoldsmith Jun 5, 2024
b55754a
Merge branch 'main' into mike/baggage-predicate
MikeGoldsmith Jun 5, 2024
1e9c77a
fix test formatting
MikeGoldsmith Jun 5, 2024
0c9ddbe
Merge branch 'mike/baggage-predicate' of github.com:honeycombio/opent…
MikeGoldsmith Jun 5, 2024
f2d32f5
tweak tests for clarity
MikeGoldsmith Jun 5, 2024
bd60f43
check errors when creating baggage in tests
MikeGoldsmith Jun 5, 2024
5a137c9
remove italics in doc comments
MikeGoldsmith Jun 5, 2024
2b7e6e2
Merge branch 'main' into mike/baggage-predicate
codeboten Jun 5, 2024
57b2875
Merge branch 'main' into mike/baggage-predicate
MikeGoldsmith Jun 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
This parameter is used as a replacement of `WithInstrumentationScope` to specify the name of the logger backing the returned `Handler`. (#5588)
- Upgrade all dependencies of `go.opentelemetry.io/otel/semconv/v1.24.0` to `go.opentelemetry.io/otel/semconv/v1.25.0`. (#5605)

- Update the span processor in `go.opentelemetry.io/contrib/processors/baggage/baggagetrace` to require a baggage key predicate. (#5619)

### Removed

- The `WithInstrumentationScope` option function in `go.opentelemetry.io/contrib/bridges/otelslog` is removed.
Expand Down
24 changes: 23 additions & 1 deletion processors/baggage/baggagetrace/doc.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,27 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

// Package baggagetrace implements a baggage span processor.
// Package baggagetrace is an OpenTelemetry [Span Processor] that reads key/values
// stored in [Baggage] in the starting span's parent context and adds them as
// attributes to the span.
//
// Keys and values added to Baggage will appear on all subsequent child spans for
// a trace within this service *and* will be propagated to external services via
MikeGoldsmith marked this conversation as resolved.
Show resolved Hide resolved
// propagation headers.
// If the external services also have a Baggage span processor, the keys and
// values will appear in those child spans as well.
//
// Do not put sensitive information in Baggage.
//
// # Usage
//
// Add the span processor when configuring the tracer provider.
//
// The convenience function [AllowAllBaggageKeys] is provided to
// allow all baggage keys to be copied to the span. Alternatively, you can
// provide a custom baggage key predicate to select which baggage keys you want
// to copy.
//
// [Span Processor]: https://opentelemetry.io/docs/specs/otel/trace/sdk/#span-processor
// [Baggage]: https://opentelemetry.io/docs/specs/otel/api/baggage
package baggagetrace // import "go.opentelemetry.io/contrib/processors/baggage/baggagetrace"
43 changes: 43 additions & 0 deletions processors/baggage/baggagetrace/example_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package baggagetrace_test

import (
"regexp"
"strings"

"go.opentelemetry.io/contrib/processors/baggage/baggagetrace"
"go.opentelemetry.io/otel/sdk/trace"
)

func ExampleNew_allKeys() {
trace.NewTracerProvider(
trace.WithSpanProcessor(baggagetrace.New(baggagetrace.AllowAllBaggageKeys)),
)
}

func ExampleNew_keysWithPrefix() {
trace.NewTracerProvider(
trace.WithSpanProcessor(
baggagetrace.New(
func(baggageKey string) bool {
return strings.HasPrefix(baggageKey, "my-key")
},
),
),
)
}

func ExampleNew_keysMatchingRegex() {
expr := regexp.MustCompile(`^key.+`)
trace.NewTracerProvider(
trace.WithSpanProcessor(
baggagetrace.New(
func(baggageKey string) bool {
return expr.MatchString(baggageKey)
},
),
),
)
}
21 changes: 17 additions & 4 deletions processors/baggage/baggagetrace/processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,36 @@ import (
"go.opentelemetry.io/otel/sdk/trace"
)

// BaggageKeyPredicate is a function that returns true if the baggage key should be added to the span.
type BaggageKeyPredicate func(baggageKey string) bool

// AllowAllBaggageKeys is a BaggageKeyPredicate that allows all baggage keys.
var AllowAllBaggageKeys = func(string) bool { return true }

// SpanProcessor is a processing pipeline for spans in the trace signal.
type SpanProcessor struct{}
type SpanProcessor struct {
baggageKeyPredicate BaggageKeyPredicate
}

var _ trace.SpanProcessor = (*SpanProcessor)(nil)

// New returns a new SpanProcessor.
//
// The Baggage span processor duplicates onto a span the attributes found
// in Baggage in the parent context at the moment the span is started.
func New() trace.SpanProcessor {
return &SpanProcessor{}
// The predicate function is used to filter which baggage keys are added to the span.
MikeGoldsmith marked this conversation as resolved.
Show resolved Hide resolved
func New(baggageKeyPredicate BaggageKeyPredicate) trace.SpanProcessor {
pellared marked this conversation as resolved.
Show resolved Hide resolved
return &SpanProcessor{
baggageKeyPredicate: baggageKeyPredicate,
}
}

// OnStart is called when a span is started and adds span attributes for baggage contents.
func (processor SpanProcessor) OnStart(ctx context.Context, span trace.ReadWriteSpan) {
for _, entry := range otelbaggage.FromContext(ctx).Members() {
span.SetAttributes(attribute.String(entry.Key(), entry.Value()))
if processor.baggageKeyPredicate(entry.Key()) {
span.SetAttributes(attribute.String(entry.Key(), entry.Value()))
}
}
}

Expand Down
115 changes: 102 additions & 13 deletions processors/baggage/baggagetrace/processor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ package baggagetrace

import (
"context"
"regexp"
"strings"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"go.opentelemetry.io/otel/attribute"
Expand All @@ -33,19 +34,15 @@ func NewTestExporter() *testExporter {
return &testExporter{}
}

func TestSpanProcessorAppendsBaggageAttributes(t *testing.T) {
suitcase, err := otelbaggage.New()
require.NoError(t, err)
packingCube, err := otelbaggage.NewMemberRaw("baggage.test", "baggage value")
require.NoError(t, err)
suitcase, err = suitcase.SetMember(packingCube)
require.NoError(t, err)
ctx := otelbaggage.ContextWithBaggage(context.Background(), suitcase)
func TestSpanProcessorAppendsAllBaggageAttributes(t *testing.T) {
baggage, _ := otelbaggage.New()
baggage = addEntryToBaggage(baggage, "baggage.test", "baggage value")
ctx := otelbaggage.ContextWithBaggage(context.Background(), baggage)

// create trace provider with baggage processor and test exporter
exporter := NewTestExporter()
tp := trace.NewTracerProvider(
trace.WithSpanProcessor(New()),
trace.WithSpanProcessor(New(AllowAllBaggageKeys)),
trace.WithSpanProcessor(trace.NewSimpleSpanProcessor(exporter)),
)

Expand All @@ -54,9 +51,101 @@ func TestSpanProcessorAppendsBaggageAttributes(t *testing.T) {
_, span := tracer.Start(ctx, "test")
span.End()

assert.Len(t, exporter.spans, 1)
assert.Len(t, exporter.spans[0].Attributes(), 1)
require.Len(t, exporter.spans, 1)
require.Len(t, exporter.spans[0].Attributes(), 1)

want := []attribute.KeyValue{attribute.String("baggage.test", "baggage value")}
assert.Equal(t, want, exporter.spans[0].Attributes())
require.Equal(t, want, exporter.spans[0].Attributes())
}

func TestSpanProcessorAppendsBaggageAttributesWithHaPrefixPredicate(t *testing.T) {
baggage, _ := otelbaggage.New()
baggage = addEntryToBaggage(baggage, "baggage.test", "baggage value")
ctx := otelbaggage.ContextWithBaggage(context.Background(), baggage)

baggageKeyPredicate := func(key string) bool {
return strings.HasPrefix(key, "baggage.")
}

// create trace provider with baggage processor and test exporter
exporter := NewTestExporter()
tp := trace.NewTracerProvider(
trace.WithSpanProcessor(New(baggageKeyPredicate)),
trace.WithSpanProcessor(trace.NewSimpleSpanProcessor(exporter)),
)

// create tracer and start/end span
tracer := tp.Tracer("test")
_, span := tracer.Start(ctx, "test")
span.End()

require.Len(t, exporter.spans, 1)
require.Len(t, exporter.spans[0].Attributes(), 1)

want := []attribute.KeyValue{attribute.String("baggage.test", "baggage value")}
require.Equal(t, want, exporter.spans[0].Attributes())
}

func TestSpanProcessorAppendsBaggageAttributesWithRegexPredicate(t *testing.T) {
baggage, _ := otelbaggage.New()
baggage = addEntryToBaggage(baggage, "baggage.test", "baggage value")
ctx := otelbaggage.ContextWithBaggage(context.Background(), baggage)

expr := regexp.MustCompile(`^baggage\..*`)
baggageKeyPredicate := func(key string) bool {
return expr.MatchString(key)
}

// create trace provider with baggage processor and test exporter
exporter := NewTestExporter()
tp := trace.NewTracerProvider(
trace.WithSpanProcessor(New(baggageKeyPredicate)),
trace.WithSpanProcessor(trace.NewSimpleSpanProcessor(exporter)),
)

// create tracer and start/end span
tracer := tp.Tracer("test")
_, span := tracer.Start(ctx, "test")
span.End()

require.Len(t, exporter.spans, 1)
require.Len(t, exporter.spans[0].Attributes(), 1)

want := []attribute.KeyValue{attribute.String("baggage.test", "baggage value")}
require.Equal(t, want, exporter.spans[0].Attributes())
}

func TestOnlyAddsBaggageEntriesThatMatchPredicate(t *testing.T) {
baggage, _ := otelbaggage.New()
baggage = addEntryToBaggage(baggage, "baggage.test", "baggage value")
baggage = addEntryToBaggage(baggage, "foo", "bar")
ctx := otelbaggage.ContextWithBaggage(context.Background(), baggage)

baggageKeyPredicate := func(key string) bool {
return key == "baggage.test"
}

// create trace provider with baggage processor and test exporter
exporter := NewTestExporter()
tp := trace.NewTracerProvider(
trace.WithSpanProcessor(New(baggageKeyPredicate)),
trace.WithSpanProcessor(trace.NewSimpleSpanProcessor(exporter)),
)

// create tracer and start/end span
tracer := tp.Tracer("test")
_, span := tracer.Start(ctx, "test")
span.End()

require.Len(t, exporter.spans, 1)
require.Len(t, exporter.spans[0].Attributes(), 1)

want := attribute.String("baggage.test", "baggage value")
require.Equal(t, want, exporter.spans[0].Attributes()[0])
}

func addEntryToBaggage(baggage otelbaggage.Baggage, key, value string) otelbaggage.Baggage {
member, _ := otelbaggage.NewMemberRaw(key, value)
baggage, _ = baggage.SetMember(member)
MikeGoldsmith marked this conversation as resolved.
Show resolved Hide resolved
return baggage
}