You've already forked opentelemetry-go
mirror of
https://github.com/open-telemetry/opentelemetry-go.git
synced 2025-07-15 01:04:25 +02:00
Add Baggage API and move Baggage propagator (#1217)
* Move api/baggage to the propagators package * Create Baggage API to match specification * Update CHANGELOG.md * Baggage API unit tests * Rename and add unit test * Update unit test value checking * Update TODO with issue tracking work.
This commit is contained in:
@ -11,12 +11,14 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
|||||||
### Added
|
### Added
|
||||||
|
|
||||||
- OTLP Metric exporter supports Histogram aggregation. (#1209)
|
- OTLP Metric exporter supports Histogram aggregation. (#1209)
|
||||||
|
- A Baggage API to implement the OpenTelemetry specification. (#1217)
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Set default propagator to no-op propagator. (#1184)
|
- Set default propagator to no-op propagator. (#1184)
|
||||||
- The `HTTPSupplier`, `HTTPExtractor`, `HTTPInjector`, and `HTTPPropagator` from the `go.opentelemetry.io/otel/api/propagation` package were replaced with unified `TextMapCarrier` and `TextMapPropagator` in the `go.opentelemetry.io/otel` package. (#1212)
|
- The `HTTPSupplier`, `HTTPExtractor`, `HTTPInjector`, and `HTTPPropagator` from the `go.opentelemetry.io/otel/api/propagation` package were replaced with unified `TextMapCarrier` and `TextMapPropagator` in the `go.opentelemetry.io/otel` package. (#1212)
|
||||||
- The `New` function from the `go.opentelemetry.io/otel/api/propagation` package was replaced with `NewCompositeTextMapPropagator` in the `go.opentelemetry.io/otel` package. (#1212)
|
- The `New` function from the `go.opentelemetry.io/otel/api/propagation` package was replaced with `NewCompositeTextMapPropagator` in the `go.opentelemetry.io/otel` package. (#1212)
|
||||||
|
- Move the `go.opentelemetry.io/otel/api/baggage` package into `go.opentelemetry.io/otel/propagators`. (#1217)
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
@ -24,6 +26,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
|||||||
- The `Propagators` interface from the `go.opentelemetry.io/otel/api/propagation` package was removed to conform to the OpenTelemetry specification.
|
- The `Propagators` interface from the `go.opentelemetry.io/otel/api/propagation` package was removed to conform to the OpenTelemetry specification.
|
||||||
The explicit `TextMapPropagator` type can be used in its place as this is the `Propagator` type the specification defines. (#1212)
|
The explicit `TextMapPropagator` type can be used in its place as this is the `Propagator` type the specification defines. (#1212)
|
||||||
- The `SetAttribute` method of the `Span` from the `go.opentelemetry.io/otel/api/trace` package was removed given its redundancy with the `SetAttributes` method. (#1216)
|
- The `SetAttribute` method of the `Span` from the `go.opentelemetry.io/otel/api/trace` package was removed given its redundancy with the `SetAttributes` method. (#1216)
|
||||||
|
- The internal implementation of Baggage storage is removed in favor of using the new Baggage API functionality. (#1217)
|
||||||
- Remove duplicate hostname key `HostHostNameKey` in Resource semantic conventions. (#1219)
|
- Remove duplicate hostname key `HostHostNameKey` in Resource semantic conventions. (#1219)
|
||||||
|
|
||||||
## [0.12.0] - 2020-09-24
|
## [0.12.0] - 2020-09-24
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
// 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 baggage provides types and utilities for baggage features.
|
|
||||||
package baggage // import "go.opentelemetry.io/otel/api/baggage"
|
|
@ -1,176 +0,0 @@
|
|||||||
// 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 baggage
|
|
||||||
|
|
||||||
import "go.opentelemetry.io/otel/label"
|
|
||||||
|
|
||||||
type rawMap map[label.Key]label.Value
|
|
||||||
type keySet map[label.Key]struct{}
|
|
||||||
|
|
||||||
// Map is an immutable storage for correlations.
|
|
||||||
type Map struct {
|
|
||||||
m rawMap
|
|
||||||
}
|
|
||||||
|
|
||||||
// MapUpdate contains information about correlation changes to be
|
|
||||||
// made.
|
|
||||||
type MapUpdate struct {
|
|
||||||
// DropSingleK contains a single key to be dropped from
|
|
||||||
// correlations. Use this to avoid an overhead of a slice
|
|
||||||
// allocation if there is only one key to drop.
|
|
||||||
DropSingleK label.Key
|
|
||||||
// DropMultiK contains all the keys to be dropped from
|
|
||||||
// correlations.
|
|
||||||
DropMultiK []label.Key
|
|
||||||
|
|
||||||
// SingleKV contains a single key-value pair to be added to
|
|
||||||
// correlations. Use this to avoid an overhead of a slice
|
|
||||||
// allocation if there is only one key-value pair to add.
|
|
||||||
SingleKV label.KeyValue
|
|
||||||
// MultiKV contains all the key-value pairs to be added to
|
|
||||||
// correlations.
|
|
||||||
MultiKV []label.KeyValue
|
|
||||||
}
|
|
||||||
|
|
||||||
func newMap(raw rawMap) Map {
|
|
||||||
return Map{
|
|
||||||
m: raw,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewEmptyMap creates an empty correlations map.
|
|
||||||
func NewEmptyMap() Map {
|
|
||||||
return newMap(nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMap creates a map with the contents of the update applied. In
|
|
||||||
// this function, having an update with DropSingleK or DropMultiK
|
|
||||||
// makes no sense - those fields are effectively ignored.
|
|
||||||
func NewMap(update MapUpdate) Map {
|
|
||||||
return NewEmptyMap().Apply(update)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply creates a copy of the map with the contents of the update
|
|
||||||
// applied. Apply will first drop the keys from DropSingleK and
|
|
||||||
// DropMultiK, then add key-value pairs from SingleKV and MultiKV.
|
|
||||||
func (m Map) Apply(update MapUpdate) Map {
|
|
||||||
delSet, addSet := getModificationSets(update)
|
|
||||||
mapSize := getNewMapSize(m.m, delSet, addSet)
|
|
||||||
|
|
||||||
r := make(rawMap, mapSize)
|
|
||||||
for k, v := range m.m {
|
|
||||||
// do not copy items we want to drop
|
|
||||||
if _, ok := delSet[k]; ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// do not copy items we would overwrite
|
|
||||||
if _, ok := addSet[k]; ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
r[k] = v
|
|
||||||
}
|
|
||||||
if update.SingleKV.Key.Defined() {
|
|
||||||
r[update.SingleKV.Key] = update.SingleKV.Value
|
|
||||||
}
|
|
||||||
for _, kv := range update.MultiKV {
|
|
||||||
r[kv.Key] = kv.Value
|
|
||||||
}
|
|
||||||
if len(r) == 0 {
|
|
||||||
r = nil
|
|
||||||
}
|
|
||||||
return newMap(r)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getModificationSets(update MapUpdate) (delSet, addSet keySet) {
|
|
||||||
deletionsCount := len(update.DropMultiK)
|
|
||||||
if update.DropSingleK.Defined() {
|
|
||||||
deletionsCount++
|
|
||||||
}
|
|
||||||
if deletionsCount > 0 {
|
|
||||||
delSet = make(map[label.Key]struct{}, deletionsCount)
|
|
||||||
for _, k := range update.DropMultiK {
|
|
||||||
delSet[k] = struct{}{}
|
|
||||||
}
|
|
||||||
if update.DropSingleK.Defined() {
|
|
||||||
delSet[update.DropSingleK] = struct{}{}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
additionsCount := len(update.MultiKV)
|
|
||||||
if update.SingleKV.Key.Defined() {
|
|
||||||
additionsCount++
|
|
||||||
}
|
|
||||||
if additionsCount > 0 {
|
|
||||||
addSet = make(map[label.Key]struct{}, additionsCount)
|
|
||||||
for _, k := range update.MultiKV {
|
|
||||||
addSet[k.Key] = struct{}{}
|
|
||||||
}
|
|
||||||
if update.SingleKV.Key.Defined() {
|
|
||||||
addSet[update.SingleKV.Key] = struct{}{}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func getNewMapSize(m rawMap, delSet, addSet keySet) int {
|
|
||||||
mapSizeDiff := 0
|
|
||||||
for k := range addSet {
|
|
||||||
if _, ok := m[k]; !ok {
|
|
||||||
mapSizeDiff++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for k := range delSet {
|
|
||||||
if _, ok := m[k]; ok {
|
|
||||||
if _, inAddSet := addSet[k]; !inAddSet {
|
|
||||||
mapSizeDiff--
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return len(m) + mapSizeDiff
|
|
||||||
}
|
|
||||||
|
|
||||||
// Value gets a value from correlations map and returns a boolean
|
|
||||||
// value indicating whether the key exist in the map.
|
|
||||||
func (m Map) Value(k label.Key) (label.Value, bool) {
|
|
||||||
value, ok := m.m[k]
|
|
||||||
return value, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasValue returns a boolean value indicating whether the key exist
|
|
||||||
// in the map.
|
|
||||||
func (m Map) HasValue(k label.Key) bool {
|
|
||||||
_, has := m.Value(k)
|
|
||||||
return has
|
|
||||||
}
|
|
||||||
|
|
||||||
// Len returns a length of the map.
|
|
||||||
func (m Map) Len() int {
|
|
||||||
return len(m.m)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Foreach calls a passed callback once on each key-value pair until
|
|
||||||
// all the key-value pairs of the map were iterated or the callback
|
|
||||||
// returns false, whichever happens first.
|
|
||||||
func (m Map) Foreach(f func(label.KeyValue) bool) {
|
|
||||||
for k, v := range m.m {
|
|
||||||
if !f(label.KeyValue{
|
|
||||||
Key: k,
|
|
||||||
Value: v,
|
|
||||||
}) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
67
baggage.go
Normal file
67
baggage.go
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
// 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 otel
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"go.opentelemetry.io/otel/internal/baggage"
|
||||||
|
"go.opentelemetry.io/otel/label"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Baggage returns a copy of the baggage in ctx.
|
||||||
|
func Baggage(ctx context.Context) label.Set {
|
||||||
|
// TODO (MrAlias, #1222): The underlying storage, the Map, shares many of
|
||||||
|
// the functional elements of the label.Set. These should be unified so
|
||||||
|
// this conversion is unnecessary and there is no performance hit calling
|
||||||
|
// this.
|
||||||
|
m := baggage.MapFromContext(ctx)
|
||||||
|
values := make([]label.KeyValue, 0, m.Len())
|
||||||
|
m.Foreach(func(kv label.KeyValue) bool {
|
||||||
|
values = append(values, kv)
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
return label.NewSet(values...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BaggageValue returns the value related to key in the baggage of ctx. If no
|
||||||
|
// value is set, the returned label.Value will be an uninitialized zero-value
|
||||||
|
// with type INVALID.
|
||||||
|
func BaggageValue(ctx context.Context, key label.Key) label.Value {
|
||||||
|
v, _ := baggage.MapFromContext(ctx).Value(key)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContextWithBaggageValues returns a copy of parent with pairs updated in the baggage.
|
||||||
|
func ContextWithBaggageValues(parent context.Context, pairs ...label.KeyValue) context.Context {
|
||||||
|
m := baggage.MapFromContext(parent).Apply(baggage.MapUpdate{
|
||||||
|
MultiKV: pairs,
|
||||||
|
})
|
||||||
|
return baggage.ContextWithMap(parent, m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContextWithoutBaggageValues returns a copy of parent in which the values related
|
||||||
|
// to keys have been removed from the baggage.
|
||||||
|
func ContextWithoutBaggageValues(parent context.Context, keys ...label.Key) context.Context {
|
||||||
|
m := baggage.MapFromContext(parent).Apply(baggage.MapUpdate{
|
||||||
|
DropMultiK: keys,
|
||||||
|
})
|
||||||
|
return baggage.ContextWithMap(parent, m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContextWithoutBaggage returns a copy of parent without baggage.
|
||||||
|
func ContextWithoutBaggage(parent context.Context) context.Context {
|
||||||
|
return baggage.ContextWithNoCorrelationData(parent)
|
||||||
|
}
|
86
baggage_test.go
Normal file
86
baggage_test.go
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
// 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 otel
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"go.opentelemetry.io/otel/internal/baggage"
|
||||||
|
"go.opentelemetry.io/otel/label"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBaggage(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
ctx = baggage.ContextWithMap(ctx, baggage.NewEmptyMap())
|
||||||
|
|
||||||
|
b := Baggage(ctx)
|
||||||
|
if b.Len() != 0 {
|
||||||
|
t.Fatalf("empty baggage returned a set with %d elements", b.Len())
|
||||||
|
}
|
||||||
|
|
||||||
|
first, second, third := label.Key("first"), label.Key("second"), label.Key("third")
|
||||||
|
ctx = ContextWithBaggageValues(ctx, first.Bool(true), second.String("2"))
|
||||||
|
m := baggage.MapFromContext(ctx)
|
||||||
|
v, ok := m.Value(first)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("WithBaggageValues failed to set first value")
|
||||||
|
}
|
||||||
|
if !v.AsBool() {
|
||||||
|
t.Fatal("WithBaggageValues failed to set first correct value")
|
||||||
|
}
|
||||||
|
v, ok = m.Value(second)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("WithBaggageValues failed to set second value")
|
||||||
|
}
|
||||||
|
if v.AsString() != "2" {
|
||||||
|
t.Fatal("WithBaggageValues failed to set second correct value")
|
||||||
|
}
|
||||||
|
_, ok = m.Value(third)
|
||||||
|
if ok {
|
||||||
|
t.Fatal("WithBaggageValues set an unexpected third value")
|
||||||
|
}
|
||||||
|
|
||||||
|
b = Baggage(ctx)
|
||||||
|
if b.Len() != 2 {
|
||||||
|
t.Fatalf("Baggage returned a set with %d elements, want 2", b.Len())
|
||||||
|
}
|
||||||
|
|
||||||
|
v = BaggageValue(ctx, first)
|
||||||
|
if v.Type() != label.BOOL || !v.AsBool() {
|
||||||
|
t.Fatal("BaggageValue failed to get correct first value")
|
||||||
|
}
|
||||||
|
v = BaggageValue(ctx, second)
|
||||||
|
if v.Type() != label.STRING || v.AsString() != "2" {
|
||||||
|
t.Fatal("BaggageValue failed to get correct second value")
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = ContextWithoutBaggageValues(ctx, first)
|
||||||
|
m = baggage.MapFromContext(ctx)
|
||||||
|
_, ok = m.Value(first)
|
||||||
|
if ok {
|
||||||
|
t.Fatal("WithoutBaggageValues failed to remove a baggage value")
|
||||||
|
}
|
||||||
|
_, ok = m.Value(second)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("WithoutBaggageValues removed incorrect value")
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = ContextWithoutBaggage(ctx)
|
||||||
|
m = baggage.MapFromContext(ctx)
|
||||||
|
if m.Len() != 0 {
|
||||||
|
t.Fatal("WithoutBaggage failed to clear baggage")
|
||||||
|
}
|
||||||
|
}
|
@ -26,10 +26,10 @@ import (
|
|||||||
otlog "github.com/opentracing/opentracing-go/log"
|
otlog "github.com/opentracing/opentracing-go/log"
|
||||||
|
|
||||||
"go.opentelemetry.io/otel"
|
"go.opentelemetry.io/otel"
|
||||||
otelbaggage "go.opentelemetry.io/otel/api/baggage"
|
|
||||||
otelglobal "go.opentelemetry.io/otel/api/global"
|
otelglobal "go.opentelemetry.io/otel/api/global"
|
||||||
oteltrace "go.opentelemetry.io/otel/api/trace"
|
oteltrace "go.opentelemetry.io/otel/api/trace"
|
||||||
"go.opentelemetry.io/otel/codes"
|
"go.opentelemetry.io/otel/codes"
|
||||||
|
"go.opentelemetry.io/otel/internal/baggage"
|
||||||
"go.opentelemetry.io/otel/internal/trace/noop"
|
"go.opentelemetry.io/otel/internal/trace/noop"
|
||||||
otelparent "go.opentelemetry.io/otel/internal/trace/parent"
|
otelparent "go.opentelemetry.io/otel/internal/trace/parent"
|
||||||
"go.opentelemetry.io/otel/label"
|
"go.opentelemetry.io/otel/label"
|
||||||
@ -38,7 +38,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type bridgeSpanContext struct {
|
type bridgeSpanContext struct {
|
||||||
baggageItems otelbaggage.Map
|
baggageItems baggage.Map
|
||||||
otelSpanContext oteltrace.SpanContext
|
otelSpanContext oteltrace.SpanContext
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ var _ ot.SpanContext = &bridgeSpanContext{}
|
|||||||
|
|
||||||
func newBridgeSpanContext(otelSpanContext oteltrace.SpanContext, parentOtSpanContext ot.SpanContext) *bridgeSpanContext {
|
func newBridgeSpanContext(otelSpanContext oteltrace.SpanContext, parentOtSpanContext ot.SpanContext) *bridgeSpanContext {
|
||||||
bCtx := &bridgeSpanContext{
|
bCtx := &bridgeSpanContext{
|
||||||
baggageItems: otelbaggage.NewEmptyMap(),
|
baggageItems: baggage.NewEmptyMap(),
|
||||||
otelSpanContext: otelSpanContext,
|
otelSpanContext: otelSpanContext,
|
||||||
}
|
}
|
||||||
if parentOtSpanContext != nil {
|
if parentOtSpanContext != nil {
|
||||||
@ -66,7 +66,7 @@ func (c *bridgeSpanContext) ForeachBaggageItem(handler func(k, v string) bool) {
|
|||||||
|
|
||||||
func (c *bridgeSpanContext) setBaggageItem(restrictedKey, value string) {
|
func (c *bridgeSpanContext) setBaggageItem(restrictedKey, value string) {
|
||||||
crk := http.CanonicalHeaderKey(restrictedKey)
|
crk := http.CanonicalHeaderKey(restrictedKey)
|
||||||
c.baggageItems = c.baggageItems.Apply(otelbaggage.MapUpdate{SingleKV: label.String(crk, value)})
|
c.baggageItems = c.baggageItems.Apply(baggage.MapUpdate{SingleKV: label.String(crk, value)})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *bridgeSpanContext) baggageItem(restrictedKey string) string {
|
func (c *bridgeSpanContext) baggageItem(restrictedKey string) string {
|
||||||
@ -327,8 +327,8 @@ func (t *BridgeTracer) SetTextMapPropagator(propagator otel.TextMapPropagator) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *BridgeTracer) NewHookedContext(ctx context.Context) context.Context {
|
func (t *BridgeTracer) NewHookedContext(ctx context.Context) context.Context {
|
||||||
ctx = otelbaggage.ContextWithSetHook(ctx, t.baggageSetHook)
|
ctx = baggage.ContextWithSetHook(ctx, t.baggageSetHook)
|
||||||
ctx = otelbaggage.ContextWithGetHook(ctx, t.baggageGetHook)
|
ctx = baggage.ContextWithGetHook(ctx, t.baggageGetHook)
|
||||||
return ctx
|
return ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -346,8 +346,8 @@ func (t *BridgeTracer) baggageSetHook(ctx context.Context) context.Context {
|
|||||||
// we clear the context only to avoid calling a get hook
|
// we clear the context only to avoid calling a get hook
|
||||||
// during MapFromContext, but otherwise we don't change the
|
// during MapFromContext, but otherwise we don't change the
|
||||||
// context, so we don't care about the old hooks.
|
// context, so we don't care about the old hooks.
|
||||||
clearCtx, _, _ := otelbaggage.ContextWithNoHooks(ctx)
|
clearCtx, _, _ := baggage.ContextWithNoHooks(ctx)
|
||||||
m := otelbaggage.MapFromContext(clearCtx)
|
m := baggage.MapFromContext(clearCtx)
|
||||||
m.Foreach(func(kv label.KeyValue) bool {
|
m.Foreach(func(kv label.KeyValue) bool {
|
||||||
bSpan.setBaggageItemOnly(string(kv.Key), kv.Value.Emit())
|
bSpan.setBaggageItemOnly(string(kv.Key), kv.Value.Emit())
|
||||||
return true
|
return true
|
||||||
@ -355,7 +355,7 @@ func (t *BridgeTracer) baggageSetHook(ctx context.Context) context.Context {
|
|||||||
return ctx
|
return ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *BridgeTracer) baggageGetHook(ctx context.Context, m otelbaggage.Map) otelbaggage.Map {
|
func (t *BridgeTracer) baggageGetHook(ctx context.Context, m baggage.Map) baggage.Map {
|
||||||
span := ot.SpanFromContext(ctx)
|
span := ot.SpanFromContext(ctx)
|
||||||
if span == nil {
|
if span == nil {
|
||||||
t.warningHandler("No active OpenTracing span, can not propagate the baggage items from OpenTracing span context\n")
|
t.warningHandler("No active OpenTracing span, can not propagate the baggage items from OpenTracing span context\n")
|
||||||
@ -374,7 +374,7 @@ func (t *BridgeTracer) baggageGetHook(ctx context.Context, m otelbaggage.Map) ot
|
|||||||
for k, v := range items {
|
for k, v := range items {
|
||||||
kv = append(kv, label.String(k, v))
|
kv = append(kv, label.String(k, v))
|
||||||
}
|
}
|
||||||
return m.Apply(otelbaggage.MapUpdate{MultiKV: kv})
|
return m.Apply(baggage.MapUpdate{MultiKV: kv})
|
||||||
}
|
}
|
||||||
|
|
||||||
// StartSpan is a part of the implementation of the OpenTracing Tracer
|
// StartSpan is a part of the implementation of the OpenTracing Tracer
|
||||||
@ -613,7 +613,7 @@ func (t *BridgeTracer) Inject(sm ot.SpanContext, format interface{}, carrier int
|
|||||||
sc: bridgeSC.otelSpanContext,
|
sc: bridgeSC.otelSpanContext,
|
||||||
}
|
}
|
||||||
ctx := oteltrace.ContextWithSpan(context.Background(), fs)
|
ctx := oteltrace.ContextWithSpan(context.Background(), fs)
|
||||||
ctx = otelbaggage.ContextWithMap(ctx, bridgeSC.baggageItems)
|
ctx = baggage.ContextWithMap(ctx, bridgeSC.baggageItems)
|
||||||
t.getPropagator().Inject(ctx, header)
|
t.getPropagator().Inject(ctx, header)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -632,7 +632,7 @@ func (t *BridgeTracer) Extract(format interface{}, carrier interface{}) (ot.Span
|
|||||||
}
|
}
|
||||||
header := http.Header(hhcarrier)
|
header := http.Header(hhcarrier)
|
||||||
ctx := t.getPropagator().Extract(context.Background(), header)
|
ctx := t.getPropagator().Extract(context.Background(), header)
|
||||||
baggage := otelbaggage.MapFromContext(ctx)
|
baggage := baggage.MapFromContext(ctx)
|
||||||
otelSC, _, _ := otelparent.GetSpanContextAndLinks(ctx, false)
|
otelSC, _, _ := otelparent.GetSpanContextAndLinks(ctx, false)
|
||||||
bridgeSC := &bridgeSpanContext{
|
bridgeSC := &bridgeSpanContext{
|
||||||
baggageItems: baggage,
|
baggageItems: baggage,
|
||||||
|
@ -21,9 +21,9 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
otelbaggage "go.opentelemetry.io/otel/api/baggage"
|
|
||||||
oteltrace "go.opentelemetry.io/otel/api/trace"
|
oteltrace "go.opentelemetry.io/otel/api/trace"
|
||||||
"go.opentelemetry.io/otel/codes"
|
"go.opentelemetry.io/otel/codes"
|
||||||
|
"go.opentelemetry.io/otel/internal/baggage"
|
||||||
otelparent "go.opentelemetry.io/otel/internal/trace/parent"
|
otelparent "go.opentelemetry.io/otel/internal/trace/parent"
|
||||||
"go.opentelemetry.io/otel/label"
|
"go.opentelemetry.io/otel/label"
|
||||||
|
|
||||||
@ -45,7 +45,7 @@ type MockContextKeyValue struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type MockTracer struct {
|
type MockTracer struct {
|
||||||
Resources otelbaggage.Map
|
Resources baggage.Map
|
||||||
FinishedSpans []*MockSpan
|
FinishedSpans []*MockSpan
|
||||||
SpareTraceIDs []oteltrace.ID
|
SpareTraceIDs []oteltrace.ID
|
||||||
SpareSpanIDs []oteltrace.SpanID
|
SpareSpanIDs []oteltrace.SpanID
|
||||||
@ -60,7 +60,7 @@ var _ migration.DeferredContextSetupTracerExtension = &MockTracer{}
|
|||||||
|
|
||||||
func NewMockTracer() *MockTracer {
|
func NewMockTracer() *MockTracer {
|
||||||
return &MockTracer{
|
return &MockTracer{
|
||||||
Resources: otelbaggage.NewEmptyMap(),
|
Resources: baggage.NewEmptyMap(),
|
||||||
FinishedSpans: nil,
|
FinishedSpans: nil,
|
||||||
SpareTraceIDs: nil,
|
SpareTraceIDs: nil,
|
||||||
SpareSpanIDs: nil,
|
SpareSpanIDs: nil,
|
||||||
@ -86,7 +86,7 @@ func (t *MockTracer) Start(ctx context.Context, name string, opts ...oteltrace.S
|
|||||||
officialTracer: t,
|
officialTracer: t,
|
||||||
spanContext: spanContext,
|
spanContext: spanContext,
|
||||||
recording: config.Record,
|
recording: config.Record,
|
||||||
Attributes: otelbaggage.NewMap(otelbaggage.MapUpdate{
|
Attributes: baggage.NewMap(baggage.MapUpdate{
|
||||||
MultiKV: config.Attributes,
|
MultiKV: config.Attributes,
|
||||||
}),
|
}),
|
||||||
StartTime: startTime,
|
StartTime: startTime,
|
||||||
@ -179,10 +179,10 @@ func (t *MockTracer) DeferredContextSetupHook(ctx context.Context, span oteltrac
|
|||||||
}
|
}
|
||||||
|
|
||||||
type MockEvent struct {
|
type MockEvent struct {
|
||||||
CtxAttributes otelbaggage.Map
|
CtxAttributes baggage.Map
|
||||||
Timestamp time.Time
|
Timestamp time.Time
|
||||||
Name string
|
Name string
|
||||||
Attributes otelbaggage.Map
|
Attributes baggage.Map
|
||||||
}
|
}
|
||||||
|
|
||||||
type MockSpan struct {
|
type MockSpan struct {
|
||||||
@ -192,7 +192,7 @@ type MockSpan struct {
|
|||||||
SpanKind oteltrace.SpanKind
|
SpanKind oteltrace.SpanKind
|
||||||
recording bool
|
recording bool
|
||||||
|
|
||||||
Attributes otelbaggage.Map
|
Attributes baggage.Map
|
||||||
StartTime time.Time
|
StartTime time.Time
|
||||||
EndTime time.Time
|
EndTime time.Time
|
||||||
ParentSpanID oteltrace.SpanID
|
ParentSpanID oteltrace.SpanID
|
||||||
@ -223,12 +223,12 @@ func (s *MockSpan) SetError(v bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *MockSpan) SetAttributes(attributes ...label.KeyValue) {
|
func (s *MockSpan) SetAttributes(attributes ...label.KeyValue) {
|
||||||
s.applyUpdate(otelbaggage.MapUpdate{
|
s.applyUpdate(baggage.MapUpdate{
|
||||||
MultiKV: attributes,
|
MultiKV: attributes,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *MockSpan) applyUpdate(update otelbaggage.MapUpdate) {
|
func (s *MockSpan) applyUpdate(update baggage.MapUpdate) {
|
||||||
s.Attributes = s.Attributes.Apply(update)
|
s.Attributes = s.Attributes.Apply(update)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,10 +283,10 @@ func (s *MockSpan) AddEvent(ctx context.Context, name string, attrs ...label.Key
|
|||||||
|
|
||||||
func (s *MockSpan) AddEventWithTimestamp(ctx context.Context, timestamp time.Time, name string, attrs ...label.KeyValue) {
|
func (s *MockSpan) AddEventWithTimestamp(ctx context.Context, timestamp time.Time, name string, attrs ...label.KeyValue) {
|
||||||
s.Events = append(s.Events, MockEvent{
|
s.Events = append(s.Events, MockEvent{
|
||||||
CtxAttributes: otelbaggage.MapFromContext(ctx),
|
CtxAttributes: baggage.MapFromContext(ctx),
|
||||||
Timestamp: timestamp,
|
Timestamp: timestamp,
|
||||||
Name: name,
|
Name: name,
|
||||||
Attributes: otelbaggage.NewMap(otelbaggage.MapUpdate{
|
Attributes: baggage.NewMap(baggage.MapUpdate{
|
||||||
MultiKV: attrs,
|
MultiKV: attrs,
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
@ -21,9 +21,9 @@ import (
|
|||||||
|
|
||||||
ot "github.com/opentracing/opentracing-go"
|
ot "github.com/opentracing/opentracing-go"
|
||||||
|
|
||||||
otelbaggage "go.opentelemetry.io/otel/api/baggage"
|
|
||||||
otelglobal "go.opentelemetry.io/otel/api/global"
|
otelglobal "go.opentelemetry.io/otel/api/global"
|
||||||
oteltrace "go.opentelemetry.io/otel/api/trace"
|
oteltrace "go.opentelemetry.io/otel/api/trace"
|
||||||
|
otelbaggage "go.opentelemetry.io/otel/internal/baggage"
|
||||||
"go.opentelemetry.io/otel/label"
|
"go.opentelemetry.io/otel/label"
|
||||||
|
|
||||||
"go.opentelemetry.io/otel/bridge/opentracing/internal"
|
"go.opentelemetry.io/otel/bridge/opentracing/internal"
|
||||||
|
@ -18,12 +18,13 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"go.opentelemetry.io/otel/api/baggage"
|
"go.opentelemetry.io/otel"
|
||||||
"go.opentelemetry.io/otel/api/global"
|
"go.opentelemetry.io/otel/api/global"
|
||||||
"go.opentelemetry.io/otel/api/metric"
|
"go.opentelemetry.io/otel/api/metric"
|
||||||
"go.opentelemetry.io/otel/api/trace"
|
"go.opentelemetry.io/otel/api/trace"
|
||||||
"go.opentelemetry.io/otel/exporters/stdout"
|
"go.opentelemetry.io/otel/exporters/stdout"
|
||||||
"go.opentelemetry.io/otel/label"
|
"go.opentelemetry.io/otel/label"
|
||||||
|
"go.opentelemetry.io/otel/propagators"
|
||||||
"go.opentelemetry.io/otel/sdk/metric/controller/push"
|
"go.opentelemetry.io/otel/sdk/metric/controller/push"
|
||||||
"go.opentelemetry.io/otel/sdk/metric/processor/basic"
|
"go.opentelemetry.io/otel/sdk/metric/processor/basic"
|
||||||
"go.opentelemetry.io/otel/sdk/metric/selector/simple"
|
"go.opentelemetry.io/otel/sdk/metric/selector/simple"
|
||||||
@ -62,7 +63,7 @@ func main() {
|
|||||||
global.SetMeterProvider(pusher.MeterProvider())
|
global.SetMeterProvider(pusher.MeterProvider())
|
||||||
|
|
||||||
// set global propagator to baggage (the default is no-op).
|
// set global propagator to baggage (the default is no-op).
|
||||||
global.SetTextMapPropagator(baggage.Baggage{})
|
global.SetTextMapPropagator(propagators.Baggage{})
|
||||||
tracer := global.Tracer("ex.com/basic")
|
tracer := global.Tracer("ex.com/basic")
|
||||||
meter := global.Meter("ex.com/basic")
|
meter := global.Meter("ex.com/basic")
|
||||||
|
|
||||||
@ -78,11 +79,7 @@ func main() {
|
|||||||
valuerecorderTwo := metric.Must(meter).NewFloat64ValueRecorder("ex.com.two")
|
valuerecorderTwo := metric.Must(meter).NewFloat64ValueRecorder("ex.com.two")
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
ctx = otel.ContextWithBaggageValues(ctx, fooKey.String("foo1"), barKey.String("bar1"))
|
||||||
ctx = baggage.NewContext(ctx,
|
|
||||||
fooKey.String("foo1"),
|
|
||||||
barKey.String("bar1"),
|
|
||||||
)
|
|
||||||
|
|
||||||
valuerecorder := valuerecorderTwo.Bind(commonLabels...)
|
valuerecorder := valuerecorderTwo.Bind(commonLabels...)
|
||||||
defer valuerecorder.Unbind()
|
defer valuerecorder.Unbind()
|
||||||
@ -97,7 +94,7 @@ func main() {
|
|||||||
|
|
||||||
meter.RecordBatch(
|
meter.RecordBatch(
|
||||||
// Note: call-site variables added as context Entries:
|
// Note: call-site variables added as context Entries:
|
||||||
baggage.NewContext(ctx, anotherKey.String("xyz")),
|
otel.ContextWithBaggageValues(ctx, anotherKey.String("xyz")),
|
||||||
commonLabels,
|
commonLabels,
|
||||||
|
|
||||||
valuerecorderTwo.Measurement(2.0),
|
valuerecorderTwo.Measurement(2.0),
|
||||||
|
@ -18,7 +18,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"go.opentelemetry.io/otel/api/baggage"
|
"go.opentelemetry.io/otel"
|
||||||
"go.opentelemetry.io/otel/api/global"
|
"go.opentelemetry.io/otel/api/global"
|
||||||
"go.opentelemetry.io/otel/api/trace"
|
"go.opentelemetry.io/otel/api/trace"
|
||||||
"go.opentelemetry.io/otel/example/namedtracer/foo"
|
"go.opentelemetry.io/otel/example/namedtracer/foo"
|
||||||
@ -64,11 +64,7 @@ func main() {
|
|||||||
// Create a named tracer with package path as its name.
|
// Create a named tracer with package path as its name.
|
||||||
tracer := tp.Tracer("example/namedtracer/main")
|
tracer := tp.Tracer("example/namedtracer/main")
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
ctx = otel.ContextWithBaggageValues(ctx, fooKey.String("foo1"), barKey.String("bar1"))
|
||||||
ctx = baggage.NewContext(ctx,
|
|
||||||
fooKey.String("foo1"),
|
|
||||||
barKey.String("bar1"),
|
|
||||||
)
|
|
||||||
|
|
||||||
var span trace.Span
|
var span trace.Span
|
||||||
ctx, span = tracer.Start(ctx, "operation")
|
ctx, span = tracer.Start(ctx, "operation")
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
// Package baggage provides types and functions to manage W3C Baggage.
|
||||||
package baggage
|
package baggage
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -20,6 +21,165 @@ import (
|
|||||||
"go.opentelemetry.io/otel/label"
|
"go.opentelemetry.io/otel/label"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type rawMap map[label.Key]label.Value
|
||||||
|
type keySet map[label.Key]struct{}
|
||||||
|
|
||||||
|
// Map is an immutable storage for correlations.
|
||||||
|
type Map struct {
|
||||||
|
m rawMap
|
||||||
|
}
|
||||||
|
|
||||||
|
// MapUpdate contains information about correlation changes to be
|
||||||
|
// made.
|
||||||
|
type MapUpdate struct {
|
||||||
|
// DropSingleK contains a single key to be dropped from
|
||||||
|
// correlations. Use this to avoid an overhead of a slice
|
||||||
|
// allocation if there is only one key to drop.
|
||||||
|
DropSingleK label.Key
|
||||||
|
// DropMultiK contains all the keys to be dropped from
|
||||||
|
// correlations.
|
||||||
|
DropMultiK []label.Key
|
||||||
|
|
||||||
|
// SingleKV contains a single key-value pair to be added to
|
||||||
|
// correlations. Use this to avoid an overhead of a slice
|
||||||
|
// allocation if there is only one key-value pair to add.
|
||||||
|
SingleKV label.KeyValue
|
||||||
|
// MultiKV contains all the key-value pairs to be added to
|
||||||
|
// correlations.
|
||||||
|
MultiKV []label.KeyValue
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMap(raw rawMap) Map {
|
||||||
|
return Map{
|
||||||
|
m: raw,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEmptyMap creates an empty correlations map.
|
||||||
|
func NewEmptyMap() Map {
|
||||||
|
return newMap(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMap creates a map with the contents of the update applied. In
|
||||||
|
// this function, having an update with DropSingleK or DropMultiK
|
||||||
|
// makes no sense - those fields are effectively ignored.
|
||||||
|
func NewMap(update MapUpdate) Map {
|
||||||
|
return NewEmptyMap().Apply(update)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply creates a copy of the map with the contents of the update
|
||||||
|
// applied. Apply will first drop the keys from DropSingleK and
|
||||||
|
// DropMultiK, then add key-value pairs from SingleKV and MultiKV.
|
||||||
|
func (m Map) Apply(update MapUpdate) Map {
|
||||||
|
delSet, addSet := getModificationSets(update)
|
||||||
|
mapSize := getNewMapSize(m.m, delSet, addSet)
|
||||||
|
|
||||||
|
r := make(rawMap, mapSize)
|
||||||
|
for k, v := range m.m {
|
||||||
|
// do not copy items we want to drop
|
||||||
|
if _, ok := delSet[k]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// do not copy items we would overwrite
|
||||||
|
if _, ok := addSet[k]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
r[k] = v
|
||||||
|
}
|
||||||
|
if update.SingleKV.Key.Defined() {
|
||||||
|
r[update.SingleKV.Key] = update.SingleKV.Value
|
||||||
|
}
|
||||||
|
for _, kv := range update.MultiKV {
|
||||||
|
r[kv.Key] = kv.Value
|
||||||
|
}
|
||||||
|
if len(r) == 0 {
|
||||||
|
r = nil
|
||||||
|
}
|
||||||
|
return newMap(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getModificationSets(update MapUpdate) (delSet, addSet keySet) {
|
||||||
|
deletionsCount := len(update.DropMultiK)
|
||||||
|
if update.DropSingleK.Defined() {
|
||||||
|
deletionsCount++
|
||||||
|
}
|
||||||
|
if deletionsCount > 0 {
|
||||||
|
delSet = make(map[label.Key]struct{}, deletionsCount)
|
||||||
|
for _, k := range update.DropMultiK {
|
||||||
|
delSet[k] = struct{}{}
|
||||||
|
}
|
||||||
|
if update.DropSingleK.Defined() {
|
||||||
|
delSet[update.DropSingleK] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
additionsCount := len(update.MultiKV)
|
||||||
|
if update.SingleKV.Key.Defined() {
|
||||||
|
additionsCount++
|
||||||
|
}
|
||||||
|
if additionsCount > 0 {
|
||||||
|
addSet = make(map[label.Key]struct{}, additionsCount)
|
||||||
|
for _, k := range update.MultiKV {
|
||||||
|
addSet[k.Key] = struct{}{}
|
||||||
|
}
|
||||||
|
if update.SingleKV.Key.Defined() {
|
||||||
|
addSet[update.SingleKV.Key] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func getNewMapSize(m rawMap, delSet, addSet keySet) int {
|
||||||
|
mapSizeDiff := 0
|
||||||
|
for k := range addSet {
|
||||||
|
if _, ok := m[k]; !ok {
|
||||||
|
mapSizeDiff++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for k := range delSet {
|
||||||
|
if _, ok := m[k]; ok {
|
||||||
|
if _, inAddSet := addSet[k]; !inAddSet {
|
||||||
|
mapSizeDiff--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len(m) + mapSizeDiff
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value gets a value from correlations map and returns a boolean
|
||||||
|
// value indicating whether the key exist in the map.
|
||||||
|
func (m Map) Value(k label.Key) (label.Value, bool) {
|
||||||
|
value, ok := m.m[k]
|
||||||
|
return value, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasValue returns a boolean value indicating whether the key exist
|
||||||
|
// in the map.
|
||||||
|
func (m Map) HasValue(k label.Key) bool {
|
||||||
|
_, has := m.Value(k)
|
||||||
|
return has
|
||||||
|
}
|
||||||
|
|
||||||
|
// Len returns a length of the map.
|
||||||
|
func (m Map) Len() int {
|
||||||
|
return len(m.m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Foreach calls a passed callback once on each key-value pair until
|
||||||
|
// all the key-value pairs of the map were iterated or the callback
|
||||||
|
// returns false, whichever happens first.
|
||||||
|
func (m Map) Foreach(f func(label.KeyValue) bool) {
|
||||||
|
for k, v := range m.m {
|
||||||
|
if !f(label.KeyValue{
|
||||||
|
Key: k,
|
||||||
|
Value: v,
|
||||||
|
}) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type correlationsType struct{}
|
type correlationsType struct{}
|
||||||
|
|
||||||
// SetHookFunc describes a type of a callback that is called when
|
// SetHookFunc describes a type of a callback that is called when
|
||||||
@ -148,6 +308,12 @@ func ContextWithMap(ctx context.Context, m Map) context.Context {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ContextWithNoCorrelationData returns a context stripped of correlation
|
||||||
|
// data.
|
||||||
|
func ContextWithNoCorrelationData(ctx context.Context) context.Context {
|
||||||
|
return context.WithValue(ctx, correlationsKey, nil)
|
||||||
|
}
|
||||||
|
|
||||||
// NewContext returns a context with the map from passed context
|
// NewContext returns a context with the map from passed context
|
||||||
// updated with the passed key-value pairs.
|
// updated with the passed key-value pairs.
|
||||||
func NewContext(ctx context.Context, keyvalues ...label.KeyValue) context.Context {
|
func NewContext(ctx context.Context, keyvalues ...label.KeyValue) context.Context {
|
@ -12,7 +12,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package baggage
|
package propagators
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
@ -20,6 +20,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"go.opentelemetry.io/otel"
|
"go.opentelemetry.io/otel"
|
||||||
|
"go.opentelemetry.io/otel/internal/baggage"
|
||||||
"go.opentelemetry.io/otel/label"
|
"go.opentelemetry.io/otel/label"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -27,15 +28,17 @@ import (
|
|||||||
// https://github.com/open-telemetry/opentelemetry-specification/blob/18b2752ebe6c7f0cdd8c7b2bcbdceb0ae3f5ad95/specification/correlationcontext/api.md#header-name
|
// https://github.com/open-telemetry/opentelemetry-specification/blob/18b2752ebe6c7f0cdd8c7b2bcbdceb0ae3f5ad95/specification/correlationcontext/api.md#header-name
|
||||||
const baggageHeader = "otcorrelations"
|
const baggageHeader = "otcorrelations"
|
||||||
|
|
||||||
// Baggage propagates Key:Values in W3C CorrelationContext format.
|
// Baggage is a propagator that supports the W3C Baggage format.
|
||||||
// nolint:golint
|
//
|
||||||
|
// This propagates user-defined baggage associated with a trace. The complete
|
||||||
|
// specification is defined at https://w3c.github.io/baggage/.
|
||||||
type Baggage struct{}
|
type Baggage struct{}
|
||||||
|
|
||||||
var _ otel.TextMapPropagator = Baggage{}
|
var _ otel.TextMapPropagator = Baggage{}
|
||||||
|
|
||||||
// Inject set baggage key-values from the Context into the carrier.
|
// Inject sets baggage key-values from ctx into the carrier.
|
||||||
func (b Baggage) Inject(ctx context.Context, carrier otel.TextMapCarrier) {
|
func (b Baggage) Inject(ctx context.Context, carrier otel.TextMapCarrier) {
|
||||||
baggageMap := MapFromContext(ctx)
|
baggageMap := baggage.MapFromContext(ctx)
|
||||||
firstIter := true
|
firstIter := true
|
||||||
var headerValueBuilder strings.Builder
|
var headerValueBuilder strings.Builder
|
||||||
baggageMap.Foreach(func(kv label.KeyValue) bool {
|
baggageMap.Foreach(func(kv label.KeyValue) bool {
|
||||||
@ -54,14 +57,14 @@ func (b Baggage) Inject(ctx context.Context, carrier otel.TextMapCarrier) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract reads baggage key-values from the carrier into a returned Context.
|
// Extract returns a copy of parent with the baggage from the carrier added.
|
||||||
func (b Baggage) Extract(ctx context.Context, carrier otel.TextMapCarrier) context.Context {
|
func (b Baggage) Extract(parent context.Context, carrier otel.TextMapCarrier) context.Context {
|
||||||
baggage := carrier.Get(baggageHeader)
|
bVal := carrier.Get(baggageHeader)
|
||||||
if baggage == "" {
|
if bVal == "" {
|
||||||
return ctx
|
return parent
|
||||||
}
|
}
|
||||||
|
|
||||||
baggageValues := strings.Split(baggage, ",")
|
baggageValues := strings.Split(bVal, ",")
|
||||||
keyValues := make([]label.KeyValue, 0, len(baggageValues))
|
keyValues := make([]label.KeyValue, 0, len(baggageValues))
|
||||||
for _, baggageValue := range baggageValues {
|
for _, baggageValue := range baggageValues {
|
||||||
valueAndProps := strings.Split(baggageValue, ";")
|
valueAndProps := strings.Split(baggageValue, ";")
|
||||||
@ -97,12 +100,12 @@ func (b Baggage) Extract(ctx context.Context, carrier otel.TextMapCarrier) conte
|
|||||||
|
|
||||||
if len(keyValues) > 0 {
|
if len(keyValues) > 0 {
|
||||||
// Only update the context if valid values were found
|
// Only update the context if valid values were found
|
||||||
return ContextWithMap(ctx, NewMap(MapUpdate{
|
return baggage.ContextWithMap(parent, baggage.NewMap(baggage.MapUpdate{
|
||||||
MultiKV: keyValues,
|
MultiKV: keyValues,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
return ctx
|
return parent
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fields returns the keys who's values are set with Inject.
|
// Fields returns the keys who's values are set with Inject.
|
@ -12,7 +12,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package baggage_test
|
package propagators_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
@ -23,12 +23,13 @@ import (
|
|||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
|
|
||||||
"go.opentelemetry.io/otel"
|
"go.opentelemetry.io/otel"
|
||||||
"go.opentelemetry.io/otel/api/baggage"
|
"go.opentelemetry.io/otel/internal/baggage"
|
||||||
"go.opentelemetry.io/otel/label"
|
"go.opentelemetry.io/otel/label"
|
||||||
|
"go.opentelemetry.io/otel/propagators"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestExtractValidBaggageFromHTTPReq(t *testing.T) {
|
func TestExtractValidBaggageFromHTTPReq(t *testing.T) {
|
||||||
prop := otel.TextMapPropagator(baggage.Baggage{})
|
prop := otel.TextMapPropagator(propagators.Baggage{})
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
header string
|
header string
|
||||||
@ -117,7 +118,7 @@ func TestExtractValidBaggageFromHTTPReq(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestExtractInvalidDistributedContextFromHTTPReq(t *testing.T) {
|
func TestExtractInvalidDistributedContextFromHTTPReq(t *testing.T) {
|
||||||
prop := otel.TextMapPropagator(baggage.Baggage{})
|
prop := otel.TextMapPropagator(propagators.Baggage{})
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
header string
|
header string
|
||||||
@ -175,7 +176,7 @@ func TestExtractInvalidDistributedContextFromHTTPReq(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestInjectBaggageToHTTPReq(t *testing.T) {
|
func TestInjectBaggageToHTTPReq(t *testing.T) {
|
||||||
propagator := baggage.Baggage{}
|
propagator := propagators.Baggage{}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
kvs []label.KeyValue
|
kvs []label.KeyValue
|
||||||
@ -248,8 +249,8 @@ func TestInjectBaggageToHTTPReq(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTraceContextPropagator_GetAllKeys(t *testing.T) {
|
func TestBaggagePropagatorGetAllKeys(t *testing.T) {
|
||||||
var propagator baggage.Baggage
|
var propagator propagators.Baggage
|
||||||
want := []string{"otcorrelations"}
|
want := []string{"otcorrelations"}
|
||||||
got := propagator.Fields()
|
got := propagator.Fields()
|
||||||
if diff := cmp.Diff(got, want); diff != "" {
|
if diff := cmp.Diff(got, want); diff != "" {
|
@ -17,6 +17,8 @@ Package propagators contains OpenTelemetry context propagators.
|
|||||||
|
|
||||||
OpenTelemetry propagators are used to extract and inject context data from and
|
OpenTelemetry propagators are used to extract and inject context data from and
|
||||||
into messages exchanged by applications. The propagator supported by this
|
into messages exchanged by applications. The propagator supported by this
|
||||||
package is the W3C Trace Context encoding (https://www.w3.org/TR/trace-context/).
|
package is the W3C Trace Context encoding
|
||||||
|
(https://www.w3.org/TR/trace-context/), and W3C Baggage
|
||||||
|
(https://w3c.github.io/baggage/).
|
||||||
*/
|
*/
|
||||||
package propagators // import "go.opentelemetry.io/otel/propagators"
|
package propagators // import "go.opentelemetry.io/otel/propagators"
|
||||||
|
Reference in New Issue
Block a user