Skip to content

Commit

Permalink
feat: add tracing helper
Browse files Browse the repository at this point in the history
  • Loading branch information
alnr committed Dec 30, 2022
1 parent 716ad47 commit 8c2bcf5
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 19 deletions.
1 change: 0 additions & 1 deletion go.mod
Expand Up @@ -34,7 +34,6 @@ require (
github.com/hashicorp/go-retryablehttp v0.7.1
github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf
github.com/instana/go-sensor v1.46.0
github.com/instana/testify v1.6.2-0.20200721153833-94b1851f4d65
github.com/jackc/pgconn v1.13.0
github.com/jackc/pgx/v4 v4.17.2
github.com/jandelgado/gcov2lcov v1.0.5
Expand Down
2 changes: 1 addition & 1 deletion otelx/otel_test.go
Expand Up @@ -16,7 +16,7 @@ import (
"testing"
"time"

"github.com/instana/testify/assert"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.opentelemetry.io/otel/attribute"
"golang.org/x/sync/errgroup"
Expand Down
54 changes: 41 additions & 13 deletions otelx/withspan.go
Expand Up @@ -5,6 +5,7 @@ package otelx

import (
"context"
"fmt"

"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/trace"
Expand All @@ -21,21 +22,48 @@ func WithSpan(ctx context.Context, name string, f func(context.Context) error, o
ctx, span := trace.SpanFromContext(ctx).TracerProvider().Tracer("").Start(ctx, name, opts...)
defer func() {
defer span.End()
if err != nil {
span.SetStatus(codes.Error, err.Error())
} else if r := recover(); r != nil {
switch e := r.(type) {
case error:
span.SetStatus(codes.Error, "panic: "+e.Error())
case interface{ String() string }:
span.SetStatus(codes.Error, "panic: "+e.String())
case string:
span.SetStatus(codes.Error, "panic: "+e)
default:
span.SetStatus(codes.Error, "panic")
}
if r := recover(); r != nil {
setErrorStatusPanic(span, r)
panic(r)
} else if err != nil {
span.SetStatus(codes.Error, err.Error())
}
}()
return f(ctx)
}

// End finishes span, and automatically sets the error state if *err is not nil
// or during panicking.
//
// Usage:
//
// func Divide(ctx context.Context, numerator, denominator int) (ratio int, err error) {
// ctx, span := tracer.Start(ctx, "my-operation")
// defer otelx.End(span, &err)
// if denominator == 0 {
// return 0, errors.New("cannot divide by zero")
// }
// return numerator / denominator, nil
// }
func End(span trace.Span, err *error) {
defer span.End()
if r := recover(); r != nil {
setErrorStatusPanic(span, r)
panic(r)
}
if err == nil || *err == nil {
return
}
span.SetStatus(codes.Error, (*err).Error())
}

func setErrorStatusPanic(span trace.Span, recovered any) {
switch e := recovered.(type) {
case error, string, fmt.Stringer:
span.SetStatus(codes.Error, fmt.Sprintf("panic: %v", e))
default:
span.SetStatus(codes.Error, "panic")
case nil:
// nothing
}
}
36 changes: 34 additions & 2 deletions otelx/withspan_test.go
Expand Up @@ -8,10 +8,16 @@ import (
"errors"
"testing"

"github.com/instana/testify/assert"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.opentelemetry.io/otel/codes"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
"go.opentelemetry.io/otel/sdk/trace/tracetest"
"go.opentelemetry.io/otel/trace"
)

var errPanic = errors.New("panic-error")

func TestWithSpan(t *testing.T) {
tracer := trace.NewNoopTracerProvider().Tracer("test")
ctx, span := tracer.Start(context.Background(), "parent")
Expand All @@ -36,4 +42,30 @@ func TestWithSpan(t *testing.T) {
})
}

var errPanic = errors.New("panic-error")
func returnsError(ctx context.Context) (err error) {
_, span := trace.SpanFromContext(ctx).TracerProvider().Tracer("").Start(ctx, "returnsError")
defer End(span, &err)
return errors.New("error from returnsError()")
}

func panics(ctx context.Context) (err error) {
_, span := trace.SpanFromContext(ctx).TracerProvider().Tracer("").Start(ctx, "panics")
defer End(span, &err)
panic(errors.New("panic from panics()"))
}

func TestEnd(t *testing.T) {
recorder := tracetest.NewSpanRecorder()
tracer := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(recorder)).Tracer("test")
ctx, span := tracer.Start(context.Background(), "parent")
defer span.End()

assert.Errorf(t, returnsError(ctx), "error from returnsError()")
require.NotEmpty(t, recorder.Ended())
assert.Equal(t, recorder.Ended()[len(recorder.Ended())-1].Status(), sdktrace.Status{codes.Error, "error from returnsError()"})

assert.PanicsWithError(t, "panic from panics()", func() { panics(ctx) })
require.NotEmpty(t, recorder.Ended())
assert.Equal(t, recorder.Ended()[len(recorder.Ended())-1].Status(), sdktrace.Status{codes.Error, "panic: panic from panics()"})

}
2 changes: 1 addition & 1 deletion pagination/keysetpagination/header_test.go
Expand Up @@ -8,7 +8,7 @@ import (
"net/url"
"testing"

"github.com/instana/testify/assert"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

Expand Down
2 changes: 1 addition & 1 deletion requirex/time_test.go
Expand Up @@ -7,7 +7,7 @@ import (
"testing"
"time"

"github.com/instana/testify/require"
"github.com/stretchr/testify/require"
)

type MockT struct {
Expand Down

0 comments on commit 8c2bcf5

Please sign in to comment.