1
0
mirror of https://github.com/open-telemetry/opentelemetry-go.git synced 2026-06-03 18:35:08 +02:00
Files
opentelemetry-go/propagation/baggage.go
T
Sam Xie 97447f5c54 Add max baggage length as limitation (#8222)
```
goos: darwin
goarch: arm64
pkg: go.opentelemetry.io/otel/baggage
cpu: Apple M1 Max
                                 │   /tmp/old.txt    │             /tmp/new.txt             │
                                 │      sec/op       │   sec/op     vs base                 │
New-10                                  413.5n ±  1%   410.1n ± 1%         ~ (p=0.184 n=10)
NewMemberRaw-10                         12.65n ±  1%   12.62n ± 1%         ~ (p=0.270 n=10)
Parse-10                                1.252µ ±  2%   1.254µ ± 1%         ~ (p=0.778 n=10)
String-10                               594.9n ±  1%   593.4n ± 1%         ~ (p=0.279 n=10)
ValueEscape/nothing_to_escape-10        4.890n ±  1%   4.885n ± 0%         ~ (p=0.579 n=10)
ValueEscape/requires_escaping-10        22.02n ±  1%   21.47n ± 1%    -2.50% (p=0.000 n=10)
ValueEscape/long_value-10               507.4n ±  1%   506.6n ± 2%         ~ (p=0.481 n=10)
MemberString-10                         486.7n ± 15%   514.0n ± 5%         ~ (p=0.190 n=10)
ParseOversized-10                  22544795.0n ±  1%   130.8n ± 4%  -100.00% (p=0.000 n=10)
geomean                                 510.0n         133.8n        -73.76%

                                 │   /tmp/old.txt   │              /tmp/new.txt              │
                                 │       B/op       │     B/op      vs base                  │
New-10                                 592.0 ± 0%       592.0 ± 0%        ~ (p=1.000 n=10) ¹
NewMemberRaw-10                        0.000 ± 0%       0.000 ± 0%        ~ (p=1.000 n=10) ¹
Parse-10                             1.039Ki ± 0%     1.039Ki ± 0%        ~ (p=1.000 n=10) ¹
String-10                              840.0 ± 0%       840.0 ± 0%        ~ (p=1.000 n=10) ¹
ValueEscape/nothing_to_escape-10       0.000 ± 0%       0.000 ± 0%        ~ (p=1.000 n=10) ¹
ValueEscape/requires_escaping-10       16.00 ± 0%       16.00 ± 0%        ~ (p=1.000 n=10) ¹
ValueEscape/long_value-10              576.0 ± 0%       576.0 ± 0%        ~ (p=1.000 n=10) ¹
MemberString-10                        656.0 ± 0%       656.0 ± 0%        ~ (p=1.000 n=10) ¹
ParseOversized-10                  801126.50 ± 0%       88.00 ± 0%  -99.99% (p=0.000 n=10)
geomean                                           ²                 -63.68%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                                 │   /tmp/old.txt    │             /tmp/new.txt              │
                                 │     allocs/op     │ allocs/op   vs base                   │
New-10                                  6.000 ± 0%     6.000 ± 0%         ~ (p=1.000 n=10) ¹
NewMemberRaw-10                         0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
Parse-10                                18.00 ± 0%     18.00 ± 0%         ~ (p=1.000 n=10) ¹
String-10                               8.000 ± 0%     8.000 ± 0%         ~ (p=1.000 n=10) ¹
ValueEscape/nothing_to_escape-10        0.000 ± 0%     0.000 ± 0%         ~ (p=1.000 n=10) ¹
ValueEscape/requires_escaping-10        1.000 ± 0%     1.000 ± 0%         ~ (p=1.000 n=10) ¹
ValueEscape/long_value-10               2.000 ± 0%     2.000 ± 0%         ~ (p=1.000 n=10) ¹
MemberString-10                         4.000 ± 0%     4.000 ± 0%         ~ (p=1.000 n=10) ¹
ParseOversized-10                  250007.000 ± 0%     3.000 ± 0%  -100.00% (p=0.000 n=10)
geomean                                            ²                -71.61%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean
```

---------

Co-authored-by: Robert Pająk <pellared@hotmail.com>
2026-05-20 16:25:54 +02:00

135 lines
3.5 KiB
Go

// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
package propagation // import "go.opentelemetry.io/otel/propagation"
import (
"context"
"errors"
"fmt"
"go.opentelemetry.io/otel/baggage"
"go.opentelemetry.io/otel/internal/errorhandler"
)
const (
baggageHeader = "baggage"
maxParseErrors = 5
// W3C Baggage specification limits.
// https://www.w3.org/TR/baggage/#limits
maxMembers = 64
maxBytesPerBaggageString = 8192
)
// Baggage is a propagator that supports the W3C Baggage format.
//
// This propagates user-defined baggage associated with a trace. The complete
// specification is defined at https://www.w3.org/TR/baggage/.
type Baggage struct{}
var _ TextMapPropagator = Baggage{}
// Inject sets baggage key-values from ctx into the carrier.
func (Baggage) Inject(ctx context.Context, carrier TextMapCarrier) {
bStr := baggage.FromContext(ctx).String()
if bStr != "" {
carrier.Set(baggageHeader, bStr)
}
}
// Extract returns a copy of parent with the baggage from the carrier added.
// If carrier implements [ValuesGetter] (e.g. [HeaderCarrier]), Values is invoked
// for multiple values extraction. Otherwise, Get is called.
func (Baggage) Extract(parent context.Context, carrier TextMapCarrier) context.Context {
if multiCarrier, ok := carrier.(ValuesGetter); ok {
return extractMultiBaggage(parent, multiCarrier)
}
return extractSingleBaggage(parent, carrier)
}
// Fields returns the keys who's values are set with Inject.
func (Baggage) Fields() []string {
return []string{baggageHeader}
}
func extractSingleBaggage(parent context.Context, carrier TextMapCarrier) context.Context {
bStr := carrier.Get(baggageHeader)
if bStr == "" {
return parent
}
bag, err := baggage.Parse(bStr)
if err != nil {
errorhandler.GetErrorHandler().Handle(err)
}
if bag.Len() == 0 {
return parent
}
return baggage.ContextWithBaggage(parent, bag)
}
func extractMultiBaggage(parent context.Context, carrier ValuesGetter) context.Context {
bVals := carrier.Values(baggageHeader)
if len(bVals) == 0 {
return parent
}
var members []baggage.Member
var totalBytes int
var parseErrors int
var truncateErr error
for i, bStr := range bVals {
if i > 0 {
totalBytes++ // comma separator between combined header values
}
totalBytes += len(bStr)
if totalBytes > maxBytesPerBaggageString {
// Per the W3C Baggage spec, the byte limit applies to the
// combination of all baggage headers, not each header
// individually. Mirror the single-header behavior of
// reporting the error and returning the parent context
// with no baggage attached.
errorhandler.GetErrorHandler().Handle(fmt.Errorf(
"baggage: aggregate header size %d exceeds %d byte limit",
totalBytes,
maxBytesPerBaggageString,
))
return parent
}
// If members exceed the limit, stop parsing baggage.
if len(members) <= maxMembers {
currBag, err := baggage.Parse(bStr)
if err != nil {
parseErrors++
if parseErrors <= maxParseErrors {
truncateErr = errors.Join(truncateErr, err)
}
}
if currBag.Len() == 0 {
continue
}
members = append(members, currBag.Members()...)
}
}
if dropped := parseErrors - maxParseErrors; dropped > 0 {
truncateErr = errors.Join(truncateErr, fmt.Errorf("and %d more error(s)", dropped))
}
b, err := baggage.New(members...)
if err != nil {
truncateErr = errors.Join(truncateErr, err)
}
if truncateErr != nil {
errorhandler.GetErrorHandler().Handle(truncateErr)
}
if b.Len() == 0 {
return parent
}
return baggage.ContextWithBaggage(parent, b)
}