...
1 package test
2
3 import (
4 "context"
5 "fmt"
6 "sort"
7 "strings"
8 "time"
9
10 "go.opencensus.io/metric/metricdata"
11 "go.opencensus.io/metric/metricexport"
12 "go.opencensus.io/stats/view"
13 )
14
15
16
17
18 type Exporter struct {
19
20
21 points map[string]metricdata.Point
22 metricReader *metricexport.Reader
23 }
24
25 var _ metricexport.Exporter = &Exporter{}
26
27
28 func NewExporter(metricReader *metricexport.Reader) *Exporter {
29 return &Exporter{points: make(map[string]metricdata.Point), metricReader: metricReader}
30 }
31
32
33 func (e *Exporter) ExportMetrics(ctx context.Context, data []*metricdata.Metric) error {
34 for _, metric := range data {
35 for _, ts := range metric.TimeSeries {
36 signature := labelSignature(metric.Descriptor.Name, labelObjectsToKeyValue(metric.Descriptor.LabelKeys, ts.LabelValues))
37 e.points[signature] = ts.Points[len(ts.Points)-1]
38 }
39 }
40 return nil
41 }
42
43
44 func (e *Exporter) GetPoint(metricName string, labels map[string]string) (metricdata.Point, bool) {
45 v, ok := e.points[labelSignature(metricName, labelMapToKeyValue(labels))]
46 return v, ok
47 }
48
49
50 func (e *Exporter) ReadAndExport() {
51
52
53
54
55 view.SetReportingPeriod(time.Minute)
56 e.metricReader.ReadAndExport(e)
57 }
58
59
60 func (e *Exporter) String() string {
61 return fmt.Sprintf("points{%v}", e.points)
62 }
63
64 type keyValue struct {
65 Key string
66 Value string
67 }
68
69 func sortKeyValue(kv []keyValue) {
70 sort.Slice(kv, func(i, j int) bool { return kv[i].Key < kv[j].Key })
71 }
72
73 func labelMapToKeyValue(labels map[string]string) []keyValue {
74 kv := make([]keyValue, 0, len(labels))
75 for k, v := range labels {
76 kv = append(kv, keyValue{Key: k, Value: v})
77 }
78 sortKeyValue(kv)
79 return kv
80 }
81
82 func labelObjectsToKeyValue(keys []metricdata.LabelKey, values []metricdata.LabelValue) []keyValue {
83 if len(keys) != len(values) {
84 panic("keys and values must have the same length")
85 }
86 kv := make([]keyValue, 0, len(values))
87 for i := range keys {
88 if values[i].Present {
89 kv = append(kv, keyValue{Key: keys[i].Key, Value: values[i].Value})
90 }
91 }
92 sortKeyValue(kv)
93 return kv
94 }
95
96
97 func labelSignature(metricName string, kv []keyValue) string {
98 var builder strings.Builder
99 for _, x := range kv {
100 builder.WriteString(x.Key)
101 builder.WriteString(x.Value)
102 }
103 return fmt.Sprintf("%s{%s}", metricName, builder.String())
104 }
105
View as plain text