github.com/v2fly/tools@v0.100.0/internal/event/export/ocagent/metrics.go (about) 1 // Copyright 2019 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package ocagent 6 7 import ( 8 "time" 9 10 "github.com/v2fly/tools/internal/event/export/metric" 11 "github.com/v2fly/tools/internal/event/export/ocagent/wire" 12 "github.com/v2fly/tools/internal/event/label" 13 ) 14 15 // dataToMetricDescriptor return a *wire.MetricDescriptor based on data. 16 func dataToMetricDescriptor(data metric.Data) *wire.MetricDescriptor { 17 if data == nil { 18 return nil 19 } 20 descriptor := &wire.MetricDescriptor{ 21 Name: data.Handle(), 22 Description: getDescription(data), 23 // TODO: Unit? 24 Type: dataToMetricDescriptorType(data), 25 LabelKeys: getLabelKeys(data), 26 } 27 28 return descriptor 29 } 30 31 // getDescription returns the description of data. 32 func getDescription(data metric.Data) string { 33 switch d := data.(type) { 34 case *metric.Int64Data: 35 return d.Info.Description 36 37 case *metric.Float64Data: 38 return d.Info.Description 39 40 case *metric.HistogramInt64Data: 41 return d.Info.Description 42 43 case *metric.HistogramFloat64Data: 44 return d.Info.Description 45 } 46 47 return "" 48 } 49 50 // getLabelKeys returns a slice of *wire.LabelKeys based on the keys 51 // in data. 52 func getLabelKeys(data metric.Data) []*wire.LabelKey { 53 switch d := data.(type) { 54 case *metric.Int64Data: 55 return infoKeysToLabelKeys(d.Info.Keys) 56 57 case *metric.Float64Data: 58 return infoKeysToLabelKeys(d.Info.Keys) 59 60 case *metric.HistogramInt64Data: 61 return infoKeysToLabelKeys(d.Info.Keys) 62 63 case *metric.HistogramFloat64Data: 64 return infoKeysToLabelKeys(d.Info.Keys) 65 } 66 67 return nil 68 } 69 70 // dataToMetricDescriptorType returns a wire.MetricDescriptor_Type based on the 71 // underlying type of data. 72 func dataToMetricDescriptorType(data metric.Data) wire.MetricDescriptor_Type { 73 switch d := data.(type) { 74 case *metric.Int64Data: 75 if d.IsGauge { 76 return wire.MetricDescriptor_GAUGE_INT64 77 } 78 return wire.MetricDescriptor_CUMULATIVE_INT64 79 80 case *metric.Float64Data: 81 if d.IsGauge { 82 return wire.MetricDescriptor_GAUGE_DOUBLE 83 } 84 return wire.MetricDescriptor_CUMULATIVE_DOUBLE 85 86 case *metric.HistogramInt64Data: 87 return wire.MetricDescriptor_CUMULATIVE_DISTRIBUTION 88 89 case *metric.HistogramFloat64Data: 90 return wire.MetricDescriptor_CUMULATIVE_DISTRIBUTION 91 } 92 93 return wire.MetricDescriptor_UNSPECIFIED 94 } 95 96 // dataToTimeseries returns a slice of *wire.TimeSeries based on the 97 // points in data. 98 func dataToTimeseries(data metric.Data, start time.Time) []*wire.TimeSeries { 99 if data == nil { 100 return nil 101 } 102 103 numRows := numRows(data) 104 startTimestamp := convertTimestamp(start) 105 timeseries := make([]*wire.TimeSeries, 0, numRows) 106 107 for i := 0; i < numRows; i++ { 108 timeseries = append(timeseries, &wire.TimeSeries{ 109 StartTimestamp: &startTimestamp, 110 // TODO: labels? 111 Points: dataToPoints(data, i), 112 }) 113 } 114 115 return timeseries 116 } 117 118 // numRows returns the number of rows in data. 119 func numRows(data metric.Data) int { 120 switch d := data.(type) { 121 case *metric.Int64Data: 122 return len(d.Rows) 123 case *metric.Float64Data: 124 return len(d.Rows) 125 case *metric.HistogramInt64Data: 126 return len(d.Rows) 127 case *metric.HistogramFloat64Data: 128 return len(d.Rows) 129 } 130 131 return 0 132 } 133 134 // dataToPoints returns an array of *wire.Points based on the point(s) 135 // in data at index i. 136 func dataToPoints(data metric.Data, i int) []*wire.Point { 137 switch d := data.(type) { 138 case *metric.Int64Data: 139 timestamp := convertTimestamp(d.EndTime) 140 return []*wire.Point{ 141 { 142 Value: wire.PointInt64Value{ 143 Int64Value: d.Rows[i], 144 }, 145 Timestamp: ×tamp, 146 }, 147 } 148 case *metric.Float64Data: 149 timestamp := convertTimestamp(d.EndTime) 150 return []*wire.Point{ 151 { 152 Value: wire.PointDoubleValue{ 153 DoubleValue: d.Rows[i], 154 }, 155 Timestamp: ×tamp, 156 }, 157 } 158 case *metric.HistogramInt64Data: 159 row := d.Rows[i] 160 bucketBounds := make([]float64, len(d.Info.Buckets)) 161 for i, val := range d.Info.Buckets { 162 bucketBounds[i] = float64(val) 163 } 164 return distributionToPoints(row.Values, row.Count, float64(row.Sum), bucketBounds, d.EndTime) 165 case *metric.HistogramFloat64Data: 166 row := d.Rows[i] 167 return distributionToPoints(row.Values, row.Count, row.Sum, d.Info.Buckets, d.EndTime) 168 } 169 170 return nil 171 } 172 173 // distributionToPoints returns an array of *wire.Points containing a 174 // wire.PointDistributionValue representing a distribution with the 175 // supplied counts, count, and sum. 176 func distributionToPoints(counts []int64, count int64, sum float64, bucketBounds []float64, end time.Time) []*wire.Point { 177 buckets := make([]*wire.Bucket, len(counts)) 178 for i := 0; i < len(counts); i++ { 179 buckets[i] = &wire.Bucket{ 180 Count: counts[i], 181 } 182 } 183 timestamp := convertTimestamp(end) 184 return []*wire.Point{ 185 { 186 Value: wire.PointDistributionValue{ 187 DistributionValue: &wire.DistributionValue{ 188 Count: count, 189 Sum: sum, 190 // TODO: SumOfSquaredDeviation? 191 Buckets: buckets, 192 BucketOptions: &wire.BucketOptionsExplicit{ 193 Bounds: bucketBounds, 194 }, 195 }, 196 }, 197 Timestamp: ×tamp, 198 }, 199 } 200 } 201 202 // infoKeysToLabelKeys returns an array of *wire.LabelKeys containing the 203 // string values of the elements of labelKeys. 204 func infoKeysToLabelKeys(infoKeys []label.Key) []*wire.LabelKey { 205 labelKeys := make([]*wire.LabelKey, 0, len(infoKeys)) 206 for _, key := range infoKeys { 207 labelKeys = append(labelKeys, &wire.LabelKey{ 208 Key: key.Name(), 209 }) 210 } 211 212 return labelKeys 213 }