Skip to content

Commit

Permalink
Merge branch 'main' into prevent-conflict-metric-description
Browse files Browse the repository at this point in the history
  • Loading branch information
fatsheep9146 committed Dec 2, 2022
2 parents e1aaaeb + 69ad652 commit 69f5348
Show file tree
Hide file tree
Showing 9 changed files with 278 additions and 9 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -29,6 +29,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- The `Instrument` and `InstrumentKind` type are added to `go.opentelemetry.io/otel/sdk/metric`.
These additions are replacements for the `Instrument` and `InstrumentKind` types from `go.opentelemetry.io/otel/sdk/metric/view`. (#3459)
- The `Stream` type is added to `go.opentelemetry.io/otel/sdk/metric` to define a metric data stream a view will produce. (#3459)
- The `AssertHasAttributes` allows instrument authors to test that datapoints returned have appropriate attributes. (#3487)

### Changed

Expand Down
6 changes: 4 additions & 2 deletions example/otel-collector/Makefile
@@ -1,9 +1,11 @@
JAEGER_OPERATOR_VERSION = v1.36.0

namespace-k8s:
kubectl apply -f k8s/namespace.yaml

jaeger-operator-k8s:
# Create the jaeger operator and necessary artifacts in ns observability
kubectl create -n observability -f https://github.com/jaegertracing/jaeger-operator/releases/download/v1.31.0/jaeger-operator.yaml
kubectl create -n observability -f https://github.com/jaegertracing/jaeger-operator/releases/download/$(JAEGER_OPERATOR_VERSION)/jaeger-operator.yaml

jaeger-k8s:
kubectl apply -f k8s/jaeger.yaml
Expand All @@ -23,4 +25,4 @@ clean-k8s:

- kubectl delete -f k8s/jaeger.yaml

- kubectl delete -n observability -f https://github.com/jaegertracing/jaeger-operator/releases/download/v1.31.0/jaeger-operator.yaml
- kubectl delete -n observability -f https://github.com/jaegertracing/jaeger-operator/releases/download/$(JAEGER_OPERATOR_VERSION)/jaeger-operator.yaml
8 changes: 6 additions & 2 deletions example/otel-collector/main.go
Expand Up @@ -57,10 +57,14 @@ func initProvider() (func(context.Context) error, error) {
// microk8s), it should be accessible through the NodePort service at the
// `localhost:30080` endpoint. Otherwise, replace `localhost` with the
// endpoint of your cluster. If you run the app inside k8s, then you can
// probably connect directly to the service through dns
// probably connect directly to the service through dns.
ctx, cancel := context.WithTimeout(ctx, time.Second)
defer cancel()
conn, err := grpc.DialContext(ctx, "localhost:30080", grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithBlock())
conn, err := grpc.DialContext(ctx, "localhost:30080",
// Note the use of insecure transport here. TLS is recommended in production.
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithBlock(),
)
if err != nil {
return nil, fmt.Errorf("failed to create gRPC connection to collector: %w", err)
}
Expand Down
17 changes: 14 additions & 3 deletions example/prometheus/main.go
Expand Up @@ -18,9 +18,11 @@ import (
"context"
"fmt"
"log"
"math/rand"
"net/http"
"os"
"os/signal"
"time"

"github.com/prometheus/client_golang/prometheus/promhttp"

Expand All @@ -30,6 +32,10 @@ import (
"go.opentelemetry.io/otel/sdk/metric"
)

func init() {
rand.Seed(time.Now().UnixNano())
}

func main() {
ctx := context.Background()

Expand Down Expand Up @@ -58,12 +64,17 @@ func main() {
}
counter.Add(ctx, 5, attrs...)

gauge, err := meter.SyncFloat64().UpDownCounter("bar", instrument.WithDescription("a fun little gauge"))
gauge, err := meter.AsyncFloat64().Gauge("bar", instrument.WithDescription("a fun little gauge"))
if err != nil {
log.Fatal(err)
}
err = meter.RegisterCallback([]instrument.Asynchronous{gauge}, func(ctx context.Context) {
n := -10. + rand.Float64()*(90.) // [-10, 100)
gauge.Observe(ctx, n, attrs...)
})
if err != nil {
log.Fatal(err)
}
gauge.Add(ctx, 100, attrs...)
gauge.Add(ctx, -25, attrs...)

// This is the equivalent of prometheus.NewHistogramVec
histogram, err := meter.SyncFloat64().Histogram("baz", instrument.WithDescription("a very nice histogram"))
Expand Down
4 changes: 2 additions & 2 deletions exporters/otlp/otlptrace/README.md
Expand Up @@ -12,8 +12,8 @@ go get -u go.opentelemetry.io/otel/exporters/otlp/otlptrace

## Examples

- [Exporter setup and examples](./otlptracehttp/example_test.go)
- [Full example sending telemetry to a local collector](../../../example/otel-collector)
- [HTTP Exporter setup and examples](./otlptracehttp/example_test.go)
- [Full example of gRPC Exporter sending telemetry to a local collector](../../../example/otel-collector)

## [`otlptrace`](https://pkg.go.dev/go.opentelemetry.io/otel/exporters/otlp/otlptrace)

Expand Down
44 changes: 44 additions & 0 deletions sdk/metric/metricdata/metricdatatest/assertion.go
Expand Up @@ -20,6 +20,7 @@ import (
"fmt"
"testing"

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

Expand Down Expand Up @@ -129,3 +130,46 @@ func AssertAggregationsEqual(t *testing.T, expected, actual metricdata.Aggregati
}
return true
}

// AssertHasAttributes asserts that all Datapoints or HistogramDataPoints have all passed attrs.
func AssertHasAttributes[T Datatypes](t *testing.T, actual T, attrs ...attribute.KeyValue) bool {
t.Helper()

var reasons []string

switch e := interface{}(actual).(type) {
case metricdata.DataPoint[int64]:
reasons = hasAttributesDataPoints(e, attrs...)
case metricdata.DataPoint[float64]:
reasons = hasAttributesDataPoints(e, attrs...)
case metricdata.Gauge[int64]:
reasons = hasAttributesGauge(e, attrs...)
case metricdata.Gauge[float64]:
reasons = hasAttributesGauge(e, attrs...)
case metricdata.Sum[int64]:
reasons = hasAttributesSum(e, attrs...)
case metricdata.Sum[float64]:
reasons = hasAttributesSum(e, attrs...)
case metricdata.HistogramDataPoint:
reasons = hasAttributesHistogramDataPoints(e, attrs...)
case metricdata.Histogram:
reasons = hasAttributesHistogram(e, attrs...)
case metricdata.Metrics:
reasons = hasAttributesMetrics(e, attrs...)
case metricdata.ScopeMetrics:
reasons = hasAttributesScopeMetrics(e, attrs...)
case metricdata.ResourceMetrics:
reasons = hasAttributesResourceMetrics(e, attrs...)
default:
// We control all types passed to this, panic to signal developers
// early they changed things in an incompatible way.
panic(fmt.Sprintf("unknown types: %T", actual))
}

if len(reasons) > 0 {
t.Error(reasons)
return false
}

return true
}
19 changes: 19 additions & 0 deletions sdk/metric/metricdata/metricdatatest/assertion_fail_test.go
Expand Up @@ -19,6 +19,8 @@ package metricdatatest // import "go.opentelemetry.io/otel/sdk/metric/metricdata

import (
"testing"

"go.opentelemetry.io/otel/attribute"
)

// These tests are used to develop the failure messages of this package's
Expand Down Expand Up @@ -57,3 +59,20 @@ func TestFailAssertAggregationsEqual(t *testing.T) {
AssertAggregationsEqual(t, gaugeFloat64A, gaugeFloat64B)
AssertAggregationsEqual(t, histogramA, histogramB)
}

func TestFailAssertAttribute(t *testing.T) {
AssertHasAttributes(t, dataPointInt64A, attribute.Bool("A", false))
AssertHasAttributes(t, dataPointFloat64A, attribute.Bool("B", true))
AssertHasAttributes(t, gaugeInt64A, attribute.Bool("A", false))
AssertHasAttributes(t, gaugeFloat64A, attribute.Bool("B", true))
AssertHasAttributes(t, sumInt64A, attribute.Bool("A", false))
AssertHasAttributes(t, sumFloat64A, attribute.Bool("B", true))
AssertHasAttributes(t, histogramDataPointA, attribute.Bool("A", false))
AssertHasAttributes(t, histogramDataPointA, attribute.Bool("B", true))
AssertHasAttributes(t, histogramA, attribute.Bool("A", false))
AssertHasAttributes(t, histogramA, attribute.Bool("B", true))
AssertHasAttributes(t, metricsA, attribute.Bool("A", false))
AssertHasAttributes(t, metricsA, attribute.Bool("B", true))
AssertHasAttributes(t, resourceMetricsA, attribute.Bool("A", false))
AssertHasAttributes(t, resourceMetricsA, attribute.Bool("B", true))
}
75 changes: 75 additions & 0 deletions sdk/metric/metricdata/metricdatatest/assertion_test.go
Expand Up @@ -314,3 +314,78 @@ func TestAssertAggregationsEqual(t *testing.T) {
r = equalAggregations(histogramA, histogramC, config{ignoreTimestamp: true})
assert.Equalf(t, len(r), 0, "%v == %v", histogramA, histogramC)
}

func TestAssertAttributes(t *testing.T) {
AssertHasAttributes(t, dataPointInt64A, attribute.Bool("A", true))
AssertHasAttributes(t, dataPointFloat64A, attribute.Bool("A", true))
AssertHasAttributes(t, gaugeInt64A, attribute.Bool("A", true))
AssertHasAttributes(t, gaugeFloat64A, attribute.Bool("A", true))
AssertHasAttributes(t, sumInt64A, attribute.Bool("A", true))
AssertHasAttributes(t, sumFloat64A, attribute.Bool("A", true))
AssertHasAttributes(t, histogramDataPointA, attribute.Bool("A", true))
AssertHasAttributes(t, histogramA, attribute.Bool("A", true))
AssertHasAttributes(t, metricsA, attribute.Bool("A", true))
AssertHasAttributes(t, scopeMetricsA, attribute.Bool("A", true))
AssertHasAttributes(t, resourceMetricsA, attribute.Bool("A", true))

r := hasAttributesAggregation(gaugeInt64A, attribute.Bool("A", true))
assert.Equal(t, len(r), 0, "gaugeInt64A has A=True")
r = hasAttributesAggregation(gaugeFloat64A, attribute.Bool("A", true))
assert.Equal(t, len(r), 0, "gaugeFloat64A has A=True")
r = hasAttributesAggregation(sumInt64A, attribute.Bool("A", true))
assert.Equal(t, len(r), 0, "sumInt64A has A=True")
r = hasAttributesAggregation(sumFloat64A, attribute.Bool("A", true))
assert.Equal(t, len(r), 0, "sumFloat64A has A=True")
r = hasAttributesAggregation(histogramA, attribute.Bool("A", true))
assert.Equal(t, len(r), 0, "histogramA has A=True")

r = hasAttributesAggregation(gaugeInt64A, attribute.Bool("A", false))
assert.Greater(t, len(r), 0, "gaugeInt64A does not have A=False")
r = hasAttributesAggregation(gaugeFloat64A, attribute.Bool("A", false))
assert.Greater(t, len(r), 0, "gaugeFloat64A does not have A=False")
r = hasAttributesAggregation(sumInt64A, attribute.Bool("A", false))
assert.Greater(t, len(r), 0, "sumInt64A does not have A=False")
r = hasAttributesAggregation(sumFloat64A, attribute.Bool("A", false))
assert.Greater(t, len(r), 0, "sumFloat64A does not have A=False")
r = hasAttributesAggregation(histogramA, attribute.Bool("A", false))
assert.Greater(t, len(r), 0, "histogramA does not have A=False")

r = hasAttributesAggregation(gaugeInt64A, attribute.Bool("B", true))
assert.Greater(t, len(r), 0, "gaugeInt64A does not have Attribute B")
r = hasAttributesAggregation(gaugeFloat64A, attribute.Bool("B", true))
assert.Greater(t, len(r), 0, "gaugeFloat64A does not have Attribute B")
r = hasAttributesAggregation(sumInt64A, attribute.Bool("B", true))
assert.Greater(t, len(r), 0, "sumInt64A does not have Attribute B")
r = hasAttributesAggregation(sumFloat64A, attribute.Bool("B", true))
assert.Greater(t, len(r), 0, "sumFloat64A does not have Attribute B")
r = hasAttributesAggregation(histogramA, attribute.Bool("B", true))
assert.Greater(t, len(r), 0, "histogramA does not have Attribute B")
}

func TestAssertAttributesFail(t *testing.T) {
fakeT := &testing.T{}
assert.False(t, AssertHasAttributes(fakeT, dataPointInt64A, attribute.Bool("A", false)))
assert.False(t, AssertHasAttributes(fakeT, dataPointFloat64A, attribute.Bool("B", true)))
assert.False(t, AssertHasAttributes(fakeT, gaugeInt64A, attribute.Bool("A", false)))
assert.False(t, AssertHasAttributes(fakeT, gaugeFloat64A, attribute.Bool("B", true)))
assert.False(t, AssertHasAttributes(fakeT, sumInt64A, attribute.Bool("A", false)))
assert.False(t, AssertHasAttributes(fakeT, sumFloat64A, attribute.Bool("B", true)))
assert.False(t, AssertHasAttributes(fakeT, histogramDataPointA, attribute.Bool("A", false)))
assert.False(t, AssertHasAttributes(fakeT, histogramDataPointA, attribute.Bool("B", true)))
assert.False(t, AssertHasAttributes(fakeT, histogramA, attribute.Bool("A", false)))
assert.False(t, AssertHasAttributes(fakeT, histogramA, attribute.Bool("B", true)))
assert.False(t, AssertHasAttributes(fakeT, metricsA, attribute.Bool("A", false)))
assert.False(t, AssertHasAttributes(fakeT, metricsA, attribute.Bool("B", true)))
assert.False(t, AssertHasAttributes(fakeT, resourceMetricsA, attribute.Bool("A", false)))
assert.False(t, AssertHasAttributes(fakeT, resourceMetricsA, attribute.Bool("B", true)))

sum := metricdata.Sum[int64]{
Temporality: metricdata.CumulativeTemporality,
IsMonotonic: true,
DataPoints: []metricdata.DataPoint[int64]{
dataPointInt64A,
dataPointInt64B,
},
}
assert.False(t, AssertHasAttributes(fakeT, sum, attribute.Bool("A", true)))
}
113 changes: 113 additions & 0 deletions sdk/metric/metricdata/metricdatatest/comparisons.go
Expand Up @@ -358,3 +358,116 @@ func compareDiff[T any](extraExpected, extraActual []T) string {

return msg.String()
}

func missingAttrStr(name string) string {
return fmt.Sprintf("missing attribute %s", name)
}

func hasAttributesDataPoints[T int64 | float64](dp metricdata.DataPoint[T], attrs ...attribute.KeyValue) (reasons []string) {
for _, attr := range attrs {
val, ok := dp.Attributes.Value(attr.Key)
if !ok {
reasons = append(reasons, missingAttrStr(string(attr.Key)))
continue
}
if val != attr.Value {
reasons = append(reasons, notEqualStr(string(attr.Key), attr.Value.Emit(), val.Emit()))
}
}
return reasons
}

func hasAttributesGauge[T int64 | float64](gauge metricdata.Gauge[T], attrs ...attribute.KeyValue) (reasons []string) {
for n, dp := range gauge.DataPoints {
reas := hasAttributesDataPoints(dp, attrs...)
if len(reas) > 0 {
reasons = append(reasons, fmt.Sprintf("gauge datapoint %d attributes:\n", n))
reasons = append(reasons, reas...)
}
}
return reasons
}

func hasAttributesSum[T int64 | float64](sum metricdata.Sum[T], attrs ...attribute.KeyValue) (reasons []string) {
for n, dp := range sum.DataPoints {
reas := hasAttributesDataPoints(dp, attrs...)
if len(reas) > 0 {
reasons = append(reasons, fmt.Sprintf("sum datapoint %d attributes:\n", n))
reasons = append(reasons, reas...)
}
}
return reasons
}

func hasAttributesHistogramDataPoints(dp metricdata.HistogramDataPoint, attrs ...attribute.KeyValue) (reasons []string) {
for _, attr := range attrs {
val, ok := dp.Attributes.Value(attr.Key)
if !ok {
reasons = append(reasons, missingAttrStr(string(attr.Key)))
continue
}
if val != attr.Value {
reasons = append(reasons, notEqualStr(string(attr.Key), attr.Value.Emit(), val.Emit()))
}
}
return reasons
}

func hasAttributesHistogram(histogram metricdata.Histogram, attrs ...attribute.KeyValue) (reasons []string) {
for n, dp := range histogram.DataPoints {
reas := hasAttributesHistogramDataPoints(dp, attrs...)
if len(reas) > 0 {
reasons = append(reasons, fmt.Sprintf("histogram datapoint %d attributes:\n", n))
reasons = append(reasons, reas...)
}
}
return reasons
}

func hasAttributesAggregation(agg metricdata.Aggregation, attrs ...attribute.KeyValue) (reasons []string) {
switch agg := agg.(type) {
case metricdata.Gauge[int64]:
reasons = hasAttributesGauge(agg, attrs...)
case metricdata.Gauge[float64]:
reasons = hasAttributesGauge(agg, attrs...)
case metricdata.Sum[int64]:
reasons = hasAttributesSum(agg, attrs...)
case metricdata.Sum[float64]:
reasons = hasAttributesSum(agg, attrs...)
case metricdata.Histogram:
reasons = hasAttributesHistogram(agg, attrs...)
default:
reasons = []string{fmt.Sprintf("unknown aggregation %T", agg)}
}
return reasons
}

func hasAttributesMetrics(metrics metricdata.Metrics, attrs ...attribute.KeyValue) (reasons []string) {
reas := hasAttributesAggregation(metrics.Data, attrs...)
if len(reas) > 0 {
reasons = append(reasons, fmt.Sprintf("Metric %s:\n", metrics.Name))
reasons = append(reasons, reas...)
}
return reasons
}

func hasAttributesScopeMetrics(sm metricdata.ScopeMetrics, attrs ...attribute.KeyValue) (reasons []string) {
for n, metrics := range sm.Metrics {
reas := hasAttributesMetrics(metrics, attrs...)
if len(reas) > 0 {
reasons = append(reasons, fmt.Sprintf("ScopeMetrics %s Metrics %d:\n", sm.Scope.Name, n))
reasons = append(reasons, reas...)
}
}
return reasons
}
func hasAttributesResourceMetrics(rm metricdata.ResourceMetrics, attrs ...attribute.KeyValue) (reasons []string) {
for n, sm := range rm.ScopeMetrics {
reas := hasAttributesScopeMetrics(sm, attrs...)
if len(reas) > 0 {
reasons = append(reasons, fmt.Sprintf("ResourceMetrics ScopeMetrics %d:\n", n))
reasons = append(reasons, reas...)
}
}
return reasons
}

0 comments on commit 69f5348

Please sign in to comment.