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