internal/telemetry/export/ocagent: convert Histogram metrics

This change adds support for converting HistogramFloat64Data and
HistogramInt64Data to *wire.Metric. Timestamps are not attached
as they are not yet available.

What works:
* convertMetric will now convert HistogramInt64Data and
HistogramFloat64Data to *wire.Metric.

What does not work yet:
* StartTime and EndTime will not be attached to timeseries and
points.
* MetricDescriptors will not have a unit attached.
* No labels will be attached to timeseries.
* Distributions will not have SumOfSquaredDeviation attached.

Updates golang/go#33819

Change-Id: Iee52ab751542ee1ade07ef32120de853b41fd27b
Reviewed-on: https://go-review.googlesource.com/c/tools/+/200538
Run-TryBot: Emmanuel Odeke <emm.odeke@gmail.com>
Reviewed-by: Emmanuel Odeke <emm.odeke@gmail.com>
This commit is contained in:
Nathan Dias 2019-10-10 20:41:28 -05:00 committed by Emmanuel Odeke
parent a3bc800455
commit e4d7c6f25b
2 changed files with 517 additions and 0 deletions

View File

@ -36,6 +36,12 @@ func getDescription(data telemetry.MetricData) string {
case *metric.Float64Data:
return d.Info.Description
case *metric.HistogramInt64Data:
return d.Info.Description
case *metric.HistogramFloat64Data:
return d.Info.Description
}
return ""
@ -50,6 +56,12 @@ func getLabelKeys(data telemetry.MetricData) []*wire.LabelKey {
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
@ -70,6 +82,12 @@ func dataToMetricDescriptorType(data telemetry.MetricData) wire.MetricDescriptor
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
@ -103,6 +121,10 @@ func numRows(data telemetry.MetricData) int {
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
@ -130,11 +152,48 @@ func dataToPoints(data telemetry.MetricData, i int) []*wire.Point {
// TODO: attach Timestamp
},
}
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)
case *metric.HistogramFloat64Data:
row := d.Rows[i]
return distributionToPoints(row.Values, row.Count, row.Sum, d.Info.Buckets)
}
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) []*wire.Point {
buckets := make([]*wire.Bucket, len(counts))
for i := 0; i < len(counts); i++ {
buckets[i] = &wire.Bucket{
Count: counts[i],
}
}
return []*wire.Point{
{
Value: wire.PointDistributionValue{
DistributionValue: &wire.DistributionValue{
Count: count,
Sum: sum,
// TODO: SumOfSquaredDeviation?
Buckets: buckets,
BucketOptions: wire.BucketOptionsExplicit{
Bounds: bucketBounds,
},
},
},
},
}
}
// infoKeysToLabelKeys returns an array of *wire.LabelKeys containing the
// string values of the elements of labelKeys.
func infoKeysToLabelKeys(infoKeys []interface{}) []*wire.LabelKey {

View File

@ -62,6 +62,46 @@ func TestDataToMetricDescriptor(t *testing.T) {
},
},
},
{
"HistogramInt64",
&metric.HistogramInt64Data{
Info: &metric.HistogramInt64{
Name: "histogram int",
Description: "histogram int metric",
Keys: []interface{}{"hello"},
},
},
&wire.MetricDescriptor{
Name: "histogram int",
Description: "histogram int metric",
Type: wire.MetricDescriptor_CUMULATIVE_DISTRIBUTION,
LabelKeys: []*wire.LabelKey{
&wire.LabelKey{
Key: "hello",
},
},
},
},
{
"HistogramFloat64",
&metric.HistogramFloat64Data{
Info: &metric.HistogramFloat64{
Name: "histogram float",
Description: "histogram float metric",
Keys: []interface{}{"hello"},
},
},
&wire.MetricDescriptor{
Name: "histogram float",
Description: "histogram float metric",
Type: wire.MetricDescriptor_CUMULATIVE_DISTRIBUTION,
LabelKeys: []*wire.LabelKey{
&wire.LabelKey{
Key: "hello",
},
},
},
},
}
for _, tt := range tests {
@ -103,6 +143,24 @@ func TestGetDescription(t *testing.T) {
},
"float metric",
},
{
"HistogramInt64Data description",
&metric.HistogramInt64Data{
Info: &metric.HistogramInt64{
Description: "histogram int metric",
},
},
"histogram int metric",
},
{
"HistogramFloat64Data description",
&metric.HistogramFloat64Data{
Info: &metric.HistogramFloat64{
Description: "histogram float metric",
},
},
"histogram float metric",
},
}
for _, tt := range tests {
@ -157,6 +215,36 @@ func TestGetLabelKeys(t *testing.T) {
},
},
},
{
"HistogramInt64Data label keys",
&metric.HistogramInt64Data{
Info: &metric.HistogramInt64{
Keys: []interface{}{
"hello",
},
},
},
[]*wire.LabelKey{
&wire.LabelKey{
Key: "hello",
},
},
},
{
"HistogramFloat64Data label keys",
&metric.HistogramFloat64Data{
Info: &metric.HistogramFloat64{
Keys: []interface{}{
"hello",
},
},
},
[]*wire.LabelKey{
&wire.LabelKey{
Key: "hello",
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
@ -207,6 +295,16 @@ func TestDataToMetricDescriptorType(t *testing.T) {
},
wire.MetricDescriptor_CUMULATIVE_DOUBLE,
},
{
"HistogramInt64",
&metric.HistogramInt64Data{},
wire.MetricDescriptor_CUMULATIVE_DISTRIBUTION,
},
{
"HistogramFloat64",
&metric.HistogramFloat64Data{},
wire.MetricDescriptor_CUMULATIVE_DISTRIBUTION,
},
}
for _, tt := range tests {
@ -288,6 +386,104 @@ func TestDataToTimeseries(t *testing.T) {
},
},
},
{
"HistogramInt64Data",
&metric.HistogramInt64Data{
Rows: []*metric.HistogramInt64Row{
{
Count: 6,
Sum: 40,
Values: []int64{
1,
2,
3,
},
},
},
Info: &metric.HistogramInt64{
Buckets: []int64{
0, 5, 10,
},
},
},
[]*wire.TimeSeries{
&wire.TimeSeries{
Points: []*wire.Point{
&wire.Point{
Value: wire.PointDistributionValue{
DistributionValue: &wire.DistributionValue{
Count: 6,
Sum: 40,
Buckets: []*wire.Bucket{
{
Count: 1,
},
{
Count: 2,
},
{
Count: 3,
},
},
BucketOptions: wire.BucketOptionsExplicit{
Bounds: []float64{
0, 5, 10,
},
},
},
},
},
},
},
},
},
{
"HistogramFloat64Data",
&metric.HistogramFloat64Data{
Rows: []*metric.HistogramFloat64Row{
{
Count: 3,
Sum: 10,
Values: []int64{
1,
2,
},
},
},
Info: &metric.HistogramFloat64{
Buckets: []float64{
0, 5,
},
},
},
[]*wire.TimeSeries{
&wire.TimeSeries{
Points: []*wire.Point{
&wire.Point{
Value: wire.PointDistributionValue{
DistributionValue: &wire.DistributionValue{
Count: 3,
Sum: 10,
Buckets: []*wire.Bucket{
{
Count: 1,
},
{
Count: 2,
},
},
BucketOptions: wire.BucketOptionsExplicit{
Bounds: []float64{
0, 5,
},
},
},
},
},
},
},
},
},
}
for _, tt := range tests {
@ -330,6 +526,26 @@ func TestNumRows(t *testing.T) {
},
2,
},
{
"1 row HistogramInt64Data",
&metric.HistogramInt64Data{
Rows: []*metric.HistogramInt64Row{
{},
},
},
1,
},
{
"3 row HistogramFloat64Data",
&metric.HistogramFloat64Data{
Rows: []*metric.HistogramFloat64Row{
{},
{},
{},
},
},
3,
},
}
for _, tt := range tests {
@ -357,6 +573,62 @@ func TestDataToPoints(t *testing.T) {
},
}
histogramInt64Data := &metric.HistogramInt64Data{
Rows: []*metric.HistogramInt64Row{
{
Count: 6,
Sum: 40,
Values: []int64{
1,
2,
3,
},
},
{
Count: 12,
Sum: 80,
Values: []int64{
2,
4,
6,
},
},
},
Info: &metric.HistogramInt64{
Buckets: []int64{
0, 5, 10,
},
},
}
histogramFloat64Data := &metric.HistogramFloat64Data{
Rows: []*metric.HistogramFloat64Row{
{
Count: 6,
Sum: 40,
Values: []int64{
1,
2,
3,
},
},
{
Count: 18,
Sum: 80,
Values: []int64{
3,
6,
9,
},
},
},
Info: &metric.HistogramFloat64{
Buckets: []float64{
0, 5, 10,
},
},
}
tests := []struct {
name string
data telemetry.MetricData
@ -417,6 +689,130 @@ func TestDataToPoints(t *testing.T) {
},
},
},
{
"HistogramInt64Data index 0",
histogramInt64Data,
0,
[]*wire.Point{
{
Value: wire.PointDistributionValue{
DistributionValue: &wire.DistributionValue{
Count: 6,
Sum: 40,
Buckets: []*wire.Bucket{
{
Count: 1,
},
{
Count: 2,
},
{
Count: 3,
},
},
BucketOptions: wire.BucketOptionsExplicit{
Bounds: []float64{
0, 5, 10,
},
},
},
},
},
},
},
{
"HistogramInt64Data index 1",
histogramInt64Data,
1,
[]*wire.Point{
{
Value: wire.PointDistributionValue{
DistributionValue: &wire.DistributionValue{
Count: 12,
Sum: 80,
Buckets: []*wire.Bucket{
{
Count: 2,
},
{
Count: 4,
},
{
Count: 6,
},
},
BucketOptions: wire.BucketOptionsExplicit{
Bounds: []float64{
0, 5, 10,
},
},
},
},
},
},
},
{
"HistogramFloat64Data index 0",
histogramFloat64Data,
0,
[]*wire.Point{
{
Value: wire.PointDistributionValue{
DistributionValue: &wire.DistributionValue{
Count: 6,
Sum: 40,
Buckets: []*wire.Bucket{
{
Count: 1,
},
{
Count: 2,
},
{
Count: 3,
},
},
BucketOptions: wire.BucketOptionsExplicit{
Bounds: []float64{
0, 5, 10,
},
},
},
},
},
},
},
{
"HistogramFloat64Data index 1",
histogramFloat64Data,
1,
[]*wire.Point{
{
Value: wire.PointDistributionValue{
DistributionValue: &wire.DistributionValue{
Count: 18,
Sum: 80,
Buckets: []*wire.Bucket{
{
Count: 3,
},
{
Count: 6,
},
{
Count: 9,
},
},
BucketOptions: wire.BucketOptionsExplicit{
Bounds: []float64{
0, 5, 10,
},
},
},
},
},
},
},
}
for _, tt := range tests {
@ -429,6 +825,68 @@ func TestDataToPoints(t *testing.T) {
}
}
func TestDistributionToPoints(t *testing.T) {
tests := []struct {
name string
counts []int64
count int64
sum float64
buckets []float64
want []*wire.Point
}{
{
name: "3 buckets",
counts: []int64{
1,
2,
3,
},
count: 6,
sum: 40,
buckets: []float64{
0, 5, 10,
},
want: []*wire.Point{
{
Value: wire.PointDistributionValue{
DistributionValue: &wire.DistributionValue{
Count: 6,
Sum: 40,
// TODO: SumOfSquaredDeviation?
Buckets: []*wire.Bucket{
&wire.Bucket{
Count: 1,
},
&wire.Bucket{
Count: 2,
},
&wire.Bucket{
Count: 3,
},
},
BucketOptions: wire.BucketOptionsExplicit{
Bounds: []float64{
0, 5, 10,
},
},
},
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := distributionToPoints(tt.counts, tt.count, tt.sum, tt.buckets)
if !reflect.DeepEqual(got, tt.want) {
t.Fatalf("Got:\n%s\nWant:\n%s", marshaled(got), marshaled(tt.want))
}
})
}
}
func TestInfoKeysToLabelKeys(t *testing.T) {
tests := []struct {
name string