From 66414ef4828e1254a1b72c7c0973be00cdc04471 Mon Sep 17 00:00:00 2001 From: Krzesimir Nowak Date: Wed, 6 Nov 2019 20:34:29 +0100 Subject: [PATCH 1/7] ignore propagation stuff --- api/propagation/doc.go | 2 ++ api/propagation/noop_propagator.go | 2 ++ api/propagation/propagator.go | 2 ++ propagation/binary_propagator.go | 2 ++ propagation/binary_propagator_test.go | 2 ++ propagation/doc.go | 2 ++ propagation/http_b3_propagator.go | 2 ++ propagation/http_b3_propagator_benchmark_test.go | 2 ++ propagation/http_b3_propagator_data_test.go | 2 ++ propagation/http_b3_propagator_test.go | 2 ++ propagation/http_trace_context_propagator.go | 2 ++ propagation/http_trace_context_propagator_benchmark_test.go | 2 ++ propagation/http_trace_context_propagator_test.go | 2 ++ 13 files changed, 26 insertions(+) diff --git a/api/propagation/doc.go b/api/propagation/doc.go index 460d7fe97b3..3eb1ec96463 100644 --- a/api/propagation/doc.go +++ b/api/propagation/doc.go @@ -12,5 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +// +build ignore + // Package propagation contains interface definition for Binary and TextFormat propagators. package propagation // import "go.opentelemetry.io/otel/api/propagation" diff --git a/api/propagation/noop_propagator.go b/api/propagation/noop_propagator.go index 77576b2cfa6..ae137729c4d 100644 --- a/api/propagation/noop_propagator.go +++ b/api/propagation/noop_propagator.go @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +// +build ignore + package propagation import ( diff --git a/api/propagation/propagator.go b/api/propagation/propagator.go index ddefe1f8b05..ade67258b1b 100644 --- a/api/propagation/propagator.go +++ b/api/propagation/propagator.go @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +// +build ignore + package propagation import ( diff --git a/propagation/binary_propagator.go b/propagation/binary_propagator.go index e6108b26692..c2adaa5c357 100644 --- a/propagation/binary_propagator.go +++ b/propagation/binary_propagator.go @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +// +build ignore + package propagation import ( diff --git a/propagation/binary_propagator_test.go b/propagation/binary_propagator_test.go index 94f5e21ee8e..05ffa31b4d7 100644 --- a/propagation/binary_propagator_test.go +++ b/propagation/binary_propagator_test.go @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +// +build ignore + package propagation_test import ( diff --git a/propagation/doc.go b/propagation/doc.go index 78315a8b40f..0ed382bdb39 100644 --- a/propagation/doc.go +++ b/propagation/doc.go @@ -12,5 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +// +build ignore + // Package propagation contains propagators for different format and carriers. package propagation // import "go.opentelemetry.io/otel/propagation" diff --git a/propagation/http_b3_propagator.go b/propagation/http_b3_propagator.go index 227f7f7d795..89967f532b0 100644 --- a/propagation/http_b3_propagator.go +++ b/propagation/http_b3_propagator.go @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +// +build ignore + package propagation import ( diff --git a/propagation/http_b3_propagator_benchmark_test.go b/propagation/http_b3_propagator_benchmark_test.go index dd61c420166..743bebeb501 100644 --- a/propagation/http_b3_propagator_benchmark_test.go +++ b/propagation/http_b3_propagator_benchmark_test.go @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +// +build ignore + package propagation_test import ( diff --git a/propagation/http_b3_propagator_data_test.go b/propagation/http_b3_propagator_data_test.go index bab850f460f..7df100a75d4 100644 --- a/propagation/http_b3_propagator_data_test.go +++ b/propagation/http_b3_propagator_data_test.go @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +// +build ignore + package propagation_test import ( diff --git a/propagation/http_b3_propagator_test.go b/propagation/http_b3_propagator_test.go index 4b491a2190b..7223327de90 100644 --- a/propagation/http_b3_propagator_test.go +++ b/propagation/http_b3_propagator_test.go @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +// +build ignore + package propagation_test import ( diff --git a/propagation/http_trace_context_propagator.go b/propagation/http_trace_context_propagator.go index 86014f7f31c..748bdeaa4b4 100644 --- a/propagation/http_trace_context_propagator.go +++ b/propagation/http_trace_context_propagator.go @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +// +build ignore + package propagation import ( diff --git a/propagation/http_trace_context_propagator_benchmark_test.go b/propagation/http_trace_context_propagator_benchmark_test.go index 74b1e587382..fee1dbadbe2 100644 --- a/propagation/http_trace_context_propagator_benchmark_test.go +++ b/propagation/http_trace_context_propagator_benchmark_test.go @@ -1,3 +1,5 @@ +// +build ignore + package propagation import ( diff --git a/propagation/http_trace_context_propagator_test.go b/propagation/http_trace_context_propagator_test.go index bcb148554a5..d9dcad6af4f 100644 --- a/propagation/http_trace_context_propagator_test.go +++ b/propagation/http_trace_context_propagator_test.go @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +// +build ignore + package propagation_test import ( From a5d60f430854269ab2bf3933855fd625f9571243 Mon Sep 17 00:00:00 2001 From: Krzesimir Nowak Date: Wed, 6 Nov 2019 11:16:51 +0100 Subject: [PATCH 2/7] update distributed context --- api/distributedcontext/baggage.go | 110 +++++++++++++++++++++ api/distributedcontext/context.go | 50 +++++++--- api/distributedcontext/correlations.go | 131 +++++++++++++++++++++++++ api/distributedcontext/map.go | 94 ------------------ api/distributedcontext/map_test.go | 2 + 5 files changed, 279 insertions(+), 108 deletions(-) create mode 100644 api/distributedcontext/baggage.go create mode 100644 api/distributedcontext/correlations.go delete mode 100644 api/distributedcontext/map.go diff --git a/api/distributedcontext/baggage.go b/api/distributedcontext/baggage.go new file mode 100644 index 00000000000..ca4b7a617ca --- /dev/null +++ b/api/distributedcontext/baggage.go @@ -0,0 +1,110 @@ +// Copyright 2019, 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 distributedcontext + +import ( + "go.opentelemetry.io/otel/api/core" +) + +type rawBaggageMap map[core.Key]core.Value + +type Baggage struct { + m rawBaggageMap +} + +type BaggageUpdate struct { + DropSingleK core.Key + DropMultiK []core.Key + + SingleKV core.KeyValue + MultiKV []core.KeyValue + Map Baggage +} + +func newBaggage(raw rawBaggageMap) Baggage { + return Baggage{ + m: raw, + } +} + +func NewEmptyBaggage() Baggage { + return newBaggage(nil) +} + +func NewBaggage(update BaggageUpdate) Baggage { + return NewEmptyBaggage().Apply(update) +} + +func (m Baggage) Apply(update BaggageUpdate) Baggage { + r := make(rawBaggageMap, len(m.m)+len(update.MultiKV)+update.Map.Len()) + for k, v := range m.m { + r[k] = v + } + if update.DropSingleK.Defined() { + delete(r, update.DropSingleK) + } + for _, k := range update.DropMultiK { + delete(r, k) + } + if update.SingleKV.Key.Defined() { + r[update.SingleKV.Key] = update.SingleKV.Value + } + for _, kv := range update.MultiKV { + r[kv.Key] = kv.Value + } + for k, v := range update.Map.m { + r[k] = v + } + if len(r) == 0 { + r = nil + } + return newBaggage(r) +} + +func (m Baggage) Value(k core.Key) (core.Value, bool) { + v, ok := m.m[k] + return v, ok +} + +func (m Baggage) HasValue(k core.Key) bool { + _, has := m.Value(k) + return has +} + +func (m Baggage) Len() int { + return len(m.m) +} + +func (m Baggage) Foreach(f func(kv core.KeyValue) bool) { + for k, v := range m.m { + if !f(core.KeyValue{ + Key: k, + Value: v, + }) { + return + } + } +} + +func (m Baggage) KeyValues() []core.KeyValue { + a := make([]core.KeyValue, 0, len(m.m)) + for k, v := range m.m { + a = append(a, core.KeyValue{ + Key: k, + Value: v, + }) + } + return a +} diff --git a/api/distributedcontext/context.go b/api/distributedcontext/context.go index e1e62ff4f8e..736ba29871c 100644 --- a/api/distributedcontext/context.go +++ b/api/distributedcontext/context.go @@ -16,34 +16,55 @@ package distributedcontext import ( "context" - "runtime/pprof" - - "go.opentelemetry.io/otel/api/core" ) -type ctxEntriesType struct{} +type ( + ctxCorrelationsType struct{} + ctxBaggageType struct{} +) var ( - ctxEntriesKey = &ctxEntriesType{} + ctxCorrelationsKey = &ctxCorrelationsType{} + ctxBaggageKey = &ctxBaggageType{} ) -func WithMap(ctx context.Context, m Map) context.Context { - return context.WithValue(ctx, ctxEntriesKey, m) +func NewCorrelationsContextKV(ctx context.Context, correlations ...Correlation) context.Context { + return withCorrelationsMapUpdate(ctx, CorrelationsUpdate{ + MultiKV: correlations, + }) } -func NewContext(ctx context.Context, keyvalues ...core.KeyValue) context.Context { - return WithMap(ctx, FromContext(ctx).Apply(MapUpdate{ - MultiKV: keyvalues, - })) +func NewCorrelationsContextMap(ctx context.Context, correlations Correlations) context.Context { + return withCorrelationsMapUpdate(ctx, CorrelationsUpdate{ + Map: correlations, + }) } -func FromContext(ctx context.Context) Map { - if m, ok := ctx.Value(ctxEntriesKey).(Map); ok { +func CorrelationsFromContext(ctx context.Context) Correlations { + if m, ok := ctx.Value(ctxCorrelationsKey).(Correlations); ok { return m } - return NewEmptyMap() + return NewEmptyCorrelations() +} + +func NewBaggageContext(ctx context.Context, baggage Baggage) context.Context { + return context.WithValue(ctx, ctxBaggageKey, baggage) } +func BaggageFromContext(ctx context.Context) Baggage { + if m, ok := ctx.Value(ctxBaggageKey).(Baggage); ok { + return m + } + return NewEmptyBaggage() +} + +func withCorrelationsMapUpdate(ctx context.Context, update CorrelationsUpdate) context.Context { + return context.WithValue(ctx, ctxCorrelationsKey, CorrelationsFromContext(ctx).Apply(update)) +} + +/* +// TODO(krnowak): I don't know what's the point of this function… + // Note: the golang pprof.Do API forces this memory allocation, we // should file an issue about that. (There's a TODO in the source.) func Do(ctx context.Context, f func(ctx context.Context)) { @@ -54,3 +75,4 @@ func Do(ctx context.Context, f func(ctx context.Context)) { } pprof.Do(ctx, pprof.Labels(keyvals...), f) } +*/ diff --git a/api/distributedcontext/correlations.go b/api/distributedcontext/correlations.go new file mode 100644 index 00000000000..ab55bbb1e73 --- /dev/null +++ b/api/distributedcontext/correlations.go @@ -0,0 +1,131 @@ +// Copyright 2019, 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 distributedcontext + +import ( + "go.opentelemetry.io/otel/api/core" +) + +type HopLimit int + +const ( + NoPropagation HopLimit = iota + UnlimitedPropagation +) + +type CorrelationValue struct { + core.Value + HopLimit HopLimit +} + +type Correlation struct { + core.KeyValue + HopLimit HopLimit +} + +func (c *Correlation) CorrelationValue() CorrelationValue { + return CorrelationValue{ + Value: c.Value, + HopLimit: c.HopLimit, + } +} + +type rawCorrelationsMap map[core.Key]CorrelationValue + +type Correlations struct { + m rawCorrelationsMap +} + +type CorrelationsUpdate struct { + SingleKV Correlation + MultiKV []Correlation + Map Correlations +} + +func newCorrelations(raw rawCorrelationsMap) Correlations { + return Correlations{ + m: raw, + } +} + +func NewEmptyCorrelations() Correlations { + return newCorrelations(nil) +} + +func NewCorrelations(update CorrelationsUpdate) Correlations { + return NewEmptyCorrelations().Apply(update) +} + +func (m Correlations) Apply(update CorrelationsUpdate) Correlations { + r := make(rawCorrelationsMap, len(m.m)+len(update.MultiKV)+update.Map.Len()) + for k, v := range m.m { + r[k] = v + } + if update.SingleKV.Key.Defined() { + r[update.SingleKV.Key] = update.SingleKV.CorrelationValue() + } + for _, kv := range update.MultiKV { + r[kv.Key] = kv.CorrelationValue() + } + for k, v := range update.Map.m { + r[k] = v + } + if len(r) == 0 { + r = nil + } + return newCorrelations(r) +} + +func (m Correlations) Value(k core.Key) (CorrelationValue, bool) { + v, ok := m.m[k] + return v, ok +} + +func (m Correlations) HasValue(k core.Key) bool { + _, has := m.Value(k) + return has +} + +func (m Correlations) Len() int { + return len(m.m) +} + +func (m Correlations) Foreach(f func(kv Correlation) bool) { + for k, v := range m.m { + if !f(Correlation{ + KeyValue: core.KeyValue{ + Key: k, + Value: v.Value, + }, + HopLimit: v.HopLimit, + }) { + return + } + } +} + +func (m Correlations) Correlations() []Correlation { + a := make([]Correlation, 0, len(m.m)) + for k, v := range m.m { + a = append(a, Correlation{ + KeyValue: core.KeyValue{ + Key: k, + Value: v.Value, + }, + HopLimit: v.HopLimit, + }) + } + return a +} diff --git a/api/distributedcontext/map.go b/api/distributedcontext/map.go deleted file mode 100644 index 8dff15689ed..00000000000 --- a/api/distributedcontext/map.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2019, 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 distributedcontext - -import ( - "go.opentelemetry.io/otel/api/core" -) - -type entry struct { - value core.Value -} - -type rawMap map[core.Key]entry - -type Map struct { - m rawMap -} - -type MapUpdate struct { - SingleKV core.KeyValue - MultiKV []core.KeyValue -} - -func newMap(raw rawMap) Map { - return Map{ - m: raw, - } -} - -func NewEmptyMap() Map { - return newMap(nil) -} - -func NewMap(update MapUpdate) Map { - return NewEmptyMap().Apply(update) -} - -func (m Map) Apply(update MapUpdate) Map { - r := make(rawMap, len(m.m)+len(update.MultiKV)) - for k, v := range m.m { - r[k] = v - } - if update.SingleKV.Key.Defined() { - r[update.SingleKV.Key] = entry{ - value: update.SingleKV.Value, - } - } - for _, kv := range update.MultiKV { - r[kv.Key] = entry{ - value: kv.Value, - } - } - if len(r) == 0 { - r = nil - } - return newMap(r) -} - -func (m Map) Value(k core.Key) (core.Value, bool) { - entry, ok := m.m[k] - return entry.value, ok -} - -func (m Map) HasValue(k core.Key) bool { - _, has := m.Value(k) - return has -} - -func (m Map) Len() int { - return len(m.m) -} - -func (m Map) Foreach(f func(kv core.KeyValue) bool) { - for k, v := range m.m { - if !f(core.KeyValue{ - Key: k, - Value: v.value, - }) { - return - } - } -} diff --git a/api/distributedcontext/map_test.go b/api/distributedcontext/map_test.go index 172cdd73443..9afe3597dc9 100644 --- a/api/distributedcontext/map_test.go +++ b/api/distributedcontext/map_test.go @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +// +build ignore + package distributedcontext import ( From 5e4aeb7b5b9605a341e2fff570745c3a9e099c37 Mon Sep 17 00:00:00 2001 From: Krzesimir Nowak Date: Wed, 6 Nov 2019 20:34:58 +0100 Subject: [PATCH 3/7] new propagators stuff --- api/propagation/binary/noop.go | 78 ++++++++ api/propagation/binary/propagators.go | 68 +++++++ api/propagation/binary/propagators_test.go | 52 +++++ api/propagation/http/noop.go | 74 +++++++ api/propagation/http/propagators.go | 156 +++++++++++++++ api/propagation/http/propagators_test.go | 50 +++++ propagation/binary/propagator.go | 71 +++++++ propagation/http/b3_propagators.go | 196 ++++++++++++++++++ propagation/http/trace_context_propagator.go | 198 +++++++++++++++++++ 9 files changed, 943 insertions(+) create mode 100644 api/propagation/binary/noop.go create mode 100644 api/propagation/binary/propagators.go create mode 100644 api/propagation/binary/propagators_test.go create mode 100644 api/propagation/http/noop.go create mode 100644 api/propagation/http/propagators.go create mode 100644 api/propagation/http/propagators_test.go create mode 100644 propagation/binary/propagator.go create mode 100644 propagation/http/b3_propagators.go create mode 100644 propagation/http/trace_context_propagator.go diff --git a/api/propagation/binary/noop.go b/api/propagation/binary/noop.go new file mode 100644 index 00000000000..fbda1129d7f --- /dev/null +++ b/api/propagation/binary/noop.go @@ -0,0 +1,78 @@ +// Copyright 2019, 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 binary + +import ( + "go.opentelemetry.io/otel/api/core" + dctx "go.opentelemetry.io/otel/api/distributedcontext" +) + +type ( + NoopSpanContextPropagator struct{} + NoopCorrelationsPropagator struct{} + NoopBaggagePropagator struct{} + NoopPropagator struct{} +) + +var ( + _ SpanContextPropagator = NoopSpanContextPropagator{} + _ CorrelationsPropagator = NoopCorrelationsPropagator{} + _ BaggagePropagator = NoopBaggagePropagator{} + _ Propagator = NoopPropagator{} +) + +func (NoopSpanContextPropagator) ToBytes(core.SpanContext) []byte { + return nil +} + +func (NoopSpanContextPropagator) FromBytes([]byte) core.SpanContext { + return core.EmptySpanContext() +} + +func (NoopCorrelationsPropagator) ToBytes(dctx.Correlations) []byte { + return nil +} + +func (NoopCorrelationsPropagator) FromBytes([]byte) dctx.Correlations { + return dctx.NewEmptyCorrelations() +} + +func (NoopBaggagePropagator) ToBytes(dctx.Baggage) []byte { + return nil +} + +func (NoopBaggagePropagator) FromBytes([]byte) dctx.Baggage { + return dctx.NewEmptyBaggage() +} + +func (NoopPropagator) ToBytes(core.SpanContext, dctx.Correlations, dctx.Baggage) []byte { + return nil +} + +func (NoopPropagator) FromBytes([]byte) (core.SpanContext, dctx.Correlations, dctx.Baggage) { + return core.EmptySpanContext(), dctx.NewEmptyCorrelations(), dctx.NewEmptyBaggage() +} + +func (NoopPropagator) SpanContextPropagator() SpanContextPropagator { + return NoopSpanContextPropagator{} +} + +func (NoopPropagator) CorrelationsPropagator() CorrelationsPropagator { + return NoopCorrelationsPropagator{} +} + +func (NoopPropagator) BaggagePropagator() BaggagePropagator { + return NoopBaggagePropagator{} +} diff --git a/api/propagation/binary/propagators.go b/api/propagation/binary/propagators.go new file mode 100644 index 00000000000..d1f4ae65e18 --- /dev/null +++ b/api/propagation/binary/propagators.go @@ -0,0 +1,68 @@ +// Copyright 2019, 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 binary + +import ( + "go.opentelemetry.io/otel/api/core" + dctx "go.opentelemetry.io/otel/api/distributedcontext" +) + +// SpanContextPropagator is an interface that specifies methods to +// convert SpanContext to/from byte array. +type SpanContextPropagator interface { + // ToBytes serializes span context into a byte array and + // returns the array. + ToBytes(core.SpanContext) []byte + + // FromBytes de-serializes byte array into span context and + // returns the span context. + FromBytes([]byte) core.SpanContext +} + +type CorrelationsPropagator interface { + ToBytes(dctx.Correlations) []byte + FromBytes([]byte) dctx.Correlations +} + +type BaggagePropagator interface { + ToBytes(dctx.Baggage) []byte + FromBytes([]byte) dctx.Baggage +} + +type Propagator interface { + ToBytes(core.SpanContext, dctx.Correlations, dctx.Baggage) []byte + FromBytes([]byte) (core.SpanContext, dctx.Correlations, dctx.Baggage) + SpanContextPropagator() SpanContextPropagator + CorrelationsPropagator() CorrelationsPropagator + BaggagePropagator() BaggagePropagator +} + +type Propagators struct { + Scp SpanContextPropagator + Cp CorrelationsPropagator + Bp BaggagePropagator +} + +func (p Propagators) SpanContextPropagator() SpanContextPropagator { + return p.Scp +} + +func (p Propagators) CorrelationsPropagator() CorrelationsPropagator { + return p.Cp +} + +func (p Propagators) BaggagePropagator() BaggagePropagator { + return p.Bp +} diff --git a/api/propagation/binary/propagators_test.go b/api/propagation/binary/propagators_test.go new file mode 100644 index 00000000000..421e387475c --- /dev/null +++ b/api/propagation/binary/propagators_test.go @@ -0,0 +1,52 @@ +// Copyright 2019, 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 binary_test + +import ( + "go.opentelemetry.io/otel/api/core" + dctx "go.opentelemetry.io/otel/api/distributedcontext" + "go.opentelemetry.io/otel/api/propagation/binary" +) + +type ( + testValuePropagator struct { + binary.Propagators + } + + testPointerPropagator struct { + binary.Propagators + } +) + +var ( + _ binary.Propagator = testValuePropagator{} + _ binary.Propagator = &testPointerPropagator{} +) + +func (testValuePropagator) ToBytes(core.SpanContext, dctx.Correlations, dctx.Baggage) []byte { + return nil +} + +func (testValuePropagator) FromBytes([]byte) (core.SpanContext, dctx.Correlations, dctx.Baggage) { + return core.EmptySpanContext(), dctx.NewEmptyCorrelations(), dctx.NewEmptyBaggage() +} + +func (*testPointerPropagator) ToBytes(core.SpanContext, dctx.Correlations, dctx.Baggage) []byte { + return nil +} + +func (*testPointerPropagator) FromBytes([]byte) (core.SpanContext, dctx.Correlations, dctx.Baggage) { + return core.EmptySpanContext(), dctx.NewEmptyCorrelations(), dctx.NewEmptyBaggage() +} diff --git a/api/propagation/http/noop.go b/api/propagation/http/noop.go new file mode 100644 index 00000000000..71628dbc0b3 --- /dev/null +++ b/api/propagation/http/noop.go @@ -0,0 +1,74 @@ +// Copyright 2019, 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 http + +import ( + "go.opentelemetry.io/otel/api/core" + dctx "go.opentelemetry.io/otel/api/distributedcontext" +) + +type ( + NoopSpanContextPropagator struct{} + NoopCorrelationsPropagator struct{} + NoopBaggagePropagator struct{} + NoopPropagator struct{} +) + +var ( + _ SpanContextPropagator = NoopSpanContextPropagator{} + _ CorrelationsPropagator = NoopCorrelationsPropagator{} + _ BaggagePropagator = NoopBaggagePropagator{} + _ Propagator = NoopPropagator{} +) + +func (NoopSpanContextPropagator) Inject(core.SpanContext, Supplier) { +} + +func (NoopSpanContextPropagator) Extract(Supplier) core.SpanContext { + return core.EmptySpanContext() +} + +func (NoopCorrelationsPropagator) Inject(dctx.Correlations, Supplier) { +} + +func (NoopCorrelationsPropagator) Extract(Supplier) dctx.Correlations { + return dctx.NewEmptyCorrelations() +} + +func (NoopBaggagePropagator) Inject(dctx.Baggage, Supplier) { +} + +func (NoopBaggagePropagator) Extract(Supplier) dctx.Baggage { + return dctx.NewEmptyBaggage() +} + +func (NoopPropagator) Inject(core.SpanContext, dctx.Correlations, dctx.Baggage, Supplier) { +} + +func (NoopPropagator) Extract(Supplier) (core.SpanContext, dctx.Correlations, dctx.Baggage) { + return core.EmptySpanContext(), dctx.NewEmptyCorrelations(), dctx.NewEmptyBaggage() +} + +func (NoopPropagator) SpanContextPropagator() SpanContextPropagator { + return NoopSpanContextPropagator{} +} + +func (NoopPropagator) CorrelationsPropagator() CorrelationsPropagator { + return NoopCorrelationsPropagator{} +} + +func (NoopPropagator) BaggagePropagator() BaggagePropagator { + return NoopBaggagePropagator{} +} diff --git a/api/propagation/http/propagators.go b/api/propagation/http/propagators.go new file mode 100644 index 00000000000..c3a9316194e --- /dev/null +++ b/api/propagation/http/propagators.go @@ -0,0 +1,156 @@ +// Copyright 2019, 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 http + +import ( + "go.opentelemetry.io/otel/api/core" + dctx "go.opentelemetry.io/otel/api/distributedcontext" +) + +// Supplier is an interface that specifies methods to retrieve and store +// value for a key to an associated carrier. +// Get method retrieves the value for a given key. +// Set method stores the value for a given key. +type Supplier interface { + Get(key string) string + Set(key, value string) +} + +// SpanContextPropagator is an interface that specifies methods to +// convert SpanContext to/from byte array. +type SpanContextPropagator interface { + Inject(core.SpanContext, Supplier) + Extract(Supplier) core.SpanContext +} + +type chainSpanContextPropagator struct { + propagators []SpanContextPropagator +} + +var _ SpanContextPropagator = chainSpanContextPropagator{} + +func NewChainSpanContextPropagator(propagators ...SpanContextPropagator) SpanContextPropagator { + return chainSpanContextPropagator{ + propagators: propagators, + } +} + +func (c chainSpanContextPropagator) Inject(sc core.SpanContext, supplier Supplier) { + for _, p := range c.propagators { + p.Inject(sc, supplier) + } +} + +func (c chainSpanContextPropagator) Extract(supplier Supplier) core.SpanContext { + for _, p := range c.propagators { + if sc := p.Extract(supplier); sc.IsValid() { + return sc + } + } + + return core.EmptySpanContext() +} + +type CorrelationsPropagator interface { + Inject(dctx.Correlations, Supplier) + Extract(Supplier) dctx.Correlations +} + +type chainCorrelationsPropagator struct { + propagators []CorrelationsPropagator +} + +var _ CorrelationsPropagator = chainCorrelationsPropagator{} + +func NewChainCorrelationsPropagator(propagators ...CorrelationsPropagator) CorrelationsPropagator { + return chainCorrelationsPropagator{ + propagators: propagators, + } +} + +func (c chainCorrelationsPropagator) Inject(correlations dctx.Correlations, supplier Supplier) { + for _, p := range c.propagators { + p.Inject(correlations, supplier) + } +} + +func (c chainCorrelationsPropagator) Extract(supplier Supplier) dctx.Correlations { + for _, p := range c.propagators { + if correlations := p.Extract(supplier); correlations.Len() > 0 { + return correlations + } + } + + return dctx.NewEmptyCorrelations() +} + +type BaggagePropagator interface { + Inject(dctx.Baggage, Supplier) + Extract(Supplier) dctx.Baggage +} + +type chainBaggagePropagator struct { + propagators []BaggagePropagator +} + +var _ BaggagePropagator = chainBaggagePropagator{} + +func NewChainBaggagePropagator(propagators ...BaggagePropagator) BaggagePropagator { + return chainBaggagePropagator{ + propagators: propagators, + } +} + +func (c chainBaggagePropagator) Inject(baggage dctx.Baggage, supplier Supplier) { + for _, p := range c.propagators { + p.Inject(baggage, supplier) + } +} + +func (c chainBaggagePropagator) Extract(supplier Supplier) dctx.Baggage { + for _, p := range c.propagators { + if baggage := p.Extract(supplier); baggage.Len() > 0 { + return baggage + } + } + + return dctx.NewEmptyBaggage() +} + +type Propagator interface { + Inject(core.SpanContext, dctx.Correlations, dctx.Baggage, Supplier) + Extract(Supplier) (core.SpanContext, dctx.Correlations, dctx.Baggage) + SpanContextPropagator() SpanContextPropagator + CorrelationsPropagator() CorrelationsPropagator + BaggagePropagator() BaggagePropagator +} + +type Propagators struct { + Scp SpanContextPropagator + Cp CorrelationsPropagator + Bp BaggagePropagator +} + +func (p Propagators) SpanContextPropagator() SpanContextPropagator { + return p.Scp +} + +func (p Propagators) CorrelationsPropagator() CorrelationsPropagator { + return p.Cp +} + +func (p Propagators) BaggagePropagator() BaggagePropagator { + return p.Bp +} diff --git a/api/propagation/http/propagators_test.go b/api/propagation/http/propagators_test.go new file mode 100644 index 00000000000..e132a43b1ce --- /dev/null +++ b/api/propagation/http/propagators_test.go @@ -0,0 +1,50 @@ +// Copyright 2019, 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 http_test + +import ( + "go.opentelemetry.io/otel/api/core" + dctx "go.opentelemetry.io/otel/api/distributedcontext" + "go.opentelemetry.io/otel/api/propagation/http" +) + +type ( + testValuePropagator struct { + http.Propagators + } + + testPointerPropagator struct { + http.Propagators + } +) + +var ( + _ http.Propagator = testValuePropagator{} + _ http.Propagator = &testPointerPropagator{} +) + +func (testValuePropagator) Inject(core.SpanContext, dctx.Correlations, dctx.Baggage, http.Supplier) { +} + +func (testValuePropagator) Extract(http.Supplier) (core.SpanContext, dctx.Correlations, dctx.Baggage) { + return core.EmptySpanContext(), dctx.NewEmptyCorrelations(), dctx.NewEmptyBaggage() +} + +func (*testPointerPropagator) Inject(core.SpanContext, dctx.Correlations, dctx.Baggage, http.Supplier) { +} + +func (*testPointerPropagator) Extract(http.Supplier) (core.SpanContext, dctx.Correlations, dctx.Baggage) { + return core.EmptySpanContext(), dctx.NewEmptyCorrelations(), dctx.NewEmptyBaggage() +} diff --git a/propagation/binary/propagator.go b/propagation/binary/propagator.go new file mode 100644 index 00000000000..a6296322c47 --- /dev/null +++ b/propagation/binary/propagator.go @@ -0,0 +1,71 @@ +// Copyright 2019, 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 binary + +import ( + "go.opentelemetry.io/otel/api/core" + apipropagation "go.opentelemetry.io/otel/api/propagation/binary" +) + +type binaryPropagator struct{} + +var _ apipropagation.SpanContextPropagator = binaryPropagator{} + +// BinaryPropagator creates a new propagator. The propagator implements +// ToBytes and FromBytes method to transform SpanContext to/from byte array. +func SpanContextPropagator() apipropagation.SpanContextPropagator { + return binaryPropagator{} +} + +// ToBytes implements ToBytes method of propagation.SpanContextPropagator. +// It serializes core.SpanContext into a byte array. +func (bp binaryPropagator) ToBytes(sc core.SpanContext) []byte { + if sc == core.EmptySpanContext() { + return nil + } + var b [29]byte + copy(b[2:18], sc.TraceID[:]) + b[18] = 1 + copy(b[19:27], sc.SpanID[:]) + b[27] = 2 + b[28] = sc.TraceFlags + return b[:] +} + +// FromBytes implements FromBytes method of propagation.SpanContextPropagator. +// It de-serializes bytes into core.SpanContext. +func (bp binaryPropagator) FromBytes(b []byte) (sc core.SpanContext) { + if len(b) == 0 { + return core.EmptySpanContext() + } + b = b[1:] + if len(b) >= 17 && b[0] == 0 { + copy(sc.TraceID[:], b[1:17]) + b = b[17:] + } else { + return core.EmptySpanContext() + } + if len(b) >= 9 && b[0] == 1 { + copy(sc.SpanID[:], b[1:9]) + b = b[9:] + } + if len(b) >= 2 && b[0] == 2 { + sc.TraceFlags = b[1] + } + if sc.IsValid() { + return sc + } + return core.EmptySpanContext() +} diff --git a/propagation/http/b3_propagators.go b/propagation/http/b3_propagators.go new file mode 100644 index 00000000000..083ffd6bea9 --- /dev/null +++ b/propagation/http/b3_propagators.go @@ -0,0 +1,196 @@ +// Copyright 2019, 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 http + +import ( + "fmt" + "strings" + + "go.opentelemetry.io/otel/api/core" + apipropagation "go.opentelemetry.io/otel/api/propagation/http" +) + +const ( + B3SingleHeader = "X-B3" + B3DebugFlagHeader = "X-B3-Flags" + B3TraceIDHeader = "X-B3-TraceId" + B3SpanIDHeader = "X-B3-SpanId" + B3SampledHeader = "X-B3-Sampled" + B3ParentSpanIDHeader = "X-B3-ParentSpanId" +) + +// B3Propagator that facilitates core.SpanContext +// propagation using B3 Headers. +// This propagator supports both version of B3 headers, +// 1. Single Header : +// X-B3: {TraceId}-{SpanId}-{SamplingState}-{ParentSpanId} +// 2. Multiple Headers: +// X-B3-TraceId: {TraceId} +// X-B3-ParentSpanId: {ParentSpanId} +// X-B3-SpanId: {SpanId} +// X-B3-Sampled: {SamplingState} +// X-B3-Flags: {DebugFlag} +// +// If SingleHeader is set to true then X-B3 header is used to inject +// and extract. Otherwise, separate headers are used to inject and +// extract. +type B3Propagator struct { + SingleHeader bool +} + +var _ apipropagation.SpanContextPropagator = B3Propagator{} + +func (b3 B3Propagator) Inject(sc core.SpanContext, supplier apipropagation.Supplier) { + if sc.IsValid() { + if b3.SingleHeader { + sampled := sc.TraceFlags & core.TraceFlagsSampled + supplier.Set(B3SingleHeader, + fmt.Sprintf("%s-%.16x-%.1d", sc.TraceIDString(), sc.SpanID, sampled)) + } else { + supplier.Set(B3TraceIDHeader, sc.TraceIDString()) + supplier.Set(B3SpanIDHeader, + fmt.Sprintf("%.16x", sc.SpanID)) + + var sampled string + if sc.IsSampled() { + sampled = "1" + } else { + sampled = "0" + } + supplier.Set(B3SampledHeader, sampled) + } + } +} + +// Extract retrieves B3 Headers from the supplier +func (b3 B3Propagator) Extract(supplier apipropagation.Supplier) core.SpanContext { + if b3.SingleHeader { + return b3.extractSingleHeader(supplier) + } + return b3.extract(supplier) +} + +func (b3 B3Propagator) extract(supplier apipropagation.Supplier) core.SpanContext { + tid, err := core.TraceIDFromHex(supplier.Get(B3TraceIDHeader)) + if err != nil { + return core.EmptySpanContext() + } + sid, err := core.SpanIDFromHex(supplier.Get(B3SpanIDHeader)) + if err != nil { + return core.EmptySpanContext() + } + sampled, ok := b3.extractSampledState(supplier.Get(B3SampledHeader)) + if !ok { + return core.EmptySpanContext() + } + + debug, ok := b3.extractDebugFlag(supplier.Get(B3DebugFlagHeader)) + if !ok { + return core.EmptySpanContext() + } + if debug == core.TraceFlagsSampled { + sampled = core.TraceFlagsSampled + } + + sc := core.SpanContext{ + TraceID: tid, + SpanID: sid, + TraceFlags: sampled, + } + + if !sc.IsValid() { + return core.EmptySpanContext() + } + + return sc +} + +func (b3 B3Propagator) extractSingleHeader(supplier apipropagation.Supplier) core.SpanContext { + h := supplier.Get(B3SingleHeader) + if h == "" || h == "0" { + core.EmptySpanContext() + } + sc := core.SpanContext{} + parts := strings.Split(h, "-") + l := len(parts) + if l > 4 { + return core.EmptySpanContext() + } + + if l < 2 { + return core.EmptySpanContext() + } + + var err error + sc.TraceID, err = core.TraceIDFromHex(parts[0]) + if err != nil { + return core.EmptySpanContext() + } + + sc.SpanID, err = core.SpanIDFromHex(parts[1]) + if err != nil { + return core.EmptySpanContext() + } + + if l > 2 { + var ok bool + sc.TraceFlags, ok = b3.extractSampledState(parts[2]) + if !ok { + return core.EmptySpanContext() + } + } + if l == 4 { + _, err = core.SpanIDFromHex(parts[3]) + if err != nil { + return core.EmptySpanContext() + } + } + + if !sc.IsValid() { + return core.EmptySpanContext() + } + + return sc +} + +// extractSampledState parses the value of the X-B3-Sampled b3Header. +func (b3 B3Propagator) extractSampledState(sampled string) (flag byte, ok bool) { + switch sampled { + case "", "0": + return 0, true + case "1": + return core.TraceFlagsSampled, true + case "true": + if !b3.SingleHeader { + return core.TraceFlagsSampled, true + } + case "d": + if b3.SingleHeader { + return core.TraceFlagsSampled, true + } + } + return 0, false +} + +// extractDebugFlag parses the value of the X-B3-Sampled b3Header. +func (b3 B3Propagator) extractDebugFlag(debug string) (flag byte, ok bool) { + switch debug { + case "", "0": + return 0, true + case "1": + return core.TraceFlagsSampled, true + } + return 0, false +} diff --git a/propagation/http/trace_context_propagator.go b/propagation/http/trace_context_propagator.go new file mode 100644 index 00000000000..b5820018c57 --- /dev/null +++ b/propagation/http/trace_context_propagator.go @@ -0,0 +1,198 @@ +// Copyright 2019, 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 http + +import ( + "encoding/hex" + "fmt" + "net/url" + "regexp" + "strings" + + "go.opentelemetry.io/otel/api/core" + dctx "go.opentelemetry.io/otel/api/distributedcontext" + "go.opentelemetry.io/otel/api/key" + apipropagation "go.opentelemetry.io/otel/api/propagation/http" +) + +const ( + supportedVersion = 0 + maxVersion = 254 + TraceparentHeader = "Traceparent" + CorrelationContextHeader = "Correlation-Context" +) + +// TraceContextPropagator propagates SpanContext in W3C TraceContext format. +type ( + TraceContextPropagator struct{} + CorrelationContextPropagator struct{} + // TODO: BaggageContextPropagator, likely similar to + // CorrelationContextPropagator + // + // TODO: ContextPropagator, grouping all three +) + +var ( + _ apipropagation.SpanContextPropagator = TraceContextPropagator{} + _ apipropagation.CorrelationsPropagator = CorrelationContextPropagator{} + traceCtxRegExp = regexp.MustCompile("^[0-9a-f]{2}-[a-f0-9]{32}-[a-f0-9]{16}-[a-f0-9]{2}-?") +) + +func (TraceContextPropagator) Inject(sc core.SpanContext, supplier apipropagation.Supplier) { + if sc.IsValid() { + h := fmt.Sprintf("%.2x-%s-%.16x-%.2x", + supportedVersion, + sc.TraceIDString(), + sc.SpanID, + sc.TraceFlags&core.TraceFlagsSampled) + supplier.Set(TraceparentHeader, h) + } +} + +func (TraceContextPropagator) Extract(supplier apipropagation.Supplier) core.SpanContext { + h := supplier.Get(TraceparentHeader) + if h == "" { + return core.EmptySpanContext() + } + + h = strings.Trim(h, "-") + if !traceCtxRegExp.MatchString(h) { + return core.EmptySpanContext() + } + + sections := strings.Split(h, "-") + if len(sections) < 4 { + return core.EmptySpanContext() + } + + if len(sections[0]) != 2 { + return core.EmptySpanContext() + } + ver, err := hex.DecodeString(sections[0]) + if err != nil { + return core.EmptySpanContext() + } + version := int(ver[0]) + if version > maxVersion { + return core.EmptySpanContext() + } + + if version == 0 && len(sections) != 4 { + return core.EmptySpanContext() + } + + if len(sections[1]) != 32 { + return core.EmptySpanContext() + } + + var sc core.SpanContext + + sc.TraceID, err = core.TraceIDFromHex(sections[1][:32]) + if err != nil { + return core.EmptySpanContext() + } + + if len(sections[2]) != 16 { + return core.EmptySpanContext() + } + sc.SpanID, err = core.SpanIDFromHex(sections[2][:]) + if err != nil { + return core.EmptySpanContext() + } + + if len(sections[3]) != 2 { + return core.EmptySpanContext() + } + opts, err := hex.DecodeString(sections[3]) + if err != nil || len(opts) < 1 || (version == 0 && opts[0] > 2) { + return core.EmptySpanContext() + } + sc.TraceFlags = opts[0] &^ core.TraceFlagsUnused + + if !sc.IsValid() { + return core.EmptySpanContext() + } + + return sc +} + +func (CorrelationContextPropagator) Inject(correlations dctx.Correlations, supplier apipropagation.Supplier) { + firstIter := true + var headerValueBuilder strings.Builder + correlations.Foreach(func(kv dctx.Correlation) bool { + if kv.HopLimit == dctx.NoPropagation { + return true + } + if !firstIter { + headerValueBuilder.WriteRune(',') + } + firstIter = false + headerValueBuilder.WriteString(url.QueryEscape(strings.TrimSpace((string)(kv.Key)))) + headerValueBuilder.WriteRune('=') + headerValueBuilder.WriteString(url.QueryEscape(strings.TrimSpace(kv.Value.Emit()))) + return true + }) + if headerValueBuilder.Len() > 0 { + headerString := headerValueBuilder.String() + supplier.Set(CorrelationContextHeader, headerString) + } +} + +func (CorrelationContextPropagator) Extract(supplier apipropagation.Supplier) dctx.Correlations { + correlationContext := supplier.Get(CorrelationContextHeader) + if correlationContext == "" { + return dctx.NewEmptyCorrelations() + } + + contextValues := strings.Split(correlationContext, ",") + keyValues := make([]dctx.Correlation, 0, len(contextValues)) + for _, contextValue := range contextValues { + valueAndProps := strings.Split(contextValue, ";") + if len(valueAndProps) < 1 { + continue + } + nameValue := strings.Split(valueAndProps[0], "=") + if len(nameValue) < 2 { + continue + } + name, err := url.QueryUnescape(nameValue[0]) + if err != nil { + continue + } + trimmedName := strings.TrimSpace(name) + value, err := url.QueryUnescape(nameValue[1]) + if err != nil { + continue + } + trimmedValue := strings.TrimSpace(value) + + // TODO (skaris): properties defined https://w3c.github.io/correlation-context/, are currently + // just put as part of the value. + var trimmedValueWithProps strings.Builder + trimmedValueWithProps.WriteString(trimmedValue) + for _, prop := range valueAndProps[1:] { + trimmedValueWithProps.WriteRune(';') + trimmedValueWithProps.WriteString(prop) + } + + keyValues = append(keyValues, dctx.Correlation{ + KeyValue: key.String(trimmedName, trimmedValueWithProps.String()), + HopLimit: dctx.UnlimitedPropagation, + }) + } + return dctx.NewCorrelations(dctx.CorrelationsUpdate{ + MultiKV: keyValues, + }) +} From f1c59085cac1630cfe1e3660c96e1752a1c84a1b Mon Sep 17 00:00:00 2001 From: Krzesimir Nowak Date: Wed, 6 Nov 2019 22:03:07 +0100 Subject: [PATCH 4/7] update stuff --- bridge/opentracing/internal/mock.go | 58 +++++++++++------------ example/basic/main.go | 17 +++++-- example/http-stackdriver/client/client.go | 7 ++- example/http-stackdriver/server/server.go | 4 +- example/http/client/client.go | 7 ++- example/http/server/server.go | 4 +- example/namedtracer/main.go | 12 +++-- plugin/httptrace/httptrace.go | 23 +++++---- plugin/othttp/handler.go | 54 +++++++++++++++++---- plugin/othttp/handler_test.go | 2 +- plugin/othttp/wrap.go | 2 +- 11 files changed, 121 insertions(+), 69 deletions(-) diff --git a/bridge/opentracing/internal/mock.go b/bridge/opentracing/internal/mock.go index 19dde5f5d87..883c08853ef 100644 --- a/bridge/opentracing/internal/mock.go +++ b/bridge/opentracing/internal/mock.go @@ -44,7 +44,6 @@ type MockContextKeyValue struct { } type MockTracer struct { - Resources oteldctx.Map FinishedSpans []*MockSpan SpareTraceIDs []otelcore.TraceID SpareSpanIDs []otelcore.SpanID @@ -59,7 +58,6 @@ var _ migration.DeferredContextSetupTracerExtension = &MockTracer{} func NewMockTracer() *MockTracer { return &MockTracer{ - Resources: oteldctx.NewEmptyMap(), FinishedSpans: nil, SpareTraceIDs: nil, SpareSpanIDs: nil, @@ -94,14 +92,12 @@ func (t *MockTracer) Start(ctx context.Context, name string, opts ...oteltrace.S officialTracer: t, spanContext: spanContext, recording: spanOpts.Record, - Attributes: oteldctx.NewMap(oteldctx.MapUpdate{ - MultiKV: spanOpts.Attributes, - }), - StartTime: startTime, - EndTime: time.Time{}, - ParentSpanID: t.getParentSpanID(ctx, &spanOpts), - Events: nil, - SpanKind: oteltrace.ValidateSpanKind(spanOpts.SpanKind), + Attributes: spanOpts.Attributes, + StartTime: startTime, + EndTime: time.Time{}, + ParentSpanID: t.getParentSpanID(ctx, &spanOpts), + Events: nil, + SpanKind: oteltrace.ValidateSpanKind(spanOpts.SpanKind), } if !migration.SkipContextSetup(ctx) { ctx = oteltrace.SetCurrentSpan(ctx, span) @@ -193,10 +189,10 @@ func (t *MockTracer) DeferredContextSetupHook(ctx context.Context, span oteltrac } type MockEvent struct { - CtxAttributes oteldctx.Map - Timestamp time.Time - Msg string - Attributes oteldctx.Map + Correlations oteldctx.Correlations + Timestamp time.Time + Msg string + Attributes []otelcore.KeyValue } type MockSpan struct { @@ -206,7 +202,7 @@ type MockSpan struct { SpanKind oteltrace.SpanKind recording bool - Attributes oteldctx.Map + Attributes []otelcore.KeyValue StartTime time.Time EndTime time.Time ParentSpanID otelcore.SpanID @@ -237,19 +233,25 @@ func (s *MockSpan) SetError(v bool) { } func (s *MockSpan) SetAttribute(attribute otelcore.KeyValue) { - s.applyUpdate(oteldctx.MapUpdate{ - SingleKV: attribute, - }) + s.applyUpdate(attribute) } func (s *MockSpan) SetAttributes(attributes ...otelcore.KeyValue) { - s.applyUpdate(oteldctx.MapUpdate{ - MultiKV: attributes, - }) + s.applyUpdate(attributes...) } -func (s *MockSpan) applyUpdate(update oteldctx.MapUpdate) { - s.Attributes = s.Attributes.Apply(update) +func (s *MockSpan) applyUpdate(attributes ...otelcore.KeyValue) { + m := make(map[otelcore.Key]int, len(s.Attributes)) + for idx, kv := range s.Attributes { + m[kv.Key] = idx + } + for _, kv := range attributes { + if idx, ok := m[kv.Key]; ok { + s.Attributes[idx].Value = kv.Value + } else { + s.Attributes = append(s.Attributes, kv) + } + } } func (s *MockSpan) End(options ...oteltrace.EndOption) { @@ -280,12 +282,10 @@ func (s *MockSpan) AddEvent(ctx context.Context, msg string, attrs ...otelcore.K func (s *MockSpan) AddEventWithTimestamp(ctx context.Context, timestamp time.Time, msg string, attrs ...otelcore.KeyValue) { s.Events = append(s.Events, MockEvent{ - CtxAttributes: oteldctx.FromContext(ctx), - Timestamp: timestamp, - Msg: msg, - Attributes: oteldctx.NewMap(oteldctx.MapUpdate{ - MultiKV: attrs, - }), + Correlations: oteldctx.CorrelationsFromContext(ctx), + Timestamp: timestamp, + Msg: msg, + Attributes: attrs, }) } diff --git a/example/basic/main.go b/example/basic/main.go index ac4280c2dec..8757b418f66 100644 --- a/example/basic/main.go +++ b/example/basic/main.go @@ -65,9 +65,15 @@ func main() { ctx := context.Background() - ctx = distributedcontext.NewContext(ctx, - fooKey.String("foo1"), - barKey.String("bar1"), + ctx = distributedcontext.NewCorrelationsContextKV(ctx, + distributedcontext.Correlation{ + KeyValue: fooKey.String("foo1"), + HopLimit: distributedcontext.UnlimitedPropagation, + }, + distributedcontext.Correlation{ + KeyValue: barKey.String("bar1"), + HopLimit: distributedcontext.UnlimitedPropagation, + }, ) commonLabels := meter.Labels(lemonsKey.Int(10)) @@ -88,7 +94,10 @@ func main() { meter.RecordBatch( // Note: call-site variables added as context Entries: - distributedcontext.NewContext(ctx, anotherKey.String("xyz")), + distributedcontext.NewCorrelationsContextKV(ctx, distributedcontext.Correlation{ + KeyValue: anotherKey.String("xyz"), + HopLimit: distributedcontext.UnlimitedPropagation, + }), commonLabels, oneMetric.Measurement(1.0), diff --git a/example/http-stackdriver/client/client.go b/example/http-stackdriver/client/client.go index ea57c73b226..dfb782d602c 100644 --- a/example/http-stackdriver/client/client.go +++ b/example/http-stackdriver/client/client.go @@ -62,8 +62,11 @@ func main() { tr := global.TraceProvider().GetTracer("stackdriver/example/client") client := http.DefaultClient - ctx := distributedcontext.NewContext(context.Background(), - key.String("username", "donuts"), + ctx := distributedcontext.NewCorrelationsContextKV(context.Background(), + distributedcontext.Correlation{ + KeyValue: key.String("username", "donuts"), + HopLimit: distributedcontext.UnlimitedPropagation, + }, ) var body []byte diff --git a/example/http-stackdriver/server/server.go b/example/http-stackdriver/server/server.go index 7f74f8c9d13..f0608001e48 100644 --- a/example/http-stackdriver/server/server.go +++ b/example/http-stackdriver/server/server.go @@ -58,9 +58,7 @@ func main() { helloHandler := func(w http.ResponseWriter, req *http.Request) { attrs, entries, spanCtx := httptrace.Extract(req.Context(), req) - req = req.WithContext(distributedcontext.WithMap(req.Context(), distributedcontext.NewMap(distributedcontext.MapUpdate{ - MultiKV: entries, - }))) + req = req.WithContext(distributedcontext.NewCorrelationsContextKV(req.Context(), entries...)) ctx, span := tr.Start( req.Context(), diff --git a/example/http/client/client.go b/example/http/client/client.go index a9aebb0a1b9..2bac80e6b2a 100644 --- a/example/http/client/client.go +++ b/example/http/client/client.go @@ -56,8 +56,11 @@ func main() { initTracer() client := http.DefaultClient - ctx := distributedcontext.NewContext(context.Background(), - key.String("username", "donuts"), + ctx := distributedcontext.NewCorrelationsContextKV(context.Background(), + distributedcontext.Correlation{ + KeyValue: key.String("username", "donuts"), + HopLimit: distributedcontext.UnlimitedPropagation, + }, ) var body []byte diff --git a/example/http/server/server.go b/example/http/server/server.go index 13b75d4548d..3b67e8fe539 100644 --- a/example/http/server/server.go +++ b/example/http/server/server.go @@ -52,9 +52,7 @@ func main() { helloHandler := func(w http.ResponseWriter, req *http.Request) { attrs, entries, spanCtx := httptrace.Extract(req.Context(), req) - req = req.WithContext(distributedcontext.WithMap(req.Context(), distributedcontext.NewMap(distributedcontext.MapUpdate{ - MultiKV: entries, - }))) + req = req.WithContext(distributedcontext.NewCorrelationsContextKV(req.Context(), entries...)) ctx, span := tr.Start( req.Context(), diff --git a/example/namedtracer/main.go b/example/namedtracer/main.go index 8cf0b6b9dec..aaf344f3648 100644 --- a/example/namedtracer/main.go +++ b/example/namedtracer/main.go @@ -59,9 +59,15 @@ func main() { tracer := tp.GetTracer("example/namedtracer/main") ctx := context.Background() - ctx = distributedcontext.NewContext(ctx, - fooKey.String("foo1"), - barKey.String("bar1"), + ctx = distributedcontext.NewCorrelationsContextKV(ctx, + distributedcontext.Correlation{ + KeyValue: fooKey.String("foo1"), + HopLimit: distributedcontext.UnlimitedPropagation, + }, + distributedcontext.Correlation{ + KeyValue: barKey.String("bar1"), + HopLimit: distributedcontext.UnlimitedPropagation, + }, ) err := tracer.WithSpan(ctx, "operation", func(ctx context.Context) error { diff --git a/plugin/httptrace/httptrace.go b/plugin/httptrace/httptrace.go index 585ac0d901a..f6e420ee5c6 100644 --- a/plugin/httptrace/httptrace.go +++ b/plugin/httptrace/httptrace.go @@ -19,8 +19,10 @@ import ( "net/http" "go.opentelemetry.io/otel/api/core" + dctx "go.opentelemetry.io/otel/api/distributedcontext" "go.opentelemetry.io/otel/api/key" - "go.opentelemetry.io/otel/propagation" + "go.opentelemetry.io/otel/api/trace" + propagation "go.opentelemetry.io/otel/propagation/http" ) const ( @@ -31,27 +33,24 @@ var ( HostKey = key.New("http.host") URLKey = key.New("http.url") - propagator = propagation.HTTPTraceContextPropagator{} + scPropagator = propagation.TraceContextPropagator{} + cPropagator = propagation.CorrelationContextPropagator{} ) // Returns the Attributes, Context Entries, and SpanContext that were encoded by Inject. -func Extract(ctx context.Context, req *http.Request) ([]core.KeyValue, []core.KeyValue, core.SpanContext) { - sc, correlationCtx := propagator.Extract(ctx, req.Header) +func Extract(ctx context.Context, req *http.Request) ([]core.KeyValue, []dctx.Correlation, core.SpanContext) { + sc := scPropagator.Extract(req.Header) + correlationCtx := cPropagator.Extract(req.Header) attrs := []core.KeyValue{ URLKey.String(req.URL.String()), // Etc. } - var correlationCtxKVs []core.KeyValue - correlationCtx.Foreach(func(kv core.KeyValue) bool { - correlationCtxKVs = append(correlationCtxKVs, kv) - return true - }) - - return attrs, correlationCtxKVs, sc + return attrs, correlationCtx.Correlations(), sc } func Inject(ctx context.Context, req *http.Request) { - propagator.Inject(ctx, req.Header) + scPropagator.Inject(trace.CurrentSpan(ctx).SpanContext(), req.Header) + cPropagator.Inject(dctx.CorrelationsFromContext(ctx), req.Header) } diff --git a/plugin/othttp/handler.go b/plugin/othttp/handler.go index 361bf83503d..e7f1a137514 100644 --- a/plugin/othttp/handler.go +++ b/plugin/othttp/handler.go @@ -15,14 +15,16 @@ package othttp import ( + "context" "io" "net/http" "go.opentelemetry.io/otel/api/core" - "go.opentelemetry.io/otel/api/propagation" + dctx "go.opentelemetry.io/otel/api/distributedcontext" + propagation "go.opentelemetry.io/otel/api/propagation/http" "go.opentelemetry.io/otel/api/trace" "go.opentelemetry.io/otel/global" - prop "go.opentelemetry.io/otel/propagation" + prop "go.opentelemetry.io/otel/propagation/http" ) var _ http.Handler = &Handler{} @@ -51,7 +53,7 @@ type Handler struct { handler http.Handler tracer trace.Tracer - prop propagation.TextFormatPropagator + prop propagation.Propagator spanOptions []trace.SpanOption public bool readEvent bool @@ -81,7 +83,7 @@ func WithPublicEndpoint() Option { // WithPropagator configures the Handler with a specific propagator. If this // option isn't specificed then // go.opentelemetry.io/otel/propagation.HTTPTraceContextPropagator is used. -func WithPropagator(p propagation.TextFormatPropagator) Option { +func WithPropagator(p propagation.Propagator) Option { return func(h *Handler) { h.prop = p } @@ -125,13 +127,37 @@ func WithMessageEvents(events ...event) Option { } } +type defaultPropagator struct { + propagation.Propagators +} + +func newDefaultPropagator() propagation.Propagator { + return defaultPropagator{ + Propagators: propagation.Propagators{ + Scp: prop.TraceContextPropagator{}, + Cp: prop.CorrelationContextPropagator{}, + Bp: propagation.NoopBaggagePropagator{}, + }, + } +} + +func (d defaultPropagator) Inject(sc core.SpanContext, c dctx.Correlations, b dctx.Baggage, s propagation.Supplier) { + d.Scp.Inject(sc, s) + d.Cp.Inject(c, s) + d.Bp.Inject(b, s) +} + +func (d defaultPropagator) Extract(s propagation.Supplier) (core.SpanContext, dctx.Correlations, dctx.Baggage) { + return d.Scp.Extract(s), d.Cp.Extract(s), d.Bp.Extract(s) +} + // NewHandler wraps the passed handler, functioning like middleware, in a span // named after the operation and with any provided HandlerOptions. func NewHandler(handler http.Handler, operation string, opts ...Option) http.Handler { h := Handler{handler: handler, operation: operation} defaultOpts := []Option{ - WithTracer(global.TraceProvider().GetTracer("go.opentelemtry.io/plugin/othttp")), - WithPropagator(prop.HTTPTraceContextPropagator{}), + WithTracer(global.TraceProvider().GetTracer("go.opentelemetry.io/otel/plugin/othttp")), + WithPropagator(newDefaultPropagator()), WithSpanOptions(trace.WithSpanKind(trace.SpanKindServer)), } @@ -141,12 +167,20 @@ func NewHandler(handler http.Handler, operation string, opts ...Option) http.Han return &h } +type propagatorAsInjector struct { + prop propagation.Propagator +} + +func (p propagatorAsInjector) Inject(ctx context.Context, s propagation.Supplier) { + p.prop.Inject(trace.CurrentSpan(ctx).SpanContext(), dctx.CorrelationsFromContext(ctx), dctx.BaggageFromContext(ctx), s) +} + // ServeHTTP serves HTTP requests (http.Handler) func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { opts := append([]trace.SpanOption{}, h.spanOptions...) // start with the configured options // TODO: do something with the correlation context - sc, _ := h.prop.Extract(r.Context(), r.Header) + sc, c, b := h.prop.Extract(r.Header) if sc.IsValid() { // not a valid span context, so no link / parent relationship to establish var opt trace.SpanOption if h.public { @@ -159,7 +193,9 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { opts = append(opts, opt) } - ctx, span := h.tracer.Start(r.Context(), h.operation, opts...) + ctx := dctx.NewCorrelationsContextMap(r.Context(), c) + ctx = dctx.NewBaggageContext(ctx, b) + ctx, span := h.tracer.Start(ctx, h.operation, opts...) defer span.End() readRecordFunc := func(int64) {} @@ -178,7 +214,7 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } } - rww := &respWriterWrapper{ResponseWriter: w, record: writeRecordFunc, ctx: ctx, injector: h.prop} + rww := &respWriterWrapper{ResponseWriter: w, record: writeRecordFunc, ctx: ctx, injector: propagatorAsInjector{prop: h.prop}} // Setup basic span attributes before calling handler.ServeHTTP so that they // are available to be mutated by the handler if needed. diff --git a/plugin/othttp/handler_test.go b/plugin/othttp/handler_test.go index cf902133a0e..3156c88daef 100644 --- a/plugin/othttp/handler_test.go +++ b/plugin/othttp/handler_test.go @@ -20,7 +20,7 @@ import ( "net/http/httptest" "testing" - "go.opentelemetry.io/otel/propagation" + propagation "go.opentelemetry.io/otel/propagation/http" mocktrace "go.opentelemetry.io/otel/internal/trace" ) diff --git a/plugin/othttp/wrap.go b/plugin/othttp/wrap.go index 171eb2afddc..9fbd87a90f7 100644 --- a/plugin/othttp/wrap.go +++ b/plugin/othttp/wrap.go @@ -19,7 +19,7 @@ import ( "io" "net/http" - "go.opentelemetry.io/otel/api/propagation" + propagation "go.opentelemetry.io/otel/api/propagation/http" ) var _ io.ReadCloser = &bodyWrapper{} From 784c626d7cdb58eb1b9f242d4be48cc505480df1 Mon Sep 17 00:00:00 2001 From: Krzesimir Nowak Date: Sun, 10 Nov 2019 10:32:03 +0100 Subject: [PATCH 5/7] simplify distributed context constructors --- api/distributedcontext/baggage.go | 22 +++++++------------- api/distributedcontext/context.go | 4 ++-- api/distributedcontext/correlations.go | 22 +++++++------------- api/propagation/binary/noop.go | 6 +++--- api/propagation/binary/propagators_test.go | 4 ++-- api/propagation/http/noop.go | 6 +++--- api/propagation/http/propagators.go | 4 ++-- api/propagation/http/propagators_test.go | 4 ++-- propagation/http/trace_context_propagator.go | 2 +- 9 files changed, 29 insertions(+), 45 deletions(-) diff --git a/api/distributedcontext/baggage.go b/api/distributedcontext/baggage.go index ca4b7a617ca..e2a20f477d7 100644 --- a/api/distributedcontext/baggage.go +++ b/api/distributedcontext/baggage.go @@ -18,10 +18,8 @@ import ( "go.opentelemetry.io/otel/api/core" ) -type rawBaggageMap map[core.Key]core.Value - type Baggage struct { - m rawBaggageMap + m map[core.Key]core.Value } type BaggageUpdate struct { @@ -33,22 +31,14 @@ type BaggageUpdate struct { Map Baggage } -func newBaggage(raw rawBaggageMap) Baggage { +func NewBaggage() Baggage { return Baggage{ - m: raw, + m: nil, } } -func NewEmptyBaggage() Baggage { - return newBaggage(nil) -} - -func NewBaggage(update BaggageUpdate) Baggage { - return NewEmptyBaggage().Apply(update) -} - func (m Baggage) Apply(update BaggageUpdate) Baggage { - r := make(rawBaggageMap, len(m.m)+len(update.MultiKV)+update.Map.Len()) + r := make(map[core.Key]core.Value, len(m.m)+len(update.MultiKV)+update.Map.Len()) for k, v := range m.m { r[k] = v } @@ -70,7 +60,9 @@ func (m Baggage) Apply(update BaggageUpdate) Baggage { if len(r) == 0 { r = nil } - return newBaggage(r) + return Baggage{ + m: r, + } } func (m Baggage) Value(k core.Key) (core.Value, bool) { diff --git a/api/distributedcontext/context.go b/api/distributedcontext/context.go index 736ba29871c..2cb7c88b64a 100644 --- a/api/distributedcontext/context.go +++ b/api/distributedcontext/context.go @@ -44,7 +44,7 @@ func CorrelationsFromContext(ctx context.Context) Correlations { if m, ok := ctx.Value(ctxCorrelationsKey).(Correlations); ok { return m } - return NewEmptyCorrelations() + return NewCorrelations() } func NewBaggageContext(ctx context.Context, baggage Baggage) context.Context { @@ -55,7 +55,7 @@ func BaggageFromContext(ctx context.Context) Baggage { if m, ok := ctx.Value(ctxBaggageKey).(Baggage); ok { return m } - return NewEmptyBaggage() + return NewBaggage() } func withCorrelationsMapUpdate(ctx context.Context, update CorrelationsUpdate) context.Context { diff --git a/api/distributedcontext/correlations.go b/api/distributedcontext/correlations.go index ab55bbb1e73..d5304e3a21b 100644 --- a/api/distributedcontext/correlations.go +++ b/api/distributedcontext/correlations.go @@ -42,10 +42,8 @@ func (c *Correlation) CorrelationValue() CorrelationValue { } } -type rawCorrelationsMap map[core.Key]CorrelationValue - type Correlations struct { - m rawCorrelationsMap + m map[core.Key]CorrelationValue } type CorrelationsUpdate struct { @@ -54,22 +52,14 @@ type CorrelationsUpdate struct { Map Correlations } -func newCorrelations(raw rawCorrelationsMap) Correlations { +func NewCorrelations() Correlations { return Correlations{ - m: raw, + m: nil, } } -func NewEmptyCorrelations() Correlations { - return newCorrelations(nil) -} - -func NewCorrelations(update CorrelationsUpdate) Correlations { - return NewEmptyCorrelations().Apply(update) -} - func (m Correlations) Apply(update CorrelationsUpdate) Correlations { - r := make(rawCorrelationsMap, len(m.m)+len(update.MultiKV)+update.Map.Len()) + r := make(map[core.Key]CorrelationValue, len(m.m)+len(update.MultiKV)+update.Map.Len()) for k, v := range m.m { r[k] = v } @@ -85,7 +75,9 @@ func (m Correlations) Apply(update CorrelationsUpdate) Correlations { if len(r) == 0 { r = nil } - return newCorrelations(r) + return Correlations{ + m: r, + } } func (m Correlations) Value(k core.Key) (CorrelationValue, bool) { diff --git a/api/propagation/binary/noop.go b/api/propagation/binary/noop.go index fbda1129d7f..0c47727489e 100644 --- a/api/propagation/binary/noop.go +++ b/api/propagation/binary/noop.go @@ -46,7 +46,7 @@ func (NoopCorrelationsPropagator) ToBytes(dctx.Correlations) []byte { } func (NoopCorrelationsPropagator) FromBytes([]byte) dctx.Correlations { - return dctx.NewEmptyCorrelations() + return dctx.NewCorrelations() } func (NoopBaggagePropagator) ToBytes(dctx.Baggage) []byte { @@ -54,7 +54,7 @@ func (NoopBaggagePropagator) ToBytes(dctx.Baggage) []byte { } func (NoopBaggagePropagator) FromBytes([]byte) dctx.Baggage { - return dctx.NewEmptyBaggage() + return dctx.NewBaggage() } func (NoopPropagator) ToBytes(core.SpanContext, dctx.Correlations, dctx.Baggage) []byte { @@ -62,7 +62,7 @@ func (NoopPropagator) ToBytes(core.SpanContext, dctx.Correlations, dctx.Baggage) } func (NoopPropagator) FromBytes([]byte) (core.SpanContext, dctx.Correlations, dctx.Baggage) { - return core.EmptySpanContext(), dctx.NewEmptyCorrelations(), dctx.NewEmptyBaggage() + return core.EmptySpanContext(), dctx.NewCorrelations(), dctx.NewBaggage() } func (NoopPropagator) SpanContextPropagator() SpanContextPropagator { diff --git a/api/propagation/binary/propagators_test.go b/api/propagation/binary/propagators_test.go index 421e387475c..55ac0b5287f 100644 --- a/api/propagation/binary/propagators_test.go +++ b/api/propagation/binary/propagators_test.go @@ -40,7 +40,7 @@ func (testValuePropagator) ToBytes(core.SpanContext, dctx.Correlations, dctx.Bag } func (testValuePropagator) FromBytes([]byte) (core.SpanContext, dctx.Correlations, dctx.Baggage) { - return core.EmptySpanContext(), dctx.NewEmptyCorrelations(), dctx.NewEmptyBaggage() + return core.EmptySpanContext(), dctx.NewCorrelations(), dctx.NewBaggage() } func (*testPointerPropagator) ToBytes(core.SpanContext, dctx.Correlations, dctx.Baggage) []byte { @@ -48,5 +48,5 @@ func (*testPointerPropagator) ToBytes(core.SpanContext, dctx.Correlations, dctx. } func (*testPointerPropagator) FromBytes([]byte) (core.SpanContext, dctx.Correlations, dctx.Baggage) { - return core.EmptySpanContext(), dctx.NewEmptyCorrelations(), dctx.NewEmptyBaggage() + return core.EmptySpanContext(), dctx.NewCorrelations(), dctx.NewBaggage() } diff --git a/api/propagation/http/noop.go b/api/propagation/http/noop.go index 71628dbc0b3..8131383d602 100644 --- a/api/propagation/http/noop.go +++ b/api/propagation/http/noop.go @@ -44,21 +44,21 @@ func (NoopCorrelationsPropagator) Inject(dctx.Correlations, Supplier) { } func (NoopCorrelationsPropagator) Extract(Supplier) dctx.Correlations { - return dctx.NewEmptyCorrelations() + return dctx.NewCorrelations() } func (NoopBaggagePropagator) Inject(dctx.Baggage, Supplier) { } func (NoopBaggagePropagator) Extract(Supplier) dctx.Baggage { - return dctx.NewEmptyBaggage() + return dctx.NewBaggage() } func (NoopPropagator) Inject(core.SpanContext, dctx.Correlations, dctx.Baggage, Supplier) { } func (NoopPropagator) Extract(Supplier) (core.SpanContext, dctx.Correlations, dctx.Baggage) { - return core.EmptySpanContext(), dctx.NewEmptyCorrelations(), dctx.NewEmptyBaggage() + return core.EmptySpanContext(), dctx.NewCorrelations(), dctx.NewBaggage() } func (NoopPropagator) SpanContextPropagator() SpanContextPropagator { diff --git a/api/propagation/http/propagators.go b/api/propagation/http/propagators.go index c3a9316194e..808ab0f39de 100644 --- a/api/propagation/http/propagators.go +++ b/api/propagation/http/propagators.go @@ -93,7 +93,7 @@ func (c chainCorrelationsPropagator) Extract(supplier Supplier) dctx.Correlation } } - return dctx.NewEmptyCorrelations() + return dctx.NewCorrelations() } type BaggagePropagator interface { @@ -126,7 +126,7 @@ func (c chainBaggagePropagator) Extract(supplier Supplier) dctx.Baggage { } } - return dctx.NewEmptyBaggage() + return dctx.NewBaggage() } type Propagator interface { diff --git a/api/propagation/http/propagators_test.go b/api/propagation/http/propagators_test.go index e132a43b1ce..61b8d4f1517 100644 --- a/api/propagation/http/propagators_test.go +++ b/api/propagation/http/propagators_test.go @@ -39,12 +39,12 @@ func (testValuePropagator) Inject(core.SpanContext, dctx.Correlations, dctx.Bagg } func (testValuePropagator) Extract(http.Supplier) (core.SpanContext, dctx.Correlations, dctx.Baggage) { - return core.EmptySpanContext(), dctx.NewEmptyCorrelations(), dctx.NewEmptyBaggage() + return core.EmptySpanContext(), dctx.NewCorrelations(), dctx.NewBaggage() } func (*testPointerPropagator) Inject(core.SpanContext, dctx.Correlations, dctx.Baggage, http.Supplier) { } func (*testPointerPropagator) Extract(http.Supplier) (core.SpanContext, dctx.Correlations, dctx.Baggage) { - return core.EmptySpanContext(), dctx.NewEmptyCorrelations(), dctx.NewEmptyBaggage() + return core.EmptySpanContext(), dctx.NewCorrelations(), dctx.NewBaggage() } diff --git a/propagation/http/trace_context_propagator.go b/propagation/http/trace_context_propagator.go index b5820018c57..9385f8a48e3 100644 --- a/propagation/http/trace_context_propagator.go +++ b/propagation/http/trace_context_propagator.go @@ -153,7 +153,7 @@ func (CorrelationContextPropagator) Inject(correlations dctx.Correlations, suppl func (CorrelationContextPropagator) Extract(supplier apipropagation.Supplier) dctx.Correlations { correlationContext := supplier.Get(CorrelationContextHeader) if correlationContext == "" { - return dctx.NewEmptyCorrelations() + return dctx.NewCorrelations() } contextValues := strings.Split(correlationContext, ",") From bf731ef24cd0ce1b1bb787dfeef6147907e1badc Mon Sep 17 00:00:00 2001 From: Krzesimir Nowak Date: Sun, 10 Nov 2019 10:32:56 +0100 Subject: [PATCH 6/7] add a comment about testing propagators helper struct --- api/propagation/binary/propagators_test.go | 6 ++++++ api/propagation/http/propagators_test.go | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/api/propagation/binary/propagators_test.go b/api/propagation/binary/propagators_test.go index 55ac0b5287f..9613f627bc1 100644 --- a/api/propagation/binary/propagators_test.go +++ b/api/propagation/binary/propagators_test.go @@ -21,10 +21,16 @@ import ( ) type ( + // This is to test that embedding binary.Propagators helps to + // implement the Propagator interface with the implementation + // having a value receiver. testValuePropagator struct { binary.Propagators } + // This is to test that embedding binary.Propagators helps to + // implement the Propagator interface with the implementation + // having a pointer receiver. testPointerPropagator struct { binary.Propagators } diff --git a/api/propagation/http/propagators_test.go b/api/propagation/http/propagators_test.go index 61b8d4f1517..c8277a4ed04 100644 --- a/api/propagation/http/propagators_test.go +++ b/api/propagation/http/propagators_test.go @@ -21,10 +21,16 @@ import ( ) type ( + // This is to test that embedding binary.Propagators helps to + // implement the Propagator interface with the implementation + // having a value receiver. testValuePropagator struct { http.Propagators } + // This is to test that embedding binary.Propagators helps to + // implement the Propagator interface with the implementation + // having a pointer receiver. testPointerPropagator struct { http.Propagators } From cf717aa2257cf4a55a04d74cc447eae80e6769f6 Mon Sep 17 00:00:00 2001 From: Krzesimir Nowak Date: Sun, 10 Nov 2019 10:38:39 +0100 Subject: [PATCH 7/7] make context keys a single integral type --- api/distributedcontext/context.go | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/api/distributedcontext/context.go b/api/distributedcontext/context.go index 2cb7c88b64a..588ca30075a 100644 --- a/api/distributedcontext/context.go +++ b/api/distributedcontext/context.go @@ -18,14 +18,11 @@ import ( "context" ) -type ( - ctxCorrelationsType struct{} - ctxBaggageType struct{} -) +type ctxKey int -var ( - ctxCorrelationsKey = &ctxCorrelationsType{} - ctxBaggageKey = &ctxBaggageType{} +const ( + ctxCorrelationsKey ctxKey = iota + ctxBaggageKey ) func NewCorrelationsContextKV(ctx context.Context, correlations ...Correlation) context.Context {