Skip to content

Commit

Permalink
Merge branch 'main' into ret-reader-structs
Browse files Browse the repository at this point in the history
  • Loading branch information
pellared committed Jun 22, 2023
2 parents 4c92152 + ca2aa83 commit e3467a6
Show file tree
Hide file tree
Showing 4 changed files with 264 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ See our [versioning policy](VERSIONING.md) for more information about these stab
- The `go.opentelemetry.io/otel/semconv/v1.20.0` package.
The package contains semantic conventions from the `v1.20.0` version of the OpenTelemetry specification. (#4078)
- The Exponential Histogram data types in `go.opentelemetry.io/otel/sdk/metric/metricdata`. (#4165)
- OTLP metrics exporter now supports the Exponential Histogram Data Type. (#4222)

### Changed

Expand Down
25 changes: 25 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -475,8 +475,33 @@ documentation are allowed to be extended with additional methods.

> Warning: methods may be added to this interface in minor releases.
These interfaces are defined by the OpenTelemetry specification and will be
updated as the specification evolves.

Otherwise, stable interfaces MUST NOT be modified.

#### How to Change Specification Interfaces

When an API change must be made, we will update the SDK with the new method one
release before the API change. This will allow the SDK one version before the
API change to work seamlessly with the new API.

If an incompatible version of the SDK is used with the new API the application
will fail to compile.

#### How Not to Change Specification Interfaces

We have explored using a v2 of the API to change interfaces and found that there
was no way to introduce a v2 and have it work seamlessly with the v1 of the API.
Problems happened with libraries that upgraded to v2 when an application did not,
and would not produce any telemetry.

More detail of the approaches considered and their limitations can be found in
the [Use a V2 API to evolve interfaces](https://github.com/open-telemetry/opentelemetry-go/issues/3920)
issue.

#### How to Change Other Interfaces

If new functionality is needed for an interface that cannot be changed it MUST
be added by including an additional interface. That added interface can be a
simple interface for the specific functionality that you want to add or it can
Expand Down
66 changes: 62 additions & 4 deletions exporters/otlp/otlpmetric/internal/transform/metricdata.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ func metric(m metricdata.Metrics) (*mpb.Metric, error) {
out.Data, err = Histogram(a)
case metricdata.Histogram[float64]:
out.Data, err = Histogram(a)
case metricdata.ExponentialHistogram[int64]:
out.Data, err = ExponentialHistogram(a)
case metricdata.ExponentialHistogram[float64]:
out.Data, err = ExponentialHistogram(a)
default:
return out, fmt.Errorf("%w: %T", errUnknownAggregation, a)
}
Expand All @@ -114,8 +118,8 @@ func Gauge[N int64 | float64](g metricdata.Gauge[N]) *mpb.Metric_Gauge {
}
}

// Sum returns an OTLP Metric_Sum generated from s. An error is returned with
// a partial Metric_Sum if the temporality of s is unknown.
// Sum returns an OTLP Metric_Sum generated from s. An error is returned
// if the temporality of s is unknown.
func Sum[N int64 | float64](s metricdata.Sum[N]) (*mpb.Metric_Sum, error) {
t, err := Temporality(s.Temporality)
if err != nil {
Expand Down Expand Up @@ -155,8 +159,7 @@ func DataPoints[N int64 | float64](dPts []metricdata.DataPoint[N]) []*mpb.Number
}

// Histogram returns an OTLP Metric_Histogram generated from h. An error is
// returned with a partial Metric_Histogram if the temporality of h is
// unknown.
// returned if the temporality of h is unknown.
func Histogram[N int64 | float64](h metricdata.Histogram[N]) (*mpb.Metric_Histogram, error) {
t, err := Temporality(h.Temporality)
if err != nil {
Expand Down Expand Up @@ -198,6 +201,61 @@ func HistogramDataPoints[N int64 | float64](dPts []metricdata.HistogramDataPoint
return out
}

// ExponentialHistogram returns an OTLP Metric_ExponentialHistogram generated from h. An error is
// returned if the temporality of h is unknown.
func ExponentialHistogram[N int64 | float64](h metricdata.ExponentialHistogram[N]) (*mpb.Metric_ExponentialHistogram, error) {
t, err := Temporality(h.Temporality)
if err != nil {
return nil, err
}
return &mpb.Metric_ExponentialHistogram{
ExponentialHistogram: &mpb.ExponentialHistogram{
AggregationTemporality: t,
DataPoints: ExponentialHistogramDataPoints(h.DataPoints),
},
}, nil
}

// ExponentialHistogramDataPoints returns a slice of OTLP ExponentialHistogramDataPoint generated
// from dPts.
func ExponentialHistogramDataPoints[N int64 | float64](dPts []metricdata.ExponentialHistogramDataPoint[N]) []*mpb.ExponentialHistogramDataPoint {
out := make([]*mpb.ExponentialHistogramDataPoint, 0, len(dPts))
for _, dPt := range dPts {
sum := float64(dPt.Sum)
ehdp := &mpb.ExponentialHistogramDataPoint{
Attributes: AttrIter(dPt.Attributes.Iter()),
StartTimeUnixNano: uint64(dPt.StartTime.UnixNano()),
TimeUnixNano: uint64(dPt.Time.UnixNano()),
Count: dPt.Count,
Sum: &sum,
Scale: dPt.Scale,
ZeroCount: dPt.ZeroCount,

Positive: ExponentialHistogramDataPointBuckets(dPt.PositiveBucket),
Negative: ExponentialHistogramDataPointBuckets(dPt.NegativeBucket),
}
if v, ok := dPt.Min.Value(); ok {
vF64 := float64(v)
ehdp.Min = &vF64
}
if v, ok := dPt.Max.Value(); ok {
vF64 := float64(v)
ehdp.Max = &vF64
}
out = append(out, ehdp)
}
return out
}

// ExponentialHistogramDataPointBuckets returns an OTLP ExponentialHistogramDataPoint_Buckets generated
// from bucket.
func ExponentialHistogramDataPointBuckets(bucket metricdata.ExponentialBucket) *mpb.ExponentialHistogramDataPoint_Buckets {
return &mpb.ExponentialHistogramDataPoint_Buckets{
Offset: bucket.Offset,
BucketCounts: bucket.Counts,
}
}

// Temporality returns an OTLP AggregationTemporality generated from t. If t
// is unknown, an error is returned along with the invalid
// AggregationTemporality_AGGREGATION_TEMPORALITY_UNSPECIFIED.
Expand Down
176 changes: 176 additions & 0 deletions exporters/otlp/otlpmetric/internal/transform/metricdata_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,78 @@ var (
Sum: sumB,
}}

otelEBucketA = metricdata.ExponentialBucket{
Offset: 5,
Counts: []uint64{0, 5, 0, 5},
}
otelEBucketB = metricdata.ExponentialBucket{
Offset: 3,
Counts: []uint64{0, 5, 0, 5},
}
otelEBucketsC = metricdata.ExponentialBucket{
Offset: 5,
Counts: []uint64{0, 1},
}
otelEBucketsD = metricdata.ExponentialBucket{
Offset: 3,
Counts: []uint64{0, 1},
}

otelEHDPInt64 = []metricdata.ExponentialHistogramDataPoint[int64]{{
Attributes: alice,
StartTime: start,
Time: end,
Count: 30,
Scale: 2,
ZeroCount: 10,
PositiveBucket: otelEBucketA,
NegativeBucket: otelEBucketB,
ZeroThreshold: .01,
Min: metricdata.NewExtrema(int64(minA)),
Max: metricdata.NewExtrema(int64(maxA)),
Sum: int64(sumA),
}, {
Attributes: bob,
StartTime: start,
Time: end,
Count: 3,
Scale: 4,
ZeroCount: 1,
PositiveBucket: otelEBucketsC,
NegativeBucket: otelEBucketsD,
ZeroThreshold: .02,
Min: metricdata.NewExtrema(int64(minB)),
Max: metricdata.NewExtrema(int64(maxB)),
Sum: int64(sumB),
}}
otelEHDPFloat64 = []metricdata.ExponentialHistogramDataPoint[float64]{{
Attributes: alice,
StartTime: start,
Time: end,
Count: 30,
Scale: 2,
ZeroCount: 10,
PositiveBucket: otelEBucketA,
NegativeBucket: otelEBucketB,
ZeroThreshold: .01,
Min: metricdata.NewExtrema(minA),
Max: metricdata.NewExtrema(maxA),
Sum: sumA,
}, {
Attributes: bob,
StartTime: start,
Time: end,
Count: 3,
Scale: 4,
ZeroCount: 1,
PositiveBucket: otelEBucketsC,
NegativeBucket: otelEBucketsD,
ZeroThreshold: .02,
Min: metricdata.NewExtrema(minB),
Max: metricdata.NewExtrema(maxB),
Sum: sumB,
}}

pbHDP = []*mpb.HistogramDataPoint{{
Attributes: []*cpb.KeyValue{pbAlice},
StartTimeUnixNano: uint64(start.UnixNano()),
Expand All @@ -117,6 +189,49 @@ var (
Max: &maxB,
}}

pbEHDPBA = &mpb.ExponentialHistogramDataPoint_Buckets{
Offset: 5,
BucketCounts: []uint64{0, 5, 0, 5},
}
pbEHDPBB = &mpb.ExponentialHistogramDataPoint_Buckets{
Offset: 3,
BucketCounts: []uint64{0, 5, 0, 5},
}
pbEHDPBC = &mpb.ExponentialHistogramDataPoint_Buckets{
Offset: 5,
BucketCounts: []uint64{0, 1},
}
pbEHDPBD = &mpb.ExponentialHistogramDataPoint_Buckets{
Offset: 3,
BucketCounts: []uint64{0, 1},
}

pbEHDP = []*mpb.ExponentialHistogramDataPoint{{
Attributes: []*cpb.KeyValue{pbAlice},
StartTimeUnixNano: uint64(start.UnixNano()),
TimeUnixNano: uint64(end.UnixNano()),
Count: 30,
Sum: &sumA,
Scale: 2,
ZeroCount: 10,
Positive: pbEHDPBA,
Negative: pbEHDPBB,
Min: &minA,
Max: &maxA,
}, {
Attributes: []*cpb.KeyValue{pbBob},
StartTimeUnixNano: uint64(start.UnixNano()),
TimeUnixNano: uint64(end.UnixNano()),
Count: 3,
Sum: &sumB,
Scale: 4,
ZeroCount: 1,
Positive: pbEHDPBC,
Negative: pbEHDPBD,
Min: &minB,
Max: &maxB,
}}

otelHistInt64 = metricdata.Histogram[int64]{
Temporality: metricdata.DeltaTemporality,
DataPoints: otelHDPInt64,
Expand All @@ -131,11 +246,29 @@ var (
DataPoints: otelHDPInt64,
}

otelExpoHistInt64 = metricdata.ExponentialHistogram[int64]{
Temporality: metricdata.DeltaTemporality,
DataPoints: otelEHDPInt64,
}
otelExpoHistFloat64 = metricdata.ExponentialHistogram[float64]{
Temporality: metricdata.DeltaTemporality,
DataPoints: otelEHDPFloat64,
}
otelExpoHistInvalid = metricdata.ExponentialHistogram[int64]{
Temporality: invalidTemporality,
DataPoints: otelEHDPInt64,
}

pbHist = &mpb.Histogram{
AggregationTemporality: mpb.AggregationTemporality_AGGREGATION_TEMPORALITY_DELTA,
DataPoints: pbHDP,
}

pbExpoHist = &mpb.ExponentialHistogram{
AggregationTemporality: mpb.AggregationTemporality_AGGREGATION_TEMPORALITY_DELTA,
DataPoints: pbEHDP,
}

otelDPtsInt64 = []metricdata.DataPoint[int64]{
{Attributes: alice, StartTime: start, Time: end, Value: 1},
{Attributes: bob, StartTime: start, Time: end, Value: 2},
Expand Down Expand Up @@ -263,6 +396,24 @@ var (
Unit: "1",
Data: unknownAgg,
},
{
Name: "int64-ExponentialHistogram",
Description: "Exponential Histogram",
Unit: "1",
Data: otelExpoHistInt64,
},
{
Name: "float64-ExponentialHistogram",
Description: "Exponential Histogram",
Unit: "1",
Data: otelExpoHistFloat64,
},
{
Name: "invalid-ExponentialHistogram",
Description: "Invalid Exponential Histogram",
Unit: "1",
Data: otelExpoHistInvalid,
},
}

pbMetrics = []*mpb.Metric{
Expand Down Expand Up @@ -302,6 +453,18 @@ var (
Unit: "1",
Data: &mpb.Metric_Histogram{Histogram: pbHist},
},
{
Name: "int64-ExponentialHistogram",
Description: "Exponential Histogram",
Unit: "1",
Data: &mpb.Metric_ExponentialHistogram{ExponentialHistogram: pbExpoHist},
},
{
Name: "float64-ExponentialHistogram",
Description: "Exponential Histogram",
Unit: "1",
Data: &mpb.Metric_ExponentialHistogram{ExponentialHistogram: pbExpoHist},
},
}

otelScopeMetrics = []metricdata.ScopeMetrics{{
Expand Down Expand Up @@ -368,6 +531,9 @@ func TestTransformations(t *testing.T) {
assert.Equal(t, pbHDP, HistogramDataPoints(otelHDPFloat64))
assert.Equal(t, pbDPtsInt64, DataPoints[int64](otelDPtsInt64))
require.Equal(t, pbDPtsFloat64, DataPoints[float64](otelDPtsFloat64))
assert.Equal(t, pbEHDP, ExponentialHistogramDataPoints(otelEHDPInt64))
assert.Equal(t, pbEHDP, ExponentialHistogramDataPoints(otelEHDPFloat64))
assert.Equal(t, pbEHDPBA, ExponentialHistogramDataPointBuckets(otelEBucketA))

// Aggregations.
h, err := Histogram(otelHistInt64)
Expand All @@ -393,6 +559,16 @@ func TestTransformations(t *testing.T) {
assert.Equal(t, &mpb.Metric_Gauge{Gauge: pbGaugeInt64}, Gauge[int64](otelGaugeInt64))
require.Equal(t, &mpb.Metric_Gauge{Gauge: pbGaugeFloat64}, Gauge[float64](otelGaugeFloat64))

e, err := ExponentialHistogram(otelExpoHistInt64)
assert.NoError(t, err)
assert.Equal(t, &mpb.Metric_ExponentialHistogram{ExponentialHistogram: pbExpoHist}, e)
e, err = ExponentialHistogram(otelExpoHistFloat64)
assert.NoError(t, err)
assert.Equal(t, &mpb.Metric_ExponentialHistogram{ExponentialHistogram: pbExpoHist}, e)
e, err = ExponentialHistogram(otelExpoHistInvalid)
assert.ErrorIs(t, err, errUnknownTemporality)
assert.Nil(t, e)

// Metrics.
m, err := Metrics(otelMetrics)
assert.ErrorIs(t, err, errUnknownTemporality)
Expand Down

0 comments on commit e3467a6

Please sign in to comment.