diff --git a/README.md b/README.md index fd1cbf09..bc01b389 100644 --- a/README.md +++ b/README.md @@ -574,7 +574,7 @@ async.Wait() ``` -### OpenTelemetry +## OpenTelemetry Tracing tools using OpenTelemetry client SDK and Jaeger Tracing server. See [tracing @@ -582,7 +582,7 @@ readme](https://github.com/mailgun/holster/blob/master/tracing/README.md) for details. -### Context Utilities +## Context Utilities See package directory `ctxutil`. Use functions `ctxutil.WithDeadline()`/`WithTimeout()` instead of the `context` diff --git a/go.mod b/go.mod index 4f83294b..c7703007 100644 --- a/go.mod +++ b/go.mod @@ -26,10 +26,10 @@ require ( require ( github.com/uptrace/opentelemetry-go-extra/otellogrus v0.1.7 - go.opentelemetry.io/otel v1.3.0 + go.opentelemetry.io/otel v1.4.1 go.opentelemetry.io/otel/exporters/jaeger v1.3.0 go.opentelemetry.io/otel/sdk v1.3.0 - go.opentelemetry.io/otel/trace v1.3.0 + go.opentelemetry.io/otel/trace v1.4.1 ) require ( @@ -38,8 +38,8 @@ require ( github.com/coreos/go-systemd/v22 v22.3.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/fatih/color v1.9.0 // indirect - github.com/go-logr/logr v1.2.1 // indirect - github.com/go-logr/stdr v1.2.0 // indirect + github.com/go-logr/logr v1.2.2 // indirect + github.com/go-logr/stdr v1.2.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c // indirect github.com/hashicorp/errwrap v1.0.0 // indirect diff --git a/go.sum b/go.sum index 616a75ee..85df134e 100644 --- a/go.sum +++ b/go.sum @@ -54,10 +54,12 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.1 h1:DX7uPQ4WgAWfoh+NGGlbJQswnYIVvz0SRlLS3rPZQDA= github.com/go-logr/logr v1.2.1/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/stdr v1.2.0 h1:j4LrlVXgrbIWO83mmQUnK0Hi+YnbD+vzrE1z/EphbFE= +github.com/go-logr/logr v1.2.2 h1:ahHml/yUpnlb96Rp8HCvtYVPY8ZYpxq3g7UYchIYwbs= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.0/go.mod h1:YkVgnZu1ZjjL7xTxrfm/LLZBfkhTqSR1ydtm6jTKKwI= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -89,8 +91,9 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= @@ -238,16 +241,18 @@ go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3 go.etcd.io/etcd/client/v3 v3.5.0 h1:62Eh0XOro+rDwkrypAGDfgmNh5Joq+z+W9HZdlXMzek= go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= go.opentelemetry.io/otel v1.0.1/go.mod h1:OPEOD4jIT2SlZPMmwT6FqZz2C0ZNdQqiWcoK6M0SNFU= -go.opentelemetry.io/otel v1.3.0 h1:APxLf0eiBwLl+SOXiJJCVYzA1OOJNyAoV8C5RNRyy7Y= go.opentelemetry.io/otel v1.3.0/go.mod h1:PWIKzi6JCp7sM0k9yZ43VX+T345uNbAkDKwHVjb2PTs= +go.opentelemetry.io/otel v1.4.1 h1:QbINgGDDcoQUoMJa2mMaWno49lja9sHwp6aoa2n3a4g= +go.opentelemetry.io/otel v1.4.1/go.mod h1:StM6F/0fSwpd8dKWDCdRr7uRvEPYdW0hBSlbdTiUde4= go.opentelemetry.io/otel/exporters/jaeger v1.3.0 h1:HfydzioALdtcB26H5WHc4K47iTETJCdloL7VN579/L0= go.opentelemetry.io/otel/exporters/jaeger v1.3.0/go.mod h1:KoYHi1BtkUPncGSRtCe/eh1ijsnePhSkxwzz07vU0Fc= go.opentelemetry.io/otel/sdk v1.0.1/go.mod h1:HrdXne+BiwsOHYYkBE5ysIcv2bvdZstxzmCQhxTcZkI= go.opentelemetry.io/otel/sdk v1.3.0 h1:3278edCoH89MEJ0Ky8WQXVmDQv3FX4ZJ3Pp+9fJreAI= go.opentelemetry.io/otel/sdk v1.3.0/go.mod h1:rIo4suHNhQwBIPg9axF8V9CA72Wz2mKF1teNrup8yzs= go.opentelemetry.io/otel/trace v1.0.1/go.mod h1:5g4i4fKLaX2BQpSBsxw8YYcgKpMMSW3x7ZTuYBr3sUk= -go.opentelemetry.io/otel/trace v1.3.0 h1:doy8Hzb1RJ+I3yFhtDmwNc7tIyw1tNMOIsyPzp1NOGY= go.opentelemetry.io/otel/trace v1.3.0/go.mod h1:c/VDhno8888bvQYmbYLqe41/Ldmr/KKunbvWM4/fEjk= +go.opentelemetry.io/otel/trace v1.4.1 h1:O+16qcdTrT7zxv2J6GejTPFinSwA++cYerC5iSiF8EQ= +go.opentelemetry.io/otel/trace v1.4.1/go.mod h1:iYEVbroFCNut9QkwEczV9vMRPHNKSSwYZjulEtsmhFc= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= @@ -327,7 +332,6 @@ golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/tracing/README.md b/tracing/README.md index fe58271c..fd17e659 100644 --- a/tracing/README.md +++ b/tracing/README.md @@ -45,14 +45,15 @@ See unit tests for usage examples. ### Configuration Configuration via environment variables: -[https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md) +[https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md). Such as: ``` OTEL_SERVICE_NAME=myapp OTEL_EXPORTER_JAEGER_AGENT_HOST= ``` -Note: Setting `OTEL_SERVICE_NAME` is recommended or default will be "unknown\_service:\". +The service name appears in the Jaeger "Service" dropdown. If unset, default +is `unknown_service:`. #### Probabilistic Sampling By default, all traces are sampled. @@ -70,10 +71,15 @@ Previously in OpenTracing, this was configured in environment variables `JAEGER_ The OpenTelemetry client must be initialized to read configuration and prepare a `Tracer` object. When application is exiting, call `CloseTracing()`. +The library name passed in the second argument appears in spans as metadata +`otel.library.name`. This is used to identify the library or module that +generated that span. This usually the fully qualified module name of your +repo. + ```go import "github.com/mailgun/holster/v4/tracing" -ctx, tracer, err := tracing.InitTracing(ctx, "My service") +ctx, tracer, err := tracing.InitTracing(ctx, "github.com/myrepo/myservice") tracing.SetDefaultTracer(tracer) // ... @@ -81,6 +87,36 @@ tracing.SetDefaultTracer(tracer) tracing.CloseTracing(context.Background()) ``` +### Setting Resources +OpenTelemetry is configured by environment variables and supplemental resource +settings. Some of these resources also map to environment variables. + +#### Service Name +As an alternative to configuring service name with environment variable +`OTEL_SERVICE_NAME`, it may be provided as a resource. The resource setting +takes precedent over the environment variable. + +```go +import ( + "go.opentelemetry.io/otel/sdk/resource" + sdktrace "go.opentelemetry.io/otel/sdk/trace" + semconv "go.opentelemetry.io/otel/semconv/v1.7.0" +) + +res, err := resource.Merge( + resource.Default(), + resource.NewWithAttributes( + semconv.SchemaURL, + semconv.ServiceNameKey.String("My service"), + semconv.ServiceVersionKey.String("v1.0.0"), + ), +) +ctx, tracer, err := tracing.InitTracing(ctx, "github.com/myrepo/myservice", sdktrace.WithResource(res)) +``` + +If neither resource nor environment variable are provided, the default service +name is `unknown_service:`. + ### Manual Tracing Basic instrumentation. Traces function duration as a span and captures logrus logs. diff --git a/tracing/tracing.go b/tracing/tracing.go index 7515611e..2118f756 100644 --- a/tracing/tracing.go +++ b/tracing/tracing.go @@ -102,6 +102,8 @@ func CloseTracing(ctx context.Context) error { return errors.New("OpenTelemetry global tracer provider has not be initialized") } + defaultTracer = nil + ctx, cancel := context.WithTimeout(ctx, 5 * time.Second) defer cancel() err := tp.Shutdown(ctx) diff --git a/tracing/tracing_test.go b/tracing/tracing_test.go index dabeeaaf..69e83ae5 100644 --- a/tracing/tracing_test.go +++ b/tracing/tracing_test.go @@ -10,20 +10,61 @@ import ( "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" + "go.opentelemetry.io/otel/sdk/resource" + sdktrace "go.opentelemetry.io/otel/sdk/trace" + semconv "go.opentelemetry.io/otel/semconv/v1.7.0" "go.opentelemetry.io/otel/trace" ) func TestTracing(t *testing.T) { ctx := context.Background() logrus.SetLevel(logrus.DebugLevel) - ctx, tracer, err := tracing.InitTracing(ctx, "TestTracing") - require.NoError(t, err) - defer func() { - err := tracing.CloseTracing(ctx) - require.NoError(t, err) - }() + + t.Run("InitTracing()", func(t *testing.T) { + t.Run("Happy path", func(t *testing.T) { + ctx, tracer, err := tracing.InitTracing(ctx, "TestTracing") + require.NotNil(t, ctx) + require.NotNil(t, tracer) + require.NoError(t, err) + + err = tracing.CloseTracing(ctx) + require.NoError(t, err) + }) + + t.Run("Set service name", func(t *testing.T) { + // Sets service name resource. + // This overrides environment variable `OTEL_SERVICE_NAME`. + // If neither provided, default service name is + // "unknown_service:". + // See: https://opentelemetry.io/docs/instrumentation/go/getting-started/#creating-a-resource + res, err := resource.Merge( + resource.Default(), + resource.NewWithAttributes( + semconv.SchemaURL, + semconv.ServiceNameKey.String("Foobar service"), + semconv.ServiceVersionKey.String("v1.0.0"), + ), + ) + require.NoError(t, err) + + ctx, tracer, err := tracing.InitTracing(ctx, "TestTracing", sdktrace.WithResource(res)) + require.NotNil(t, ctx) + require.NotNil(t, tracer) + require.NoError(t, err) + + err = tracing.CloseTracing(ctx) + require.NoError(t, err) + }) + }) t.Run("Manual tracing", func(t *testing.T) { + ctx, tracer, err := tracing.InitTracing(ctx, "TestTracing") + require.NoError(t, err) + defer func() { + err := tracing.CloseTracing(ctx) + require.NoError(t, err) + }() + t.Run("Simple traces", func(t *testing.T) { ctx, span := tracer.Start(ctx, t.Name()) defer span.End() @@ -69,6 +110,13 @@ func TestTracing(t *testing.T) { }) t.Run("Scope()", func(t *testing.T) { + ctx, _, err := tracing.InitTracing(ctx, "TestTracing") + require.NoError(t, err) + defer func() { + err := tracing.CloseTracing(ctx) + require.NoError(t, err) + }() + t.Run("Simple traces", func(t *testing.T) { err := tracing.NamedScope(ctx, t.Name(), func(ctx context.Context) error { for i := 0; i < 10; i++ {