Skip to content

Commit

Permalink
ddtrace/tracer: add service version to tracer. (DataDog#607)
Browse files Browse the repository at this point in the history
This commit adds the concept of a service version to the tracer. The service version should be the current version of the application (service). the service version will be picked up from the DD_VERSION environment variable, or can be set with the WithServiceVersion StartOption when starting the tracer. WithServiceVersion takes priority over the environment variable.

Spans that have a service name equal to the application's service name (set with DD_SERVICE or the WithServiceName StartOption) will be given a "version" tag with the service version as its value.
  • Loading branch information
knusbaum authored and mingrammer committed Dec 22, 2020
1 parent c8b6653 commit 054fa5e
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 17 deletions.
17 changes: 8 additions & 9 deletions contrib/google.golang.org/grpc/stats_client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,14 @@ func TestClientStatsHandler(t *testing.T) {
assert.NotZero(span.StartTime())
assert.True(span.FinishTime().After(span.StartTime()))
assert.Equal("grpc.client", span.OperationName())
assert.Equal(map[string]interface{}{
"span.type": ext.AppTypeRPC,
"grpc.code": codes.OK.String(),
"service.name": serviceName,
"resource.name": "/grpc.Fixture/Ping",
tagMethodName: "/grpc.Fixture/Ping",
ext.TargetHost: "127.0.0.1",
ext.TargetPort: server.port,
}, span.Tags())
tags := span.Tags()
assert.Equal(ext.AppTypeRPC, tags["span.type"])
assert.Equal(codes.OK.String(), tags["grpc.code"])
assert.Equal(serviceName, tags["service.name"])
assert.Equal("/grpc.Fixture/Ping", tags["resource.name"])
assert.Equal("/grpc.Fixture/Ping", tags[tagMethodName])
assert.Equal("127.0.0.1", tags[ext.TargetHost])
assert.Equal(server.port, tags[ext.TargetPort])
}

func newClientStatsHandlerTestServer(statsHandler stats.Handler) (*rig, error) {
Expand Down
15 changes: 7 additions & 8 deletions contrib/google.golang.org/grpc/stats_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,13 @@ func TestServerStatsHandler(t *testing.T) {
assert.NotZero(span.StartTime())
assert.True(span.FinishTime().After(span.StartTime()))
assert.Equal("grpc.server", span.OperationName())
assert.Equal(map[string]interface{}{
"span.type": ext.AppTypeRPC,
"grpc.code": codes.OK.String(),
"service.name": serviceName,
"resource.name": "/grpc.Fixture/Ping",
tagMethodName: "/grpc.Fixture/Ping",
"_dd.measured": 1,
}, span.Tags())
tags := span.Tags()
assert.Equal(ext.AppTypeRPC, tags["span.type"])
assert.Equal(codes.OK.String(), tags["grpc.code"])
assert.Equal(serviceName, tags["service.name"])
assert.Equal("/grpc.Fixture/Ping", tags["resource.name"])
assert.Equal("/grpc.Fixture/Ping", tags[tagMethodName])
assert.Equal(1, tags["_dd.measured"])
}

func newServerStatsHandlerTestServer(statsHandler stats.Handler) (*rig, error) {
Expand Down
3 changes: 3 additions & 0 deletions ddtrace/ext/tags.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ const (
// ServiceName defines the Service name for this Span.
ServiceName = "service.name"

// Version is a tag that specifies the current application version.
Version = "version"

// ResourceName defines the Resource name for the Span.
ResourceName = "resource.name"

Expand Down
14 changes: 14 additions & 0 deletions ddtrace/tracer/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ type config struct {
// serviceName specifies the name of this application.
serviceName string

// version specifies the version of this application
version string

// sampler specifies the sampler that will be used for sampling traces.
sampler Sampler

Expand Down Expand Up @@ -110,6 +113,9 @@ func defaults(c *config) {
} else {
c.serviceName = filepath.Base(os.Args[0])
}
if ver := os.Getenv("DD_VERSION"); ver != "" {
c.version = ver
}
if v := os.Getenv("DD_TAGS"); v != "" {
for _, tag := range strings.Split(v, ",") {
tag = strings.TrimSpace(tag)
Expand Down Expand Up @@ -283,6 +289,14 @@ func WithSamplingRules(rules []SamplingRule) StartOption {
}
}

// WithServiceVersion specifies the version of the service that is running. This will
// be included in spans from this service in the "version" tag.
func WithServiceVersion(version string) StartOption {
return func(cfg *config) {
cfg.version = version
}
}

// StartSpanOption is a configuration option for StartSpan. It is aliased in order
// to help godoc group all the functions returning it together. It is considered
// more correct to refer to it as the type as the origin, ddtrace.StartSpanOption.
Expand Down
3 changes: 3 additions & 0 deletions ddtrace/tracer/tracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,9 @@ func (t *tracer) StartSpan(operationName string, options ...ddtrace.StartSpanOpt
for k, v := range t.config.globalTags {
span.SetTag(k, v)
}
if t.config.version != "" && span.Service == t.config.serviceName {
span.SetTag(ext.Version, t.config.version)
}
if context == nil {
// this is a brand new trace, sample it
t.sample(span)
Expand Down
56 changes: 56 additions & 0 deletions ddtrace/tracer/tracer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1014,6 +1014,62 @@ func TestTracerReportsHostname(t *testing.T) {
})
}

func TestVersion(t *testing.T) {
t.Run("env", func(t *testing.T) {
os.Setenv("DD_VERSION", "1.2.3")
defer os.Unsetenv("DD_VERSION")

tracer, _, _, stop := startTestTracer(t)
defer stop()

assert := assert.New(t)
sp := tracer.StartSpan("http.request").(*span)
v := sp.Meta[ext.Version]
assert.Equal("1.2.3", v)
})

t.Run("option", func(t *testing.T) {
os.Setenv("DD_VERSION", "1.2.3")
defer os.Unsetenv("DD_VERSION")

tracer, _, _, stop := startTestTracer(t, WithServiceVersion("4.5.6"))
defer stop()

assert := assert.New(t)
sp := tracer.StartSpan("http.request").(*span)
v := sp.Meta[ext.Version]
assert.Equal("4.5.6", v)
})

t.Run("unset", func(t *testing.T) {
os.Setenv("DD_VERSION", "1.2.3")
defer os.Unsetenv("DD_VERSION")

tracer, _, _, stop := startTestTracer(t, WithService("servenv"))
defer stop()

assert := assert.New(t)
sp := tracer.StartSpan("http.request", ServiceName("otherservenv")).(*span)
_, ok := sp.Meta[ext.Version]
assert.False(ok)
})

t.Run("unset2", func(t *testing.T) {
os.Setenv("DD_SERVICE", "servenv")
defer os.Unsetenv("DD_SERVICE")
os.Setenv("DD_VERSION", "1.2.3")
defer os.Unsetenv("DD_VERSION")

tracer, _, _, stop := startTestTracer(t)
defer stop()

assert := assert.New(t)
sp := tracer.StartSpan("http.request", ServiceName("otherservenv")).(*span)
_, ok := sp.Meta[ext.Version]
assert.False(ok)
})
}

// BenchmarkConcurrentTracing tests the performance of spawning a lot of
// goroutines where each one creates a trace with a parent and a child.
func BenchmarkConcurrentTracing(b *testing.B) {
Expand Down

0 comments on commit 054fa5e

Please sign in to comment.