...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package view
17
18 import (
19 "bytes"
20 "errors"
21 "fmt"
22 "reflect"
23 "sort"
24 "sync/atomic"
25 "time"
26
27 "go.opencensus.io/metric/metricdata"
28 "go.opencensus.io/stats"
29 "go.opencensus.io/tag"
30 )
31
32
33
34
35 type View struct {
36 Name string
37 Description string
38
39
40
41 TagKeys []tag.Key
42
43
44 Measure stats.Measure
45
46
47 Aggregation *Aggregation
48 }
49
50
51
52
53 func (v *View) WithName(name string) *View {
54 vNew := *v
55 vNew.Name = name
56 return &vNew
57 }
58
59
60 func (v *View) same(other *View) bool {
61 if v == other {
62 return true
63 }
64 if v == nil {
65 return false
66 }
67 return reflect.DeepEqual(v.Aggregation, other.Aggregation) &&
68 v.Measure.Name() == other.Measure.Name()
69 }
70
71
72
73
74 var ErrNegativeBucketBounds = errors.New("negative bucket bounds not supported")
75
76
77
78 func (v *View) canonicalize() error {
79 if v.Measure == nil {
80 return fmt.Errorf("cannot register view %q: measure not set", v.Name)
81 }
82 if v.Aggregation == nil {
83 return fmt.Errorf("cannot register view %q: aggregation not set", v.Name)
84 }
85 if v.Name == "" {
86 v.Name = v.Measure.Name()
87 }
88 if v.Description == "" {
89 v.Description = v.Measure.Description()
90 }
91 if err := checkViewName(v.Name); err != nil {
92 return err
93 }
94 sort.Slice(v.TagKeys, func(i, j int) bool {
95 return v.TagKeys[i].Name() < v.TagKeys[j].Name()
96 })
97 sort.Float64s(v.Aggregation.Buckets)
98 for _, b := range v.Aggregation.Buckets {
99 if b < 0 {
100 return ErrNegativeBucketBounds
101 }
102 }
103
104 v.Aggregation.Buckets = dropZeroBounds(v.Aggregation.Buckets...)
105
106 return nil
107 }
108
109 func dropZeroBounds(bounds ...float64) []float64 {
110 for i, bound := range bounds {
111 if bound > 0 {
112 return bounds[i:]
113 }
114 }
115 return []float64{}
116 }
117
118
119 type viewInternal struct {
120 view *View
121 subscribed uint32
122 collector *collector
123 metricDescriptor *metricdata.Descriptor
124 }
125
126 func newViewInternal(v *View) (*viewInternal, error) {
127 return &viewInternal{
128 view: v,
129 collector: &collector{make(map[string]AggregationData), v.Aggregation},
130 metricDescriptor: viewToMetricDescriptor(v),
131 }, nil
132 }
133
134 func (v *viewInternal) subscribe() {
135 atomic.StoreUint32(&v.subscribed, 1)
136 }
137
138 func (v *viewInternal) unsubscribe() {
139 atomic.StoreUint32(&v.subscribed, 0)
140 }
141
142
143
144 func (v *viewInternal) isSubscribed() bool {
145 return atomic.LoadUint32(&v.subscribed) == 1
146 }
147
148 func (v *viewInternal) clearRows() {
149 v.collector.clearRows()
150 }
151
152 func (v *viewInternal) collectedRows() []*Row {
153 return v.collector.collectedRows(v.view.TagKeys)
154 }
155
156 func (v *viewInternal) addSample(m *tag.Map, val float64, attachments map[string]interface{}, t time.Time) {
157 if !v.isSubscribed() {
158 return
159 }
160 sig := string(encodeWithKeys(m, v.view.TagKeys))
161 v.collector.addSample(sig, val, attachments, t)
162 }
163
164
165
166 type Data struct {
167 View *View
168 Start, End time.Time
169 Rows []*Row
170 }
171
172
173 type Row struct {
174 Tags []tag.Tag
175 Data AggregationData
176 }
177
178 func (r *Row) String() string {
179 var buffer bytes.Buffer
180 buffer.WriteString("{ ")
181 buffer.WriteString("{ ")
182 for _, t := range r.Tags {
183 buffer.WriteString(fmt.Sprintf("{%v %v}", t.Key.Name(), t.Value))
184 }
185 buffer.WriteString(" }")
186 buffer.WriteString(fmt.Sprintf("%v", r.Data))
187 buffer.WriteString(" }")
188 return buffer.String()
189 }
190
191
192
193
194 func (r *Row) Equal(other *Row) bool {
195 if r == other {
196 return true
197 }
198 return reflect.DeepEqual(r.Tags, other.Tags) && r.Data.equal(other.Data)
199 }
200
201 const maxNameLength = 255
202
203
204 func isPrintable(str string) bool {
205 for _, r := range str {
206 if !(r >= ' ' && r <= '~') {
207 return false
208 }
209 }
210 return true
211 }
212
213 func checkViewName(name string) error {
214 if len(name) > maxNameLength {
215 return fmt.Errorf("view name cannot be larger than %v", maxNameLength)
216 }
217 if !isPrintable(name) {
218 return fmt.Errorf("view name needs to be an ASCII string")
219 }
220 return nil
221 }
222
View as plain text