Skip to content
This repository has been archived by the owner on Jul 31, 2023. It is now read-only.

Commit

Permalink
Expose B3 header-parsing functions (#758)
Browse files Browse the repository at this point in the history
These are generally useful for parsing B3-formatted headers in
settings other than net/http. To avoid having to construct artificial
request objects, expose the parsing functions directly to allow the
header values to be passed in.
  • Loading branch information
Ramon Nogueira committed May 23, 2018
1 parent 275a4ed commit 3a82755
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 34 deletions.
30 changes: 17 additions & 13 deletions plugin/ochttp/propagation/b3/b3.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,11 @@ import (
"go.opencensus.io/trace/propagation"
)

// B3 headers that OpenCensus understands.
const (
traceIDHeader = "X-B3-TraceId"
spanIDHeader = "X-B3-SpanId"
sampledHeader = "X-B3-Sampled"
TraceIDHeader = "X-B3-TraceId"
SpanIDHeader = "X-B3-SpanId"
SampledHeader = "X-B3-Sampled"
)

// HTTPFormat implements propagation.HTTPFormat to propagate
Expand All @@ -45,23 +46,24 @@ var _ propagation.HTTPFormat = (*HTTPFormat)(nil)

// SpanContextFromRequest extracts a B3 span context from incoming requests.
func (f *HTTPFormat) SpanContextFromRequest(req *http.Request) (sc trace.SpanContext, ok bool) {
tid, ok := parseTraceID(req.Header.Get(traceIDHeader))
tid, ok := ParseTraceID(req.Header.Get(TraceIDHeader))
if !ok {
return trace.SpanContext{}, false
}
sid, ok := parseSpanID(req.Header.Get(spanIDHeader))
sid, ok := ParseSpanID(req.Header.Get(SpanIDHeader))
if !ok {
return trace.SpanContext{}, false
}
sampled, _ := parseSampled(req.Header.Get(sampledHeader))
sampled, _ := ParseSampled(req.Header.Get(SampledHeader))
return trace.SpanContext{
TraceID: tid,
SpanID: sid,
TraceOptions: sampled,
}, true
}

func parseTraceID(tid string) (trace.TraceID, bool) {
// ParseTraceID parses the value of the X-B3-TraceId header.
func ParseTraceID(tid string) (trace.TraceID, bool) {
if tid == "" {
return trace.TraceID{}, false
}
Expand All @@ -82,20 +84,22 @@ func parseTraceID(tid string) (trace.TraceID, bool) {
return traceID, true
}

func parseSpanID(sid string) (spanID trace.SpanID, ok bool) {
// ParseSpanID parses the value of the X-B3-SpanId or X-B3-ParentSpanId headers.
func ParseSpanID(sid string) (spanID trace.SpanID, ok bool) {
if sid == "" {
return trace.SpanID{}, false
}
b, err := hex.DecodeString(sid)
if err != nil {
return trace.SpanID{}, false
}
start := (8 - len(b))
start := 8 - len(b)
copy(spanID[start:], b)
return spanID, true
}

func parseSampled(sampled string) (trace.TraceOptions, bool) {
// ParseSampled parses the value of the X-B3-Sampled header.
func ParseSampled(sampled string) (trace.TraceOptions, bool) {
switch sampled {
case "true", "1":
return trace.TraceOptions(1), true
Expand All @@ -106,14 +110,14 @@ func parseSampled(sampled string) (trace.TraceOptions, bool) {

// SpanContextToRequest modifies the given request to include B3 headers.
func (f *HTTPFormat) SpanContextToRequest(sc trace.SpanContext, req *http.Request) {
req.Header.Set(traceIDHeader, hex.EncodeToString(sc.TraceID[:]))
req.Header.Set(spanIDHeader, hex.EncodeToString(sc.SpanID[:]))
req.Header.Set(TraceIDHeader, hex.EncodeToString(sc.TraceID[:]))
req.Header.Set(SpanIDHeader, hex.EncodeToString(sc.SpanID[:]))

var sampled string
if sc.IsSampled() {
sampled = "1"
} else {
sampled = "0"
}
req.Header.Set(sampledHeader, sampled)
req.Header.Set(SampledHeader, sampled)
}
42 changes: 21 additions & 21 deletions plugin/ochttp/propagation/b3/b3_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ func TestHTTPFormat_FromRequest(t *testing.T) {
name: "128-bit trace ID + 64-bit span ID; sampled=1",
makeReq: func() *http.Request {
req, _ := http.NewRequest("GET", "http://example.com", nil)
req.Header.Set(traceIDHeader, "463ac35c9f6413ad48485a3953bb6124")
req.Header.Set(spanIDHeader, "0020000000000001")
req.Header.Set(sampledHeader, "1")
req.Header.Set(TraceIDHeader, "463ac35c9f6413ad48485a3953bb6124")
req.Header.Set(SpanIDHeader, "0020000000000001")
req.Header.Set(SampledHeader, "1")
return req
},
wantSc: trace.SpanContext{
Expand All @@ -49,9 +49,9 @@ func TestHTTPFormat_FromRequest(t *testing.T) {
name: "short trace ID + short span ID; sampled=1",
makeReq: func() *http.Request {
req, _ := http.NewRequest("GET", "http://example.com", nil)
req.Header.Set(traceIDHeader, "000102")
req.Header.Set(spanIDHeader, "000102")
req.Header.Set(sampledHeader, "1")
req.Header.Set(TraceIDHeader, "000102")
req.Header.Set(SpanIDHeader, "000102")
req.Header.Set(SampledHeader, "1")
return req
},
wantSc: trace.SpanContext{
Expand All @@ -65,9 +65,9 @@ func TestHTTPFormat_FromRequest(t *testing.T) {
name: "64-bit trace ID + 64-bit span ID; sampled=0",
makeReq: func() *http.Request {
req, _ := http.NewRequest("GET", "http://example.com", nil)
req.Header.Set(traceIDHeader, "0020000000000001")
req.Header.Set(spanIDHeader, "0020000000000001")
req.Header.Set(sampledHeader, "0")
req.Header.Set(TraceIDHeader, "0020000000000001")
req.Header.Set(SpanIDHeader, "0020000000000001")
req.Header.Set(SampledHeader, "0")
return req
},
wantSc: trace.SpanContext{
Expand All @@ -81,8 +81,8 @@ func TestHTTPFormat_FromRequest(t *testing.T) {
name: "128-bit trace ID + 64-bit span ID; no sampling header",
makeReq: func() *http.Request {
req, _ := http.NewRequest("GET", "http://example.com", nil)
req.Header.Set(traceIDHeader, "463ac35c9f6413ad48485a3953bb6124")
req.Header.Set(spanIDHeader, "0020000000000001")
req.Header.Set(TraceIDHeader, "463ac35c9f6413ad48485a3953bb6124")
req.Header.Set(SpanIDHeader, "0020000000000001")
return req
},
wantSc: trace.SpanContext{
Expand All @@ -96,8 +96,8 @@ func TestHTTPFormat_FromRequest(t *testing.T) {
name: "invalid trace ID + 64-bit span ID; no sampling header",
makeReq: func() *http.Request {
req, _ := http.NewRequest("GET", "http://example.com", nil)
req.Header.Set(traceIDHeader, "")
req.Header.Set(spanIDHeader, "0020000000000001")
req.Header.Set(TraceIDHeader, "")
req.Header.Set(SpanIDHeader, "0020000000000001")
return req
},
wantSc: trace.SpanContext{},
Expand All @@ -107,8 +107,8 @@ func TestHTTPFormat_FromRequest(t *testing.T) {
name: "128-bit trace ID; invalid span ID; no sampling header",
makeReq: func() *http.Request {
req, _ := http.NewRequest("GET", "http://example.com", nil)
req.Header.Set(traceIDHeader, "463ac35c9f6413ad48485a3953bb6124")
req.Header.Set(spanIDHeader, "")
req.Header.Set(TraceIDHeader, "463ac35c9f6413ad48485a3953bb6124")
req.Header.Set(SpanIDHeader, "")
return req
},
wantSc: trace.SpanContext{},
Expand All @@ -118,9 +118,9 @@ func TestHTTPFormat_FromRequest(t *testing.T) {
name: "128-bit trace ID + 64-bit span ID; sampled=true",
makeReq: func() *http.Request {
req, _ := http.NewRequest("GET", "http://example.com", nil)
req.Header.Set(traceIDHeader, "463ac35c9f6413ad48485a3953bb6124")
req.Header.Set(spanIDHeader, "0020000000000001")
req.Header.Set(sampledHeader, "true")
req.Header.Set(TraceIDHeader, "463ac35c9f6413ad48485a3953bb6124")
req.Header.Set(SpanIDHeader, "0020000000000001")
req.Header.Set(SampledHeader, "true")
return req
},
wantSc: trace.SpanContext{
Expand All @@ -134,9 +134,9 @@ func TestHTTPFormat_FromRequest(t *testing.T) {
name: "128-bit trace ID + 64-bit span ID; sampled=false",
makeReq: func() *http.Request {
req, _ := http.NewRequest("GET", "http://example.com", nil)
req.Header.Set(traceIDHeader, "463ac35c9f6413ad48485a3953bb6124")
req.Header.Set(spanIDHeader, "0020000000000001")
req.Header.Set(sampledHeader, "false")
req.Header.Set(TraceIDHeader, "463ac35c9f6413ad48485a3953bb6124")
req.Header.Set(SpanIDHeader, "0020000000000001")
req.Header.Set(SampledHeader, "false")
return req
},
wantSc: trace.SpanContext{
Expand Down

0 comments on commit 3a82755

Please sign in to comment.