Skip to content

Commit

Permalink
Add metrics support to the OTLP exporter (#544)
Browse files Browse the repository at this point in the history
* Initial metrics addition to the OTLP exporter

* Fixes

Update to incorporate merged changes.
Fix lint issues.

* Add sum float64 transform unit test

* Fix static check

* Update comments

Fix malformed License header.
Add documentation for new transform functions.
Remove errant TODO.

* Fix test failures and handle ErrEmptyDataSet

Use `assert.NoError` instead of `assert.Nil` to correctly display
checked errors.

Use the result of `assert.NoError` to guard against `nil` pointer
dereferences.

Add check to skip `Record`s that return an `ErrEmptyDataSet` error and
include test to check this error is correctly returned from the
transform package.

Co-authored-by: Rahul Patel <[email protected]>
  • Loading branch information
MrAlias and rghetia authored Mar 13, 2020
1 parent fcc4aca commit cba1664
Show file tree
Hide file tree
Showing 6 changed files with 783 additions and 32 deletions.
143 changes: 143 additions & 0 deletions exporters/otlp/internal/transform/metric.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
// Copyright 2020, OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package transform provides translations for opentelemetry-go concepts and
// structures to otlp structures.
package transform

import (
"errors"

commonpb "github.com/open-telemetry/opentelemetry-proto/gen/go/common/v1"
metricpb "github.com/open-telemetry/opentelemetry-proto/gen/go/metrics/v1"

"go.opentelemetry.io/otel/api/core"
metricsdk "go.opentelemetry.io/otel/sdk/export/metric"
"go.opentelemetry.io/otel/sdk/export/metric/aggregator"
)

// ErrUnimplementedAgg is returned when a transformation of an unimplemented
// aggregator is attempted.
var ErrUnimplementedAgg = errors.New("unimplemented aggregator")

// Record transforms a Record into an OTLP Metric. An ErrUnimplementedAgg
// error is returned if the Record Aggregator is not supported.
func Record(r metricsdk.Record) (*metricpb.Metric, error) {
d := r.Descriptor()
l := r.Labels()
switch a := r.Aggregator().(type) {
case aggregator.MinMaxSumCount:
return minMaxSumCount(d, l, a)
case aggregator.Sum:
return sum(d, l, a)
}
return nil, ErrUnimplementedAgg
}

// sum transforms a Sum Aggregator into an OTLP Metric.
func sum(desc *metricsdk.Descriptor, labels metricsdk.Labels, a aggregator.Sum) (*metricpb.Metric, error) {
sum, err := a.Sum()
if err != nil {
return nil, err
}

m := &metricpb.Metric{
MetricDescriptor: &metricpb.MetricDescriptor{
Name: desc.Name(),
Description: desc.Description(),
Unit: string(desc.Unit()),
Labels: stringKeyValues(labels.Ordered()),
},
}

switch n := desc.NumberKind(); n {
case core.Int64NumberKind, core.Uint64NumberKind:
m.MetricDescriptor.Type = metricpb.MetricDescriptor_COUNTER_INT64
m.Int64Datapoints = []*metricpb.Int64DataPoint{
{Value: sum.CoerceToInt64(n)},
}
case core.Float64NumberKind:
m.MetricDescriptor.Type = metricpb.MetricDescriptor_COUNTER_DOUBLE
m.DoubleDatapoints = []*metricpb.DoubleDataPoint{
{Value: sum.CoerceToFloat64(n)},
}
}

return m, nil
}

// minMaxSumCountValue returns the values of the MinMaxSumCount Aggregator
// as discret values.
func minMaxSumCountValues(a aggregator.MinMaxSumCount) (min, max, sum core.Number, count int64, err error) {
if min, err = a.Min(); err != nil {
return
}
if max, err = a.Max(); err != nil {
return
}
if sum, err = a.Sum(); err != nil {
return
}
if count, err = a.Count(); err != nil {
return
}
return
}

// minMaxSumCount transforms a MinMaxSumCount Aggregator into an OTLP Metric.
func minMaxSumCount(desc *metricsdk.Descriptor, labels metricsdk.Labels, a aggregator.MinMaxSumCount) (*metricpb.Metric, error) {
min, max, sum, count, err := minMaxSumCountValues(a)
if err != nil {
return nil, err
}

numKind := desc.NumberKind()
return &metricpb.Metric{
MetricDescriptor: &metricpb.MetricDescriptor{
Name: desc.Name(),
Description: desc.Description(),
Unit: string(desc.Unit()),
Type: metricpb.MetricDescriptor_SUMMARY,
Labels: stringKeyValues(labels.Ordered()),
},
SummaryDatapoints: []*metricpb.SummaryDataPoint{
{
Count: uint64(count),
Sum: sum.CoerceToFloat64(numKind),
PercentileValues: []*metricpb.SummaryDataPoint_ValueAtPercentile{
{
Percentile: 0.0,
Value: min.CoerceToFloat64(numKind),
},
{
Percentile: 100.0,
Value: max.CoerceToFloat64(numKind),
},
},
},
},
}, nil
}

// stringKeyValues transforms a KeyValues into an OTLP StringKeyValues.
func stringKeyValues(kvs []core.KeyValue) []*commonpb.StringKeyValue {
result := make([]*commonpb.StringKeyValue, 0, len(kvs))
for _, kv := range kvs {
result = append(result, &commonpb.StringKeyValue{
Key: string(kv.Key),
Value: kv.Value.Emit(),
})
}
return result
}
Loading

0 comments on commit cba1664

Please sign in to comment.