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

Commit

Permalink
Made public traceparent/tracestate marshal/unmarshal (#1218)
Browse files Browse the repository at this point in the history
  • Loading branch information
slinkydeveloper committed Jul 16, 2020
1 parent af30f77 commit 3456e1d
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 17 deletions.
49 changes: 32 additions & 17 deletions plugin/ochttp/propagation/tracecontext/propagation.go
Expand Up @@ -47,11 +47,17 @@ type HTTPFormat struct{}

// SpanContextFromRequest extracts a span context from incoming requests.
func (f *HTTPFormat) SpanContextFromRequest(req *http.Request) (sc trace.SpanContext, ok bool) {
h, ok := getRequestHeader(req, traceparentHeader, false)
if !ok {
tp, _ := getRequestHeader(req, traceparentHeader, false)
ts, _ := getRequestHeader(req, tracestateHeader, true)
return f.SpanContextFromHeaders(tp, ts)
}

// SpanContextFromHeaders extracts a span context from provided header values.
func (f *HTTPFormat) SpanContextFromHeaders(tp string, ts string) (sc trace.SpanContext, ok bool) {
if tp == "" {
return trace.SpanContext{}, false
}
sections := strings.Split(h, "-")
sections := strings.Split(tp, "-")
if len(sections) < 4 {
return trace.SpanContext{}, false
}
Expand Down Expand Up @@ -101,7 +107,7 @@ func (f *HTTPFormat) SpanContextFromRequest(req *http.Request) (sc trace.SpanCon
return trace.SpanContext{}, false
}

sc.Tracestate = tracestateFromRequest(req)
sc.Tracestate = tracestateFromHeader(ts)
return sc, true
}

Expand All @@ -128,14 +134,13 @@ func getRequestHeader(req *http.Request, name string, commaSeparated bool) (hdr
// are resolved.
// https://github.com/w3c/distributed-tracing/issues/172
// https://github.com/w3c/distributed-tracing/issues/175
func tracestateFromRequest(req *http.Request) *tracestate.Tracestate {
h, _ := getRequestHeader(req, tracestateHeader, true)
if h == "" {
func tracestateFromHeader(ts string) *tracestate.Tracestate {
if ts == "" {
return nil
}

var entries []tracestate.Entry
pairs := strings.Split(h, ",")
pairs := strings.Split(ts, ",")
hdrLenWithoutOWS := len(pairs) - 1 // Number of commas
for _, pair := range pairs {
matches := trimOWSRegExp.FindStringSubmatch(pair)
Expand All @@ -153,15 +158,15 @@ func tracestateFromRequest(req *http.Request) *tracestate.Tracestate {
}
entries = append(entries, tracestate.Entry{Key: kv[0], Value: kv[1]})
}
ts, err := tracestate.New(nil, entries...)
tsParsed, err := tracestate.New(nil, entries...)
if err != nil {
return nil
}

return ts
return tsParsed
}

func tracestateToRequest(sc trace.SpanContext, req *http.Request) {
func tracestateToHeader(sc trace.SpanContext) string {
var pairs = make([]string, 0, len(sc.Tracestate.Entries()))
if sc.Tracestate != nil {
for _, entry := range sc.Tracestate.Entries() {
Expand All @@ -170,18 +175,28 @@ func tracestateToRequest(sc trace.SpanContext, req *http.Request) {
h := strings.Join(pairs, ",")

if h != "" && len(h) <= maxTracestateLen {
req.Header.Set(tracestateHeader, h)
return h
}
}
return ""
}

// SpanContextToRequest modifies the given request to include traceparent and tracestate headers.
func (f *HTTPFormat) SpanContextToRequest(sc trace.SpanContext, req *http.Request) {
h := fmt.Sprintf("%x-%x-%x-%x",
// SpanContextToHeaders serialize the SpanContext to traceparent and tracestate headers.
func (f *HTTPFormat) SpanContextToHeaders(sc trace.SpanContext) (tp string, ts string) {
tp = fmt.Sprintf("%x-%x-%x-%x",
[]byte{supportedVersion},
sc.TraceID[:],
sc.SpanID[:],
[]byte{byte(sc.TraceOptions)})
req.Header.Set(traceparentHeader, h)
tracestateToRequest(sc, req)
ts = tracestateToHeader(sc)
return
}

// SpanContextToRequest modifies the given request to include traceparent and tracestate headers.
func (f *HTTPFormat) SpanContextToRequest(sc trace.SpanContext, req *http.Request) {
tp, ts := f.SpanContextToHeaders(sc)
req.Header.Set(traceparentHeader, tp)
if ts != "" {
req.Header.Set(tracestateHeader, ts)
}
}
26 changes: 26 additions & 0 deletions plugin/ochttp/propagation/tracecontext/propagation_test.go
Expand Up @@ -100,6 +100,14 @@ func TestHTTPFormat_FromRequest(t *testing.T) {
if gotOk != tt.wantOk {
t.Errorf("HTTPFormat.FromRequest() gotOk = %v, want %v", gotOk, tt.wantOk)
}

gotSc, gotOk = f.SpanContextFromHeaders(tt.header, "")
if !reflect.DeepEqual(gotSc, tt.wantSc) {
t.Errorf("HTTPFormat.SpanContextFromHeaders() gotTs = %v, want %v", gotSc.Tracestate, tt.wantSc.Tracestate)
}
if gotOk != tt.wantOk {
t.Errorf("HTTPFormat.SpanContextFromHeaders() gotOk = %v, want %v", gotOk, tt.wantOk)
}
})
}
}
Expand Down Expand Up @@ -128,6 +136,11 @@ func TestHTTPFormat_ToRequest(t *testing.T) {
if got, want := h, tt.wantHeader; got != want {
t.Errorf("HTTPFormat.ToRequest() header = %v, want %v", got, want)
}

gotTp, _ := f.SpanContextToHeaders(tt.sc)
if gotTp != tt.wantHeader {
t.Errorf("HTTPFormat.SpanContextToHeaders() tracestate header = %v, want %v", gotTp, tt.wantHeader)
}
})
}
}
Expand Down Expand Up @@ -212,6 +225,14 @@ func TestHTTPFormatTracestate_FromRequest(t *testing.T) {
if gotOk != tt.wantOk {
t.Errorf("HTTPFormat.FromRequest() gotOk = %v, want %v", gotOk, tt.wantOk)
}

gotSc, gotOk = f.SpanContextFromHeaders(tt.tpHeader, tt.tsHeader)
if !reflect.DeepEqual(gotSc, tt.wantSc) {
t.Errorf("HTTPFormat.SpanContextFromHeaders() gotTs = %v, want %v", gotSc.Tracestate, tt.wantSc.Tracestate)
}
if gotOk != tt.wantOk {
t.Errorf("HTTPFormat.SpanContextFromHeaders() gotOk = %v, want %v", gotOk, tt.wantOk)
}
})
}
}
Expand Down Expand Up @@ -262,6 +283,11 @@ func TestHTTPFormatTracestate_ToRequest(t *testing.T) {
if got, want := h, tt.wantHeader; got != want {
t.Errorf("HTTPFormat.ToRequest() tracestate header = %v, want %v", got, want)
}

_, gotTs := f.SpanContextToHeaders(tt.sc)
if gotTs != tt.wantHeader {
t.Errorf("HTTPFormat.SpanContextToHeaders() tracestate header = %v, want %v", gotTs, tt.wantHeader)
}
})
}
}

0 comments on commit 3456e1d

Please sign in to comment.