Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions otmetricreader/find.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package otmetricreader

import (
"context"
"fmt"

"go.opentelemetry.io/otel/attribute"
otsdkmetric "go.opentelemetry.io/otel/sdk/metric"
"go.opentelemetry.io/otel/sdk/metric/metricdata"
)

// FindVal is a testing utility to find the value of a specific metric
// collected by the sdk [metric.ManualReader].
//
// It searches for a metric matching the provided metricName and [attribute.Set].
// The type parameter V specifies the expected value type, which must be
// either int64 or float64.
//
// An error is returned if a metric matching the name and attributes is not found,
// or if the found metric's value type does not match V.
func FindVal[V int64 | float64](ctx context.Context, r *otsdkmetric.ManualReader, metricName string, kvs attribute.Set) (V, error) {
var zv V
res := metricdata.ResourceMetrics{}
if err := r.Collect(ctx, &res); err != nil {
return zv, err
}

for _, sm := range res.ScopeMetrics {
for _, m := range sm.Metrics {
if m.Name != metricName {
continue
}
switch vs := m.Data.(type) {
case metricdata.Gauge[V]:
for _, d := range vs.DataPoints {
if !kvs.Equals(&d.Attributes) {
continue
}
return d.Value, nil
}
case metricdata.Sum[V]:
for _, d := range vs.DataPoints {
if !kvs.Equals(&d.Attributes) {
continue
}
return d.Value, nil
}
default:
// wrong metric-type (or histogram, which we'll have to implement later)
continue
}
}
}
return zv, fmt.Errorf("metric %s not found", metricName)
}
50 changes: 50 additions & 0 deletions otmetricreader/find_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package otmetricreader

import (
"context"
"testing"

"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/metric"
otsdkmetric "go.opentelemetry.io/otel/sdk/metric"
)

func TestFindMetricVal(t *testing.T) {
ctx := context.Background()

r := otsdkmetric.NewManualReader()
mp := otsdkmetric.NewMeterProvider(otsdkmetric.WithReader(r))

otM := mp.Meter("foobar")
attrSet := attribute.NewSet(attribute.String("fizzlebit", "foobar"), attribute.String("ouch", "icky"))

// read an int64 counter
counter, countErr := otM.Int64Counter("a_counter_int")
if countErr != nil {
t.Fatalf("failed to register counter metric: %s", countErr)
}
counter.Add(ctx, 2, metric.WithAttributeSet(attrSet))

counterVal, counterValErr := FindVal[int64](ctx, r, "a_counter_int", attrSet)
if counterValErr != nil {
t.Errorf("failed to fetch counter metric value: %s", counterValErr)
}
if counterVal != 2 {
t.Errorf("unexpected counter metric value: want %d; got %d", 2, counterVal)
}

// read an int64 gauge
gauge, gaugeErr := otM.Int64Gauge("a_gauge_int")
if gaugeErr != nil {
t.Fatalf("failed to register gauge metric: %s", gaugeErr)
}
gauge.Record(ctx, 3, metric.WithAttributeSet(attrSet))

gaugeVal, gaugeValErr := FindVal[int64](ctx, r, "a_gauge_int", attrSet)
if gaugeValErr != nil {
t.Errorf("failed to fetch gauge metric value: %s", gaugeValErr)
}
if gaugeVal != 3 {
t.Errorf("unexpected gauge metric value: want %d; got %d", 3, gaugeVal)
}
}
Loading