diff options
Diffstat (limited to 'vendor/go.opencensus.io/stats/view/view.go')
-rw-r--r-- | vendor/go.opencensus.io/stats/view/view.go | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/vendor/go.opencensus.io/stats/view/view.go b/vendor/go.opencensus.io/stats/view/view.go new file mode 100644 index 0000000..c2a08af --- /dev/null +++ b/vendor/go.opencensus.io/stats/view/view.go | |||
@@ -0,0 +1,185 @@ | |||
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 view | ||
17 | |||
18 | import ( | ||
19 | "bytes" | ||
20 | "fmt" | ||
21 | "reflect" | ||
22 | "sort" | ||
23 | "sync/atomic" | ||
24 | "time" | ||
25 | |||
26 | "go.opencensus.io/exemplar" | ||
27 | |||
28 | "go.opencensus.io/stats" | ||
29 | "go.opencensus.io/stats/internal" | ||
30 | "go.opencensus.io/tag" | ||
31 | ) | ||
32 | |||
33 | // View allows users to aggregate the recorded stats.Measurements. | ||
34 | // Views need to be passed to the Register function to be before data will be | ||
35 | // collected and sent to Exporters. | ||
36 | type View struct { | ||
37 | Name string // Name of View. Must be unique. If unset, will default to the name of the Measure. | ||
38 | Description string // Description is a human-readable description for this view. | ||
39 | |||
40 | // TagKeys are the tag keys describing the grouping of this view. | ||
41 | // A single Row will be produced for each combination of associated tag values. | ||
42 | TagKeys []tag.Key | ||
43 | |||
44 | // Measure is a stats.Measure to aggregate in this view. | ||
45 | Measure stats.Measure | ||
46 | |||
47 | // Aggregation is the aggregation function tp apply to the set of Measurements. | ||
48 | Aggregation *Aggregation | ||
49 | } | ||
50 | |||
51 | // WithName returns a copy of the View with a new name. This is useful for | ||
52 | // renaming views to cope with limitations placed on metric names by various | ||
53 | // backends. | ||
54 | func (v *View) WithName(name string) *View { | ||
55 | vNew := *v | ||
56 | vNew.Name = name | ||
57 | return &vNew | ||
58 | } | ||
59 | |||
60 | // same compares two views and returns true if they represent the same aggregation. | ||
61 | func (v *View) same(other *View) bool { | ||
62 | if v == other { | ||
63 | return true | ||
64 | } | ||
65 | if v == nil { | ||
66 | return false | ||
67 | } | ||
68 | return reflect.DeepEqual(v.Aggregation, other.Aggregation) && | ||
69 | v.Measure.Name() == other.Measure.Name() | ||
70 | } | ||
71 | |||
72 | // canonicalize canonicalizes v by setting explicit | ||
73 | // defaults for Name and Description and sorting the TagKeys | ||
74 | func (v *View) canonicalize() error { | ||
75 | if v.Measure == nil { | ||
76 | return fmt.Errorf("cannot register view %q: measure not set", v.Name) | ||
77 | } | ||
78 | if v.Aggregation == nil { | ||
79 | return fmt.Errorf("cannot register view %q: aggregation not set", v.Name) | ||
80 | } | ||
81 | if v.Name == "" { | ||
82 | v.Name = v.Measure.Name() | ||
83 | } | ||
84 | if v.Description == "" { | ||
85 | v.Description = v.Measure.Description() | ||
86 | } | ||
87 | if err := checkViewName(v.Name); err != nil { | ||
88 | return err | ||
89 | } | ||
90 | sort.Slice(v.TagKeys, func(i, j int) bool { | ||
91 | return v.TagKeys[i].Name() < v.TagKeys[j].Name() | ||
92 | }) | ||
93 | return nil | ||
94 | } | ||
95 | |||
96 | // viewInternal is the internal representation of a View. | ||
97 | type viewInternal struct { | ||
98 | view *View // view is the canonicalized View definition associated with this view. | ||
99 | subscribed uint32 // 1 if someone is subscribed and data need to be exported, use atomic to access | ||
100 | collector *collector | ||
101 | } | ||
102 | |||
103 | func newViewInternal(v *View) (*viewInternal, error) { | ||
104 | return &viewInternal{ | ||
105 | view: v, | ||
106 | collector: &collector{make(map[string]AggregationData), v.Aggregation}, | ||
107 | }, nil | ||
108 | } | ||
109 | |||
110 | func (v *viewInternal) subscribe() { | ||
111 | atomic.StoreUint32(&v.subscribed, 1) | ||
112 | } | ||
113 | |||
114 | func (v *viewInternal) unsubscribe() { | ||
115 | atomic.StoreUint32(&v.subscribed, 0) | ||
116 | } | ||
117 | |||
118 | // isSubscribed returns true if the view is exporting | ||
119 | // data by subscription. | ||
120 | func (v *viewInternal) isSubscribed() bool { | ||
121 | return atomic.LoadUint32(&v.subscribed) == 1 | ||
122 | } | ||
123 | |||
124 | func (v *viewInternal) clearRows() { | ||
125 | v.collector.clearRows() | ||
126 | } | ||
127 | |||
128 | func (v *viewInternal) collectedRows() []*Row { | ||
129 | return v.collector.collectedRows(v.view.TagKeys) | ||
130 | } | ||
131 | |||
132 | func (v *viewInternal) addSample(m *tag.Map, e *exemplar.Exemplar) { | ||
133 | if !v.isSubscribed() { | ||
134 | return | ||
135 | } | ||
136 | sig := string(encodeWithKeys(m, v.view.TagKeys)) | ||
137 | v.collector.addSample(sig, e) | ||
138 | } | ||
139 | |||
140 | // A Data is a set of rows about usage of the single measure associated | ||
141 | // with the given view. Each row is specific to a unique set of tags. | ||
142 | type Data struct { | ||
143 | View *View | ||
144 | Start, End time.Time | ||
145 | Rows []*Row | ||
146 | } | ||
147 | |||
148 | // Row is the collected value for a specific set of key value pairs a.k.a tags. | ||
149 | type Row struct { | ||
150 | Tags []tag.Tag | ||
151 | Data AggregationData | ||
152 | } | ||
153 | |||
154 | func (r *Row) String() string { | ||
155 | var buffer bytes.Buffer | ||
156 | buffer.WriteString("{ ") | ||
157 | buffer.WriteString("{ ") | ||
158 | for _, t := range r.Tags { | ||
159 | buffer.WriteString(fmt.Sprintf("{%v %v}", t.Key.Name(), t.Value)) | ||
160 | } | ||
161 | buffer.WriteString(" }") | ||
162 | buffer.WriteString(fmt.Sprintf("%v", r.Data)) | ||
163 | buffer.WriteString(" }") | ||
164 | return buffer.String() | ||
165 | } | ||
166 | |||
167 | // Equal returns true if both rows are equal. Tags are expected to be ordered | ||
168 | // by the key name. Even both rows have the same tags but the tags appear in | ||
169 | // different orders it will return false. | ||
170 | func (r *Row) Equal(other *Row) bool { | ||
171 | if r == other { | ||
172 | return true | ||
173 | } | ||
174 | return reflect.DeepEqual(r.Tags, other.Tags) && r.Data.equal(other.Data) | ||
175 | } | ||
176 | |||
177 | func checkViewName(name string) error { | ||
178 | if len(name) > internal.MaxNameLength { | ||
179 | return fmt.Errorf("view name cannot be larger than %v", internal.MaxNameLength) | ||
180 | } | ||
181 | if !internal.IsPrintable(name) { | ||
182 | return fmt.Errorf("view name needs to be an ASCII string") | ||
183 | } | ||
184 | return nil | ||
185 | } | ||