| // Copyright 2019 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package ocagent |
| |
| import ( |
| "time" |
| |
| "golang.org/x/tools/internal/event/export/metric" |
| "golang.org/x/tools/internal/event/export/ocagent/wire" |
| "golang.org/x/tools/internal/event/label" |
| ) |
| |
| // dataToMetricDescriptor return a *wire.MetricDescriptor based on data. |
| func dataToMetricDescriptor(data metric.Data) *wire.MetricDescriptor { |
| if data == nil { |
| return nil |
| } |
| descriptor := &wire.MetricDescriptor{ |
| Name: data.Handle(), |
| Description: getDescription(data), |
| // TODO: Unit? |
| Type: dataToMetricDescriptorType(data), |
| LabelKeys: getLabelKeys(data), |
| } |
| |
| return descriptor |
| } |
| |
| // getDescription returns the description of data. |
| func getDescription(data metric.Data) string { |
| switch d := data.(type) { |
| case *metric.Int64Data: |
| return d.Info.Description |
| |
| case *metric.Float64Data: |
| return d.Info.Description |
| |
| case *metric.HistogramInt64Data: |
| return d.Info.Description |
| |
| case *metric.HistogramFloat64Data: |
| return d.Info.Description |
| } |
| |
| return "" |
| } |
| |
| // getLabelKeys returns a slice of *wire.LabelKeys based on the keys |
| // in data. |
| func getLabelKeys(data metric.Data) []*wire.LabelKey { |
| switch d := data.(type) { |
| case *metric.Int64Data: |
| return infoKeysToLabelKeys(d.Info.Keys) |
| |
| case *metric.Float64Data: |
| return infoKeysToLabelKeys(d.Info.Keys) |
| |
| case *metric.HistogramInt64Data: |
| return infoKeysToLabelKeys(d.Info.Keys) |
| |
| case *metric.HistogramFloat64Data: |
| return infoKeysToLabelKeys(d.Info.Keys) |
| } |
| |
| return nil |
| } |
| |
| // dataToMetricDescriptorType returns a wire.MetricDescriptor_Type based on the |
| // underlying type of data. |
| func dataToMetricDescriptorType(data metric.Data) wire.MetricDescriptor_Type { |
| switch d := data.(type) { |
| case *metric.Int64Data: |
| if d.IsGauge { |
| return wire.MetricDescriptor_GAUGE_INT64 |
| } |
| return wire.MetricDescriptor_CUMULATIVE_INT64 |
| |
| case *metric.Float64Data: |
| if d.IsGauge { |
| return wire.MetricDescriptor_GAUGE_DOUBLE |
| } |
| return wire.MetricDescriptor_CUMULATIVE_DOUBLE |
| |
| case *metric.HistogramInt64Data: |
| return wire.MetricDescriptor_CUMULATIVE_DISTRIBUTION |
| |
| case *metric.HistogramFloat64Data: |
| return wire.MetricDescriptor_CUMULATIVE_DISTRIBUTION |
| } |
| |
| return wire.MetricDescriptor_UNSPECIFIED |
| } |
| |
| // dataToTimeseries returns a slice of *wire.TimeSeries based on the |
| // points in data. |
| func dataToTimeseries(data metric.Data, start time.Time) []*wire.TimeSeries { |
| if data == nil { |
| return nil |
| } |
| |
| numRows := numRows(data) |
| startTimestamp := convertTimestamp(start) |
| timeseries := make([]*wire.TimeSeries, 0, numRows) |
| |
| for i := 0; i < numRows; i++ { |
| timeseries = append(timeseries, &wire.TimeSeries{ |
| StartTimestamp: &startTimestamp, |
| // TODO: labels? |
| Points: dataToPoints(data, i), |
| }) |
| } |
| |
| return timeseries |
| } |
| |
| // numRows returns the number of rows in data. |
| func numRows(data metric.Data) int { |
| switch d := data.(type) { |
| case *metric.Int64Data: |
| return len(d.Rows) |
| case *metric.Float64Data: |
| return len(d.Rows) |
| case *metric.HistogramInt64Data: |
| return len(d.Rows) |
| case *metric.HistogramFloat64Data: |
| return len(d.Rows) |
| } |
| |
| return 0 |
| } |
| |
| // dataToPoints returns an array of *wire.Points based on the point(s) |
| // in data at index i. |
| func dataToPoints(data metric.Data, i int) []*wire.Point { |
| switch d := data.(type) { |
| case *metric.Int64Data: |
| timestamp := convertTimestamp(d.EndTime) |
| return []*wire.Point{ |
| { |
| Value: wire.PointInt64Value{ |
| Int64Value: d.Rows[i], |
| }, |
| Timestamp: ×tamp, |
| }, |
| } |
| case *metric.Float64Data: |
| timestamp := convertTimestamp(d.EndTime) |
| return []*wire.Point{ |
| { |
| Value: wire.PointDoubleValue{ |
| DoubleValue: d.Rows[i], |
| }, |
| Timestamp: ×tamp, |
| }, |
| } |
| case *metric.HistogramInt64Data: |
| row := d.Rows[i] |
| bucketBounds := make([]float64, len(d.Info.Buckets)) |
| for i, val := range d.Info.Buckets { |
| bucketBounds[i] = float64(val) |
| } |
| return distributionToPoints(row.Values, row.Count, float64(row.Sum), bucketBounds, d.EndTime) |
| case *metric.HistogramFloat64Data: |
| row := d.Rows[i] |
| return distributionToPoints(row.Values, row.Count, row.Sum, d.Info.Buckets, d.EndTime) |
| } |
| |
| return nil |
| } |
| |
| // distributionToPoints returns an array of *wire.Points containing a |
| // wire.PointDistributionValue representing a distribution with the |
| // supplied counts, count, and sum. |
| func distributionToPoints(counts []int64, count int64, sum float64, bucketBounds []float64, end time.Time) []*wire.Point { |
| buckets := make([]*wire.Bucket, len(counts)) |
| for i := 0; i < len(counts); i++ { |
| buckets[i] = &wire.Bucket{ |
| Count: counts[i], |
| } |
| } |
| timestamp := convertTimestamp(end) |
| return []*wire.Point{ |
| { |
| Value: wire.PointDistributionValue{ |
| DistributionValue: &wire.DistributionValue{ |
| Count: count, |
| Sum: sum, |
| // TODO: SumOfSquaredDeviation? |
| Buckets: buckets, |
| BucketOptions: &wire.BucketOptionsExplicit{ |
| Bounds: bucketBounds, |
| }, |
| }, |
| }, |
| Timestamp: ×tamp, |
| }, |
| } |
| } |
| |
| // infoKeysToLabelKeys returns an array of *wire.LabelKeys containing the |
| // string values of the elements of labelKeys. |
| func infoKeysToLabelKeys(infoKeys []label.Key) []*wire.LabelKey { |
| labelKeys := make([]*wire.LabelKey, 0, len(infoKeys)) |
| for _, key := range infoKeys { |
| labelKeys = append(labelKeys, &wire.LabelKey{ |
| Key: key.Name(), |
| }) |
| } |
| |
| return labelKeys |
| } |