Skip to content

Commit

Permalink
contrib: update non-client integrations to use configured service name (
Browse files Browse the repository at this point in the history
#614)

Integrations set their own service name regardless of what is configured in
the tracer. This commit updates non-client integrations to pick up the
tracer's service name if one has been configured with either the DD_SERVICE
environment variable, or the WithService StartOption. They fall back to the
previous default service name for the integration if a service name has no
been set, or if it has been set with WithServiceName, for
backwards-compatibility. WithServiceName has been deprecated, but retains
its original behavior.

Non-client integrations include things like http servers and frameworks,
grpc servers, and queue consumers.

Integrations can still be individually configured with their own service
names which will override the one configured in the tracer.

In order to do this, the tracer exposes its service name through the
internal/globalconfig package, when set with DD_SERVICE or WithService
  • Loading branch information
knusbaum authored Mar 27, 2020
1 parent 6a84ea7 commit fa73cfc
Show file tree
Hide file tree
Showing 15 changed files with 136 additions and 31 deletions.
16 changes: 12 additions & 4 deletions contrib/Shopify/sarama/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,22 @@ package sarama

import (
"math"

"gopkg.in/DataDog/dd-trace-go.v1/internal/globalconfig"
)

type config struct {
serviceName string
analyticsRate float64
consumerServiceName string
producerServiceName string
analyticsRate float64
}

func defaults(cfg *config) {
cfg.serviceName = "kafka"
cfg.producerServiceName = "kafka"
cfg.consumerServiceName = "kafka"
if svc := globalconfig.ServiceName(); svc != "" {
cfg.consumerServiceName = svc
}
// cfg.analyticsRate = globalconfig.AnalyticsRate()
cfg.analyticsRate = math.NaN()
}
Expand All @@ -26,7 +33,8 @@ type Option func(cfg *config)
// WithServiceName sets the given service name for the intercepted client.
func WithServiceName(name string) Option {
return func(cfg *config) {
cfg.serviceName = name
cfg.consumerServiceName = name
cfg.producerServiceName = name
}
}

Expand Down
4 changes: 2 additions & 2 deletions contrib/Shopify/sarama/sarama.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func WrapPartitionConsumer(pc sarama.PartitionConsumer, opts ...Option) sarama.P
for msg := range msgs {
// create the next span from the message
opts := []tracer.StartSpanOption{
tracer.ServiceName(cfg.serviceName),
tracer.ServiceName(cfg.consumerServiceName),
tracer.ResourceName("Consume Topic " + msg.Topic),
tracer.SpanType(ext.SpanTypeMessageConsumer),
tracer.Tag("partition", msg.Partition),
Expand Down Expand Up @@ -246,7 +246,7 @@ func WrapAsyncProducer(saramaConfig *sarama.Config, p sarama.AsyncProducer, opts
func startProducerSpan(cfg *config, version sarama.KafkaVersion, msg *sarama.ProducerMessage) ddtrace.Span {
carrier := NewProducerMessageCarrier(msg)
opts := []tracer.StartSpanOption{
tracer.ServiceName(cfg.serviceName),
tracer.ServiceName(cfg.producerServiceName),
tracer.ResourceName("Produce Topic " + msg.Topic),
tracer.SpanType(ext.SpanTypeMessageProducer),
}
Expand Down
4 changes: 2 additions & 2 deletions contrib/confluentinc/confluent-kafka-go/kafka/kafka.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func (c *Consumer) traceEventsChannel(in chan kafka.Event) chan kafka.Event {

func (c *Consumer) startSpan(msg *kafka.Message) ddtrace.Span {
opts := []tracer.StartSpanOption{
tracer.ServiceName(c.cfg.serviceName),
tracer.ServiceName(c.cfg.consumerServiceName),
tracer.ResourceName("Consume Topic " + *msg.TopicPartition.Topic),
tracer.SpanType(ext.SpanTypeMessageConsumer),
tracer.Tag("partition", msg.TopicPartition.Partition),
Expand Down Expand Up @@ -179,7 +179,7 @@ func (p *Producer) traceProduceChannel(out chan *kafka.Message) chan *kafka.Mess

func (p *Producer) startSpan(msg *kafka.Message) ddtrace.Span {
opts := []tracer.StartSpanOption{
tracer.ServiceName(p.cfg.serviceName),
tracer.ServiceName(p.cfg.producerServiceName),
tracer.ResourceName("Produce Topic " + *msg.TopicPartition.Topic),
tracer.SpanType(ext.SpanTypeMessageProducer),
tracer.Tag("partition", msg.TopicPartition.Partition),
Expand Down
20 changes: 14 additions & 6 deletions contrib/confluentinc/confluent-kafka-go/kafka/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,31 @@ package kafka
import (
"context"
"math"

"gopkg.in/DataDog/dd-trace-go.v1/internal/globalconfig"
)

type config struct {
ctx context.Context
serviceName string
analyticsRate float64
ctx context.Context
consumerServiceName string
producerServiceName string
analyticsRate float64
}

// An Option customizes the config.
type Option func(cfg *config)

func newConfig(opts ...Option) *config {
cfg := &config{
serviceName: "kafka",
ctx: context.Background(),
ctx: context.Background(),
consumerServiceName: "kafka",
producerServiceName: "kafka",
// analyticsRate: globalconfig.AnalyticsRate(),
analyticsRate: math.NaN(),
}
if svc := globalconfig.ServiceName(); svc != "" {
cfg.consumerServiceName = svc
}
for _, opt := range opts {
opt(cfg)
}
Expand All @@ -42,7 +49,8 @@ func WithContext(ctx context.Context) Option {
// WithServiceName sets the config service name to serviceName.
func WithServiceName(serviceName string) Option {
return func(cfg *config) {
cfg.serviceName = serviceName
cfg.consumerServiceName = serviceName
cfg.producerServiceName = serviceName
}
}

Expand Down
3 changes: 3 additions & 0 deletions contrib/go-chi/chi/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ type Option func(*config)

func defaults(cfg *config) {
cfg.serviceName = "chi.router"
if svc := globalconfig.ServiceName(); svc != "" {
cfg.serviceName = svc
}
cfg.analyticsRate = globalconfig.AnalyticsRate()
}

Expand Down
4 changes: 4 additions & 0 deletions contrib/google.golang.org/grpc.v12/grpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace"
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/ext"
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer"
"gopkg.in/DataDog/dd-trace-go.v1/internal/globalconfig"

context "golang.org/x/net/context"
"google.golang.org/grpc"
Expand All @@ -32,6 +33,9 @@ func UnaryServerInterceptor(opts ...InterceptorOption) grpc.UnaryServerIntercept
}
if cfg.serviceName == "" {
cfg.serviceName = "grpc.server"
if svc := globalconfig.ServiceName(); svc != "" {
cfg.serviceName = svc
}
}
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
span, ctx := startSpanFromContext(ctx, info.FullMethod, cfg.serviceName, cfg.analyticsRate)
Expand Down
7 changes: 6 additions & 1 deletion contrib/google.golang.org/grpc/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ package grpc
import (
"math"

"gopkg.in/DataDog/dd-trace-go.v1/internal/globalconfig"

"google.golang.org/grpc/codes"
)

Expand All @@ -27,7 +29,10 @@ type config struct {

func (cfg *config) serverServiceName() string {
if cfg.serviceName == "" {
return "grpc.server"
cfg.serviceName = "grpc.server"
if svc := globalconfig.ServiceName(); svc != "" {
cfg.serviceName = svc
}
}
return cfg.serviceName
}
Expand Down
3 changes: 3 additions & 0 deletions contrib/gorilla/mux/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ type RouterOption func(*routerConfig)
func defaults(cfg *routerConfig) {
cfg.analyticsRate = globalconfig.AnalyticsRate()
cfg.serviceName = "mux.router"
if svc := globalconfig.ServiceName(); svc != "" {
cfg.serviceName = svc
}
cfg.resourceNamer = defaultResourceNamer
}

Expand Down
5 changes: 5 additions & 0 deletions contrib/graph-gophers/graphql-go/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ package graphql

import (
"math"

"gopkg.in/DataDog/dd-trace-go.v1/internal/globalconfig"
)

type config struct {
Expand All @@ -19,6 +21,9 @@ type Option func(*config)

func defaults(cfg *config) {
cfg.serviceName = "graphql.server"
if svc := globalconfig.ServiceName(); svc != "" {
cfg.serviceName = svc
}
// cfg.analyticsRate = globalconfig.AnalyticsRate()
cfg.analyticsRate = math.NaN()
}
Expand Down
3 changes: 3 additions & 0 deletions contrib/julienschmidt/httprouter/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ type RouterOption func(*routerConfig)
func defaults(cfg *routerConfig) {
cfg.analyticsRate = globalconfig.AnalyticsRate()
cfg.serviceName = "http.router"
if svc := globalconfig.ServiceName(); svc != "" {
cfg.serviceName = svc
}
}

// WithServiceName sets the given service name for the returned router.
Expand Down
5 changes: 5 additions & 0 deletions contrib/labstack/echo/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ package echo

import (
"math"

"gopkg.in/DataDog/dd-trace-go.v1/internal/globalconfig"
)

type config struct {
Expand All @@ -19,6 +21,9 @@ type Option func(*config)

func defaults(cfg *config) {
cfg.serviceName = "echo"
if svc := globalconfig.ServiceName(); svc != "" {
cfg.serviceName = svc
}
cfg.analyticsRate = math.NaN()
}

Expand Down
3 changes: 3 additions & 0 deletions contrib/net/http/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ type Option func(*config)
func defaults(cfg *config) {
cfg.analyticsRate = globalconfig.AnalyticsRate()
cfg.serviceName = "http.router"
if svc := globalconfig.ServiceName(); svc != "" {
cfg.serviceName = svc
}
cfg.spanOpts = []ddtrace.StartSpanOption{tracer.Measured()}
if !math.IsNaN(cfg.analyticsRate) {
cfg.spanOpts = append(cfg.spanOpts, tracer.Tag(ext.EventSampleRate, cfg.analyticsRate))
Expand Down
19 changes: 15 additions & 4 deletions ddtrace/tracer/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ func defaults(c *config) {
}
if v := os.Getenv("DD_SERVICE"); v != "" {
c.serviceName = v
globalconfig.SetServiceName(v)
} else {
c.serviceName = filepath.Base(os.Args[0])
}
Expand Down Expand Up @@ -186,16 +187,26 @@ func WithPropagator(p Propagator) StartOption {
}
}

// WithServiceName sets the default service name to be used with the tracer. It is
// deprecated in favour of WithService and will be removed in the next major version.
// WithServiceName is deprecated. Please use WithService.
// If you are using an older version and you are upgrading from WithServiceName
// to WithService, please note that WithService will determine the service name of
// server and framework integrations.
func WithServiceName(name string) StartOption {
return WithService(name)
return func(c *config) {
c.serviceName = name
if globalconfig.ServiceName() != "" {
log.Warn("ddtrace/tracer: deprecated config WithServiceName should not be used " +
"with `WithService` or `DD_SERVICE`; integration service name will not be set.")
}
globalconfig.SetServiceName("")
}
}

// WithService sets the default service name to be used with the tracer.
// WithService sets the default service name for the program.
func WithService(name string) StartOption {
return func(c *config) {
c.serviceName = name
globalconfig.SetServiceName(c.serviceName)
}
}

Expand Down
56 changes: 44 additions & 12 deletions ddtrace/tracer/option_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,32 +114,20 @@ func TestTracerOptionsDefaults(t *testing.T) {
assert := assert.New(t)
tracer := newTracer(
WithSampler(NewRateSampler(0.5)),
WithServiceName("api-intake"),
WithAgentAddr("ddagent.consul.local:58126"),
WithGlobalTag("k", "v"),
WithDebugMode(true),
WithEnv("testEnv"),
)
c := tracer.config
assert.Equal(float64(0.5), c.sampler.(RateSampler).Rate())
assert.Equal("api-intake", c.serviceName)
assert.Equal("ddagent.consul.local:58126", c.agentAddr)
assert.NotNil(c.globalTags)
assert.Equal("v", c.globalTags["k"])
assert.Equal("testEnv", c.globalTags[ext.Environment])
assert.True(c.debug)
})

t.Run("env-service", func(t *testing.T) {
os.Setenv("DD_SERVICE", "TEST_SERVICE")
defer os.Unsetenv("DD_SERVICE")

assert := assert.New(t)
var c config
defaults(&c)
assert.Equal("TEST_SERVICE", c.serviceName)
})

t.Run("env-tags", func(t *testing.T) {
os.Setenv("DD_TAGS", "env:test, aKey:aVal,bKey:bVal, cKey:")
defer os.Unsetenv("DD_TAGS")
Expand All @@ -158,3 +146,47 @@ func TestTracerOptionsDefaults(t *testing.T) {
assert.Equal(nil, dVal)
})
}

func TestServiceName(t *testing.T) {
t.Run("WithServiceName", func(t *testing.T) {
assert := assert.New(t)
tracer := newTracer(
WithServiceName("api-intake"),
)

assert.Equal("api-intake", tracer.config.serviceName)
assert.Equal("", globalconfig.ServiceName())
})

t.Run("WithService", func(t *testing.T) {
assert := assert.New(t)
tracer := newTracer(
WithService("api-intake"),
)
assert.Equal("api-intake", tracer.config.serviceName)
assert.Equal("api-intake", globalconfig.ServiceName())
})

t.Run("env", func(t *testing.T) {
os.Setenv("DD_SERVICE", "api-intake")
defer os.Unsetenv("DD_SERVICE")
assert := assert.New(t)
tracer := newTracer()

assert.Equal("api-intake", tracer.config.serviceName)
assert.Equal("api-intake", globalconfig.ServiceName())
})

t.Run("combo", func(t *testing.T) {
os.Setenv("DD_SERVICE", "api-intake")
defer os.Unsetenv("DD_SERVICE")
assert := assert.New(t)

tracer := newTracer(
WithServiceName("api-intake"),
)

assert.Equal("api-intake", tracer.config.serviceName)
assert.Equal("", globalconfig.ServiceName())
})
}
15 changes: 15 additions & 0 deletions internal/globalconfig/globalconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ var cfg = &config{
type config struct {
mu sync.RWMutex
analyticsRate float64
serviceName string
}

// AnalyticsRate returns the sampling rate at which events should be marked. It uses
Expand All @@ -36,3 +37,17 @@ func SetAnalyticsRate(rate float64) {
cfg.analyticsRate = rate
cfg.mu.Unlock()
}

// ServiceName returns the default service name used by non-client integrations such as servers and frameworks.
func ServiceName() string {
cfg.mu.RLock()
defer cfg.mu.RUnlock()
return cfg.serviceName
}

// SetServiceName sets the global service name set for this application.
func SetServiceName(name string) {
cfg.mu.RLock()
defer cfg.mu.RUnlock()
cfg.serviceName = name
}

0 comments on commit fa73cfc

Please sign in to comment.