diff options
Diffstat (limited to 'vendor/go.opencensus.io/trace')
-rw-r--r-- | vendor/go.opencensus.io/trace/basetypes.go | 114 | ||||
-rw-r--r-- | vendor/go.opencensus.io/trace/config.go | 48 | ||||
-rw-r--r-- | vendor/go.opencensus.io/trace/doc.go | 53 | ||||
-rw-r--r-- | vendor/go.opencensus.io/trace/exemplar.go | 43 | ||||
-rw-r--r-- | vendor/go.opencensus.io/trace/export.go | 90 | ||||
-rw-r--r-- | vendor/go.opencensus.io/trace/internal/internal.go | 21 | ||||
-rw-r--r-- | vendor/go.opencensus.io/trace/propagation/propagation.go | 108 | ||||
-rw-r--r-- | vendor/go.opencensus.io/trace/sampling.go | 75 | ||||
-rw-r--r-- | vendor/go.opencensus.io/trace/spanbucket.go | 130 | ||||
-rw-r--r-- | vendor/go.opencensus.io/trace/spanstore.go | 306 | ||||
-rw-r--r-- | vendor/go.opencensus.io/trace/status_codes.go | 37 | ||||
-rw-r--r-- | vendor/go.opencensus.io/trace/trace.go | 516 | ||||
-rw-r--r-- | vendor/go.opencensus.io/trace/trace_go11.go | 32 | ||||
-rw-r--r-- | vendor/go.opencensus.io/trace/trace_nongo11.go | 25 | ||||
-rw-r--r-- | vendor/go.opencensus.io/trace/tracestate/tracestate.go | 147 |
15 files changed, 1745 insertions, 0 deletions
diff --git a/vendor/go.opencensus.io/trace/basetypes.go b/vendor/go.opencensus.io/trace/basetypes.go new file mode 100644 index 0000000..01f0f90 --- /dev/null +++ b/vendor/go.opencensus.io/trace/basetypes.go | |||
@@ -0,0 +1,114 @@ | |||
1 | // Copyright 2017, OpenCensus 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 trace | ||
16 | |||
17 | import ( | ||
18 | "fmt" | ||
19 | "time" | ||
20 | ) | ||
21 | |||
22 | type ( | ||
23 | // TraceID is a 16-byte identifier for a set of spans. | ||
24 | TraceID [16]byte | ||
25 | |||
26 | // SpanID is an 8-byte identifier for a single span. | ||
27 | SpanID [8]byte | ||
28 | ) | ||
29 | |||
30 | func (t TraceID) String() string { | ||
31 | return fmt.Sprintf("%02x", t[:]) | ||
32 | } | ||
33 | |||
34 | func (s SpanID) String() string { | ||
35 | return fmt.Sprintf("%02x", s[:]) | ||
36 | } | ||
37 | |||
38 | // Annotation represents a text annotation with a set of attributes and a timestamp. | ||
39 | type Annotation struct { | ||
40 | Time time.Time | ||
41 | Message string | ||
42 | Attributes map[string]interface{} | ||
43 | } | ||
44 | |||
45 | // Attribute represents a key-value pair on a span, link or annotation. | ||
46 | // Construct with one of: BoolAttribute, Int64Attribute, or StringAttribute. | ||
47 | type Attribute struct { | ||
48 | key string | ||
49 | value interface{} | ||
50 | } | ||
51 | |||
52 | // BoolAttribute returns a bool-valued attribute. | ||
53 | func BoolAttribute(key string, value bool) Attribute { | ||
54 | return Attribute{key: key, value: value} | ||
55 | } | ||
56 | |||
57 | // Int64Attribute returns an int64-valued attribute. | ||
58 | func Int64Attribute(key string, value int64) Attribute { | ||
59 | return Attribute{key: key, value: value} | ||
60 | } | ||
61 | |||
62 | // StringAttribute returns a string-valued attribute. | ||
63 | func StringAttribute(key string, value string) Attribute { | ||
64 | return Attribute{key: key, value: value} | ||
65 | } | ||
66 | |||
67 | // LinkType specifies the relationship between the span that had the link | ||
68 | // added, and the linked span. | ||
69 | type LinkType int32 | ||
70 | |||
71 | // LinkType values. | ||
72 | const ( | ||
73 | LinkTypeUnspecified LinkType = iota // The relationship of the two spans is unknown. | ||
74 | LinkTypeChild // The current span is a child of the linked span. | ||
75 | LinkTypeParent // The current span is the parent of the linked span. | ||
76 | ) | ||
77 | |||
78 | // Link represents a reference from one span to another span. | ||
79 | type Link struct { | ||
80 | TraceID TraceID | ||
81 | SpanID SpanID | ||
82 | Type LinkType | ||
83 | // Attributes is a set of attributes on the link. | ||
84 | Attributes map[string]interface{} | ||
85 | } | ||
86 | |||
87 | // MessageEventType specifies the type of message event. | ||
88 | type MessageEventType int32 | ||
89 | |||
90 | // MessageEventType values. | ||
91 | const ( | ||
92 | MessageEventTypeUnspecified MessageEventType = iota // Unknown event type. | ||
93 | MessageEventTypeSent // Indicates a sent RPC message. | ||
94 | MessageEventTypeRecv // Indicates a received RPC message. | ||
95 | ) | ||
96 | |||
97 | // MessageEvent represents an event describing a message sent or received on the network. | ||
98 | type MessageEvent struct { | ||
99 | Time time.Time | ||
100 | EventType MessageEventType | ||
101 | MessageID int64 | ||
102 | UncompressedByteSize int64 | ||
103 | CompressedByteSize int64 | ||
104 | } | ||
105 | |||
106 | // Status is the status of a Span. | ||
107 | type Status struct { | ||
108 | // Code is a status code. Zero indicates success. | ||
109 | // | ||
110 | // If Code will be propagated to Google APIs, it ideally should be a value from | ||
111 | // https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto . | ||
112 | Code int32 | ||
113 | Message string | ||
114 | } | ||
diff --git a/vendor/go.opencensus.io/trace/config.go b/vendor/go.opencensus.io/trace/config.go new file mode 100644 index 0000000..0816892 --- /dev/null +++ b/vendor/go.opencensus.io/trace/config.go | |||
@@ -0,0 +1,48 @@ | |||
1 | // Copyright 2018, OpenCensus 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 trace | ||
16 | |||
17 | import ( | ||
18 | "sync" | ||
19 | |||
20 | "go.opencensus.io/trace/internal" | ||
21 | ) | ||
22 | |||
23 | // Config represents the global tracing configuration. | ||
24 | type Config struct { | ||
25 | // DefaultSampler is the default sampler used when creating new spans. | ||
26 | DefaultSampler Sampler | ||
27 | |||
28 | // IDGenerator is for internal use only. | ||
29 | IDGenerator internal.IDGenerator | ||
30 | } | ||
31 | |||
32 | var configWriteMu sync.Mutex | ||
33 | |||
34 | // ApplyConfig applies changes to the global tracing configuration. | ||
35 | // | ||
36 | // Fields not provided in the given config are going to be preserved. | ||
37 | func ApplyConfig(cfg Config) { | ||
38 | configWriteMu.Lock() | ||
39 | defer configWriteMu.Unlock() | ||
40 | c := *config.Load().(*Config) | ||
41 | if cfg.DefaultSampler != nil { | ||
42 | c.DefaultSampler = cfg.DefaultSampler | ||
43 | } | ||
44 | if cfg.IDGenerator != nil { | ||
45 | c.IDGenerator = cfg.IDGenerator | ||
46 | } | ||
47 | config.Store(&c) | ||
48 | } | ||
diff --git a/vendor/go.opencensus.io/trace/doc.go b/vendor/go.opencensus.io/trace/doc.go new file mode 100644 index 0000000..04b1ee4 --- /dev/null +++ b/vendor/go.opencensus.io/trace/doc.go | |||
@@ -0,0 +1,53 @@ | |||
1 | // Copyright 2017, OpenCensus 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 | /* | ||
16 | Package trace contains support for OpenCensus distributed tracing. | ||
17 | |||
18 | The following assumes a basic familiarity with OpenCensus concepts. | ||
19 | See http://opencensus.io | ||
20 | |||
21 | |||
22 | Exporting Traces | ||
23 | |||
24 | To export collected tracing data, register at least one exporter. You can use | ||
25 | one of the provided exporters or write your own. | ||
26 | |||
27 | trace.RegisterExporter(exporter) | ||
28 | |||
29 | By default, traces will be sampled relatively rarely. To change the sampling | ||
30 | frequency for your entire program, call ApplyConfig. Use a ProbabilitySampler | ||
31 | to sample a subset of traces, or use AlwaysSample to collect a trace on every run: | ||
32 | |||
33 | trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()}) | ||
34 | |||
35 | Be careful about using trace.AlwaysSample in a production application with | ||
36 | significant traffic: a new trace will be started and exported for every request. | ||
37 | |||
38 | Adding Spans to a Trace | ||
39 | |||
40 | A trace consists of a tree of spans. In Go, the current span is carried in a | ||
41 | context.Context. | ||
42 | |||
43 | It is common to want to capture all the activity of a function call in a span. For | ||
44 | this to work, the function must take a context.Context as a parameter. Add these two | ||
45 | lines to the top of the function: | ||
46 | |||
47 | ctx, span := trace.StartSpan(ctx, "example.com/Run") | ||
48 | defer span.End() | ||
49 | |||
50 | StartSpan will create a new top-level span if the context | ||
51 | doesn't contain another span, otherwise it will create a child span. | ||
52 | */ | ||
53 | package trace // import "go.opencensus.io/trace" | ||
diff --git a/vendor/go.opencensus.io/trace/exemplar.go b/vendor/go.opencensus.io/trace/exemplar.go new file mode 100644 index 0000000..416d805 --- /dev/null +++ b/vendor/go.opencensus.io/trace/exemplar.go | |||
@@ -0,0 +1,43 @@ | |||
1 | // Copyright 2018, OpenCensus 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 trace | ||
16 | |||
17 | import ( | ||
18 | "context" | ||
19 | "encoding/hex" | ||
20 | |||
21 | "go.opencensus.io/exemplar" | ||
22 | ) | ||
23 | |||
24 | func init() { | ||
25 | exemplar.RegisterAttachmentExtractor(attachSpanContext) | ||
26 | } | ||
27 | |||
28 | func attachSpanContext(ctx context.Context, a exemplar.Attachments) exemplar.Attachments { | ||
29 | span := FromContext(ctx) | ||
30 | if span == nil { | ||
31 | return a | ||
32 | } | ||
33 | sc := span.SpanContext() | ||
34 | if !sc.IsSampled() { | ||
35 | return a | ||
36 | } | ||
37 | if a == nil { | ||
38 | a = make(exemplar.Attachments) | ||
39 | } | ||
40 | a[exemplar.KeyTraceID] = hex.EncodeToString(sc.TraceID[:]) | ||
41 | a[exemplar.KeySpanID] = hex.EncodeToString(sc.SpanID[:]) | ||
42 | return a | ||
43 | } | ||
diff --git a/vendor/go.opencensus.io/trace/export.go b/vendor/go.opencensus.io/trace/export.go new file mode 100644 index 0000000..77a8c73 --- /dev/null +++ b/vendor/go.opencensus.io/trace/export.go | |||
@@ -0,0 +1,90 @@ | |||
1 | // Copyright 2017, OpenCensus 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 trace | ||
16 | |||
17 | import ( | ||
18 | "sync" | ||
19 | "sync/atomic" | ||
20 | "time" | ||
21 | ) | ||
22 | |||
23 | // Exporter is a type for functions that receive sampled trace spans. | ||
24 | // | ||
25 | // The ExportSpan method should be safe for concurrent use and should return | ||
26 | // quickly; if an Exporter takes a significant amount of time to process a | ||
27 | // SpanData, that work should be done on another goroutine. | ||
28 | // | ||
29 | // The SpanData should not be modified, but a pointer to it can be kept. | ||
30 | type Exporter interface { | ||
31 | ExportSpan(s *SpanData) | ||
32 | } | ||
33 | |||
34 | type exportersMap map[Exporter]struct{} | ||
35 | |||
36 | var ( | ||
37 | exporterMu sync.Mutex | ||
38 | exporters atomic.Value | ||
39 | ) | ||
40 | |||
41 | // RegisterExporter adds to the list of Exporters that will receive sampled | ||
42 | // trace spans. | ||
43 | // | ||
44 | // Binaries can register exporters, libraries shouldn't register exporters. | ||
45 | func RegisterExporter(e Exporter) { | ||
46 | exporterMu.Lock() | ||
47 | new := make(exportersMap) | ||
48 | if old, ok := exporters.Load().(exportersMap); ok { | ||
49 | for k, v := range old { | ||
50 | new[k] = v | ||
51 | } | ||
52 | } | ||
53 | new[e] = struct{}{} | ||
54 | exporters.Store(new) | ||
55 | exporterMu.Unlock() | ||
56 | } | ||
57 | |||
58 | // UnregisterExporter removes from the list of Exporters the Exporter that was | ||
59 | // registered with the given name. | ||
60 | func UnregisterExporter(e Exporter) { | ||
61 | exporterMu.Lock() | ||
62 | new := make(exportersMap) | ||
63 | if old, ok := exporters.Load().(exportersMap); ok { | ||
64 | for k, v := range old { | ||
65 | new[k] = v | ||
66 | } | ||
67 | } | ||
68 | delete(new, e) | ||
69 | exporters.Store(new) | ||
70 | exporterMu.Unlock() | ||
71 | } | ||
72 | |||
73 | // SpanData contains all the information collected by a Span. | ||
74 | type SpanData struct { | ||
75 | SpanContext | ||
76 | ParentSpanID SpanID | ||
77 | SpanKind int | ||
78 | Name string | ||
79 | StartTime time.Time | ||
80 | // The wall clock time of EndTime will be adjusted to always be offset | ||
81 | // from StartTime by the duration of the span. | ||
82 | EndTime time.Time | ||
83 | // The values of Attributes each have type string, bool, or int64. | ||
84 | Attributes map[string]interface{} | ||
85 | Annotations []Annotation | ||
86 | MessageEvents []MessageEvent | ||
87 | Status | ||
88 | Links []Link | ||
89 | HasRemoteParent bool | ||
90 | } | ||
diff --git a/vendor/go.opencensus.io/trace/internal/internal.go b/vendor/go.opencensus.io/trace/internal/internal.go new file mode 100644 index 0000000..1c8b9b3 --- /dev/null +++ b/vendor/go.opencensus.io/trace/internal/internal.go | |||
@@ -0,0 +1,21 @@ | |||
1 | // Copyright 2018, OpenCensus 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 internal provides trace internals. | ||
16 | package internal | ||
17 | |||
18 | type IDGenerator interface { | ||
19 | NewTraceID() [16]byte | ||
20 | NewSpanID() [8]byte | ||
21 | } | ||
diff --git a/vendor/go.opencensus.io/trace/propagation/propagation.go b/vendor/go.opencensus.io/trace/propagation/propagation.go new file mode 100644 index 0000000..1eb190a --- /dev/null +++ b/vendor/go.opencensus.io/trace/propagation/propagation.go | |||
@@ -0,0 +1,108 @@ | |||
1 | // Copyright 2017, OpenCensus 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 propagation implements the binary trace context format. | ||
16 | package propagation // import "go.opencensus.io/trace/propagation" | ||
17 | |||
18 | // TODO: link to external spec document. | ||
19 | |||
20 | // BinaryFormat format: | ||
21 | // | ||
22 | // Binary value: <version_id><version_format> | ||
23 | // version_id: 1 byte representing the version id. | ||
24 | // | ||
25 | // For version_id = 0: | ||
26 | // | ||
27 | // version_format: <field><field> | ||
28 | // field_format: <field_id><field_format> | ||
29 | // | ||
30 | // Fields: | ||
31 | // | ||
32 | // TraceId: (field_id = 0, len = 16, default = "0000000000000000") - 16-byte array representing the trace_id. | ||
33 | // SpanId: (field_id = 1, len = 8, default = "00000000") - 8-byte array representing the span_id. | ||
34 | // TraceOptions: (field_id = 2, len = 1, default = "0") - 1-byte array representing the trace_options. | ||
35 | // | ||
36 | // Fields MUST be encoded using the field id order (smaller to higher). | ||
37 | // | ||
38 | // Valid value example: | ||
39 | // | ||
40 | // {0, 0, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 1, 97, | ||
41 | // 98, 99, 100, 101, 102, 103, 104, 2, 1} | ||
42 | // | ||
43 | // version_id = 0; | ||
44 | // trace_id = {64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79} | ||
45 | // span_id = {97, 98, 99, 100, 101, 102, 103, 104}; | ||
46 | // trace_options = {1}; | ||
47 | |||
48 | import ( | ||
49 | "net/http" | ||
50 | |||
51 | "go.opencensus.io/trace" | ||
52 | ) | ||
53 | |||
54 | // Binary returns the binary format representation of a SpanContext. | ||
55 | // | ||
56 | // If sc is the zero value, Binary returns nil. | ||
57 | func Binary(sc trace.SpanContext) []byte { | ||
58 | if sc == (trace.SpanContext{}) { | ||
59 | return nil | ||
60 | } | ||
61 | var b [29]byte | ||
62 | copy(b[2:18], sc.TraceID[:]) | ||
63 | b[18] = 1 | ||
64 | copy(b[19:27], sc.SpanID[:]) | ||
65 | b[27] = 2 | ||
66 | b[28] = uint8(sc.TraceOptions) | ||
67 | return b[:] | ||
68 | } | ||
69 | |||
70 | // FromBinary returns the SpanContext represented by b. | ||
71 | // | ||
72 | // If b has an unsupported version ID or contains no TraceID, FromBinary | ||
73 | // returns with ok==false. | ||
74 | func FromBinary(b []byte) (sc trace.SpanContext, ok bool) { | ||
75 | if len(b) == 0 || b[0] != 0 { | ||
76 | return trace.SpanContext{}, false | ||
77 | } | ||
78 | b = b[1:] | ||
79 | if len(b) >= 17 && b[0] == 0 { | ||
80 | copy(sc.TraceID[:], b[1:17]) | ||
81 | b = b[17:] | ||
82 | } else { | ||
83 | return trace.SpanContext{}, false | ||
84 | } | ||
85 | if len(b) >= 9 && b[0] == 1 { | ||
86 | copy(sc.SpanID[:], b[1:9]) | ||
87 | b = b[9:] | ||
88 | } | ||
89 | if len(b) >= 2 && b[0] == 2 { | ||
90 | sc.TraceOptions = trace.TraceOptions(b[1]) | ||
91 | } | ||
92 | return sc, true | ||
93 | } | ||
94 | |||
95 | // HTTPFormat implementations propagate span contexts | ||
96 | // in HTTP requests. | ||
97 | // | ||
98 | // SpanContextFromRequest extracts a span context from incoming | ||
99 | // requests. | ||
100 | // | ||
101 | // SpanContextToRequest modifies the given request to include the given | ||
102 | // span context. | ||
103 | type HTTPFormat interface { | ||
104 | SpanContextFromRequest(req *http.Request) (sc trace.SpanContext, ok bool) | ||
105 | SpanContextToRequest(sc trace.SpanContext, req *http.Request) | ||
106 | } | ||
107 | |||
108 | // TODO(jbd): Find a more representative but short name for HTTPFormat. | ||
diff --git a/vendor/go.opencensus.io/trace/sampling.go b/vendor/go.opencensus.io/trace/sampling.go new file mode 100644 index 0000000..71c10f9 --- /dev/null +++ b/vendor/go.opencensus.io/trace/sampling.go | |||
@@ -0,0 +1,75 @@ | |||
1 | // Copyright 2017, OpenCensus 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 trace | ||
16 | |||
17 | import ( | ||
18 | "encoding/binary" | ||
19 | ) | ||
20 | |||
21 | const defaultSamplingProbability = 1e-4 | ||
22 | |||
23 | // Sampler decides whether a trace should be sampled and exported. | ||
24 | type Sampler func(SamplingParameters) SamplingDecision | ||
25 | |||
26 | // SamplingParameters contains the values passed to a Sampler. | ||
27 | type SamplingParameters struct { | ||
28 | ParentContext SpanContext | ||
29 | TraceID TraceID | ||
30 | SpanID SpanID | ||
31 | Name string | ||
32 | HasRemoteParent bool | ||
33 | } | ||
34 | |||
35 | // SamplingDecision is the value returned by a Sampler. | ||
36 | type SamplingDecision struct { | ||
37 | Sample bool | ||
38 | } | ||
39 | |||
40 | // ProbabilitySampler returns a Sampler that samples a given fraction of traces. | ||
41 | // | ||
42 | // It also samples spans whose parents are sampled. | ||
43 | func ProbabilitySampler(fraction float64) Sampler { | ||
44 | if !(fraction >= 0) { | ||
45 | fraction = 0 | ||
46 | } else if fraction >= 1 { | ||
47 | return AlwaysSample() | ||
48 | } | ||
49 | |||
50 | traceIDUpperBound := uint64(fraction * (1 << 63)) | ||
51 | return Sampler(func(p SamplingParameters) SamplingDecision { | ||
52 | if p.ParentContext.IsSampled() { | ||
53 | return SamplingDecision{Sample: true} | ||
54 | } | ||
55 | x := binary.BigEndian.Uint64(p.TraceID[0:8]) >> 1 | ||
56 | return SamplingDecision{Sample: x < traceIDUpperBound} | ||
57 | }) | ||
58 | } | ||
59 | |||
60 | // AlwaysSample returns a Sampler that samples every trace. | ||
61 | // Be careful about using this sampler in a production application with | ||
62 | // significant traffic: a new trace will be started and exported for every | ||
63 | // request. | ||
64 | func AlwaysSample() Sampler { | ||
65 | return func(p SamplingParameters) SamplingDecision { | ||
66 | return SamplingDecision{Sample: true} | ||
67 | } | ||
68 | } | ||
69 | |||
70 | // NeverSample returns a Sampler that samples no traces. | ||
71 | func NeverSample() Sampler { | ||
72 | return func(p SamplingParameters) SamplingDecision { | ||
73 | return SamplingDecision{Sample: false} | ||
74 | } | ||
75 | } | ||
diff --git a/vendor/go.opencensus.io/trace/spanbucket.go b/vendor/go.opencensus.io/trace/spanbucket.go new file mode 100644 index 0000000..fbabad3 --- /dev/null +++ b/vendor/go.opencensus.io/trace/spanbucket.go | |||
@@ -0,0 +1,130 @@ | |||
1 | // Copyright 2017, OpenCensus 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 trace | ||
16 | |||
17 | import ( | ||
18 | "time" | ||
19 | ) | ||
20 | |||
21 | // samplePeriod is the minimum time between accepting spans in a single bucket. | ||
22 | const samplePeriod = time.Second | ||
23 | |||
24 | // defaultLatencies contains the default latency bucket bounds. | ||
25 | // TODO: consider defaults, make configurable | ||
26 | var defaultLatencies = [...]time.Duration{ | ||
27 | 10 * time.Microsecond, | ||
28 | 100 * time.Microsecond, | ||
29 | time.Millisecond, | ||
30 | 10 * time.Millisecond, | ||
31 | 100 * time.Millisecond, | ||
32 | time.Second, | ||
33 | 10 * time.Second, | ||
34 | time.Minute, | ||
35 | } | ||
36 | |||
37 | // bucket is a container for a set of spans for a particular error code or latency range. | ||
38 | type bucket struct { | ||
39 | nextTime time.Time // next time we can accept a span | ||
40 | buffer []*SpanData // circular buffer of spans | ||
41 | nextIndex int // location next SpanData should be placed in buffer | ||
42 | overflow bool // whether the circular buffer has wrapped around | ||
43 | } | ||
44 | |||
45 | func makeBucket(bufferSize int) bucket { | ||
46 | return bucket{ | ||
47 | buffer: make([]*SpanData, bufferSize), | ||
48 | } | ||
49 | } | ||
50 | |||
51 | // add adds a span to the bucket, if nextTime has been reached. | ||
52 | func (b *bucket) add(s *SpanData) { | ||
53 | if s.EndTime.Before(b.nextTime) { | ||
54 | return | ||
55 | } | ||
56 | if len(b.buffer) == 0 { | ||
57 | return | ||
58 | } | ||
59 | b.nextTime = s.EndTime.Add(samplePeriod) | ||
60 | b.buffer[b.nextIndex] = s | ||
61 | b.nextIndex++ | ||
62 | if b.nextIndex == len(b.buffer) { | ||
63 | b.nextIndex = 0 | ||
64 | b.overflow = true | ||
65 | } | ||
66 | } | ||
67 | |||
68 | // size returns the number of spans in the bucket. | ||
69 | func (b *bucket) size() int { | ||
70 | if b.overflow { | ||
71 | return len(b.buffer) | ||
72 | } | ||
73 | return b.nextIndex | ||
74 | } | ||
75 | |||
76 | // span returns the ith span in the bucket. | ||
77 | func (b *bucket) span(i int) *SpanData { | ||
78 | if !b.overflow { | ||
79 | return b.buffer[i] | ||
80 | } | ||
81 | if i < len(b.buffer)-b.nextIndex { | ||
82 | return b.buffer[b.nextIndex+i] | ||
83 | } | ||
84 | return b.buffer[b.nextIndex+i-len(b.buffer)] | ||
85 | } | ||
86 | |||
87 | // resize changes the size of the bucket to n, keeping up to n existing spans. | ||
88 | func (b *bucket) resize(n int) { | ||
89 | cur := b.size() | ||
90 | newBuffer := make([]*SpanData, n) | ||
91 | if cur < n { | ||
92 | for i := 0; i < cur; i++ { | ||
93 | newBuffer[i] = b.span(i) | ||
94 | } | ||
95 | b.buffer = newBuffer | ||
96 | b.nextIndex = cur | ||
97 | b.overflow = false | ||
98 | return | ||
99 | } | ||
100 | for i := 0; i < n; i++ { | ||
101 | newBuffer[i] = b.span(i + cur - n) | ||
102 | } | ||
103 | b.buffer = newBuffer | ||
104 | b.nextIndex = 0 | ||
105 | b.overflow = true | ||
106 | } | ||
107 | |||
108 | // latencyBucket returns the appropriate bucket number for a given latency. | ||
109 | func latencyBucket(latency time.Duration) int { | ||
110 | i := 0 | ||
111 | for i < len(defaultLatencies) && latency >= defaultLatencies[i] { | ||
112 | i++ | ||
113 | } | ||
114 | return i | ||
115 | } | ||
116 | |||
117 | // latencyBucketBounds returns the lower and upper bounds for a latency bucket | ||
118 | // number. | ||
119 | // | ||
120 | // The lower bound is inclusive, the upper bound is exclusive (except for the | ||
121 | // last bucket.) | ||
122 | func latencyBucketBounds(index int) (lower time.Duration, upper time.Duration) { | ||
123 | if index == 0 { | ||
124 | return 0, defaultLatencies[index] | ||
125 | } | ||
126 | if index == len(defaultLatencies) { | ||
127 | return defaultLatencies[index-1], 1<<63 - 1 | ||
128 | } | ||
129 | return defaultLatencies[index-1], defaultLatencies[index] | ||
130 | } | ||
diff --git a/vendor/go.opencensus.io/trace/spanstore.go b/vendor/go.opencensus.io/trace/spanstore.go new file mode 100644 index 0000000..c442d99 --- /dev/null +++ b/vendor/go.opencensus.io/trace/spanstore.go | |||
@@ -0,0 +1,306 @@ | |||
1 | // Copyright 2017, OpenCensus 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 trace | ||
16 | |||
17 | import ( | ||
18 | "sync" | ||
19 | "time" | ||
20 | |||
21 | "go.opencensus.io/internal" | ||
22 | ) | ||
23 | |||
24 | const ( | ||
25 | maxBucketSize = 100000 | ||
26 | defaultBucketSize = 10 | ||
27 | ) | ||
28 | |||
29 | var ( | ||
30 | ssmu sync.RWMutex // protects spanStores | ||
31 | spanStores = make(map[string]*spanStore) | ||
32 | ) | ||
33 | |||
34 | // This exists purely to avoid exposing internal methods used by z-Pages externally. | ||
35 | type internalOnly struct{} | ||
36 | |||
37 | func init() { | ||
38 | //TODO(#412): remove | ||
39 | internal.Trace = &internalOnly{} | ||
40 | } | ||
41 | |||
42 | // ReportActiveSpans returns the active spans for the given name. | ||
43 | func (i internalOnly) ReportActiveSpans(name string) []*SpanData { | ||
44 | s := spanStoreForName(name) | ||
45 | if s == nil { | ||
46 | return nil | ||
47 | } | ||
48 | var out []*SpanData | ||
49 | s.mu.Lock() | ||
50 | defer s.mu.Unlock() | ||
51 | for span := range s.active { | ||
52 | out = append(out, span.makeSpanData()) | ||
53 | } | ||
54 | return out | ||
55 | } | ||
56 | |||
57 | // ReportSpansByError returns a sample of error spans. | ||
58 | // | ||
59 | // If code is nonzero, only spans with that status code are returned. | ||
60 | func (i internalOnly) ReportSpansByError(name string, code int32) []*SpanData { | ||
61 | s := spanStoreForName(name) | ||
62 | if s == nil { | ||
63 | return nil | ||
64 | } | ||
65 | var out []*SpanData | ||
66 | s.mu.Lock() | ||
67 | defer s.mu.Unlock() | ||
68 | if code != 0 { | ||
69 | if b, ok := s.errors[code]; ok { | ||
70 | for _, sd := range b.buffer { | ||
71 | if sd == nil { | ||
72 | break | ||
73 | } | ||
74 | out = append(out, sd) | ||
75 | } | ||
76 | } | ||
77 | } else { | ||
78 | for _, b := range s.errors { | ||
79 | for _, sd := range b.buffer { | ||
80 | if sd == nil { | ||
81 | break | ||
82 | } | ||
83 | out = append(out, sd) | ||
84 | } | ||
85 | } | ||
86 | } | ||
87 | return out | ||
88 | } | ||
89 | |||
90 | // ConfigureBucketSizes sets the number of spans to keep per latency and error | ||
91 | // bucket for different span names. | ||
92 | func (i internalOnly) ConfigureBucketSizes(bcs []internal.BucketConfiguration) { | ||
93 | for _, bc := range bcs { | ||
94 | latencyBucketSize := bc.MaxRequestsSucceeded | ||
95 | if latencyBucketSize < 0 { | ||
96 | latencyBucketSize = 0 | ||
97 | } | ||
98 | if latencyBucketSize > maxBucketSize { | ||
99 | latencyBucketSize = maxBucketSize | ||
100 | } | ||
101 | errorBucketSize := bc.MaxRequestsErrors | ||
102 | if errorBucketSize < 0 { | ||
103 | errorBucketSize = 0 | ||
104 | } | ||
105 | if errorBucketSize > maxBucketSize { | ||
106 | errorBucketSize = maxBucketSize | ||
107 | } | ||
108 | spanStoreSetSize(bc.Name, latencyBucketSize, errorBucketSize) | ||
109 | } | ||
110 | } | ||
111 | |||
112 | // ReportSpansPerMethod returns a summary of what spans are being stored for each span name. | ||
113 | func (i internalOnly) ReportSpansPerMethod() map[string]internal.PerMethodSummary { | ||
114 | out := make(map[string]internal.PerMethodSummary) | ||
115 | ssmu.RLock() | ||
116 | defer ssmu.RUnlock() | ||
117 | for name, s := range spanStores { | ||
118 | s.mu.Lock() | ||
119 | p := internal.PerMethodSummary{ | ||
120 | Active: len(s.active), | ||
121 | } | ||
122 | for code, b := range s.errors { | ||
123 | p.ErrorBuckets = append(p.ErrorBuckets, internal.ErrorBucketSummary{ | ||
124 | ErrorCode: code, | ||
125 | Size: b.size(), | ||
126 | }) | ||
127 | } | ||
128 | for i, b := range s.latency { | ||
129 | min, max := latencyBucketBounds(i) | ||
130 | p.LatencyBuckets = append(p.LatencyBuckets, internal.LatencyBucketSummary{ | ||
131 | MinLatency: min, | ||
132 | MaxLatency: max, | ||
133 | Size: b.size(), | ||
134 | }) | ||
135 | } | ||
136 | s.mu.Unlock() | ||
137 | out[name] = p | ||
138 | } | ||
139 | return out | ||
140 | } | ||
141 | |||
142 | // ReportSpansByLatency returns a sample of successful spans. | ||
143 | // | ||
144 | // minLatency is the minimum latency of spans to be returned. | ||
145 | // maxLatency, if nonzero, is the maximum latency of spans to be returned. | ||
146 | func (i internalOnly) ReportSpansByLatency(name string, minLatency, maxLatency time.Duration) []*SpanData { | ||
147 | s := spanStoreForName(name) | ||
148 | if s == nil { | ||
149 | return nil | ||
150 | } | ||
151 | var out []*SpanData | ||
152 | s.mu.Lock() | ||
153 | defer s.mu.Unlock() | ||
154 | for i, b := range s.latency { | ||
155 | min, max := latencyBucketBounds(i) | ||
156 | if i+1 != len(s.latency) && max <= minLatency { | ||
157 | continue | ||
158 | } | ||
159 | if maxLatency != 0 && maxLatency < min { | ||
160 | continue | ||
161 | } | ||
162 | for _, sd := range b.buffer { | ||
163 | if sd == nil { | ||
164 | break | ||
165 | } | ||
166 | if minLatency != 0 || maxLatency != 0 { | ||
167 | d := sd.EndTime.Sub(sd.StartTime) | ||
168 | if d < minLatency { | ||
169 | continue | ||
170 | } | ||
171 | if maxLatency != 0 && d > maxLatency { | ||
172 | continue | ||
173 | } | ||
174 | } | ||
175 | out = append(out, sd) | ||
176 | } | ||
177 | } | ||
178 | return out | ||
179 | } | ||
180 | |||
181 | // spanStore keeps track of spans stored for a particular span name. | ||
182 | // | ||
183 | // It contains all active spans; a sample of spans for failed requests, | ||
184 | // categorized by error code; and a sample of spans for successful requests, | ||
185 | // bucketed by latency. | ||
186 | type spanStore struct { | ||
187 | mu sync.Mutex // protects everything below. | ||
188 | active map[*Span]struct{} | ||
189 | errors map[int32]*bucket | ||
190 | latency []bucket | ||
191 | maxSpansPerErrorBucket int | ||
192 | } | ||
193 | |||
194 | // newSpanStore creates a span store. | ||
195 | func newSpanStore(name string, latencyBucketSize int, errorBucketSize int) *spanStore { | ||
196 | s := &spanStore{ | ||
197 | active: make(map[*Span]struct{}), | ||
198 | latency: make([]bucket, len(defaultLatencies)+1), | ||
199 | maxSpansPerErrorBucket: errorBucketSize, | ||
200 | } | ||
201 | for i := range s.latency { | ||
202 | s.latency[i] = makeBucket(latencyBucketSize) | ||
203 | } | ||
204 | return s | ||
205 | } | ||
206 | |||
207 | // spanStoreForName returns the spanStore for the given name. | ||
208 | // | ||
209 | // It returns nil if it doesn't exist. | ||
210 | func spanStoreForName(name string) *spanStore { | ||
211 | var s *spanStore | ||
212 | ssmu.RLock() | ||
213 | s, _ = spanStores[name] | ||
214 | ssmu.RUnlock() | ||
215 | return s | ||
216 | } | ||
217 | |||
218 | // spanStoreForNameCreateIfNew returns the spanStore for the given name. | ||
219 | // | ||
220 | // It creates it if it didn't exist. | ||
221 | func spanStoreForNameCreateIfNew(name string) *spanStore { | ||
222 | ssmu.RLock() | ||
223 | s, ok := spanStores[name] | ||
224 | ssmu.RUnlock() | ||
225 | if ok { | ||
226 | return s | ||
227 | } | ||
228 | ssmu.Lock() | ||
229 | defer ssmu.Unlock() | ||
230 | s, ok = spanStores[name] | ||
231 | if ok { | ||
232 | return s | ||
233 | } | ||
234 | s = newSpanStore(name, defaultBucketSize, defaultBucketSize) | ||
235 | spanStores[name] = s | ||
236 | return s | ||
237 | } | ||
238 | |||
239 | // spanStoreSetSize resizes the spanStore for the given name. | ||
240 | // | ||
241 | // It creates it if it didn't exist. | ||
242 | func spanStoreSetSize(name string, latencyBucketSize int, errorBucketSize int) { | ||
243 | ssmu.RLock() | ||
244 | s, ok := spanStores[name] | ||
245 | ssmu.RUnlock() | ||
246 | if ok { | ||
247 | s.resize(latencyBucketSize, errorBucketSize) | ||
248 | return | ||
249 | } | ||
250 | ssmu.Lock() | ||
251 | defer ssmu.Unlock() | ||
252 | s, ok = spanStores[name] | ||
253 | if ok { | ||
254 | s.resize(latencyBucketSize, errorBucketSize) | ||
255 | return | ||
256 | } | ||
257 | s = newSpanStore(name, latencyBucketSize, errorBucketSize) | ||
258 | spanStores[name] = s | ||
259 | } | ||
260 | |||
261 | func (s *spanStore) resize(latencyBucketSize int, errorBucketSize int) { | ||
262 | s.mu.Lock() | ||
263 | for i := range s.latency { | ||
264 | s.latency[i].resize(latencyBucketSize) | ||
265 | } | ||
266 | for _, b := range s.errors { | ||
267 | b.resize(errorBucketSize) | ||
268 | } | ||
269 | s.maxSpansPerErrorBucket = errorBucketSize | ||
270 | s.mu.Unlock() | ||
271 | } | ||
272 | |||
273 | // add adds a span to the active bucket of the spanStore. | ||
274 | func (s *spanStore) add(span *Span) { | ||
275 | s.mu.Lock() | ||
276 | s.active[span] = struct{}{} | ||
277 | s.mu.Unlock() | ||
278 | } | ||
279 | |||
280 | // finished removes a span from the active set, and adds a corresponding | ||
281 | // SpanData to a latency or error bucket. | ||
282 | func (s *spanStore) finished(span *Span, sd *SpanData) { | ||
283 | latency := sd.EndTime.Sub(sd.StartTime) | ||
284 | if latency < 0 { | ||
285 | latency = 0 | ||
286 | } | ||
287 | code := sd.Status.Code | ||
288 | |||
289 | s.mu.Lock() | ||
290 | delete(s.active, span) | ||
291 | if code == 0 { | ||
292 | s.latency[latencyBucket(latency)].add(sd) | ||
293 | } else { | ||
294 | if s.errors == nil { | ||
295 | s.errors = make(map[int32]*bucket) | ||
296 | } | ||
297 | if b := s.errors[code]; b != nil { | ||
298 | b.add(sd) | ||
299 | } else { | ||
300 | b := makeBucket(s.maxSpansPerErrorBucket) | ||
301 | s.errors[code] = &b | ||
302 | b.add(sd) | ||
303 | } | ||
304 | } | ||
305 | s.mu.Unlock() | ||
306 | } | ||
diff --git a/vendor/go.opencensus.io/trace/status_codes.go b/vendor/go.opencensus.io/trace/status_codes.go new file mode 100644 index 0000000..ec60eff --- /dev/null +++ b/vendor/go.opencensus.io/trace/status_codes.go | |||
@@ -0,0 +1,37 @@ | |||
1 | // Copyright 2018, OpenCensus 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 trace | ||
16 | |||
17 | // Status codes for use with Span.SetStatus. These correspond to the status | ||
18 | // codes used by gRPC defined here: https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto | ||
19 | const ( | ||
20 | StatusCodeOK = 0 | ||
21 | StatusCodeCancelled = 1 | ||
22 | StatusCodeUnknown = 2 | ||
23 | StatusCodeInvalidArgument = 3 | ||
24 | StatusCodeDeadlineExceeded = 4 | ||
25 | StatusCodeNotFound = 5 | ||
26 | StatusCodeAlreadyExists = 6 | ||
27 | StatusCodePermissionDenied = 7 | ||
28 | StatusCodeResourceExhausted = 8 | ||
29 | StatusCodeFailedPrecondition = 9 | ||
30 | StatusCodeAborted = 10 | ||
31 | StatusCodeOutOfRange = 11 | ||
32 | StatusCodeUnimplemented = 12 | ||
33 | StatusCodeInternal = 13 | ||
34 | StatusCodeUnavailable = 14 | ||
35 | StatusCodeDataLoss = 15 | ||
36 | StatusCodeUnauthenticated = 16 | ||
37 | ) | ||
diff --git a/vendor/go.opencensus.io/trace/trace.go b/vendor/go.opencensus.io/trace/trace.go new file mode 100644 index 0000000..9e5e5f0 --- /dev/null +++ b/vendor/go.opencensus.io/trace/trace.go | |||
@@ -0,0 +1,516 @@ | |||
1 | // Copyright 2017, OpenCensus 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 trace | ||
16 | |||
17 | import ( | ||
18 | "context" | ||
19 | crand "crypto/rand" | ||
20 | "encoding/binary" | ||
21 | "fmt" | ||
22 | "math/rand" | ||
23 | "sync" | ||
24 | "sync/atomic" | ||
25 | "time" | ||
26 | |||
27 | "go.opencensus.io/internal" | ||
28 | "go.opencensus.io/trace/tracestate" | ||
29 | ) | ||
30 | |||
31 | // Span represents a span of a trace. It has an associated SpanContext, and | ||
32 | // stores data accumulated while the span is active. | ||
33 | // | ||
34 | // Ideally users should interact with Spans by calling the functions in this | ||
35 | // package that take a Context parameter. | ||
36 | type Span struct { | ||
37 | // data contains information recorded about the span. | ||
38 | // | ||
39 | // It will be non-nil if we are exporting the span or recording events for it. | ||
40 | // Otherwise, data is nil, and the Span is simply a carrier for the | ||
41 | // SpanContext, so that the trace ID is propagated. | ||
42 | data *SpanData | ||
43 | mu sync.Mutex // protects the contents of *data (but not the pointer value.) | ||
44 | spanContext SpanContext | ||
45 | // spanStore is the spanStore this span belongs to, if any, otherwise it is nil. | ||
46 | *spanStore | ||
47 | endOnce sync.Once | ||
48 | |||
49 | executionTracerTaskEnd func() // ends the execution tracer span | ||
50 | } | ||
51 | |||
52 | // IsRecordingEvents returns true if events are being recorded for this span. | ||
53 | // Use this check to avoid computing expensive annotations when they will never | ||
54 | // be used. | ||
55 | func (s *Span) IsRecordingEvents() bool { | ||
56 | if s == nil { | ||
57 | return false | ||
58 | } | ||
59 | return s.data != nil | ||
60 | } | ||
61 | |||
62 | // TraceOptions contains options associated with a trace span. | ||
63 | type TraceOptions uint32 | ||
64 | |||
65 | // IsSampled returns true if the span will be exported. | ||
66 | func (sc SpanContext) IsSampled() bool { | ||
67 | return sc.TraceOptions.IsSampled() | ||
68 | } | ||
69 | |||
70 | // setIsSampled sets the TraceOptions bit that determines whether the span will be exported. | ||
71 | func (sc *SpanContext) setIsSampled(sampled bool) { | ||
72 | if sampled { | ||
73 | sc.TraceOptions |= 1 | ||
74 | } else { | ||
75 | sc.TraceOptions &= ^TraceOptions(1) | ||
76 | } | ||
77 | } | ||
78 | |||
79 | // IsSampled returns true if the span will be exported. | ||
80 | func (t TraceOptions) IsSampled() bool { | ||
81 | return t&1 == 1 | ||
82 | } | ||
83 | |||
84 | // SpanContext contains the state that must propagate across process boundaries. | ||
85 | // | ||
86 | // SpanContext is not an implementation of context.Context. | ||
87 | // TODO: add reference to external Census docs for SpanContext. | ||
88 | type SpanContext struct { | ||
89 | TraceID TraceID | ||
90 | SpanID SpanID | ||
91 | TraceOptions TraceOptions | ||
92 | Tracestate *tracestate.Tracestate | ||
93 | } | ||
94 | |||
95 | type contextKey struct{} | ||
96 | |||
97 | // FromContext returns the Span stored in a context, or nil if there isn't one. | ||
98 | func FromContext(ctx context.Context) *Span { | ||
99 | s, _ := ctx.Value(contextKey{}).(*Span) | ||
100 | return s | ||
101 | } | ||
102 | |||
103 | // NewContext returns a new context with the given Span attached. | ||
104 | func NewContext(parent context.Context, s *Span) context.Context { | ||
105 | return context.WithValue(parent, contextKey{}, s) | ||
106 | } | ||
107 | |||
108 | // All available span kinds. Span kind must be either one of these values. | ||
109 | const ( | ||
110 | SpanKindUnspecified = iota | ||
111 | SpanKindServer | ||
112 | SpanKindClient | ||
113 | ) | ||
114 | |||
115 | // StartOptions contains options concerning how a span is started. | ||
116 | type StartOptions struct { | ||
117 | // Sampler to consult for this Span. If provided, it is always consulted. | ||
118 | // | ||
119 | // If not provided, then the behavior differs based on whether | ||
120 | // the parent of this Span is remote, local, or there is no parent. | ||
121 | // In the case of a remote parent or no parent, the | ||
122 | // default sampler (see Config) will be consulted. Otherwise, | ||
123 | // when there is a non-remote parent, no new sampling decision will be made: | ||
124 | // we will preserve the sampling of the parent. | ||
125 | Sampler Sampler | ||
126 | |||
127 | // SpanKind represents the kind of a span. If none is set, | ||
128 | // SpanKindUnspecified is used. | ||
129 | SpanKind int | ||
130 | } | ||
131 | |||
132 | // StartOption apply changes to StartOptions. | ||
133 | type StartOption func(*StartOptions) | ||
134 | |||
135 | // WithSpanKind makes new spans to be created with the given kind. | ||
136 | func WithSpanKind(spanKind int) StartOption { | ||
137 | return func(o *StartOptions) { | ||
138 | o.SpanKind = spanKind | ||
139 | } | ||
140 | } | ||
141 | |||
142 | // WithSampler makes new spans to be be created with a custom sampler. | ||
143 | // Otherwise, the global sampler is used. | ||
144 | func WithSampler(sampler Sampler) StartOption { | ||
145 | return func(o *StartOptions) { | ||
146 | o.Sampler = sampler | ||
147 | } | ||
148 | } | ||
149 | |||
150 | // StartSpan starts a new child span of the current span in the context. If | ||
151 | // there is no span in the context, creates a new trace and span. | ||
152 | // | ||
153 | // Returned context contains the newly created span. You can use it to | ||
154 | // propagate the returned span in process. | ||
155 | func StartSpan(ctx context.Context, name string, o ...StartOption) (context.Context, *Span) { | ||
156 | var opts StartOptions | ||
157 | var parent SpanContext | ||
158 | if p := FromContext(ctx); p != nil { | ||
159 | parent = p.spanContext | ||
160 | } | ||
161 | for _, op := range o { | ||
162 | op(&opts) | ||
163 | } | ||
164 | span := startSpanInternal(name, parent != SpanContext{}, parent, false, opts) | ||
165 | |||
166 | ctx, end := startExecutionTracerTask(ctx, name) | ||
167 | span.executionTracerTaskEnd = end | ||
168 | return NewContext(ctx, span), span | ||
169 | } | ||
170 | |||
171 | // StartSpanWithRemoteParent starts a new child span of the span from the given parent. | ||
172 | // | ||
173 | // If the incoming context contains a parent, it ignores. StartSpanWithRemoteParent is | ||
174 | // preferred for cases where the parent is propagated via an incoming request. | ||
175 | // | ||
176 | // Returned context contains the newly created span. You can use it to | ||
177 | // propagate the returned span in process. | ||
178 | func StartSpanWithRemoteParent(ctx context.Context, name string, parent SpanContext, o ...StartOption) (context.Context, *Span) { | ||
179 | var opts StartOptions | ||
180 | for _, op := range o { | ||
181 | op(&opts) | ||
182 | } | ||
183 | span := startSpanInternal(name, parent != SpanContext{}, parent, true, opts) | ||
184 | ctx, end := startExecutionTracerTask(ctx, name) | ||
185 | span.executionTracerTaskEnd = end | ||
186 | return NewContext(ctx, span), span | ||
187 | } | ||
188 | |||
189 | func startSpanInternal(name string, hasParent bool, parent SpanContext, remoteParent bool, o StartOptions) *Span { | ||
190 | span := &Span{} | ||
191 | span.spanContext = parent | ||
192 | |||
193 | cfg := config.Load().(*Config) | ||
194 | |||
195 | if !hasParent { | ||
196 | span.spanContext.TraceID = cfg.IDGenerator.NewTraceID() | ||
197 | } | ||
198 | span.spanContext.SpanID = cfg.IDGenerator.NewSpanID() | ||
199 | sampler := cfg.DefaultSampler | ||
200 | |||
201 | if !hasParent || remoteParent || o.Sampler != nil { | ||
202 | // If this span is the child of a local span and no Sampler is set in the | ||
203 | // options, keep the parent's TraceOptions. | ||
204 | // | ||
205 | // Otherwise, consult the Sampler in the options if it is non-nil, otherwise | ||
206 | // the default sampler. | ||
207 | if o.Sampler != nil { | ||
208 | sampler = o.Sampler | ||
209 | } | ||
210 | span.spanContext.setIsSampled(sampler(SamplingParameters{ | ||
211 | ParentContext: parent, | ||
212 | TraceID: span.spanContext.TraceID, | ||
213 | SpanID: span.spanContext.SpanID, | ||
214 | Name: name, | ||
215 | HasRemoteParent: remoteParent}).Sample) | ||
216 | } | ||
217 | |||
218 | if !internal.LocalSpanStoreEnabled && !span.spanContext.IsSampled() { | ||
219 | return span | ||
220 | } | ||
221 | |||
222 | span.data = &SpanData{ | ||
223 | SpanContext: span.spanContext, | ||
224 | StartTime: time.Now(), | ||
225 | SpanKind: o.SpanKind, | ||
226 | Name: name, | ||
227 | HasRemoteParent: remoteParent, | ||
228 | } | ||
229 | if hasParent { | ||
230 | span.data.ParentSpanID = parent.SpanID | ||
231 | } | ||
232 | if internal.LocalSpanStoreEnabled { | ||
233 | var ss *spanStore | ||
234 | ss = spanStoreForNameCreateIfNew(name) | ||
235 | if ss != nil { | ||
236 | span.spanStore = ss | ||
237 | ss.add(span) | ||
238 | } | ||
239 | } | ||
240 | |||
241 | return span | ||
242 | } | ||
243 | |||
244 | // End ends the span. | ||
245 | func (s *Span) End() { | ||
246 | if s == nil { | ||
247 | return | ||
248 | } | ||
249 | if s.executionTracerTaskEnd != nil { | ||
250 | s.executionTracerTaskEnd() | ||
251 | } | ||
252 | if !s.IsRecordingEvents() { | ||
253 | return | ||
254 | } | ||
255 | s.endOnce.Do(func() { | ||
256 | exp, _ := exporters.Load().(exportersMap) | ||
257 | mustExport := s.spanContext.IsSampled() && len(exp) > 0 | ||
258 | if s.spanStore != nil || mustExport { | ||
259 | sd := s.makeSpanData() | ||
260 | sd.EndTime = internal.MonotonicEndTime(sd.StartTime) | ||
261 | if s.spanStore != nil { | ||
262 | s.spanStore.finished(s, sd) | ||
263 | } | ||
264 | if mustExport { | ||
265 | for e := range exp { | ||
266 | e.ExportSpan(sd) | ||
267 | } | ||
268 | } | ||
269 | } | ||
270 | }) | ||
271 | } | ||
272 | |||
273 | // makeSpanData produces a SpanData representing the current state of the Span. | ||
274 | // It requires that s.data is non-nil. | ||
275 | func (s *Span) makeSpanData() *SpanData { | ||
276 | var sd SpanData | ||
277 | s.mu.Lock() | ||
278 | sd = *s.data | ||
279 | if s.data.Attributes != nil { | ||
280 | sd.Attributes = make(map[string]interface{}) | ||
281 | for k, v := range s.data.Attributes { | ||
282 | sd.Attributes[k] = v | ||
283 | } | ||
284 | } | ||
285 | s.mu.Unlock() | ||
286 | return &sd | ||
287 | } | ||
288 | |||
289 | // SpanContext returns the SpanContext of the span. | ||
290 | func (s *Span) SpanContext() SpanContext { | ||
291 | if s == nil { | ||
292 | return SpanContext{} | ||
293 | } | ||
294 | return s.spanContext | ||
295 | } | ||
296 | |||
297 | // SetName sets the name of the span, if it is recording events. | ||
298 | func (s *Span) SetName(name string) { | ||
299 | if !s.IsRecordingEvents() { | ||
300 | return | ||
301 | } | ||
302 | s.mu.Lock() | ||
303 | s.data.Name = name | ||
304 | s.mu.Unlock() | ||
305 | } | ||
306 | |||
307 | // SetStatus sets the status of the span, if it is recording events. | ||
308 | func (s *Span) SetStatus(status Status) { | ||
309 | if !s.IsRecordingEvents() { | ||
310 | return | ||
311 | } | ||
312 | s.mu.Lock() | ||
313 | s.data.Status = status | ||
314 | s.mu.Unlock() | ||
315 | } | ||
316 | |||
317 | // AddAttributes sets attributes in the span. | ||
318 | // | ||
319 | // Existing attributes whose keys appear in the attributes parameter are overwritten. | ||
320 | func (s *Span) AddAttributes(attributes ...Attribute) { | ||
321 | if !s.IsRecordingEvents() { | ||
322 | return | ||
323 | } | ||
324 | s.mu.Lock() | ||
325 | if s.data.Attributes == nil { | ||
326 | s.data.Attributes = make(map[string]interface{}) | ||
327 | } | ||
328 | copyAttributes(s.data.Attributes, attributes) | ||
329 | s.mu.Unlock() | ||
330 | } | ||
331 | |||
332 | // copyAttributes copies a slice of Attributes into a map. | ||
333 | func copyAttributes(m map[string]interface{}, attributes []Attribute) { | ||
334 | for _, a := range attributes { | ||
335 | m[a.key] = a.value | ||
336 | } | ||
337 | } | ||
338 | |||
339 | func (s *Span) lazyPrintfInternal(attributes []Attribute, format string, a ...interface{}) { | ||
340 | now := time.Now() | ||
341 | msg := fmt.Sprintf(format, a...) | ||
342 | var m map[string]interface{} | ||
343 | s.mu.Lock() | ||
344 | if len(attributes) != 0 { | ||
345 | m = make(map[string]interface{}) | ||
346 | copyAttributes(m, attributes) | ||
347 | } | ||
348 | s.data.Annotations = append(s.data.Annotations, Annotation{ | ||
349 | Time: now, | ||
350 | Message: msg, | ||
351 | Attributes: m, | ||
352 | }) | ||
353 | s.mu.Unlock() | ||
354 | } | ||
355 | |||
356 | func (s *Span) printStringInternal(attributes []Attribute, str string) { | ||
357 | now := time.Now() | ||
358 | var a map[string]interface{} | ||
359 | s.mu.Lock() | ||
360 | if len(attributes) != 0 { | ||
361 | a = make(map[string]interface{}) | ||
362 | copyAttributes(a, attributes) | ||
363 | } | ||
364 | s.data.Annotations = append(s.data.Annotations, Annotation{ | ||
365 | Time: now, | ||
366 | Message: str, | ||
367 | Attributes: a, | ||
368 | }) | ||
369 | s.mu.Unlock() | ||
370 | } | ||
371 | |||
372 | // Annotate adds an annotation with attributes. | ||
373 | // Attributes can be nil. | ||
374 | func (s *Span) Annotate(attributes []Attribute, str string) { | ||
375 | if !s.IsRecordingEvents() { | ||
376 | return | ||
377 | } | ||
378 | s.printStringInternal(attributes, str) | ||
379 | } | ||
380 | |||
381 | // Annotatef adds an annotation with attributes. | ||
382 | func (s *Span) Annotatef(attributes []Attribute, format string, a ...interface{}) { | ||
383 | if !s.IsRecordingEvents() { | ||
384 | return | ||
385 | } | ||
386 | s.lazyPrintfInternal(attributes, format, a...) | ||
387 | } | ||
388 | |||
389 | // AddMessageSendEvent adds a message send event to the span. | ||
390 | // | ||
391 | // messageID is an identifier for the message, which is recommended to be | ||
392 | // unique in this span and the same between the send event and the receive | ||
393 | // event (this allows to identify a message between the sender and receiver). | ||
394 | // For example, this could be a sequence id. | ||
395 | func (s *Span) AddMessageSendEvent(messageID, uncompressedByteSize, compressedByteSize int64) { | ||
396 | if !s.IsRecordingEvents() { | ||
397 | return | ||
398 | } | ||
399 | now := time.Now() | ||
400 | s.mu.Lock() | ||
401 | s.data.MessageEvents = append(s.data.MessageEvents, MessageEvent{ | ||
402 | Time: now, | ||
403 | EventType: MessageEventTypeSent, | ||
404 | MessageID: messageID, | ||
405 | UncompressedByteSize: uncompressedByteSize, | ||
406 | CompressedByteSize: compressedByteSize, | ||
407 | }) | ||
408 | s.mu.Unlock() | ||
409 | } | ||
410 | |||
411 | // AddMessageReceiveEvent adds a message receive event to the span. | ||
412 | // | ||
413 | // messageID is an identifier for the message, which is recommended to be | ||
414 | // unique in this span and the same between the send event and the receive | ||
415 | // event (this allows to identify a message between the sender and receiver). | ||
416 | // For example, this could be a sequence id. | ||
417 | func (s *Span) AddMessageReceiveEvent(messageID, uncompressedByteSize, compressedByteSize int64) { | ||
418 | if !s.IsRecordingEvents() { | ||
419 | return | ||
420 | } | ||
421 | now := time.Now() | ||
422 | s.mu.Lock() | ||
423 | s.data.MessageEvents = append(s.data.MessageEvents, MessageEvent{ | ||
424 | Time: now, | ||
425 | EventType: MessageEventTypeRecv, | ||
426 | MessageID: messageID, | ||
427 | UncompressedByteSize: uncompressedByteSize, | ||
428 | CompressedByteSize: compressedByteSize, | ||
429 | }) | ||
430 | s.mu.Unlock() | ||
431 | } | ||
432 | |||
433 | // AddLink adds a link to the span. | ||
434 | func (s *Span) AddLink(l Link) { | ||
435 | if !s.IsRecordingEvents() { | ||
436 | return | ||
437 | } | ||
438 | s.mu.Lock() | ||
439 | s.data.Links = append(s.data.Links, l) | ||
440 | s.mu.Unlock() | ||
441 | } | ||
442 | |||
443 | func (s *Span) String() string { | ||
444 | if s == nil { | ||
445 | return "<nil>" | ||
446 | } | ||
447 | if s.data == nil { | ||
448 | return fmt.Sprintf("span %s", s.spanContext.SpanID) | ||
449 | } | ||
450 | s.mu.Lock() | ||
451 | str := fmt.Sprintf("span %s %q", s.spanContext.SpanID, s.data.Name) | ||
452 | s.mu.Unlock() | ||
453 | return str | ||
454 | } | ||
455 | |||
456 | var config atomic.Value // access atomically | ||
457 | |||
458 | func init() { | ||
459 | gen := &defaultIDGenerator{} | ||
460 | // initialize traceID and spanID generators. | ||
461 | var rngSeed int64 | ||
462 | for _, p := range []interface{}{ | ||
463 | &rngSeed, &gen.traceIDAdd, &gen.nextSpanID, &gen.spanIDInc, | ||
464 | } { | ||
465 | binary.Read(crand.Reader, binary.LittleEndian, p) | ||
466 | } | ||
467 | gen.traceIDRand = rand.New(rand.NewSource(rngSeed)) | ||
468 | gen.spanIDInc |= 1 | ||
469 | |||
470 | config.Store(&Config{ | ||
471 | DefaultSampler: ProbabilitySampler(defaultSamplingProbability), | ||
472 | IDGenerator: gen, | ||
473 | }) | ||
474 | } | ||
475 | |||
476 | type defaultIDGenerator struct { | ||
477 | sync.Mutex | ||
478 | |||
479 | // Please keep these as the first fields | ||
480 | // so that these 8 byte fields will be aligned on addresses | ||
481 | // divisible by 8, on both 32-bit and 64-bit machines when | ||
482 | // performing atomic increments and accesses. | ||
483 | // See: | ||
484 | // * https://github.com/census-instrumentation/opencensus-go/issues/587 | ||
485 | // * https://github.com/census-instrumentation/opencensus-go/issues/865 | ||
486 | // * https://golang.org/pkg/sync/atomic/#pkg-note-BUG | ||
487 | nextSpanID uint64 | ||
488 | spanIDInc uint64 | ||
489 | |||
490 | traceIDAdd [2]uint64 | ||
491 | traceIDRand *rand.Rand | ||
492 | } | ||
493 | |||
494 | // NewSpanID returns a non-zero span ID from a randomly-chosen sequence. | ||
495 | func (gen *defaultIDGenerator) NewSpanID() [8]byte { | ||
496 | var id uint64 | ||
497 | for id == 0 { | ||
498 | id = atomic.AddUint64(&gen.nextSpanID, gen.spanIDInc) | ||
499 | } | ||
500 | var sid [8]byte | ||
501 | binary.LittleEndian.PutUint64(sid[:], id) | ||
502 | return sid | ||
503 | } | ||
504 | |||
505 | // NewTraceID returns a non-zero trace ID from a randomly-chosen sequence. | ||
506 | // mu should be held while this function is called. | ||
507 | func (gen *defaultIDGenerator) NewTraceID() [16]byte { | ||
508 | var tid [16]byte | ||
509 | // Construct the trace ID from two outputs of traceIDRand, with a constant | ||
510 | // added to each half for additional entropy. | ||
511 | gen.Lock() | ||
512 | binary.LittleEndian.PutUint64(tid[0:8], gen.traceIDRand.Uint64()+gen.traceIDAdd[0]) | ||
513 | binary.LittleEndian.PutUint64(tid[8:16], gen.traceIDRand.Uint64()+gen.traceIDAdd[1]) | ||
514 | gen.Unlock() | ||
515 | return tid | ||
516 | } | ||
diff --git a/vendor/go.opencensus.io/trace/trace_go11.go b/vendor/go.opencensus.io/trace/trace_go11.go new file mode 100644 index 0000000..b7d8aaf --- /dev/null +++ b/vendor/go.opencensus.io/trace/trace_go11.go | |||
@@ -0,0 +1,32 @@ | |||
1 | // Copyright 2018, OpenCensus 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 | // +build go1.11 | ||
16 | |||
17 | package trace | ||
18 | |||
19 | import ( | ||
20 | "context" | ||
21 | t "runtime/trace" | ||
22 | ) | ||
23 | |||
24 | func startExecutionTracerTask(ctx context.Context, name string) (context.Context, func()) { | ||
25 | if !t.IsEnabled() { | ||
26 | // Avoid additional overhead if | ||
27 | // runtime/trace is not enabled. | ||
28 | return ctx, func() {} | ||
29 | } | ||
30 | nctx, task := t.NewTask(ctx, name) | ||
31 | return nctx, task.End | ||
32 | } | ||
diff --git a/vendor/go.opencensus.io/trace/trace_nongo11.go b/vendor/go.opencensus.io/trace/trace_nongo11.go new file mode 100644 index 0000000..e254198 --- /dev/null +++ b/vendor/go.opencensus.io/trace/trace_nongo11.go | |||
@@ -0,0 +1,25 @@ | |||
1 | // Copyright 2018, OpenCensus 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 | // +build !go1.11 | ||
16 | |||
17 | package trace | ||
18 | |||
19 | import ( | ||
20 | "context" | ||
21 | ) | ||
22 | |||
23 | func startExecutionTracerTask(ctx context.Context, name string) (context.Context, func()) { | ||
24 | return ctx, func() {} | ||
25 | } | ||
diff --git a/vendor/go.opencensus.io/trace/tracestate/tracestate.go b/vendor/go.opencensus.io/trace/tracestate/tracestate.go new file mode 100644 index 0000000..2d6c713 --- /dev/null +++ b/vendor/go.opencensus.io/trace/tracestate/tracestate.go | |||
@@ -0,0 +1,147 @@ | |||
1 | // Copyright 2018, OpenCensus 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 tracestate implements support for the Tracestate header of the | ||
16 | // W3C TraceContext propagation format. | ||
17 | package tracestate | ||
18 | |||
19 | import ( | ||
20 | "fmt" | ||
21 | "regexp" | ||
22 | ) | ||
23 | |||
24 | const ( | ||
25 | keyMaxSize = 256 | ||
26 | valueMaxSize = 256 | ||
27 | maxKeyValuePairs = 32 | ||
28 | ) | ||
29 | |||
30 | const ( | ||
31 | keyWithoutVendorFormat = `[a-z][_0-9a-z\-\*\/]{0,255}` | ||
32 | keyWithVendorFormat = `[a-z][_0-9a-z\-\*\/]{0,240}@[a-z][_0-9a-z\-\*\/]{0,13}` | ||
33 | keyFormat = `(` + keyWithoutVendorFormat + `)|(` + keyWithVendorFormat + `)` | ||
34 | valueFormat = `[\x20-\x2b\x2d-\x3c\x3e-\x7e]{0,255}[\x21-\x2b\x2d-\x3c\x3e-\x7e]` | ||
35 | ) | ||
36 | |||
37 | var keyValidationRegExp = regexp.MustCompile(`^(` + keyFormat + `)$`) | ||
38 | var valueValidationRegExp = regexp.MustCompile(`^(` + valueFormat + `)$`) | ||
39 | |||
40 | // Tracestate represents tracing-system specific context in a list of key-value pairs. Tracestate allows different | ||
41 | // vendors propagate additional information and inter-operate with their legacy Id formats. | ||
42 | type Tracestate struct { | ||
43 | entries []Entry | ||
44 | } | ||
45 | |||
46 | // Entry represents one key-value pair in a list of key-value pair of Tracestate. | ||
47 | type Entry struct { | ||
48 | // Key is an opaque string up to 256 characters printable. It MUST begin with a lowercase letter, | ||
49 | // and can only contain lowercase letters a-z, digits 0-9, underscores _, dashes -, asterisks *, and | ||
50 | // forward slashes /. | ||
51 | Key string | ||
52 | |||
53 | // Value is an opaque string up to 256 characters printable ASCII RFC0020 characters (i.e., the | ||
54 | // range 0x20 to 0x7E) except comma , and =. | ||
55 | Value string | ||
56 | } | ||
57 | |||
58 | // Entries returns a slice of Entry. | ||
59 | func (ts *Tracestate) Entries() []Entry { | ||
60 | if ts == nil { | ||
61 | return nil | ||
62 | } | ||
63 | return ts.entries | ||
64 | } | ||
65 | |||
66 | func (ts *Tracestate) remove(key string) *Entry { | ||
67 | for index, entry := range ts.entries { | ||
68 | if entry.Key == key { | ||
69 | ts.entries = append(ts.entries[:index], ts.entries[index+1:]...) | ||
70 | return &entry | ||
71 | } | ||
72 | } | ||
73 | return nil | ||
74 | } | ||
75 | |||
76 | func (ts *Tracestate) add(entries []Entry) error { | ||
77 | for _, entry := range entries { | ||
78 | ts.remove(entry.Key) | ||
79 | } | ||
80 | if len(ts.entries)+len(entries) > maxKeyValuePairs { | ||
81 | return fmt.Errorf("adding %d key-value pairs to current %d pairs exceeds the limit of %d", | ||
82 | len(entries), len(ts.entries), maxKeyValuePairs) | ||
83 | } | ||
84 | ts.entries = append(entries, ts.entries...) | ||
85 | return nil | ||
86 | } | ||
87 | |||
88 | func isValid(entry Entry) bool { | ||
89 | return keyValidationRegExp.MatchString(entry.Key) && | ||
90 | valueValidationRegExp.MatchString(entry.Value) | ||
91 | } | ||
92 | |||
93 | func containsDuplicateKey(entries ...Entry) (string, bool) { | ||
94 | keyMap := make(map[string]int) | ||
95 | for _, entry := range entries { | ||
96 | if _, ok := keyMap[entry.Key]; ok { | ||
97 | return entry.Key, true | ||
98 | } | ||
99 | keyMap[entry.Key] = 1 | ||
100 | } | ||
101 | return "", false | ||
102 | } | ||
103 | |||
104 | func areEntriesValid(entries ...Entry) (*Entry, bool) { | ||
105 | for _, entry := range entries { | ||
106 | if !isValid(entry) { | ||
107 | return &entry, false | ||
108 | } | ||
109 | } | ||
110 | return nil, true | ||
111 | } | ||
112 | |||
113 | // New creates a Tracestate object from a parent and/or entries (key-value pair). | ||
114 | // Entries from the parent are copied if present. The entries passed to this function | ||
115 | // are inserted in front of those copied from the parent. If an entry copied from the | ||
116 | // parent contains the same key as one of the entry in entries then the entry copied | ||
117 | // from the parent is removed. See add func. | ||
118 | // | ||
119 | // An error is returned with nil Tracestate if | ||
120 | // 1. one or more entry in entries is invalid. | ||
121 | // 2. two or more entries in the input entries have the same key. | ||
122 | // 3. the number of entries combined from the parent and the input entries exceeds maxKeyValuePairs. | ||
123 | // (duplicate entry is counted only once). | ||
124 | func New(parent *Tracestate, entries ...Entry) (*Tracestate, error) { | ||
125 | if parent == nil && len(entries) == 0 { | ||
126 | return nil, nil | ||
127 | } | ||
128 | if entry, ok := areEntriesValid(entries...); !ok { | ||
129 | return nil, fmt.Errorf("key-value pair {%s, %s} is invalid", entry.Key, entry.Value) | ||
130 | } | ||
131 | |||
132 | if key, duplicate := containsDuplicateKey(entries...); duplicate { | ||
133 | return nil, fmt.Errorf("contains duplicate keys (%s)", key) | ||
134 | } | ||
135 | |||
136 | tracestate := Tracestate{} | ||
137 | |||
138 | if parent != nil && len(parent.entries) > 0 { | ||
139 | tracestate.entries = append([]Entry{}, parent.entries...) | ||
140 | } | ||
141 | |||
142 | err := tracestate.add(entries) | ||
143 | if err != nil { | ||
144 | return nil, err | ||
145 | } | ||
146 | return &tracestate, nil | ||
147 | } | ||