Skip to content

Commit f5dcc76

Browse files
authored
add ability to serialize/deserialize b3 to Go map[string]string (#145)
Add ability to serialize/deserialize b3 to Go map[string]string
1 parent b1a3538 commit f5dcc76

File tree

3 files changed

+517
-4
lines changed

3 files changed

+517
-4
lines changed

propagation/b3/http_test.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ import (
2424
"github.com/openzipkin/zipkin-go/reporter/recorder"
2525
)
2626

27+
const (
28+
invalidID = "invalid_data"
29+
)
30+
2731
func TestHTTPExtractFlagsOnly(t *testing.T) {
2832
r := newHTTPRequest(t)
2933

@@ -188,7 +192,7 @@ func TestHTTPExtractScope(t *testing.T) {
188192
func TestHTTPExtractTraceIDError(t *testing.T) {
189193
r := newHTTPRequest(t)
190194

191-
r.Header.Set(b3.TraceID, "invalid_data")
195+
r.Header.Set(b3.TraceID, invalidID)
192196

193197
_, err := b3.ExtractHTTP(r)()
194198

@@ -200,7 +204,7 @@ func TestHTTPExtractTraceIDError(t *testing.T) {
200204
func TestHTTPExtractSpanIDError(t *testing.T) {
201205
r := newHTTPRequest(t)
202206

203-
r.Header.Set(b3.SpanID, "invalid_data")
207+
r.Header.Set(b3.SpanID, invalidID)
204208

205209
_, err := b3.ExtractHTTP(r)()
206210

@@ -250,7 +254,7 @@ func TestHTTPExtractInvalidParentIDError(t *testing.T) {
250254

251255
r.Header.Set(b3.TraceID, "1")
252256
r.Header.Set(b3.SpanID, "2")
253-
r.Header.Set(b3.ParentSpanID, "invalid_data")
257+
r.Header.Set(b3.ParentSpanID, invalidID)
254258

255259
_, err := b3.ExtractHTTP(r)()
256260

@@ -279,7 +283,7 @@ func TestHTTPExtractSingleFailsAndMultipleFallsbackFailing(t *testing.T) {
279283
r.Header.Set(b3.Context, "0000000000000001-0000000000000002-x")
280284
r.Header.Set(b3.TraceID, "1")
281285
r.Header.Set(b3.SpanID, "2")
282-
r.Header.Set(b3.ParentSpanID, "invalid_data")
286+
r.Header.Set(b3.ParentSpanID, invalidID)
283287

284288
_, err := b3.ExtractHTTP(r)()
285289

propagation/b3/map.go

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
// Copyright 2019 The OpenZipkin Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package b3
16+
17+
import (
18+
"github.com/openzipkin/zipkin-go/model"
19+
"github.com/openzipkin/zipkin-go/propagation"
20+
)
21+
22+
// Map allows serialization and deserialization of SpanContext into a standard Go map.
23+
type Map map[string]string
24+
25+
// Extract implements Extractor
26+
func (m *Map) Extract() (*model.SpanContext, error) {
27+
var (
28+
traceIDHeader = (*m)[TraceID]
29+
spanIDHeader = (*m)[SpanID]
30+
parentSpanIDHeader = (*m)[ParentSpanID]
31+
sampledHeader = (*m)[Sampled]
32+
flagsHeader = (*m)[Flags]
33+
singleHeader = (*m)[Context]
34+
)
35+
36+
var (
37+
sc *model.SpanContext
38+
sErr error
39+
mErr error
40+
)
41+
if singleHeader != "" {
42+
sc, sErr = ParseSingleHeader(singleHeader)
43+
if sErr == nil {
44+
return sc, nil
45+
}
46+
}
47+
48+
sc, mErr = ParseHeaders(
49+
traceIDHeader, spanIDHeader, parentSpanIDHeader,
50+
sampledHeader, flagsHeader,
51+
)
52+
53+
if mErr != nil && sErr != nil {
54+
return nil, sErr
55+
}
56+
57+
return sc, mErr
58+
59+
}
60+
61+
// Inject implements Injector
62+
func (m *Map) Inject(opts ...InjectOption) propagation.Injector {
63+
options := InjectOptions{shouldInjectMultiHeader: true}
64+
for _, opt := range opts {
65+
opt(&options)
66+
}
67+
68+
return func(sc model.SpanContext) error {
69+
if (model.SpanContext{}) == sc {
70+
return ErrEmptyContext
71+
}
72+
73+
if options.shouldInjectMultiHeader {
74+
if sc.Debug {
75+
(*m)[Flags] = "1"
76+
} else if sc.Sampled != nil {
77+
// Debug is encoded as X-B3-Flags: 1. Since Debug implies Sampled,
78+
// so don't also send "X-B3-Sampled: 1".
79+
if *sc.Sampled {
80+
(*m)[Sampled] = "1"
81+
} else {
82+
(*m)[Sampled] = "0"
83+
}
84+
}
85+
86+
if !sc.TraceID.Empty() && sc.ID > 0 {
87+
(*m)[TraceID] = sc.TraceID.String()
88+
(*m)[SpanID] = sc.ID.String()
89+
if sc.ParentID != nil {
90+
(*m)[ParentSpanID] = sc.ParentID.String()
91+
}
92+
}
93+
}
94+
95+
if options.shouldInjectSingleHeader {
96+
(*m)[Context] = BuildSingleHeader(sc)
97+
}
98+
99+
return nil
100+
}
101+
}

0 commit comments

Comments
 (0)