...
1
2
3
4
5
6
7
8
9
10 package propagation
11
12 import (
13 "encoding/binary"
14 "encoding/hex"
15 "fmt"
16 "net/http"
17 "strconv"
18 "strings"
19
20 "go.opencensus.io/trace"
21 "go.opencensus.io/trace/propagation"
22 )
23
24 const (
25 httpHeaderMaxSize = 200
26 httpHeader = `X-Cloud-Trace-Context`
27 )
28
29 var _ propagation.HTTPFormat = (*HTTPFormat)(nil)
30
31
32
33 type HTTPFormat struct{}
34
35
36 func (f *HTTPFormat) SpanContextFromRequest(req *http.Request) (sc trace.SpanContext, ok bool) {
37 h := req.Header.Get(httpHeader)
38
39
40
41 if h == "" || len(h) > httpHeaderMaxSize {
42 return trace.SpanContext{}, false
43 }
44
45
46 slash := strings.Index(h, `/`)
47 if slash == -1 {
48 return trace.SpanContext{}, false
49 }
50 tid, h := h[:slash], h[slash+1:]
51
52 buf, err := hex.DecodeString(tid)
53 if err != nil {
54 return trace.SpanContext{}, false
55 }
56 copy(sc.TraceID[:], buf)
57
58
59 spanstr := h
60 semicolon := strings.Index(h, `;`)
61 if semicolon != -1 {
62 spanstr, h = h[:semicolon], h[semicolon+1:]
63 }
64 sid, err := strconv.ParseUint(spanstr, 10, 64)
65 if err != nil {
66 return trace.SpanContext{}, false
67 }
68 binary.BigEndian.PutUint64(sc.SpanID[:], sid)
69
70
71 if !strings.HasPrefix(h, "o=") {
72 return sc, true
73 }
74 o, err := strconv.ParseUint(h[2:], 10, 64)
75 if err != nil {
76 return trace.SpanContext{}, false
77 }
78 sc.TraceOptions = trace.TraceOptions(o)
79 return sc, true
80 }
81
82
83 func (f *HTTPFormat) SpanContextToRequest(sc trace.SpanContext, req *http.Request) {
84 sid := binary.BigEndian.Uint64(sc.SpanID[:])
85 header := fmt.Sprintf("%s/%d;o=%d", hex.EncodeToString(sc.TraceID[:]), sid, int64(sc.TraceOptions))
86 req.Header.Set(httpHeader, header)
87 }
88
View as plain text