1
0
mirror of https://github.com/open-telemetry/opentelemetry-go.git synced 2025-02-13 13:48:28 +02:00
opentelemetry-go/trace/noop/noop_test.go
ttoad 86df763d90
trace: Span in noop.Start is no longer allocated (#5457)
trace/noop/noop.Span should be instance. This will reduce memory waste.

Benchmark results

with changes:
new.txt
```
goos: darwin
goarch: arm64
pkg: go.opentelemetry.io/otel/trace/noop
BenchmarkNoopInstance-10        29894822                39.94 ns/op           48 B/op          1 allocs/op
BenchmarkNoopInstance-10        29675424                39.99 ns/op           48 B/op          1 allocs/op
BenchmarkNoopInstance-10        30064700                39.98 ns/op           48 B/op          1 allocs/op
BenchmarkNoopInstance-10        29962016                40.03 ns/op           48 B/op          1 allocs/op
BenchmarkNoopInstance-10        30060465                40.02 ns/op           48 B/op          1 allocs/op
BenchmarkNoopInstance-10        29916855                40.04 ns/op           48 B/op          1 allocs/op
BenchmarkNoopInstance-10        29829998                40.28 ns/op           48 B/op          1 allocs/op
BenchmarkNoopInstance-10        30084706                39.99 ns/op           48 B/op          1 allocs/op
BenchmarkNoopInstance-10        30087441                40.02 ns/op           48 B/op          1 allocs/op
BenchmarkNoopInstance-10        29864365                40.14 ns/op           48 B/op          1 allocs/op
```
without changes on `main`:
old.txt
```
goos: darwin
goarch: arm64
pkg: go.opentelemetry.io/otel/trace/noop
BenchmarkNoopInstance-10        14813442                67.64 ns/op          128 B/op          2 allocs/op
BenchmarkNoopInstance-10        17714486                68.17 ns/op          128 B/op          2 allocs/op
BenchmarkNoopInstance-10        17701257                67.66 ns/op          128 B/op          2 allocs/op
BenchmarkNoopInstance-10        17805859                67.69 ns/op          128 B/op          2 allocs/op
BenchmarkNoopInstance-10        17912841                67.43 ns/op          128 B/op          2 allocs/op
BenchmarkNoopInstance-10        17864120                67.58 ns/op          128 B/op          2 allocs/op
BenchmarkNoopInstance-10        17663130                68.41 ns/op          128 B/op          2 allocs/op
BenchmarkNoopInstance-10        17740423                67.57 ns/op          128 B/op          2 allocs/op
BenchmarkNoopInstance-10        17751040                67.56 ns/op          128 B/op          2 allocs/op
BenchmarkNoopInstance-10        17738064                67.91 ns/op          128 B/op          2 allocs/op

```

benchstat: 
```
goos: darwin
goarch: arm64
pkg: go.opentelemetry.io/otel/trace/noop
                │   old.txt   │               new.txt               │
                │   sec/op    │   sec/op     vs base                │
NoopInstance-10   67.65n ± 1%   40.02n ± 0%  -40.84% (p=0.000 n=10)

                │   old.txt   │              new.txt               │
                │    B/op     │    B/op     vs base                │
NoopInstance-10   128.00 ± 0%   48.00 ± 0%  -62.50% (p=0.000 n=10)

                │  old.txt   │              new.txt               │
                │ allocs/op  │ allocs/op   vs base                │
NoopInstance-10   2.000 ± 0%   1.000 ± 0%  -50.00% (p=0.000 n=10)
```

Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com>
2024-06-04 11:14:10 -07:00

120 lines
3.8 KiB
Go

// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
package noop // import "go.opentelemetry.io/otel/trace/noop"
import (
"context"
"reflect"
"testing"
"github.com/stretchr/testify/assert"
"go.opentelemetry.io/otel/trace"
)
func TestImplementationNoPanics(t *testing.T) {
// Check that if type has an embedded interface and that interface has
// methods added to it than the No-Op implementation implements them.
t.Run("TracerProvider", assertAllExportedMethodNoPanic(
reflect.ValueOf(TracerProvider{}),
reflect.TypeOf((*trace.TracerProvider)(nil)).Elem(),
))
t.Run("Tracer", assertAllExportedMethodNoPanic(
reflect.ValueOf(Tracer{}),
reflect.TypeOf((*trace.Tracer)(nil)).Elem(),
))
t.Run("Span", assertAllExportedMethodNoPanic(
reflect.ValueOf(Span{}),
reflect.TypeOf((*trace.Span)(nil)).Elem(),
))
}
func assertAllExportedMethodNoPanic(rVal reflect.Value, rType reflect.Type) func(*testing.T) {
return func(t *testing.T) {
for n := 0; n < rType.NumMethod(); n++ {
mType := rType.Method(n)
if !mType.IsExported() {
t.Logf("ignoring unexported %s", mType.Name)
continue
}
m := rVal.MethodByName(mType.Name)
if !m.IsValid() {
t.Errorf("unknown method for %s: %s", rVal.Type().Name(), mType.Name)
}
numIn := mType.Type.NumIn()
if mType.Type.IsVariadic() {
numIn--
}
args := make([]reflect.Value, numIn)
ctx := context.Background()
for i := range args {
aType := mType.Type.In(i)
if aType.Name() == "Context" {
// Do not panic on a nil context.
args[i] = reflect.ValueOf(ctx)
} else {
args[i] = reflect.New(aType).Elem()
}
}
assert.NotPanicsf(t, func() {
_ = m.Call(args)
}, "%s.%s", rVal.Type().Name(), mType.Name)
}
}
}
func TestNewTracerProvider(t *testing.T) {
tp := NewTracerProvider()
assert.Equal(t, tp, TracerProvider{})
tracer := tp.Tracer("")
assert.Equal(t, tracer, Tracer{})
}
func TestTracerStartPropagatesSpanContext(t *testing.T) {
tracer := NewTracerProvider().Tracer("")
spanCtx := trace.SpanContext{}
ctx := trace.ContextWithSpanContext(context.Background(), spanCtx)
ctx, span := tracer.Start(ctx, "test_span")
assert.Equal(t, spanCtx, trace.SpanContextFromContext(ctx), "empty span context not set in context")
assert.IsType(t, Span{}, span, "non-noop span returned")
assert.Equal(t, spanCtx, span.SpanContext(), "empty span context not returned from span")
assert.False(t, span.IsRecording(), "empty span context returned recording span")
spanCtx = spanCtx.WithTraceID(trace.TraceID([16]byte{1}))
spanCtx = spanCtx.WithSpanID(trace.SpanID([8]byte{1}))
ctx = trace.ContextWithSpanContext(context.Background(), spanCtx)
ctx, span = tracer.Start(ctx, "test_span")
assert.Equal(t, spanCtx, trace.SpanContextFromContext(ctx), "non-empty span context not set in context")
assert.Equal(t, spanCtx, span.SpanContext(), "non-empty span context not returned from span")
assert.False(t, span.IsRecording(), "non-empty span context returned recording span")
rSpan := recordingSpan{Span: Span{sc: spanCtx}}
ctx = trace.ContextWithSpan(context.Background(), rSpan)
ctx, span = tracer.Start(ctx, "test_span")
assert.Equal(t, spanCtx, trace.SpanContextFromContext(ctx), "recording span's span context not set in context")
assert.IsType(t, Span{}, span, "non-noop span returned")
assert.Equal(t, spanCtx, span.SpanContext(), "recording span's span context not returned from span")
assert.False(t, span.IsRecording(), "recording span returned")
}
func BenchmarkNoopInstance(b *testing.B) {
tracer := NewTracerProvider().Tracer("")
ctx := trace.ContextWithSpanContext(context.Background(), trace.SpanContext{})
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, span := tracer.Start(ctx, "")
span.End()
}
}
type recordingSpan struct{ Span }
func (recordingSpan) IsRecording() bool { return true }