diff --git a/.gitignore b/.gitignore index 43c69e21ff..a2804c6e1a 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,4 @@ contrib_coverage*.txt gotestsum-report*.xml /internal/apps/unit-of-work/unit-of-work tools/v2check/_stage/v2playground/* +static-analysis.datadog.yml diff --git a/contrib/IBM/sarama/option.go b/contrib/IBM/sarama/option.go index c52dfd709e..9875cc7734 100644 --- a/contrib/IBM/sarama/option.go +++ b/contrib/IBM/sarama/option.go @@ -8,12 +8,9 @@ package sarama import ( "math" - "github.com/DataDog/dd-trace-go/v2/internal" - "github.com/DataDog/dd-trace-go/v2/internal/namingschema" + "github.com/DataDog/dd-trace-go/v2/instrumentation" ) -const defaultServiceName = "kafka" - type config struct { consumerServiceName string producerServiceName string @@ -23,18 +20,14 @@ type config struct { } func defaults(cfg *config) { - cfg.consumerServiceName = namingschema.ServiceName(defaultServiceName) - cfg.producerServiceName = namingschema.ServiceNameOverrideV0(defaultServiceName, defaultServiceName) + cfg.consumerServiceName = instr.ServiceName(instrumentation.ComponentConsumer, nil) + cfg.producerServiceName = instr.ServiceName(instrumentation.ComponentProducer, nil) - cfg.consumerSpanName = namingschema.OpName(namingschema.KafkaInbound) - cfg.producerSpanName = namingschema.OpName(namingschema.KafkaOutbound) + cfg.consumerSpanName = instr.OperationName(instrumentation.ComponentConsumer, nil) + cfg.producerSpanName = instr.OperationName(instrumentation.ComponentProducer, nil) // cfg.analyticsRate = globalconfig.AnalyticsRate() - if internal.BoolEnv("DD_TRACE_SARAMA_ANALYTICS_ENABLED", false) { - cfg.analyticsRate = 1.0 - } else { - cfg.analyticsRate = math.NaN() - } + cfg.analyticsRate = instr.AnalyticsRate(false) } // Option describes options for the Sarama integration. diff --git a/contrib/IBM/sarama/sarama.go b/contrib/IBM/sarama/sarama.go index d7d5594d70..d6ed2aae26 100644 --- a/contrib/IBM/sarama/sarama.go +++ b/contrib/IBM/sarama/sarama.go @@ -12,17 +12,15 @@ import ( "github.com/DataDog/dd-trace-go/v2/ddtrace" "github.com/DataDog/dd-trace-go/v2/ddtrace/ext" "github.com/DataDog/dd-trace-go/v2/ddtrace/tracer" - "github.com/DataDog/dd-trace-go/v2/internal/log" - "github.com/DataDog/dd-trace-go/v2/internal/telemetry" + "github.com/DataDog/dd-trace-go/v2/instrumentation" "github.com/IBM/sarama" ) -const componentName = "IBM/sarama" +var instr *instrumentation.Instrumentation func init() { - telemetry.LoadIntegration(componentName) - tracer.MarkIntegrationImported("github.com/IBM/sarama") + instr = instrumentation.Load(instrumentation.PackageIBMSarama) } type partitionConsumer struct { @@ -44,7 +42,7 @@ func WrapPartitionConsumer(pc sarama.PartitionConsumer, opts ...Option) sarama.P for _, opt := range opts { opt.apply(cfg) } - log.Debug("contrib/IBM/sarama: Wrapping Partition Consumer: %#v", cfg) + instr.Logger().Debug("contrib/IBM/sarama: Wrapping Partition Consumer: %#v", cfg) wrapped := &partitionConsumer{ PartitionConsumer: pc, messages: make(chan *sarama.ConsumerMessage), @@ -60,7 +58,7 @@ func WrapPartitionConsumer(pc sarama.PartitionConsumer, opts ...Option) sarama.P tracer.SpanType(ext.SpanTypeMessageConsumer), tracer.Tag(ext.MessagingKafkaPartition, msg.Partition), tracer.Tag("offset", msg.Offset), - tracer.Tag(ext.Component, componentName), + tracer.Tag(ext.Component, instrumentation.PackageIBMSarama), tracer.Tag(ext.SpanKind, ext.SpanKindConsumer), tracer.Tag(ext.MessagingSystem, ext.MessagingSystemKafka), tracer.Measured(), @@ -155,7 +153,7 @@ func WrapSyncProducer(saramaConfig *sarama.Config, producer sarama.SyncProducer, for _, opt := range opts { opt.apply(cfg) } - log.Debug("contrib/IBM/sarama: Wrapping Sync Producer: %#v", cfg) + instr.Logger().Debug("contrib/IBM/sarama: Wrapping Sync Producer: %#v", cfg) if saramaConfig == nil { saramaConfig = sarama.NewConfig() } @@ -199,12 +197,12 @@ func WrapAsyncProducer(saramaConfig *sarama.Config, p sarama.AsyncProducer, opts for _, opt := range opts { opt.apply(cfg) } - log.Debug("contrib/IBM/sarama: Wrapping Async Producer: %#v", cfg) + instr.Logger().Debug("contrib/IBM/sarama: Wrapping Async Producer: %#v", cfg) if saramaConfig == nil { saramaConfig = sarama.NewConfig() saramaConfig.Version = sarama.V0_11_0_0 } else if !saramaConfig.Version.IsAtLeast(sarama.V0_11_0_0) { - log.Error("Tracing Sarama async producer requires at least sarama.V0_11_0_0 version") + instr.Logger().Error("Tracing Sarama async producer requires at least sarama.V0_11_0_0 version") } wrapped := &asyncProducer{ AsyncProducer: p, @@ -269,7 +267,7 @@ func startProducerSpan(cfg *config, version sarama.KafkaVersion, msg *sarama.Pro tracer.ServiceName(cfg.producerServiceName), tracer.ResourceName("Produce Topic " + msg.Topic), tracer.SpanType(ext.SpanTypeMessageProducer), - tracer.Tag(ext.Component, componentName), + tracer.Tag(ext.Component, instrumentation.PackageIBMSarama), tracer.Tag(ext.SpanKind, ext.SpanKindProducer), tracer.Tag(ext.MessagingSystem, ext.MessagingSystemKafka), } diff --git a/contrib/IBM/sarama/sarama_test.go b/contrib/IBM/sarama/sarama_test.go index e33cc73a41..fa02cbd32b 100644 --- a/contrib/IBM/sarama/sarama_test.go +++ b/contrib/IBM/sarama/sarama_test.go @@ -13,76 +13,11 @@ import ( "github.com/DataDog/dd-trace-go/v2/ddtrace/ext" "github.com/DataDog/dd-trace-go/v2/ddtrace/mocktracer" "github.com/DataDog/dd-trace-go/v2/ddtrace/tracer" - "github.com/DataDog/dd-trace-go/v2/internal/contrib/namingschematest" "github.com/IBM/sarama" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) -func genTestSpans(t *testing.T, serviceOverride string) []*mocktracer.Span { - var opts []Option - if serviceOverride != "" { - opts = append(opts, WithService(serviceOverride)) - } - mt := mocktracer.Start() - defer mt.Stop() - - broker := sarama.NewMockBroker(t, 1) - defer broker.Close() - - broker.SetHandlerByMap(map[string]sarama.MockResponse{ - "MetadataRequest": sarama.NewMockMetadataResponse(t). - SetBroker(broker.Addr(), broker.BrokerID()). - SetLeader("test-topic", 0, broker.BrokerID()), - "OffsetRequest": sarama.NewMockOffsetResponse(t). - SetOffset("test-topic", 0, sarama.OffsetOldest, 0). - SetOffset("test-topic", 0, sarama.OffsetNewest, 1), - "FetchRequest": sarama.NewMockFetchResponse(t, 1). - SetMessage("test-topic", 0, 0, sarama.StringEncoder("hello")), - "ProduceRequest": sarama.NewMockProduceResponse(t). - SetError("test-topic", 0, sarama.ErrNoError), - }) - cfg := sarama.NewConfig() - cfg.Version = sarama.MinVersion - cfg.Producer.Return.Successes = true - cfg.Producer.Flush.Messages = 1 - - producer, err := sarama.NewSyncProducer([]string{broker.Addr()}, cfg) - require.NoError(t, err) - producer = WrapSyncProducer(cfg, producer, opts...) - - c, err := sarama.NewConsumer([]string{broker.Addr()}, cfg) - require.NoError(t, err) - defer func(c sarama.Consumer) { - err := c.Close() - require.NoError(t, err) - }(c) - c = WrapConsumer(c, opts...) - - msg1 := &sarama.ProducerMessage{ - Topic: "test-topic", - Value: sarama.StringEncoder("test 1"), - Metadata: "test", - } - _, _, err = producer.SendMessage(msg1) - require.NoError(t, err) - - pc, err := c.ConsumePartition("test-topic", 0, 0) - if err != nil { - t.Fatal(err) - } - _ = <-pc.Messages() - err = pc.Close() - require.NoError(t, err) - // wait for the channel to be closed - <-pc.Messages() - - spans := mt.FinishedSpans() - require.Len(t, spans, 2) - return spans -} - func TestConsumer(t *testing.T) { mt := mocktracer.Start() defer mt.Stop() @@ -356,10 +291,6 @@ func TestAsyncProducer(t *testing.T) { }) } -func TestNamingSchema(t *testing.T) { - namingschematest.NewKafkaTest(genTestSpans)(t) -} - func newMockBroker(t *testing.T) *sarama.MockBroker { broker := sarama.NewMockBroker(t, 1) diff --git a/contrib/gorilla/mux/mux.go b/contrib/gorilla/mux/mux.go index ce3811a2c3..425b4cc4c1 100644 --- a/contrib/gorilla/mux/mux.go +++ b/contrib/gorilla/mux/mux.go @@ -12,19 +12,17 @@ import ( httptrace "github.com/DataDog/dd-trace-go/contrib/net/http/v2" "github.com/DataDog/dd-trace-go/v2/ddtrace/ext" "github.com/DataDog/dd-trace-go/v2/ddtrace/tracer" + "github.com/DataDog/dd-trace-go/v2/instrumentation" + httptraceinternal "github.com/DataDog/dd-trace-go/v2/instrumentation/httptrace" "github.com/DataDog/dd-trace-go/v2/instrumentation/options" - httptraceinternal "github.com/DataDog/dd-trace-go/v2/internal/contrib/httptrace" - "github.com/DataDog/dd-trace-go/v2/internal/log" - "github.com/DataDog/dd-trace-go/v2/internal/telemetry" "github.com/gorilla/mux" ) -const componentName = "gorilla/mux" +var instr *instrumentation.Instrumentation func init() { - telemetry.LoadIntegration(componentName) - tracer.MarkIntegrationImported("github.com/gorilla/mux") + instr = instrumentation.Load(instrumentation.PackageGorillaMux) } // Router registers routes to be matched and dispatches a handler. @@ -124,9 +122,9 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { // requests and responses served by the router. func WrapRouter(router *mux.Router, opts ...RouterOption) *Router { cfg := newConfig(opts) - cfg.spanOpts = append(cfg.spanOpts, tracer.Tag(ext.Component, componentName)) + cfg.spanOpts = append(cfg.spanOpts, tracer.Tag(ext.Component, instrumentation.PackageGorillaMux)) cfg.spanOpts = append(cfg.spanOpts, tracer.Tag(ext.SpanKind, ext.SpanKindServer)) - log.Debug("contrib/gorilla/mux: Configuring Router: %#v", cfg) + instr.Logger().Debug("contrib/gorilla/mux: Configuring Router: %#v", cfg) return &Router{ Router: router, config: cfg, diff --git a/contrib/gorilla/mux/mux_test.go b/contrib/gorilla/mux/mux_test.go index 9b6a177331..592ddcdfce 100644 --- a/contrib/gorilla/mux/mux_test.go +++ b/contrib/gorilla/mux/mux_test.go @@ -18,10 +18,8 @@ import ( "github.com/DataDog/dd-trace-go/v2/ddtrace/ext" "github.com/DataDog/dd-trace-go/v2/ddtrace/mocktracer" "github.com/DataDog/dd-trace-go/v2/ddtrace/tracer" - "github.com/DataDog/dd-trace-go/v2/internal/appsec" - "github.com/DataDog/dd-trace-go/v2/internal/contrib/namingschematest" - "github.com/DataDog/dd-trace-go/v2/internal/globalconfig" - "github.com/DataDog/dd-trace-go/v2/internal/normalizer" + "github.com/DataDog/dd-trace-go/v2/instrumentation" + "github.com/DataDog/dd-trace-go/v2/instrumentation/testutils" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -155,64 +153,58 @@ func TestWithHeaderTags(t *testing.T) { assert := assert.New(t) assert.Equal(len(spans), 1) s := spans[0] - for _, arg := range htArgs { - _, tag := normalizer.HeaderTag(arg) + instrumentation.NewHeaderTags(htArgs).Iter(func(_ string, tag string) { assert.NotContains(s.Tags(), tag) - } + }) }) t.Run("integration", func(t *testing.T) { mt := mocktracer.Start() defer mt.Stop() htArgs := []string{"h!e@a-d.e*r", "2header:tag"} - r := setupReq(WithHeaderTags(htArgs)) + _ = setupReq(WithHeaderTags(htArgs)) spans := mt.FinishedSpans() assert := assert.New(t) assert.Equal(len(spans), 1) s := spans[0] - for _, arg := range htArgs { - header, tag := normalizer.HeaderTag(arg) - assert.Equal(strings.Join(r.Header.Values(header), ","), s.Tags()[tag]) - } + assert.Equal("val,val2", s.Tags()["http.request.headers.h_e_a-d_e_r"]) + assert.Equal("2val", s.Tags()["tag"]) assert.NotContains(s.Tags(), "http.headers.x-datadog-header") }) t.Run("global", func(t *testing.T) { mt := mocktracer.Start() defer mt.Stop() - header, tag := normalizer.HeaderTag("3header") - globalconfig.SetHeaderTag(header, tag) + testutils.SetGlobalHeaderTags(t, "3header") - r := setupReq() + _ = setupReq() spans := mt.FinishedSpans() assert := assert.New(t) assert.Equal(len(spans), 1) s := spans[0] - assert.Equal(strings.Join(r.Header.Values(header), ","), s.Tags()[tag]) + assert.Equal("3val", s.Tags()["http.request.headers.3header"]) + assert.NotContains(s.Tags(), "http.request.headers.other") assert.NotContains(s.Tags(), "http.headers.x-datadog-header") }) t.Run("override", func(t *testing.T) { mt := mocktracer.Start() defer mt.Stop() - globalH, globalT := normalizer.HeaderTag("3header") - globalconfig.SetHeaderTag(globalH, globalT) + testutils.SetGlobalHeaderTags(t, "3header") htArgs := []string{"h!e@a-d.e*r", "2header:tag"} - r := setupReq(WithHeaderTags(htArgs)) + _ = setupReq(WithHeaderTags(htArgs)) spans := mt.FinishedSpans() assert := assert.New(t) assert.Equal(len(spans), 1) s := spans[0] - for _, arg := range htArgs { - header, tag := normalizer.HeaderTag(arg) - assert.Equal(strings.Join(r.Header.Values(header), ","), s.Tags()[tag]) - } + assert.Equal("val,val2", s.Tags()["http.request.headers.h_e_a-d_e_r"]) + assert.Equal("2val", s.Tags()["tag"]) assert.NotContains(s.Tags(), "http.headers.x-datadog-header") - assert.NotContains(s.Tags(), globalT) + assert.NotContains(s.Tags(), "http.request.headers.3header") }) } @@ -296,9 +288,7 @@ func TestAnalyticsSettings(t *testing.T) { mt := mocktracer.Start() defer mt.Stop() - rate := globalconfig.AnalyticsRate() - defer globalconfig.SetAnalyticsRate(rate) - globalconfig.SetAnalyticsRate(0.4) + testutils.SetGlobalAnalyticsRate(t, 0.4) assertRate(t, mt, 0.4) }) @@ -321,9 +311,7 @@ func TestAnalyticsSettings(t *testing.T) { mt := mocktracer.Start() defer mt.Stop() - rate := globalconfig.AnalyticsRate() - defer globalconfig.SetAnalyticsRate(rate) - globalconfig.SetAnalyticsRate(0.4) + testutils.SetGlobalAnalyticsRate(t, 0.4) assertRate(t, mt, 0.23, WithAnalyticsRate(0.23)) }) @@ -407,10 +395,9 @@ func okHandler() http.Handler { } func TestAppSec(t *testing.T) { - appsec.Start() - defer appsec.Stop() + testutils.StartAppSec(t) - if !appsec.Enabled() { + if !instr.AppSecEnabled() { t.Skip("appsec disabled") } @@ -535,23 +522,3 @@ func TestAppSec(t *testing.T) { require.True(t, strings.Contains(event.(string), "crs-933-130")) }) } - -func TestNamingSchema(t *testing.T) { - genSpans := namingschematest.GenSpansFn(func(t *testing.T, serviceOverride string) []*mocktracer.Span { - var opts []RouterOption - if serviceOverride != "" { - opts = append(opts, WithService(serviceOverride)) - } - mt := mocktracer.Start() - defer mt.Stop() - - mux := NewRouter(opts...) - mux.Handle("/200", okHandler()) - req := httptest.NewRequest("GET", "/200", nil) - w := httptest.NewRecorder() - mux.ServeHTTP(w, req) - - return mt.FinishedSpans() - }) - namingschematest.NewHTTPServerTest(genSpans, "mux.router")(t) -} diff --git a/contrib/gorilla/mux/option.go b/contrib/gorilla/mux/option.go index 1c196489dc..d9d20bd09a 100644 --- a/contrib/gorilla/mux/option.go +++ b/contrib/gorilla/mux/option.go @@ -11,10 +11,7 @@ import ( "github.com/DataDog/dd-trace-go/v2/ddtrace/ext" "github.com/DataDog/dd-trace-go/v2/ddtrace/tracer" - "github.com/DataDog/dd-trace-go/v2/internal" - "github.com/DataDog/dd-trace-go/v2/internal/globalconfig" - "github.com/DataDog/dd-trace-go/v2/internal/namingschema" - "github.com/DataDog/dd-trace-go/v2/internal/normalizer" + "github.com/DataDog/dd-trace-go/v2/instrumentation" ) const defaultServiceName = "mux.router" @@ -27,7 +24,7 @@ type routerConfig struct { resourceNamer func(*Router, *http.Request) string ignoreRequest func(*http.Request) bool queryParams bool - headerTags *internal.LockMap + headerTags instrumentation.HeaderTags } // RouterOption describes options for the Gorilla mux integration. @@ -55,13 +52,9 @@ func newConfig(opts []RouterOption) *routerConfig { } func defaults(cfg *routerConfig) { - if internal.BoolEnv("DD_TRACE_MUX_ANALYTICS_ENABLED", false) { - cfg.analyticsRate = 1.0 - } else { - cfg.analyticsRate = globalconfig.AnalyticsRate() - } - cfg.headerTags = globalconfig.HeaderTagMap() - cfg.serviceName = namingschema.ServiceName(defaultServiceName) + cfg.analyticsRate = instr.AnalyticsRate(true) + cfg.headerTags = instr.HTTPHeadersAsTags() + cfg.serviceName = instr.ServiceName(instrumentation.ComponentServer, nil) cfg.resourceNamer = defaultResourceNamer cfg.ignoreRequest = func(_ *http.Request) bool { return false } } @@ -134,9 +127,8 @@ func WithResourceNamer(namer func(router *Router, req *http.Request) string) Rou // Using this feature can risk exposing sensitive data such as authorization tokens to Datadog. // Special headers can not be sub-selected. E.g., an entire Cookie header would be transmitted, without the ability to choose specific Cookies. func WithHeaderTags(headers []string) RouterOptionFn { - headerTagsMap := normalizer.HeaderTagSlice(headers) return func(cfg *routerConfig) { - cfg.headerTags = internal.NewLockMap(headerTagsMap) + cfg.headerTags = instrumentation.NewHeaderTags(headers) } } diff --git a/contrib/gorilla/mux/telemetry_test.go b/contrib/gorilla/mux/telemetry_test.go deleted file mode 100644 index ac6727046c..0000000000 --- a/contrib/gorilla/mux/telemetry_test.go +++ /dev/null @@ -1,28 +0,0 @@ -// Unless explicitly stated otherwise all files in this repository are licensed -// under the Apache License Version 2.0. -// This product includes software developed at Datadog (https://www.datadoghq.com/). -// Copyright 2016 Datadog, Inc. - -package mux - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/DataDog/dd-trace-go/v2/internal/telemetry" -) - -// TestIntegrationInfo verifies that an integration leveraging instrumentation telemetry -// sends the correct data to the telemetry client. -func TestIntegrationInfo(t *testing.T) { - // mux.NewRouter() uses the net/http and gorilla/mux integration - NewRouter() - integrations := telemetry.Integrations() - require.Len(t, integrations, 2) - assert.Equal(t, integrations[0].Name, "net/http") - assert.True(t, integrations[0].Enabled) - assert.Equal(t, integrations[1].Name, "gorilla/mux") - assert.True(t, integrations[1].Enabled) -} diff --git a/contrib/gorm.io/gorm.v1/gorm.go b/contrib/gorm.io/gorm.v1/gorm.go index ed8ebd4df2..6c3270991f 100644 --- a/contrib/gorm.io/gorm.v1/gorm.go +++ b/contrib/gorm.io/gorm.v1/gorm.go @@ -13,17 +13,15 @@ import ( "github.com/DataDog/dd-trace-go/v2/ddtrace/ext" "github.com/DataDog/dd-trace-go/v2/ddtrace/tracer" - "github.com/DataDog/dd-trace-go/v2/internal/log" - "github.com/DataDog/dd-trace-go/v2/internal/telemetry" + "github.com/DataDog/dd-trace-go/v2/instrumentation" "gorm.io/gorm" ) -const componentName = "gorm.io/gorm.v1" +var instr *instrumentation.Instrumentation func init() { - telemetry.LoadIntegration(componentName) - tracer.MarkIntegrationImported(componentName) + instr = instrumentation.Load(instrumentation.PackageGormIOGormV1) } type key string @@ -54,7 +52,7 @@ func withCallbacks(db *gorm.DB, opts ...Option) (*gorm.DB, error) { for _, fn := range opts { fn.apply(cfg) } - log.Debug("Registering Callbacks: %#v", cfg) + instr.Logger().Debug("Registering Callbacks: %#v", cfg) afterFunc := func(operationName string) func(*gorm.DB) { return func(db *gorm.DB) { @@ -136,7 +134,7 @@ func after(db *gorm.DB, operationName string, cfg *config) { tracer.ServiceName(cfg.serviceName), tracer.SpanType(ext.SpanTypeSQL), tracer.ResourceName(db.Statement.SQL.String()), - tracer.Tag(ext.Component, componentName), + tracer.Tag(ext.Component, instrumentation.PackageGormIOGormV1), } if !math.IsNaN(cfg.analyticsRate) { opts = append(opts, tracer.Tag(ext.EventSampleRate, cfg.analyticsRate)) diff --git a/contrib/gorm.io/gorm.v1/gorm_test.go b/contrib/gorm.io/gorm.v1/gorm_test.go index aef65fc604..d9aeb84b64 100644 --- a/contrib/gorm.io/gorm.v1/gorm_test.go +++ b/contrib/gorm.io/gorm.v1/gorm_test.go @@ -16,8 +16,8 @@ import ( "github.com/DataDog/dd-trace-go/v2/ddtrace/ext" "github.com/DataDog/dd-trace-go/v2/ddtrace/mocktracer" "github.com/DataDog/dd-trace-go/v2/ddtrace/tracer" + "github.com/DataDog/dd-trace-go/v2/instrumentation/testutils" sqltest "github.com/DataDog/dd-trace-go/v2/instrumentation/testutils/sql" - "github.com/DataDog/dd-trace-go/v2/internal/globalconfig" "github.com/go-sql-driver/mysql" "github.com/jackc/pgx/v5/stdlib" @@ -379,9 +379,7 @@ func TestAnalyticsSettings(t *testing.T) { mt := mocktracer.Start() defer mt.Stop() - rate := globalconfig.AnalyticsRate() - defer globalconfig.SetAnalyticsRate(rate) - globalconfig.SetAnalyticsRate(0.4) + testutils.SetGlobalAnalyticsRate(t, 0.4) assertRate(t, mt, 0.4) }) @@ -404,9 +402,7 @@ func TestAnalyticsSettings(t *testing.T) { mt := mocktracer.Start() defer mt.Stop() - rate := globalconfig.AnalyticsRate() - defer globalconfig.SetAnalyticsRate(rate) - globalconfig.SetAnalyticsRate(0.4) + testutils.SetGlobalAnalyticsRate(t, 0.4) assertRate(t, mt, 0.23, WithAnalyticsRate(0.23)) }) diff --git a/contrib/gorm.io/gorm.v1/option.go b/contrib/gorm.io/gorm.v1/option.go index c8b05e9d23..f8c27376e9 100644 --- a/contrib/gorm.io/gorm.v1/option.go +++ b/contrib/gorm.io/gorm.v1/option.go @@ -8,8 +8,6 @@ package gorm import ( "math" - "github.com/DataDog/dd-trace-go/v2/internal" - "gorm.io/gorm" ) @@ -35,12 +33,7 @@ func (fn OptionFn) apply(cfg *config) { func defaults(cfg *config) { cfg.serviceName = "gorm.db" - // cfg.analyticsRate = globalconfig.AnalyticsRate() - if internal.BoolEnv("DD_TRACE_GORM_ANALYTICS_ENABLED", false) { - cfg.analyticsRate = 1.0 - } else { - cfg.analyticsRate = math.NaN() - } + cfg.analyticsRate = instr.AnalyticsRate(false) cfg.errCheck = func(error) bool { return true } cfg.tagFns = make(map[string]func(db *gorm.DB) interface{}) } diff --git a/contrib/graph-gophers/graphql-go/graphql.go b/contrib/graph-gophers/graphql-go/graphql.go index b553fac10d..b4831dd5be 100644 --- a/contrib/graph-gophers/graphql-go/graphql.go +++ b/contrib/graph-gophers/graphql-go/graphql.go @@ -18,21 +18,19 @@ import ( "github.com/DataDog/dd-trace-go/v2/ddtrace/ext" ddtracer "github.com/DataDog/dd-trace-go/v2/ddtrace/tracer" - "github.com/DataDog/dd-trace-go/v2/internal/appsec/emitter/graphqlsec" - "github.com/DataDog/dd-trace-go/v2/internal/appsec/emitter/graphqlsec/types" - "github.com/DataDog/dd-trace-go/v2/internal/log" - "github.com/DataDog/dd-trace-go/v2/internal/telemetry" + "github.com/DataDog/dd-trace-go/v2/instrumentation" + "github.com/DataDog/dd-trace-go/v2/instrumentation/appsec/emitter/graphqlsec" + "github.com/DataDog/dd-trace-go/v2/instrumentation/appsec/emitter/graphqlsec/types" "github.com/graph-gophers/graphql-go/errors" "github.com/graph-gophers/graphql-go/introspection" "github.com/graph-gophers/graphql-go/trace/tracer" ) -const componentName = "graph-gophers/graphql-go" +var instr *instrumentation.Instrumentation func init() { - telemetry.LoadIntegration(componentName) - ddtracer.MarkIntegrationImported("github.com/graph-gophers/graphql-go") + instr = instrumentation.Load(instrumentation.PackageGraphGophersGraphQLGo) } const ( @@ -57,7 +55,7 @@ func (t *Tracer) TraceQuery(ctx context.Context, queryString, operationName stri ddtracer.ServiceName(t.cfg.serviceName), ddtracer.Tag(tagGraphqlQuery, queryString), ddtracer.Tag(tagGraphqlOperationName, operationName), - ddtracer.Tag(ext.Component, componentName), + ddtracer.Tag(ext.Component, instrumentation.PackageGraphGophersGraphQLGo), ddtracer.Measured(), } if t.cfg.traceVariables { @@ -106,7 +104,7 @@ func (t *Tracer) TraceField(ctx context.Context, _, typeName, fieldName string, ddtracer.ServiceName(t.cfg.serviceName), ddtracer.Tag(tagGraphqlField, fieldName), ddtracer.Tag(tagGraphqlType, typeName), - ddtracer.Tag(ext.Component, componentName), + ddtracer.Tag(ext.Component, instrumentation.PackageGraphGophersGraphQLGo), ddtracer.Measured(), } if t.cfg.traceVariables { @@ -145,7 +143,7 @@ func NewTracer(opts ...Option) tracer.Tracer { for _, opt := range opts { opt.apply(cfg) } - log.Debug("contrib/graph-gophers/graphql-go: Configuring Graphql Tracer: %#v", cfg) + instr.Logger().Debug("contrib/graph-gophers/graphql-go: Configuring Graphql Tracer: %#v", cfg) return &Tracer{ cfg: cfg, } diff --git a/contrib/graph-gophers/graphql-go/graphql_test.go b/contrib/graph-gophers/graphql-go/graphql_test.go index 892d32be8b..ff0fbc809d 100644 --- a/contrib/graph-gophers/graphql-go/graphql_test.go +++ b/contrib/graph-gophers/graphql-go/graphql_test.go @@ -13,14 +13,11 @@ import ( "github.com/DataDog/dd-trace-go/v2/ddtrace/ext" "github.com/DataDog/dd-trace-go/v2/ddtrace/mocktracer" - "github.com/DataDog/dd-trace-go/v2/internal/contrib/namingschematest" - "github.com/DataDog/dd-trace-go/v2/internal/globalconfig" - "github.com/DataDog/dd-trace-go/v2/internal/lists" + "github.com/DataDog/dd-trace-go/v2/instrumentation/testutils" "github.com/graph-gophers/graphql-go" "github.com/graph-gophers/graphql-go/relay" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) type testResolver struct{} @@ -160,9 +157,7 @@ func TestAnalyticsSettings(t *testing.T) { mt := mocktracer.Start() defer mt.Stop() - rate := globalconfig.AnalyticsRate() - defer globalconfig.SetAnalyticsRate(rate) - globalconfig.SetAnalyticsRate(0.4) + testutils.SetGlobalAnalyticsRate(t, 0.4) assertRate(t, mt, 0.4) }) @@ -182,48 +177,8 @@ func TestAnalyticsSettings(t *testing.T) { mt := mocktracer.Start() defer mt.Stop() - rate := globalconfig.AnalyticsRate() - defer globalconfig.SetAnalyticsRate(rate) - globalconfig.SetAnalyticsRate(0.4) + testutils.SetGlobalAnalyticsRate(t, 0.4) assertRate(t, mt, 0.23, WithAnalyticsRate(0.23)) }) } - -func TestNamingSchema(t *testing.T) { - genSpans := namingschematest.GenSpansFn(func(t *testing.T, serviceOverride string) []*mocktracer.Span { - var opts []Option - if serviceOverride != "" { - opts = append(opts, WithService(serviceOverride)) - } - mt := mocktracer.Start() - defer mt.Stop() - - srv := newTestServer(opts...) - defer srv.Close() - resp, err := http.Post(srv.URL, "application/json", strings.NewReader(`{"query": "{ hello }"}`)) - require.NoError(t, err) - defer resp.Body.Close() - - return mt.FinishedSpans() - }) - assertOpV0 := func(t *testing.T, spans []*mocktracer.Span) { - require.Len(t, spans, 2) - assert.Equal(t, "graphql.field", spans[0].OperationName()) - assert.Equal(t, "graphql.request", spans[1].OperationName()) - } - assertOpV1 := func(t *testing.T, spans []*mocktracer.Span) { - require.Len(t, spans, 2) - assert.Equal(t, "graphql.field", spans[0].OperationName()) - assert.Equal(t, "graphql.server.request", spans[1].OperationName()) - } - ddService := namingschematest.TestDDService - serviceOverride := namingschematest.TestServiceOverride - wantServiceNameV0 := namingschematest.ServiceNameAssertions{ - WithDefaults: lists.RepeatString("graphql.server", 2), - WithDDService: lists.RepeatString(ddService, 2), - WithDDServiceAndOverride: lists.RepeatString(serviceOverride, 2), - } - t.Run("ServiceName", namingschematest.NewServiceNameTest(genSpans, wantServiceNameV0)) - t.Run("SpanName", namingschematest.NewSpanNameTest(genSpans, assertOpV0, assertOpV1)) -} diff --git a/contrib/graph-gophers/graphql-go/option.go b/contrib/graph-gophers/graphql-go/option.go index 1c71c13494..e4910600ad 100644 --- a/contrib/graph-gophers/graphql-go/option.go +++ b/contrib/graph-gophers/graphql-go/option.go @@ -8,8 +8,7 @@ package graphql import ( "math" - "github.com/DataDog/dd-trace-go/v2/internal" - "github.com/DataDog/dd-trace-go/v2/internal/namingschema" + "github.com/DataDog/dd-trace-go/v2/instrumentation" ) const defaultServiceName = "graphql.server" @@ -35,14 +34,9 @@ func (fn OptionFn) apply(cfg *config) { } func defaults(cfg *config) { - cfg.serviceName = namingschema.ServiceName(defaultServiceName) - cfg.querySpanName = namingschema.OpName(namingschema.GraphqlServer) - // cfg.analyticsRate = globalconfig.AnalyticsRate() - if internal.BoolEnv("DD_TRACE_GRAPHQL_ANALYTICS_ENABLED", false) { - cfg.analyticsRate = 1.0 - } else { - cfg.analyticsRate = math.NaN() - } + cfg.serviceName = instr.ServiceName(instrumentation.ComponentDefault, nil) + cfg.querySpanName = instr.OperationName(instrumentation.ComponentDefault, nil) + cfg.analyticsRate = instr.AnalyticsRate(false) } // WithService sets the given service name for the client. diff --git a/contrib/graphql-go/graphql/appsec_test.go b/contrib/graphql-go/graphql/appsec_test.go index 3ad014cce3..7327f91a58 100644 --- a/contrib/graphql-go/graphql/appsec_test.go +++ b/contrib/graphql-go/graphql/appsec_test.go @@ -17,7 +17,7 @@ import ( "github.com/stretchr/testify/require" "github.com/DataDog/dd-trace-go/v2/ddtrace/mocktracer" - "github.com/DataDog/dd-trace-go/v2/internal/appsec" + "github.com/DataDog/dd-trace-go/v2/instrumentation/testutils" ) func TestAppSec(t *testing.T) { @@ -263,14 +263,13 @@ func enableAppSec(t *testing.T) func() { require.NoError(t, err) restoreDdAppsecEnabled := setEnv("DD_APPSEC_ENABLED", "1") restoreDdAppsecRules := setEnv("DD_APPSEC_RULES", rulesFile) - appsec.Start() + testutils.StartAppSec(t) restore := func() { - appsec.Stop() restoreDdAppsecEnabled() restoreDdAppsecRules() _ = os.RemoveAll(tmpDir) } - if !appsec.Enabled() { + if !instr.AppSecEnabled() { restore() t.Skip("could not enable appsec: this platform is likely not supported") } diff --git a/contrib/graphql-go/graphql/bench_test.go b/contrib/graphql-go/graphql/bench_test.go index 6d02e2f8d6..98099c0725 100644 --- a/contrib/graphql-go/graphql/bench_test.go +++ b/contrib/graphql-go/graphql/bench_test.go @@ -15,7 +15,7 @@ import ( "github.com/stretchr/testify/require" "github.com/DataDog/dd-trace-go/v2/ddtrace/mocktracer" - "github.com/DataDog/dd-trace-go/v2/internal/appsec" + "github.com/DataDog/dd-trace-go/v2/instrumentation/testutils" ) func BenchmarkGraphQL(b *testing.B) { @@ -250,12 +250,11 @@ func enableAppSecBench(b *testing.B) func() { require.NoError(b, err) b.Setenv("DD_APPSEC_ENABLED", "1") b.Setenv("DD_APPSEC_RULES", rulesFile) - appsec.Start() + testutils.StartAppSecBench(b) restore := func() { - appsec.Stop() _ = os.RemoveAll(tmpDir) } - if !appsec.Enabled() { + if !instr.AppSecEnabled() { restore() b.Skip("could not enable appsec: this platform is likely not supported") } diff --git a/contrib/graphql-go/graphql/graphql.go b/contrib/graphql-go/graphql/graphql.go index 73bd112def..29d6780569 100644 --- a/contrib/graphql-go/graphql/graphql.go +++ b/contrib/graphql-go/graphql/graphql.go @@ -13,9 +13,9 @@ import ( "github.com/DataDog/dd-trace-go/v2/ddtrace/ext" "github.com/DataDog/dd-trace-go/v2/ddtrace/tracer" - "github.com/DataDog/dd-trace-go/v2/internal/appsec/emitter/graphqlsec" - "github.com/DataDog/dd-trace-go/v2/internal/appsec/emitter/graphqlsec/types" - "github.com/DataDog/dd-trace-go/v2/internal/telemetry" + "github.com/DataDog/dd-trace-go/v2/instrumentation" + "github.com/DataDog/dd-trace-go/v2/instrumentation/appsec/emitter/graphqlsec" + "github.com/DataDog/dd-trace-go/v2/instrumentation/appsec/emitter/graphqlsec/types" "github.com/graphql-go/graphql" "github.com/graphql-go/graphql/gqlerrors" @@ -23,16 +23,14 @@ import ( "github.com/hashicorp/go-multierror" ) -const componentName = "graphql-go/graphql" - var ( + instr *instrumentation.Instrumentation spanTagKind = tracer.Tag(ext.SpanKind, ext.SpanKindServer) spanTagType = tracer.Tag(ext.SpanType, ext.SpanTypeGraphQL) ) func init() { - telemetry.LoadIntegration(componentName) - tracer.MarkIntegrationImported("github.com/graphql-go/graphql") + instr = instrumentation.Load(instrumentation.PackageGraphQLGoGraphQL) } const ( @@ -94,7 +92,7 @@ func (i datadogExtension) Init(ctx context.Context, params *graphql.Params) cont tracer.ServiceName(i.config.serviceName), spanTagKind, spanTagType, - tracer.Tag(ext.Component, componentName), + tracer.Tag(ext.Component, instrumentation.PackageGraphQLGoGraphQL), tracer.Measured(), ) ctx, request := graphqlsec.StartRequestOperation(ctx, nil, span, types.RequestOperationArgs{ @@ -124,7 +122,7 @@ func (i datadogExtension) ParseDidStart(ctx context.Context) (context.Context, g spanTagKind, spanTagType, tracer.Tag(tagGraphqlSource, data.query), - tracer.Tag(ext.Component, componentName), + tracer.Tag(ext.Component, instrumentation.PackageGraphQLGoGraphQL), tracer.Measured(), } if data.operationName != "" { @@ -151,7 +149,7 @@ func (i datadogExtension) ValidationDidStart(ctx context.Context) (context.Conte spanTagKind, spanTagType, tracer.Tag(tagGraphqlSource, data.query), - tracer.Tag(ext.Component, componentName), + tracer.Tag(ext.Component, instrumentation.PackageGraphQLGoGraphQL), tracer.Measured(), } if data.operationName != "" { @@ -182,7 +180,7 @@ func (i datadogExtension) ExecutionDidStart(ctx context.Context) (context.Contex spanTagKind, spanTagType, tracer.Tag(tagGraphqlSource, data.query), - tracer.Tag(ext.Component, componentName), + tracer.Tag(ext.Component, instrumentation.PackageGraphQLGoGraphQL), tracer.Measured(), } if data.operationName != "" { @@ -228,7 +226,7 @@ func (i datadogExtension) ResolveFieldDidStart(ctx context.Context, info *graphq spanTagType, tracer.Tag(tagGraphqlField, info.FieldName), tracer.Tag(tagGraphqlOperationType, info.Operation.GetOperation()), - tracer.Tag(ext.Component, componentName), + tracer.Tag(ext.Component, instrumentation.PackageGraphQLGoGraphQL), tracer.Tag(ext.ResourceName, fmt.Sprintf("%s.%s", info.ParentType.Name(), info.FieldName)), tracer.Measured(), } diff --git a/contrib/graphql-go/graphql/option.go b/contrib/graphql-go/graphql/option.go index 52a17bb5fe..8773b39a28 100644 --- a/contrib/graphql-go/graphql/option.go +++ b/contrib/graphql-go/graphql/option.go @@ -8,8 +8,7 @@ package graphql import ( "math" - "github.com/DataDog/dd-trace-go/v2/internal" - "github.com/DataDog/dd-trace-go/v2/internal/namingschema" + "github.com/DataDog/dd-trace-go/v2/instrumentation" ) const defaultServiceName = "graphql.server" @@ -32,12 +31,8 @@ func (fn OptionFn) apply(cfg *config) { } func defaults(cfg *config) { - cfg.serviceName = namingschema.ServiceName(defaultServiceName) - if internal.BoolEnv("DD_TRACE_GRAPHQL_ANALYTICS_ENABLED", false) { - cfg.analyticsRate = 1.0 - } else { - cfg.analyticsRate = math.NaN() - } + cfg.serviceName = instr.ServiceName(instrumentation.ComponentDefault, nil) + cfg.analyticsRate = instr.AnalyticsRate(false) } // WithAnalytics enables Trace Analytics for all started spans. diff --git a/contrib/hashicorp/consul/consul.go b/contrib/hashicorp/consul/consul.go index 44906b2703..ca1499d4dc 100644 --- a/contrib/hashicorp/consul/consul.go +++ b/contrib/hashicorp/consul/consul.go @@ -11,17 +11,15 @@ import ( "github.com/DataDog/dd-trace-go/v2/ddtrace/ext" "github.com/DataDog/dd-trace-go/v2/ddtrace/tracer" - "github.com/DataDog/dd-trace-go/v2/internal/log" - "github.com/DataDog/dd-trace-go/v2/internal/telemetry" + "github.com/DataDog/dd-trace-go/v2/instrumentation" consul "github.com/hashicorp/consul/api" ) -const componentName = "hashicorp/consul" +var instr *instrumentation.Instrumentation func init() { - telemetry.LoadIntegration(componentName) - tracer.MarkIntegrationImported("github.com/hashicorp/consul/api") + instr = instrumentation.Load(instrumentation.PackageHashicorpConsulAPI) } // Client wraps the regular *consul.Client and augments it with tracing. Use NewClient to initialize it. @@ -49,7 +47,7 @@ func WrapClient(c *consul.Client, opts ...ClientOption) *Client { for _, fn := range opts { fn.apply(cfg) } - log.Debug("contrib/hashicorp/consul: Wrapping Client: %#v", cfg) + instr.Logger().Debug("contrib/hashicorp/consul: Wrapping Client: %#v", cfg) return &Client{c, cfg, context.Background()} } @@ -77,7 +75,7 @@ func (k *KV) startSpan(resourceName string, key string) *tracer.Span { tracer.ServiceName(k.config.serviceName), tracer.SpanType(ext.SpanTypeConsul), tracer.Tag("consul.key", key), - tracer.Tag(ext.Component, componentName), + tracer.Tag(ext.Component, instrumentation.PackageHashicorpConsulAPI), tracer.Tag(ext.SpanKind, ext.SpanKindClient), tracer.Tag(ext.DBSystem, ext.DBSystemConsulKV), } diff --git a/contrib/hashicorp/consul/consul_test.go b/contrib/hashicorp/consul/consul_test.go index 5bc5b9dccb..ecc4aa8bdd 100644 --- a/contrib/hashicorp/consul/consul_test.go +++ b/contrib/hashicorp/consul/consul_test.go @@ -13,11 +13,9 @@ import ( "github.com/DataDog/dd-trace-go/v2/ddtrace/ext" "github.com/DataDog/dd-trace-go/v2/ddtrace/mocktracer" - "github.com/DataDog/dd-trace-go/v2/internal/contrib/namingschematest" consul "github.com/hashicorp/consul/api" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestMain(m *testing.M) { @@ -107,40 +105,3 @@ func TestKV(t *testing.T) { }) } } -func TestNamingSchema(t *testing.T) { - genSpans := func(t *testing.T, serviceOverride string) []*mocktracer.Span { - var opts []ClientOption - if serviceOverride != "" { - opts = append(opts, WithService(serviceOverride)) - } - - mt := mocktracer.Start() - defer mt.Stop() - client, err := NewClient(consul.DefaultConfig(), opts...) - require.NoError(t, err) - kv := client.KV() - - pair := &consul.KVPair{Key: "test.key", Value: []byte("test_value")} - _, err = kv.Put(pair, nil) - require.NoError(t, err) - - spans := mt.FinishedSpans() - require.Len(t, spans, 1) - return spans - } - assertOpV0 := func(t *testing.T, spans []*mocktracer.Span) { - require.Len(t, spans, 1) - assert.Equal(t, "consul.command", spans[0].OperationName()) - } - assertOpV1 := func(t *testing.T, spans []*mocktracer.Span) { - require.Len(t, spans, 1) - assert.Equal(t, "consul.query", spans[0].OperationName()) - } - wantServiceNameV0 := namingschematest.ServiceNameAssertions{ - WithDefaults: []string{"consul"}, - WithDDService: []string{"consul"}, - WithDDServiceAndOverride: []string{namingschematest.TestServiceOverride}, - } - t.Run("service name", namingschematest.NewServiceNameTest(genSpans, wantServiceNameV0)) - t.Run("operation name", namingschematest.NewSpanNameTest(genSpans, assertOpV0, assertOpV1)) -} diff --git a/contrib/hashicorp/consul/option.go b/contrib/hashicorp/consul/option.go index 5e57112bb4..5dc339ee6d 100644 --- a/contrib/hashicorp/consul/option.go +++ b/contrib/hashicorp/consul/option.go @@ -9,8 +9,7 @@ import ( "math" "net" - "github.com/DataDog/dd-trace-go/v2/internal" - "github.com/DataDog/dd-trace-go/v2/internal/namingschema" + "github.com/DataDog/dd-trace-go/v2/instrumentation" consul "github.com/hashicorp/consul/api" ) @@ -39,14 +38,9 @@ func (fn ClientOptionFn) apply(cfg *clientConfig) { } func defaults(cfg *clientConfig) { - cfg.serviceName = namingschema.ServiceNameOverrideV0(defaultServiceName, defaultServiceName) - cfg.spanName = namingschema.OpName(namingschema.ConsulOutbound) - - if internal.BoolEnv("DD_TRACE_CONSUL_ANALYTICS_ENABLED", false) { - cfg.analyticsRate = 1.0 - } else { - cfg.analyticsRate = math.NaN() - } + cfg.serviceName = instr.ServiceName(instrumentation.ComponentDefault, nil) + cfg.spanName = instr.OperationName(instrumentation.ComponentDefault, nil) + cfg.analyticsRate = instr.AnalyticsRate(false) } // WithService sets the given service name for the client. diff --git a/contrib/hashicorp/vault/option.go b/contrib/hashicorp/vault/option.go index 8fc169b7e9..d6f4312d78 100644 --- a/contrib/hashicorp/vault/option.go +++ b/contrib/hashicorp/vault/option.go @@ -8,9 +8,7 @@ package vault import ( "math" - "github.com/DataDog/dd-trace-go/v2/internal" - "github.com/DataDog/dd-trace-go/v2/internal/globalconfig" - "github.com/DataDog/dd-trace-go/v2/internal/namingschema" + "github.com/DataDog/dd-trace-go/v2/instrumentation" ) type config struct { @@ -34,14 +32,9 @@ func (fn OptionFn) apply(cfg *config) { } func defaults(cfg *config) { - cfg.serviceName = namingschema.ServiceNameOverrideV0(defaultServiceName, defaultServiceName) - cfg.spanName = namingschema.OpName(namingschema.VaultOutbound) - - if internal.BoolEnv("DD_TRACE_VAULT_ANALYTICS_ENABLED", false) { - cfg.analyticsRate = 1.0 - } else { - cfg.analyticsRate = globalconfig.AnalyticsRate() - } + cfg.serviceName = instr.ServiceName(instrumentation.ComponentDefault, nil) + cfg.spanName = instr.OperationName(instrumentation.ComponentDefault, nil) + cfg.analyticsRate = instr.AnalyticsRate(true) } // WithAnalytics enables or disables Trace Analytics for all started spans. diff --git a/contrib/hashicorp/vault/vault.go b/contrib/hashicorp/vault/vault.go index 9bef92a63e..78bb65abe3 100644 --- a/contrib/hashicorp/vault/vault.go +++ b/contrib/hashicorp/vault/vault.go @@ -24,17 +24,16 @@ import ( httptrace "github.com/DataDog/dd-trace-go/contrib/net/http/v2" "github.com/DataDog/dd-trace-go/v2/ddtrace/ext" "github.com/DataDog/dd-trace-go/v2/ddtrace/tracer" - "github.com/DataDog/dd-trace-go/v2/internal/telemetry" + "github.com/DataDog/dd-trace-go/v2/instrumentation" "github.com/hashicorp/vault/api" "github.com/hashicorp/vault/sdk/helper/consts" ) -const componentName = "hashicorp/vault" +var instr *instrumentation.Instrumentation func init() { - telemetry.LoadIntegration(componentName) - tracer.MarkIntegrationImported("github.com/hashicorp/vault/api") + instr = instrumentation.Load(instrumentation.PackageHashicorpVaultAPI) } // NewHTTPClient returns an http.Client for use in the Vault API config diff --git a/contrib/hashicorp/vault/vault_test.go b/contrib/hashicorp/vault/vault_test.go index cbe4ae6c2d..60bf43d587 100644 --- a/contrib/hashicorp/vault/vault_test.go +++ b/contrib/hashicorp/vault/vault_test.go @@ -17,11 +17,9 @@ import ( "github.com/DataDog/dd-trace-go/v2/ddtrace/ext" "github.com/DataDog/dd-trace-go/v2/ddtrace/mocktracer" - "github.com/DataDog/dd-trace-go/v2/internal/contrib/namingschematest" "github.com/hashicorp/vault/api" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) const secretMountPath = "/ns1/ns2/secret" @@ -430,50 +428,3 @@ func TestOption(t *testing.T) { }) } } - -func TestNamingSchema(t *testing.T) { - genSpans := func(t *testing.T, serviceOverride string) []*mocktracer.Span { - var opts []Option - if serviceOverride != "" { - opts = append(opts, WithService(serviceOverride)) - } - - mt := mocktracer.Start() - defer mt.Stop() - - ts, cleanup := setupServer(t) - defer cleanup() - - client, err := api.NewClient(&api.Config{ - HttpClient: NewHTTPClient(opts...), - Address: ts.URL, - }) - require.NoError(t, err) - if err != nil { - t.Fatal(err) - } - defer mountKV(client, t)() - - // Write key with namespace first - data := map[string]interface{}{"Key1": "Val1", "Key2": "Val2"} - _, err = client.Logical().Write("/some/path", data) - require.NoError(t, err) - - return mt.FinishedSpans() - } - assertOpV0 := func(t *testing.T, spans []*mocktracer.Span) { - require.Len(t, spans, 2) - assert.Equal(t, "http.request", spans[0].OperationName()) - } - assertOpV1 := func(t *testing.T, spans []*mocktracer.Span) { - require.Len(t, spans, 2) - assert.Equal(t, "vault.query", spans[0].OperationName()) - } - wantServiceNameV0 := namingschematest.ServiceNameAssertions{ - WithDefaults: []string{"vault", "vault"}, - WithDDService: []string{"vault", "vault"}, - WithDDServiceAndOverride: []string{namingschematest.TestServiceOverride, namingschematest.TestServiceOverride}, - } - t.Run("service name", namingschematest.NewServiceNameTest(genSpans, wantServiceNameV0)) - t.Run("operation name", namingschematest.NewSpanNameTest(genSpans, assertOpV0, assertOpV1)) -} diff --git a/contrib/jackc/pgx.v5/option.go b/contrib/jackc/pgx.v5/option.go index 491d9467dc..6d576e6e25 100644 --- a/contrib/jackc/pgx.v5/option.go +++ b/contrib/jackc/pgx.v5/option.go @@ -5,7 +5,9 @@ package pgx -import "github.com/DataDog/dd-trace-go/v2/internal/namingschema" +import ( + "github.com/DataDog/dd-trace-go/v2/instrumentation" +) type config struct { serviceName string @@ -18,7 +20,7 @@ type config struct { func defaultConfig() *config { return &config{ - serviceName: namingschema.ServiceName(defaultServiceName), + serviceName: instr.ServiceName(instrumentation.ComponentDefault, nil), traceQuery: true, traceBatch: true, traceCopyFrom: true, diff --git a/contrib/jackc/pgx.v5/pgx.go b/contrib/jackc/pgx.v5/pgx.go index 79bfabb00d..fa4c631253 100644 --- a/contrib/jackc/pgx.v5/pgx.go +++ b/contrib/jackc/pgx.v5/pgx.go @@ -8,20 +8,19 @@ package pgx import ( "context" - "github.com/DataDog/dd-trace-go/v2/ddtrace/tracer" - "github.com/DataDog/dd-trace-go/v2/internal/telemetry" + "github.com/DataDog/dd-trace-go/v2/instrumentation" "github.com/jackc/pgx/v5" ) const ( - componentName = "jackc/pgx.v5" defaultServiceName = "postgres.db" ) +var instr *instrumentation.Instrumentation + func init() { - telemetry.LoadIntegration(componentName) - tracer.MarkIntegrationImported("github.com/jackc/pgx.v5") + instr = instrumentation.Load(instrumentation.PackageJackcPGXV5) } type Batch = pgx.Batch diff --git a/contrib/jackc/pgx.v5/pgx_tracer.go b/contrib/jackc/pgx.v5/pgx_tracer.go index 43263e27d8..45628ae8f8 100644 --- a/contrib/jackc/pgx.v5/pgx_tracer.go +++ b/contrib/jackc/pgx.v5/pgx_tracer.go @@ -10,6 +10,7 @@ import ( "github.com/DataDog/dd-trace-go/v2/ddtrace/ext" "github.com/DataDog/dd-trace-go/v2/ddtrace/tracer" + "github.com/DataDog/dd-trace-go/v2/instrumentation" "github.com/jackc/pgx/v5" ) @@ -180,7 +181,7 @@ func (t *pgxTracer) spanOptions(connConfig *pgx.ConnConfig, op operationType, sq tracer.ServiceName(t.cfg.serviceName), tracer.SpanType(ext.SpanTypeSQL), tracer.Tag(ext.DBSystem, ext.DBSystemPostgreSQL), - tracer.Tag(ext.Component, componentName), + tracer.Tag(ext.Component, instrumentation.PackageJackcPGXV5), tracer.Tag(ext.SpanKind, ext.SpanKindClient), tracer.Tag(tagOperation, string(op)), } diff --git a/contrib/jackc/pgx.v5/pgx_tracer_test.go b/contrib/jackc/pgx.v5/pgx_tracer_test.go index 97994f03f2..3e520334e6 100644 --- a/contrib/jackc/pgx.v5/pgx_tracer_test.go +++ b/contrib/jackc/pgx.v5/pgx_tracer_test.go @@ -17,6 +17,7 @@ import ( "github.com/DataDog/dd-trace-go/v2/ddtrace/ext" "github.com/DataDog/dd-trace-go/v2/ddtrace/mocktracer" "github.com/DataDog/dd-trace-go/v2/ddtrace/tracer" + "github.com/DataDog/dd-trace-go/v2/instrumentation" "github.com/jackc/pgx/v5" "github.com/stretchr/testify/assert" @@ -296,7 +297,7 @@ func assertCommonTags(t *testing.T, s *mocktracer.Span) { assert.Equal(t, defaultServiceName, s.Tag(ext.ServiceName)) assert.Equal(t, ext.SpanTypeSQL, s.Tag(ext.SpanType)) assert.Equal(t, ext.DBSystemPostgreSQL, s.Tag(ext.DBSystem)) - assert.Equal(t, componentName, s.Tag(ext.Component)) + assert.Equal(t, string(instrumentation.PackageJackcPGXV5), s.Tag(ext.Component)) assert.Equal(t, ext.SpanKindClient, s.Tag(ext.SpanKind)) assert.Equal(t, "127.0.0.1", s.Tag(ext.NetworkDestinationName)) assert.Equal(t, float64(5432), s.Tag(ext.NetworkDestinationPort)) diff --git a/contrib/jmoiron/sqlx/sql.go b/contrib/jmoiron/sqlx/sql.go index 4497004993..7322fdffc9 100644 --- a/contrib/jmoiron/sqlx/sql.go +++ b/contrib/jmoiron/sqlx/sql.go @@ -13,17 +13,15 @@ package sqlx // import "github.com/DataDog/dd-trace-go/contrib/jmoiron/sqlx/v2" import ( sqltraced "github.com/DataDog/dd-trace-go/contrib/database/sql/v2" - "github.com/DataDog/dd-trace-go/v2/ddtrace/tracer" - "github.com/DataDog/dd-trace-go/v2/internal/telemetry" + "github.com/DataDog/dd-trace-go/v2/instrumentation" "github.com/jmoiron/sqlx" ) -const componentName = "jmoiron/sqlx" +var instr *instrumentation.Instrumentation func init() { - telemetry.LoadIntegration(componentName) - tracer.MarkIntegrationImported("github.com/jmoiron/sqlx") + instr = instrumentation.Load(instrumentation.PackageJmoironSQLx) } // Open opens a new (traced) connection to the database using the given driver and source. diff --git a/contrib/julienschmidt/httprouter/httprouter.go b/contrib/julienschmidt/httprouter/httprouter.go index e737ce6dc7..7a25b48bb7 100644 --- a/contrib/julienschmidt/httprouter/httprouter.go +++ b/contrib/julienschmidt/httprouter/httprouter.go @@ -14,19 +14,17 @@ import ( httptrace "github.com/DataDog/dd-trace-go/contrib/net/http/v2" "github.com/DataDog/dd-trace-go/v2/ddtrace/ext" "github.com/DataDog/dd-trace-go/v2/ddtrace/tracer" + "github.com/DataDog/dd-trace-go/v2/instrumentation" + httptraceinstr "github.com/DataDog/dd-trace-go/v2/instrumentation/httptrace" "github.com/DataDog/dd-trace-go/v2/instrumentation/options" - httptraceinternal "github.com/DataDog/dd-trace-go/v2/internal/contrib/httptrace" - "github.com/DataDog/dd-trace-go/v2/internal/log" - "github.com/DataDog/dd-trace-go/v2/internal/telemetry" "github.com/julienschmidt/httprouter" ) -const componentName = "julienschmidt/httprouter" +var instr *instrumentation.Instrumentation func init() { - telemetry.LoadIntegration(componentName) - tracer.MarkIntegrationImported("github.com/julienschmidt/httprouter") + instr = instrumentation.Load(instrumentation.PackageJulienschmidtHTTPRouter) } // Router is a traced version of httprouter.Router. @@ -47,9 +45,9 @@ func New(opts ...RouterOption) *Router { } cfg.spanOpts = append(cfg.spanOpts, tracer.Tag(ext.SpanKind, ext.SpanKindServer)) - cfg.spanOpts = append(cfg.spanOpts, tracer.Tag(ext.Component, componentName)) + cfg.spanOpts = append(cfg.spanOpts, tracer.Tag(ext.Component, instrumentation.PackageJulienschmidtHTTPRouter)) - log.Debug("contrib/julienschmidt/httprouter: Configuring Router: %#v", cfg) + instr.Logger().Debug("contrib/julienschmidt/httprouter: Configuring Router: %#v", cfg) return &Router{httprouter.New(), cfg} } @@ -63,7 +61,7 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { } resource := req.Method + " " + route spanOpts := options.Expand(r.config.spanOpts, 0, 1) // spanOpts must be a copy of r.config.spanOpts, locally scoped, to avoid races. - spanOpts = append(spanOpts, httptraceinternal.HeaderTagsFromRequest(req, r.config.headerTags)) + spanOpts = append(spanOpts, httptraceinstr.HeaderTagsFromRequest(req, r.config.headerTags)) httptrace.TraceAndServe(r.Router, w, req, &httptrace.ServeConfig{ Service: r.config.serviceName, diff --git a/contrib/julienschmidt/httprouter/httprouter_test.go b/contrib/julienschmidt/httprouter/httprouter_test.go index fbf7cf5740..dd3aa5cc4b 100644 --- a/contrib/julienschmidt/httprouter/httprouter_test.go +++ b/contrib/julienschmidt/httprouter/httprouter_test.go @@ -8,15 +8,13 @@ package httprouter import ( "net/http" "net/http/httptest" - "strings" "testing" "github.com/DataDog/dd-trace-go/v2/ddtrace/ext" "github.com/DataDog/dd-trace-go/v2/ddtrace/mocktracer" "github.com/DataDog/dd-trace-go/v2/ddtrace/tracer" - "github.com/DataDog/dd-trace-go/v2/internal/contrib/namingschematest" - "github.com/DataDog/dd-trace-go/v2/internal/globalconfig" - "github.com/DataDog/dd-trace-go/v2/internal/normalizer" + "github.com/DataDog/dd-trace-go/v2/instrumentation" + "github.com/DataDog/dd-trace-go/v2/instrumentation/testutils" "github.com/julienschmidt/httprouter" "github.com/stretchr/testify/assert" @@ -137,9 +135,7 @@ func TestAnalyticsSettings(t *testing.T) { mt := mocktracer.Start() defer mt.Stop() - rate := globalconfig.AnalyticsRate() - defer globalconfig.SetAnalyticsRate(rate) - globalconfig.SetAnalyticsRate(0.4) + testutils.SetGlobalAnalyticsRate(t, 0.4) assertRate(t, mt, 0.4) }) @@ -162,9 +158,7 @@ func TestAnalyticsSettings(t *testing.T) { mt := mocktracer.Start() defer mt.Stop() - rate := globalconfig.AnalyticsRate() - defer globalconfig.SetAnalyticsRate(rate) - globalconfig.SetAnalyticsRate(0.4) + testutils.SetGlobalAnalyticsRate(t, 0.4) assertRate(t, mt, 0.23, WithAnalyticsRate(0.23)) }) @@ -195,26 +189,6 @@ func handler500(w http.ResponseWriter, _ *http.Request, _ httprouter.Params) { http.Error(w, "500!", http.StatusInternalServerError) } -func TestNamingSchema(t *testing.T) { - genSpans := namingschematest.GenSpansFn(func(t *testing.T, serviceOverride string) []*mocktracer.Span { - var opts []RouterOption - if serviceOverride != "" { - opts = append(opts, WithService(serviceOverride)) - } - mt := mocktracer.Start() - defer mt.Stop() - - mux := New(opts...) - mux.GET("/200", handler200) - r := httptest.NewRequest("GET", "/200", nil) - w := httptest.NewRecorder() - mux.ServeHTTP(w, r) - - return mt.FinishedSpans() - }) - namingschematest.NewHTTPServerTest(genSpans, "http.router")(t) -} - func TestWithHeaderTags(t *testing.T) { setupReq := func(opts ...RouterOption) *http.Request { mux := New(opts...) @@ -239,63 +213,58 @@ func TestWithHeaderTags(t *testing.T) { assert := assert.New(t) assert.Equal(len(spans), 1) s := spans[0] - for _, arg := range htArgs { - _, tag := normalizer.HeaderTag(arg) + + instrumentation.NewHeaderTags(htArgs).Iter(func(_ string, tag string) { assert.NotContains(s.Tags(), tag) - } + }) }) t.Run("integration", func(t *testing.T) { mt := mocktracer.Start() defer mt.Stop() htArgs := []string{"h!e@a-d.e*r", "2header:tag"} - r := setupReq(WithHeaderTags(htArgs)) + _ = setupReq(WithHeaderTags(htArgs)) spans := mt.FinishedSpans() assert := assert.New(t) assert.Equal(len(spans), 1) s := spans[0] - for _, arg := range htArgs { - header, tag := normalizer.HeaderTag(arg) - assert.Equal(strings.Join(r.Header.Values(header), ","), s.Tags()[tag]) - } + assert.Equal("val,val2", s.Tags()["http.request.headers.h_e_a-d_e_r"]) + assert.Equal("2val", s.Tags()["tag"]) assert.NotContains(s.Tags(), "http.headers.x-datadog-header") }) t.Run("global", func(t *testing.T) { mt := mocktracer.Start() defer mt.Stop() - header, tag := normalizer.HeaderTag("3header") - globalconfig.SetHeaderTag(header, tag) + testutils.SetGlobalHeaderTags(t, "3header") - r := setupReq() + _ = setupReq() spans := mt.FinishedSpans() assert := assert.New(t) assert.Equal(len(spans), 1) s := spans[0] - assert.Equal(strings.Join(r.Header.Values(header), ","), s.Tags()[tag]) + assert.Equal("3val", s.Tags()["http.request.headers.3header"]) + assert.NotContains(s.Tags(), "http.request.headers.other") assert.NotContains(s.Tags(), "http.headers.x-datadog-header") }) t.Run("override", func(t *testing.T) { mt := mocktracer.Start() defer mt.Stop() - globalH, globalT := normalizer.HeaderTag("3header") - globalconfig.SetHeaderTag(globalH, globalT) + testutils.SetGlobalHeaderTags(t, "3header") htArgs := []string{"h!e@a-d.e*r", "2header:tag"} - r := setupReq(WithHeaderTags(htArgs)) + _ = setupReq(WithHeaderTags(htArgs)) spans := mt.FinishedSpans() assert := assert.New(t) assert.Equal(len(spans), 1) s := spans[0] - for _, arg := range htArgs { - header, tag := normalizer.HeaderTag(arg) - assert.Equal(strings.Join(r.Header.Values(header), ","), s.Tags()[tag]) - } + assert.Equal("val,val2", s.Tags()["http.request.headers.h_e_a-d_e_r"]) + assert.Equal("2val", s.Tags()["tag"]) assert.NotContains(s.Tags(), "http.headers.x-datadog-header") - assert.NotContains(s.Tags(), globalT) + assert.NotContains(s.Tags(), "http.request.headers.3header") }) } diff --git a/contrib/julienschmidt/httprouter/option.go b/contrib/julienschmidt/httprouter/option.go index ad013d7ebd..b776b56102 100644 --- a/contrib/julienschmidt/httprouter/option.go +++ b/contrib/julienschmidt/httprouter/option.go @@ -9,10 +9,7 @@ import ( "math" "github.com/DataDog/dd-trace-go/v2/ddtrace/tracer" - "github.com/DataDog/dd-trace-go/v2/internal" - "github.com/DataDog/dd-trace-go/v2/internal/globalconfig" - "github.com/DataDog/dd-trace-go/v2/internal/namingschema" - "github.com/DataDog/dd-trace-go/v2/internal/normalizer" + "github.com/DataDog/dd-trace-go/v2/instrumentation" ) const defaultServiceName = "http.router" @@ -21,7 +18,7 @@ type routerConfig struct { serviceName string spanOpts []tracer.StartSpanOption analyticsRate float64 - headerTags *internal.LockMap + headerTags instrumentation.HeaderTags } // RouterOption describes options for the HTTPRouter integration. @@ -37,13 +34,9 @@ func (fn RouterOptionFn) apply(cfg *routerConfig) { } func defaults(cfg *routerConfig) { - if internal.BoolEnv("DD_TRACE_HTTPROUTER_ANALYTICS_ENABLED", false) { - cfg.analyticsRate = 1.0 - } else { - cfg.analyticsRate = globalconfig.AnalyticsRate() - } - cfg.serviceName = namingschema.ServiceName(defaultServiceName) - cfg.headerTags = globalconfig.HeaderTagMap() + cfg.analyticsRate = instr.AnalyticsRate(true) + cfg.serviceName = instr.ServiceName(instrumentation.ComponentServer, nil) + cfg.headerTags = instr.HTTPHeadersAsTags() } // WithService sets the given service name for the returned router. @@ -88,8 +81,7 @@ func WithAnalyticsRate(rate float64) RouterOptionFn { // Using this feature can risk exposing sensitive data such as authorization tokens to Datadog. // Special headers can not be sub-selected. E.g., an entire Cookie header would be transmitted, without the ability to choose specific Cookies. func WithHeaderTags(headers []string) RouterOptionFn { - headerTagsMap := normalizer.HeaderTagSlice(headers) return func(cfg *routerConfig) { - cfg.headerTags = internal.NewLockMap(headerTagsMap) + cfg.headerTags = instrumentation.NewHeaderTags(headers) } } diff --git a/contrib/k8s.io/client-go/kubernetes/kubernetes.go b/contrib/k8s.io/client-go/kubernetes/kubernetes.go index 7a3c1c04b2..eeeeb882d4 100644 --- a/contrib/k8s.io/client-go/kubernetes/kubernetes.go +++ b/contrib/k8s.io/client-go/kubernetes/kubernetes.go @@ -13,15 +13,13 @@ import ( httptrace "github.com/DataDog/dd-trace-go/contrib/net/http/v2" "github.com/DataDog/dd-trace-go/v2/ddtrace/ext" "github.com/DataDog/dd-trace-go/v2/ddtrace/tracer" - "github.com/DataDog/dd-trace-go/v2/internal/log" - "github.com/DataDog/dd-trace-go/v2/internal/telemetry" + "github.com/DataDog/dd-trace-go/v2/instrumentation" ) -const componentName = "k8s.io/client-go/kubernetes" +var instr *instrumentation.Instrumentation func init() { - telemetry.LoadIntegration(componentName) - tracer.MarkIntegrationImported(componentName) + instr = instrumentation.Load(instrumentation.PackageK8SClientGo) } const ( @@ -50,7 +48,7 @@ func wrapRoundTripperWithOptions(rt http.RoundTripper, opts ...httptrace.RoundTr copy(localOpts, opts) // make a copy of the opts, to avoid data races and side effects. localOpts = append(localOpts, httptrace.WithBefore(func(req *http.Request, span *tracer.Span) { span.SetTag(ext.ResourceName, RequestToResource(req.Method, req.URL.Path)) - span.SetTag(ext.Component, componentName) + span.SetTag(ext.Component, instrumentation.PackageK8SClientGo) span.SetTag(ext.SpanKind, ext.SpanKindClient) traceID := span.Context().TraceID() if traceID == tracer.TraceIDZero { @@ -60,7 +58,7 @@ func wrapRoundTripperWithOptions(rt http.RoundTripper, opts ...httptrace.RoundTr req.Header.Set("Audit-Id", traceID) span.SetTag("kubernetes.audit_id", traceID) })) - log.Debug("contrib/k8s.io/client-go/kubernetes: Wrapping RoundTripper.") + instr.Logger().Debug("contrib/k8s.io/client-go/kubernetes: Wrapping RoundTripper.") return httptrace.WrapRoundTripper(rt, localOpts...) } diff --git a/contrib/k8s.io/client-go/kubernetes/kubernetes_test.go b/contrib/k8s.io/client-go/kubernetes/kubernetes_test.go index fdcbefe654..6a17fa5996 100644 --- a/contrib/k8s.io/client-go/kubernetes/kubernetes_test.go +++ b/contrib/k8s.io/client-go/kubernetes/kubernetes_test.go @@ -14,7 +14,7 @@ import ( httptrace "github.com/DataDog/dd-trace-go/contrib/net/http/v2" "github.com/DataDog/dd-trace-go/v2/ddtrace/ext" "github.com/DataDog/dd-trace-go/v2/ddtrace/mocktracer" - "github.com/DataDog/dd-trace-go/v2/internal/globalconfig" + "github.com/DataDog/dd-trace-go/v2/instrumentation/testutils" "github.com/stretchr/testify/assert" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -128,9 +128,7 @@ func TestAnalyticsSettings(t *testing.T) { mt := mocktracer.Start() defer mt.Stop() - rate := globalconfig.AnalyticsRate() - defer globalconfig.SetAnalyticsRate(rate) - globalconfig.SetAnalyticsRate(0.4) + testutils.SetGlobalAnalyticsRate(t, 0.4) assertRate(t, mt, 0.4) }) @@ -153,9 +151,7 @@ func TestAnalyticsSettings(t *testing.T) { mt := mocktracer.Start() defer mt.Stop() - rate := globalconfig.AnalyticsRate() - defer globalconfig.SetAnalyticsRate(rate) - globalconfig.SetAnalyticsRate(0.4) + testutils.SetGlobalAnalyticsRate(t, 0.4) assertRate(t, mt, 0.23, httptrace.WithAnalyticsRate(0.23)) }) diff --git a/contrib/labstack/echo.v4/appsec_test.go b/contrib/labstack/echo.v4/appsec_test.go index e988e7480e..20ebaa0014 100644 --- a/contrib/labstack/echo.v4/appsec_test.go +++ b/contrib/labstack/echo.v4/appsec_test.go @@ -17,17 +17,15 @@ import ( pappsec "github.com/DataDog/dd-trace-go/v2/appsec" "github.com/DataDog/dd-trace-go/v2/ddtrace/ext" "github.com/DataDog/dd-trace-go/v2/ddtrace/mocktracer" - "github.com/DataDog/dd-trace-go/v2/internal/appsec" + "github.com/DataDog/dd-trace-go/v2/instrumentation/testutils" "github.com/labstack/echo/v4" "github.com/stretchr/testify/require" ) func TestAppSec(t *testing.T) { - appsec.Start() - defer appsec.Stop() - - if !appsec.Enabled() { + testutils.StartAppSec(t) + if !instr.AppSecEnabled() { t.Skip("appsec disabled") } @@ -239,10 +237,9 @@ func TestAppSec(t *testing.T) { // TestControlFlow ensures that the AppSec middleware behaves correctly in various execution flows and wrapping // scenarios. func TestControlFlow(t *testing.T) { - appsec.Start() - defer appsec.Stop() - if !appsec.Enabled() { - t.Skip("AppSec needs to be enabled for this test") + testutils.StartAppSec(t) + if !instr.AppSecEnabled() { + t.Skip("appsec disabled") } middlewareResponseBody := "Hello Middleware" @@ -550,10 +547,9 @@ func TestControlFlow(t *testing.T) { func TestBlocking(t *testing.T) { t.Setenv("DD_APPSEC_RULES", "../../../internal/appsec/testdata/blocking.json") - appsec.Start() - defer appsec.Stop() - if !appsec.Enabled() { - t.Skip("AppSec needs to be enabled for this test") + testutils.StartAppSec(t) + if !instr.AppSecEnabled() { + t.Skip("appsec disabled") } // Start and trace an HTTP server @@ -618,7 +614,7 @@ func TestBlocking(t *testing.T) { if tc.shouldBlock { require.Equal(t, http.StatusForbidden, res.StatusCode) - require.Equal(t, spans[0].Tag("appsec.blocked"), true) + require.Equal(t, spans[0].Tag("appsec.blocked"), "true") } else { require.Equal(t, http.StatusOK, res.StatusCode) require.NotContains(t, spans[0].Tags(), "appsec.blocked") diff --git a/contrib/labstack/echo.v4/echotrace.go b/contrib/labstack/echo.v4/echotrace.go index 1c5d223ef4..12404da339 100644 --- a/contrib/labstack/echo.v4/echotrace.go +++ b/contrib/labstack/echo.v4/echotrace.go @@ -18,19 +18,17 @@ import ( "github.com/DataDog/dd-trace-go/v2/ddtrace/ext" "github.com/DataDog/dd-trace-go/v2/ddtrace/tracer" + "github.com/DataDog/dd-trace-go/v2/instrumentation" + "github.com/DataDog/dd-trace-go/v2/instrumentation/httptrace" "github.com/DataDog/dd-trace-go/v2/instrumentation/options" - "github.com/DataDog/dd-trace-go/v2/internal/contrib/httptrace" - "github.com/DataDog/dd-trace-go/v2/internal/log" - "github.com/DataDog/dd-trace-go/v2/internal/telemetry" "github.com/labstack/echo/v4" ) -const componentName = "labstack/echo" +var instr *instrumentation.Instrumentation func init() { - telemetry.LoadIntegration(componentName) - tracer.MarkIntegrationImported("github.com/labstack/echo") + instr = instrumentation.Load(instrumentation.PackageLabstackEchoV4) } // Middleware returns echo middleware which will trace incoming requests. @@ -40,10 +38,10 @@ func Middleware(opts ...OptionFn) echo.MiddlewareFunc { for _, fn := range opts { fn(cfg) } - log.Debug("contrib/labstack/echo: Configuring Middleware: %#v", cfg) + instr.Logger().Debug("contrib/labstack/echo: Configuring Middleware: %#v", cfg) spanOpts := []tracer.StartSpanOption{ tracer.ServiceName(cfg.serviceName), - tracer.Tag(ext.Component, componentName), + tracer.Tag(ext.Component, instrumentation.PackageLabstackEchoV4), tracer.Tag(ext.SpanKind, ext.SpanKindServer), } return func(next echo.HandlerFunc) echo.HandlerFunc { @@ -72,6 +70,11 @@ func Middleware(opts ...OptionFn) echo.MiddlewareFunc { // pass the span through the request context c.SetRequest(request.WithContext(ctx)) + // Use AppSec if enabled by user + if instr.AppSecEnabled() { + next = withAppSec(next, span) + } + // serve the request to the next middleware err := next(c) if err != nil { diff --git a/contrib/labstack/echo.v4/echotrace_test.go b/contrib/labstack/echo.v4/echotrace_test.go index be12449884..afc3086b51 100644 --- a/contrib/labstack/echo.v4/echotrace_test.go +++ b/contrib/labstack/echo.v4/echotrace_test.go @@ -10,16 +10,13 @@ import ( "fmt" "net/http" "net/http/httptest" - "strings" "testing" "github.com/DataDog/dd-trace-go/v2/ddtrace/ext" "github.com/DataDog/dd-trace-go/v2/ddtrace/mocktracer" "github.com/DataDog/dd-trace-go/v2/ddtrace/tracer" - "github.com/DataDog/dd-trace-go/v2/internal/contrib/namingschematest" - "github.com/DataDog/dd-trace-go/v2/internal/globalconfig" - "github.com/DataDog/dd-trace-go/v2/internal/log" - "github.com/DataDog/dd-trace-go/v2/internal/normalizer" + "github.com/DataDog/dd-trace-go/v2/instrumentation" + "github.com/DataDog/dd-trace-go/v2/instrumentation/testutils" "github.com/labstack/echo/v4" "github.com/stretchr/testify/assert" @@ -76,26 +73,23 @@ func TestWithHeaderTags(t *testing.T) { assert := assert.New(t) assert.Equal(len(spans), 1) s := spans[0] - for _, arg := range htArgs { - _, tag := normalizer.HeaderTag(arg) + instrumentation.NewHeaderTags(htArgs).Iter(func(_ string, tag string) { assert.NotContains(s.Tags(), tag) - } + }) }) t.Run("integration", func(t *testing.T) { mt := mocktracer.Start() defer mt.Stop() htArgs := []string{"h!e@a-d.e*r", "2header:tag"} - r := setupReq(WithHeaderTags(htArgs)) + _ = setupReq(WithHeaderTags(htArgs)) spans := mt.FinishedSpans() assert := assert.New(t) assert.Equal(len(spans), 1) s := spans[0] - for _, arg := range htArgs { - header, tag := normalizer.HeaderTag(arg) - assert.Equal(strings.Join(r.Header.Values(header), ","), s.Tags()[tag]) - } + assert.Equal("val,val2", s.Tags()["http.request.headers.h_e_a-d_e_r"]) + assert.Equal("2val", s.Tags()["tag"]) assert.NotContains(s.Tags(), "http.headers.x-datadog-header") }) @@ -103,16 +97,16 @@ func TestWithHeaderTags(t *testing.T) { mt := mocktracer.Start() defer mt.Stop() - header, tag := normalizer.HeaderTag("3header") - globalconfig.SetHeaderTag(header, tag) + testutils.SetGlobalHeaderTags(t, "3header") - r := setupReq() + _ = setupReq() spans := mt.FinishedSpans() assert := assert.New(t) assert.Equal(len(spans), 1) s := spans[0] - assert.Equal(strings.Join(r.Header.Values(header), ","), s.Tags()[tag]) + assert.Equal("3val", s.Tags()["http.request.headers.3header"]) + assert.NotContains(s.Tags(), "http.request.headers.other") assert.NotContains(s.Tags(), "http.headers.x-datadog-header") }) @@ -120,22 +114,19 @@ func TestWithHeaderTags(t *testing.T) { mt := mocktracer.Start() defer mt.Stop() - globalH, globalT := normalizer.HeaderTag("3header") - globalconfig.SetHeaderTag(globalH, globalT) + testutils.SetGlobalHeaderTags(t, "3header") htArgs := []string{"h!e@a-d.e*r", "2header:tag"} - r := setupReq(WithHeaderTags(htArgs)) + _ = setupReq(WithHeaderTags(htArgs)) spans := mt.FinishedSpans() assert := assert.New(t) assert.Equal(len(spans), 1) s := spans[0] - for _, arg := range htArgs { - header, tag := normalizer.HeaderTag(arg) - assert.Equal(strings.Join(r.Header.Values(header), ","), s.Tags()[tag]) - } + assert.Equal("val,val2", s.Tags()["http.request.headers.h_e_a-d_e_r"]) + assert.Equal("2val", s.Tags()["tag"]) assert.NotContains(s.Tags(), "http.headers.x-datadog-header") - assert.NotContains(s.Tags(), globalT) + assert.NotContains(s.Tags(), "http.request.headers.3header") }) } @@ -247,14 +238,14 @@ func TestError(t *testing.T) { // setup router := echo.New() router.Use(Middleware(WithService("foobar"))) - wantErr := errors.New("oh no") + errWant := errors.New("oh no") // a handler with an error and make the requests router.GET("/err", func(c echo.Context) error { _, traced = tracer.SpanFromContext(c.Request().Context()) called = true - err := wantErr + err := errWant c.Error(err) return err }) @@ -273,8 +264,8 @@ func TestError(t *testing.T) { assert.Equal("http.request", span.OperationName()) assert.Equal("foobar", span.Tag(ext.ServiceName)) assert.Equal("500", span.Tag(ext.HTTPCode)) - require.NotNil(t, span.Tag(ext.Error)) - assert.Equal(wantErr.Error(), span.Tag(ext.Error).(error).Error()) + require.NotNil(t, span.Tag(ext.ErrorMsg)) + assert.Equal(errWant.Error(), span.Tag(ext.ErrorMsg)) assert.Equal("labstack/echo", span.Tag(ext.Component)) assert.Equal(ext.SpanKindServer, span.Tag(ext.SpanKind)) } @@ -291,13 +282,13 @@ func TestErrorHandling(t *testing.T) { ctx.Response().WriteHeader(http.StatusInternalServerError) } router.Use(Middleware(WithService("foobar"))) - wantErr := errors.New("oh no") + errWant := errors.New("oh no") // a handler with an error and make the requests router.GET("/err", func(c echo.Context) error { _, traced = tracer.SpanFromContext(c.Request().Context()) called = true - return wantErr + return errWant }) r := httptest.NewRequest("GET", "/err", nil) w := httptest.NewRecorder() @@ -314,8 +305,8 @@ func TestErrorHandling(t *testing.T) { assert.Equal("http.request", span.OperationName()) assert.Equal("foobar", span.Tag(ext.ServiceName)) assert.Equal("500", span.Tag(ext.HTTPCode)) - require.NotNil(t, span.Tag(ext.Error)) - assert.Equal(wantErr.Error(), span.Tag(ext.Error).(error).Error()) + require.NotNil(t, span.Tag(ext.ErrorMsg)) + assert.Equal(errWant.Error(), span.Tag(ext.ErrorMsg)) assert.Equal("labstack/echo", span.Tag(ext.Component)) assert.Equal(ext.SpanKindServer, span.Tag(ext.SpanKind)) } @@ -417,11 +408,10 @@ func TestStatusError(t *testing.T) { assert.Contains(span.Tag(ext.ResourceName), "/err") assert.Equal(tt.code, span.Tag(ext.HTTPCode)) assert.Equal("GET", span.Tag(ext.HTTPMethod)) - err := span.Tag(ext.Error) + err := span.Tag(ext.ErrorMsg) if tt.err != nil { assert.NotNil(err) - require.NotNil(t, span.Tag(ext.Error)) - assert.Equal(tt.err.Error(), err.(error).Error()) + assert.Equal(tt.err.Error(), err) } else { assert.Nil(err) } @@ -458,14 +448,14 @@ func TestNoDebugStack(t *testing.T) { // setup router := echo.New() router.Use(Middleware(NoDebugStack())) - wantErr := errors.New("oh no") + errWant := errors.New("oh no") // a handler with an error and make the requests router.GET("/err", func(c echo.Context) error { _, traced = tracer.SpanFromContext(c.Request().Context()) called = true - err := wantErr + err := errWant c.Error(err) return err }) @@ -481,36 +471,13 @@ func TestNoDebugStack(t *testing.T) { assert.Len(spans, 1) span := spans[0] - require.NotNil(t, span.Tag(ext.Error)) - assert.Equal(wantErr.Error(), span.Tag(ext.Error).(error).Error()) - assert.Equal("", span.Tag(ext.ErrorStack)) + require.NotNil(t, span.Tag(ext.ErrorMsg)) + assert.Equal(errWant.Error(), span.Tag(ext.ErrorMsg)) + assert.Empty(span.Tag(ext.ErrorStack)) assert.Equal("labstack/echo", span.Tag(ext.Component)) assert.Equal(ext.SpanKindServer, span.Tag(ext.SpanKind)) } -func TestNamingSchema(t *testing.T) { - genSpans := namingschematest.GenSpansFn(func(t *testing.T, serviceOverride string) []*mocktracer.Span { - var opts []OptionFn - if serviceOverride != "" { - opts = append(opts, WithService(serviceOverride)) - } - mt := mocktracer.Start() - defer mt.Stop() - - mux := echo.New() - mux.Use(Middleware(opts...)) - mux.GET("/200", func(c echo.Context) error { - return c.NoContent(200) - }) - r := httptest.NewRequest("GET", "/200", nil) - w := httptest.NewRecorder() - mux.ServeHTTP(w, r) - - return mt.FinishedSpans() - }) - namingschematest.NewHTTPServerTest(genSpans, "echo")(t) -} - func BenchmarkEchoNoTracing(b *testing.B) { mux := echo.New() mux.GET("/200", func(c echo.Context) error { @@ -526,7 +493,7 @@ func BenchmarkEchoNoTracing(b *testing.B) { } func BenchmarkEchoWithTracing(b *testing.B) { - tracer.Start(tracer.WithLogger(log.DiscardLogger{})) + tracer.Start(tracer.WithLogger(testutils.DiscardLogger())) defer tracer.Stop() mux := echo.New() diff --git a/contrib/labstack/echo.v4/option.go b/contrib/labstack/echo.v4/option.go index a6f7dff6cc..83dd89360b 100644 --- a/contrib/labstack/echo.v4/option.go +++ b/contrib/labstack/echo.v4/option.go @@ -9,16 +9,11 @@ import ( "errors" "math" - "github.com/DataDog/dd-trace-go/v2/internal" - "github.com/DataDog/dd-trace-go/v2/internal/globalconfig" - "github.com/DataDog/dd-trace-go/v2/internal/namingschema" - "github.com/DataDog/dd-trace-go/v2/internal/normalizer" + "github.com/DataDog/dd-trace-go/v2/instrumentation" "github.com/labstack/echo/v4" ) -const defaultServiceName = "echo" - type config struct { serviceName string analyticsRate float64 @@ -26,7 +21,7 @@ type config struct { ignoreRequestFunc IgnoreRequestFunc isStatusError func(statusCode int) bool translateError func(err error) (*echo.HTTPError, bool) - headerTags *internal.LockMap + headerTags instrumentation.HeaderTags errCheck func(error) bool tags map[string]interface{} } @@ -47,10 +42,10 @@ func (fn OptionFn) apply(cfg *config) { type IgnoreRequestFunc func(c echo.Context) bool func defaults(cfg *config) { - cfg.serviceName = namingschema.ServiceName(defaultServiceName) + cfg.serviceName = instr.ServiceName(instrumentation.ComponentServer, nil) cfg.analyticsRate = math.NaN() cfg.isStatusError = isServerError - cfg.headerTags = globalconfig.HeaderTagMap() + cfg.headerTags = instr.HTTPHeadersAsTags() cfg.tags = make(map[string]interface{}) cfg.translateError = func(err error) (*echo.HTTPError, bool) { var echoErr *echo.HTTPError @@ -133,9 +128,9 @@ func isServerError(statusCode int) bool { // Using this feature can risk exposing sensitive data such as authorization tokens to Datadog. // Special headers can not be sub-selected. E.g., an entire Cookie header would be transmitted, without the ability to choose specific Cookies. func WithHeaderTags(headers []string) OptionFn { - headerTagsMap := normalizer.HeaderTagSlice(headers) + headerTagsMap := instrumentation.NewHeaderTags(headers) return func(cfg *config) { - cfg.headerTags = internal.NewLockMap(headerTagsMap) + cfg.headerTags = headerTagsMap } } diff --git a/contrib/miekg/dns/dns.go b/contrib/miekg/dns/dns.go index afbdf97b4a..b58e5e0d4a 100644 --- a/contrib/miekg/dns/dns.go +++ b/contrib/miekg/dns/dns.go @@ -13,17 +13,15 @@ import ( "github.com/DataDog/dd-trace-go/v2/ddtrace/ext" "github.com/DataDog/dd-trace-go/v2/ddtrace/tracer" - "github.com/DataDog/dd-trace-go/v2/internal/log" - "github.com/DataDog/dd-trace-go/v2/internal/telemetry" + "github.com/DataDog/dd-trace-go/v2/instrumentation" "github.com/miekg/dns" ) -const componentName = "miekg/dns" +var instr *instrumentation.Instrumentation func init() { - telemetry.LoadIntegration(componentName) - tracer.MarkIntegrationImported("github.com/miekg/dns") + instr = instrumentation.Load(instrumentation.PackageMiekgDNS) } // ListenAndServe calls dns.ListenAndServe with a wrapped Handler. @@ -43,7 +41,7 @@ type Handler struct { // WrapHandler creates a new, wrapped DNS handler. func WrapHandler(handler dns.Handler) *Handler { - log.Debug("contrib/miekg/dns: Wrapping Handler") + instr.Logger().Debug("contrib/miekg/dns: Wrapping Handler") return &Handler{ Handler: handler, } @@ -122,7 +120,7 @@ func startSpan(ctx context.Context, opcode int) (*tracer.Span, context.Context) tracer.ServiceName("dns"), tracer.ResourceName(dns.OpcodeToString[opcode]), tracer.SpanType(ext.SpanTypeDNS), - tracer.Tag(ext.Component, componentName)) + tracer.Tag(ext.Component, instrumentation.PackageMiekgDNS)) } func startClientSpan(ctx context.Context, opcode int) (*tracer.Span, context.Context) { diff --git a/contrib/olivere/elastic.v5/elastictrace.go b/contrib/olivere/elastic.v5/elastictrace.go index 21d57d0cf5..99ac4a6a9f 100644 --- a/contrib/olivere/elastic.v5/elastictrace.go +++ b/contrib/olivere/elastic.v5/elastictrace.go @@ -20,15 +20,13 @@ import ( "github.com/DataDog/dd-trace-go/v2/ddtrace/ext" "github.com/DataDog/dd-trace-go/v2/ddtrace/tracer" - "github.com/DataDog/dd-trace-go/v2/internal/log" - "github.com/DataDog/dd-trace-go/v2/internal/telemetry" + "github.com/DataDog/dd-trace-go/v2/instrumentation" ) -const componentName = "olivere/elastic" +var instr *instrumentation.Instrumentation func init() { - telemetry.LoadIntegration(componentName) - tracer.MarkIntegrationImported("gopkg.in/olivere/elastic.v5") + instr = instrumentation.Load(instrumentation.PackageOlivereElasticV5) } // NewHTTPClient returns a new http.Client which traces requests under the given service name. @@ -38,7 +36,7 @@ func NewHTTPClient(opts ...ClientOption) *http.Client { for _, fn := range opts { fn.apply(cfg) } - log.Debug("contrib/olivere/elastic: Configuring HTTP Client: %#v", cfg) + instr.Logger().Debug("contrib/olivere/elastic: Configuring HTTP Client: %#v", cfg) return &http.Client{Transport: &httpTransport{config: cfg}} } @@ -62,7 +60,7 @@ func (t *httpTransport) RoundTrip(req *http.Request) (*http.Response, error) { tracer.Tag("elasticsearch.method", method), tracer.Tag("elasticsearch.url", url), tracer.Tag("elasticsearch.params", req.URL.Query().Encode()), - tracer.Tag(ext.Component, componentName), + tracer.Tag(ext.Component, instrumentation.PackageOlivereElasticV5), tracer.Tag(ext.SpanKind, ext.SpanKindClient), tracer.Tag(ext.DBSystem, ext.DBSystemElasticsearch), tracer.Tag(ext.NetworkDestinationName, req.URL.Hostname()), diff --git a/contrib/olivere/elastic.v5/elastictrace_test.go b/contrib/olivere/elastic.v5/elastictrace_test.go index f7982a0b67..53f7520aa1 100644 --- a/contrib/olivere/elastic.v5/elastictrace_test.go +++ b/contrib/olivere/elastic.v5/elastictrace_test.go @@ -16,11 +16,9 @@ import ( "github.com/DataDog/dd-trace-go/v2/ddtrace/ext" "github.com/DataDog/dd-trace-go/v2/ddtrace/mocktracer" - "github.com/DataDog/dd-trace-go/v2/internal/contrib/namingschematest" - "github.com/DataDog/dd-trace-go/v2/internal/globalconfig" + "github.com/DataDog/dd-trace-go/v2/instrumentation/testutils" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" "gopkg.in/olivere/elastic.v5" ) @@ -394,9 +392,7 @@ func TestAnalyticsSettings(t *testing.T) { mt := mocktracer.Start() defer mt.Stop() - rate := globalconfig.AnalyticsRate() - defer globalconfig.SetAnalyticsRate(rate) - globalconfig.SetAnalyticsRate(0.4) + testutils.SetGlobalAnalyticsRate(t, 0.4) assertRate(t, mt, 0.4) }) @@ -419,55 +415,8 @@ func TestAnalyticsSettings(t *testing.T) { mt := mocktracer.Start() defer mt.Stop() - rate := globalconfig.AnalyticsRate() - defer globalconfig.SetAnalyticsRate(rate) - globalconfig.SetAnalyticsRate(0.4) + testutils.SetGlobalAnalyticsRate(t, 0.4) assertRate(t, mt, 0.23, WithAnalyticsRate(0.23)) }) } - -func TestNamingSchema(t *testing.T) { - genSpans := func(t *testing.T, serviceOverride string) []*mocktracer.Span { - var opts []ClientOption - if serviceOverride != "" { - opts = append(opts, WithService(serviceOverride)) - } - mt := mocktracer.Start() - defer mt.Stop() - tc := NewHTTPClient(opts...) - client, err := elastic.NewClient( - elastic.SetURL(elasticURL), - elastic.SetHttpClient(tc), - elastic.SetSniff(false), - elastic.SetHealthcheck(false), - ) - require.NoError(t, err) - - _, err = client.Index(). - Index("twitter").Id("1"). - Type("tweet"). - BodyString(`{"user": "test", "message": "hello"}`). - Do(context.Background()) - require.NoError(t, err) - - spans := mt.FinishedSpans() - require.Len(t, spans, 1) - return spans - } - assertOpV0 := func(t *testing.T, spans []*mocktracer.Span) { - require.Len(t, spans, 1) - assert.Equal(t, "elasticsearch.query", spans[0].OperationName()) - } - assertOpV1 := func(t *testing.T, spans []*mocktracer.Span) { - require.Len(t, spans, 1) - assert.Equal(t, "elasticsearch.query", spans[0].OperationName()) - } - wantServiceNameV0 := namingschematest.ServiceNameAssertions{ - WithDefaults: []string{"elastic.client"}, - WithDDService: []string{"elastic.client"}, - WithDDServiceAndOverride: []string{namingschematest.TestServiceOverride}, - } - t.Run("ServiceName", namingschematest.NewServiceNameTest(genSpans, wantServiceNameV0)) - t.Run("SpanName", namingschematest.NewSpanNameTest(genSpans, assertOpV0, assertOpV1)) -} diff --git a/contrib/olivere/elastic.v5/option.go b/contrib/olivere/elastic.v5/option.go index dcb3ee54f1..37e10b8819 100644 --- a/contrib/olivere/elastic.v5/option.go +++ b/contrib/olivere/elastic.v5/option.go @@ -9,12 +9,9 @@ import ( "math" "net/http" - "github.com/DataDog/dd-trace-go/v2/internal" - "github.com/DataDog/dd-trace-go/v2/internal/namingschema" + "github.com/DataDog/dd-trace-go/v2/instrumentation" ) -const defaultServiceName = "elastic.client" - type clientConfig struct { serviceName string spanName string @@ -36,16 +33,11 @@ func (fn ClientOptionFn) apply(cfg *clientConfig) { } func defaults(cfg *clientConfig) { - cfg.serviceName = namingschema.ServiceNameOverrideV0(defaultServiceName, defaultServiceName) - cfg.spanName = namingschema.OpName(namingschema.ElasticSearchOutbound) + cfg.serviceName = instr.ServiceName(instrumentation.ComponentDefault, nil) + cfg.spanName = instr.OperationName(instrumentation.ComponentDefault, nil) cfg.transport = http.DefaultTransport.(*http.Transport) cfg.resourceNamer = quantize - // cfg.analyticsRate = globalconfig.AnalyticsRate() - if internal.BoolEnv("DD_TRACE_ELASTIC_ANALYTICS_ENABLED", false) { - cfg.analyticsRate = 1.0 - } else { - cfg.analyticsRate = math.NaN() - } + cfg.analyticsRate = instr.AnalyticsRate(false) } // WithService sets the given service name for the client. diff --git a/contrib/redis/go-redis.v9/option.go b/contrib/redis/go-redis.v9/option.go index d91b2ff3ad..eb690a8a0d 100644 --- a/contrib/redis/go-redis.v9/option.go +++ b/contrib/redis/go-redis.v9/option.go @@ -8,12 +8,9 @@ package redis import ( "math" - "github.com/DataDog/dd-trace-go/v2/internal" - "github.com/DataDog/dd-trace-go/v2/internal/namingschema" + "github.com/DataDog/dd-trace-go/v2/instrumentation" ) -const defaultServiceName = "redis.client" - type clientConfig struct { serviceName string spanName string @@ -35,14 +32,9 @@ func (fn ClientOptionFn) apply(cfg *clientConfig) { } func defaults(cfg *clientConfig) { - cfg.serviceName = namingschema.ServiceNameOverrideV0(defaultServiceName, defaultServiceName) - cfg.spanName = namingschema.OpName(namingschema.RedisOutbound) - // cfg.analyticsRate = globalconfig.AnalyticsRate() - if internal.BoolEnv("DD_TRACE_REDIS_ANALYTICS_ENABLED", false) { - cfg.analyticsRate = 1.0 - } else { - cfg.analyticsRate = math.NaN() - } + cfg.serviceName = instr.ServiceName(instrumentation.ComponentDefault, nil) + cfg.spanName = instr.OperationName(instrumentation.ComponentDefault, nil) + cfg.analyticsRate = instr.AnalyticsRate(false) cfg.errCheck = func(error) bool { return true } } diff --git a/contrib/redis/go-redis.v9/redis.go b/contrib/redis/go-redis.v9/redis.go index f784d89121..546fe4c7ac 100644 --- a/contrib/redis/go-redis.v9/redis.go +++ b/contrib/redis/go-redis.v9/redis.go @@ -16,16 +16,15 @@ import ( "github.com/DataDog/dd-trace-go/v2/ddtrace/ext" "github.com/DataDog/dd-trace-go/v2/ddtrace/tracer" - "github.com/DataDog/dd-trace-go/v2/internal/telemetry" + "github.com/DataDog/dd-trace-go/v2/instrumentation" "github.com/redis/go-redis/v9" ) -const componentName = "redis/go-redis.v9" +var instr *instrumentation.Instrumentation func init() { - telemetry.LoadIntegration(componentName) - tracer.MarkIntegrationImported("github.com/redis/go-redis/v9") + instr = instrumentation.Load(instrumentation.PackageRedisGoRedisV9) } type datadogHook struct { @@ -102,7 +101,7 @@ func additionalTagOptions(client redis.UniversalClient) []tracer.StartSpanOption } additionalTags = append(additionalTags, tracer.SpanType(ext.SpanTypeRedis), - tracer.Tag(ext.Component, componentName), + tracer.Tag(ext.Component, instrumentation.PackageRedisGoRedisV9), tracer.Tag(ext.SpanKind, ext.SpanKindClient), tracer.Tag(ext.DBSystem, ext.DBSystemRedis), ) diff --git a/contrib/redis/go-redis.v9/redis_test.go b/contrib/redis/go-redis.v9/redis_test.go index c7533c08a2..05feab0559 100644 --- a/contrib/redis/go-redis.v9/redis_test.go +++ b/contrib/redis/go-redis.v9/redis_test.go @@ -16,8 +16,8 @@ import ( "github.com/DataDog/dd-trace-go/v2/ddtrace/ext" "github.com/DataDog/dd-trace-go/v2/ddtrace/mocktracer" "github.com/DataDog/dd-trace-go/v2/ddtrace/tracer" - "github.com/DataDog/dd-trace-go/v2/internal/contrib/namingschematest" - "github.com/DataDog/dd-trace-go/v2/internal/globalconfig" + "github.com/DataDog/dd-trace-go/v2/instrumentation" + "github.com/DataDog/dd-trace-go/v2/instrumentation/testutils" "github.com/redis/go-redis/v9" "github.com/stretchr/testify/assert" @@ -234,7 +234,7 @@ func TestAdditionalTagsFromClient(t *testing.T) { simpleClient := redis.NewUniversalClient(simpleClientOpts) config := &tracer.StartSpanConfig{} expectedTags := map[string]interface{}{ - "component": "redis/go-redis.v9", + "component": instrumentation.PackageRedisGoRedisV9, "db.system": "redis", "out.db": "0", "out.host": "127.0.0.1", @@ -261,7 +261,7 @@ func TestAdditionalTagsFromClient(t *testing.T) { config := &tracer.StartSpanConfig{} expectedTags := map[string]interface{}{ "out.db": "0", - "component": "redis/go-redis.v9", + "component": instrumentation.PackageRedisGoRedisV9, "db.system": "redis", "span.kind": "client", "span.type": "redis", @@ -285,7 +285,7 @@ func TestAdditionalTagsFromClient(t *testing.T) { config := &tracer.StartSpanConfig{} expectedTags := map[string]interface{}{ "addrs": "127.0.0.1:6379, 127.0.0.2:6379", - "component": "redis/go-redis.v9", + "component": instrumentation.PackageRedisGoRedisV9, "db.system": "redis", "span.kind": "client", "span.type": "redis", @@ -577,9 +577,7 @@ func TestAnalyticsSettings(t *testing.T) { mt := mocktracer.Start() defer mt.Stop() - rate := globalconfig.AnalyticsRate() - defer globalconfig.SetAnalyticsRate(rate) - globalconfig.SetAnalyticsRate(0.4) + testutils.SetGlobalAnalyticsRate(t, 0.4) assertRate(t, mt, 0.4) }) @@ -602,9 +600,7 @@ func TestAnalyticsSettings(t *testing.T) { mt := mocktracer.Start() defer mt.Stop() - rate := globalconfig.AnalyticsRate() - defer globalconfig.SetAnalyticsRate(rate) - globalconfig.SetAnalyticsRate(0.4) + testutils.SetGlobalAnalyticsRate(t, 0.4) assertRate(t, mt, 0.23, WithAnalyticsRate(0.23)) }) @@ -687,31 +683,3 @@ func TestDial(t *testing.T) { assert.Equal(ext.SpanKindClient, span.Tag(ext.SpanKind)) assert.Equal("redis", span.Tag(ext.DBSystem)) } - -func TestNamingSchema(t *testing.T) { - genSpans := namingschematest.GenSpansFn(func(t *testing.T, serviceOverride string) []*mocktracer.Span { - var opts []ClientOption - if serviceOverride != "" { - opts = append(opts, WithService(serviceOverride)) - } - mt := mocktracer.Start() - defer mt.Stop() - - client := NewClient(&redis.Options{Addr: "127.0.0.1:6379"}, opts...) - st := client.Set(context.Background(), "test_key", "test_value", 0) - require.NoError(t, st.Err()) - - spans := mt.FinishedSpans() - var span *mocktracer.Span - for _, s := range spans { - // pick up the redis.command span except dial - if s.OperationName() == "redis.command" { - span = s - } - } - assert.NotNil(t, span) - return []*mocktracer.Span{span} - }) - - namingschematest.NewRedisTest(genSpans, "redis.client")(t) -} diff --git a/contrib/segmentio/kafka-go/kafka.go b/contrib/segmentio/kafka-go/kafka.go index 5c68238b77..0432813c06 100644 --- a/contrib/segmentio/kafka-go/kafka.go +++ b/contrib/segmentio/kafka-go/kafka.go @@ -14,17 +14,15 @@ import ( "github.com/DataDog/dd-trace-go/v2/datastreams/options" "github.com/DataDog/dd-trace-go/v2/ddtrace/ext" "github.com/DataDog/dd-trace-go/v2/ddtrace/tracer" - "github.com/DataDog/dd-trace-go/v2/internal/log" - "github.com/DataDog/dd-trace-go/v2/internal/telemetry" + "github.com/DataDog/dd-trace-go/v2/instrumentation" "github.com/segmentio/kafka-go" ) -const componentName = "segmentio/kafka.go.v0" +var instr *instrumentation.Instrumentation func init() { - telemetry.LoadIntegration(componentName) - tracer.MarkIntegrationImported("github.com/segmentio/kafka-go") + instr = instrumentation.Load(instrumentation.PackageSegmentioKafkaGo) } // NewReader calls kafka.NewReader and wraps the resulting Consumer. @@ -52,7 +50,7 @@ func WrapReader(c *kafka.Reader, opts ...Option) *Reader { wrapped.groupID = c.Config().GroupID } - log.Debug("contrib/segmentio/kafka-go.v0/kafka: Wrapping Reader: %#v", wrapped.cfg) + instr.Logger().Debug("contrib/segmentio/kafka-go.v0/kafka: Wrapping Reader: %#v", wrapped.cfg) return wrapped } @@ -77,7 +75,7 @@ func (r *Reader) startSpan(ctx context.Context, msg *kafka.Message) *tracer.Span tracer.SpanType(ext.SpanTypeMessageConsumer), tracer.Tag(ext.MessagingKafkaPartition, msg.Partition), tracer.Tag("offset", msg.Offset), - tracer.Tag(ext.Component, componentName), + tracer.Tag(ext.Component, instrumentation.PackageSegmentioKafkaGo), tracer.Tag(ext.SpanKind, ext.SpanKindConsumer), tracer.Tag(ext.MessagingSystem, ext.MessagingSystemKafka), tracer.Tag(ext.KafkaBootstrapServers, r.bootstrapServers), @@ -95,7 +93,7 @@ func (r *Reader) startSpan(ctx context.Context, msg *kafka.Message) *tracer.Span span, _ := tracer.StartSpanFromContext(ctx, r.cfg.consumerSpanName, opts...) // reinject the span context so consumers can pick it up if err := tracer.Inject(span.Context(), carrier); err != nil { - log.Debug("contrib/segmentio/kafka-go: Failed to inject span context into carrier in reader, %v", err) + instr.Logger().Debug("contrib/segmentio/kafka-go: Failed to inject span context into carrier in reader, %v", err) } return span } @@ -176,7 +174,7 @@ func WrapWriter(w *kafka.Writer, opts ...Option) *Writer { if w.Addr.String() != "" { writer.bootstrapServers = w.Addr.String() } - log.Debug("contrib/segmentio/kafka-go: Wrapping Writer: %#v", writer.cfg) + instr.Logger().Debug("contrib/segmentio/kafka-go: Wrapping Writer: %#v", writer.cfg) return writer } @@ -191,7 +189,7 @@ func (w *Writer) startSpan(ctx context.Context, msg *kafka.Message) *tracer.Span opts := []tracer.StartSpanOption{ tracer.ServiceName(w.cfg.producerServiceName), tracer.SpanType(ext.SpanTypeMessageProducer), - tracer.Tag(ext.Component, componentName), + tracer.Tag(ext.Component, instrumentation.PackageSegmentioKafkaGo), tracer.Tag(ext.SpanKind, ext.SpanKindProducer), tracer.Tag(ext.MessagingSystem, ext.MessagingSystemKafka), tracer.Tag(ext.KafkaBootstrapServers, w.bootstrapServers), @@ -207,7 +205,7 @@ func (w *Writer) startSpan(ctx context.Context, msg *kafka.Message) *tracer.Span carrier := messageCarrier{msg} span, _ := tracer.StartSpanFromContext(ctx, w.cfg.producerSpanName, opts...) if err := tracer.Inject(span.Context(), carrier); err != nil { - log.Debug("contrib/segmentio/kafka-go: Failed to inject span context into carrier in writer, %v", err) + instr.Logger().Debug("contrib/segmentio/kafka-go: Failed to inject span context into carrier in writer, %v", err) } return span } diff --git a/contrib/segmentio/kafka-go/kafka_test.go b/contrib/segmentio/kafka-go/kafka_test.go index 97ece3eab8..836ac02ef6 100644 --- a/contrib/segmentio/kafka-go/kafka_test.go +++ b/contrib/segmentio/kafka-go/kafka_test.go @@ -15,7 +15,6 @@ import ( "github.com/DataDog/dd-trace-go/v2/ddtrace/ext" "github.com/DataDog/dd-trace-go/v2/ddtrace/mocktracer" "github.com/DataDog/dd-trace-go/v2/ddtrace/tracer" - "github.com/DataDog/dd-trace-go/v2/internal/contrib/namingschematest" kafka "github.com/segmentio/kafka-go" "github.com/stretchr/testify/assert" @@ -240,48 +239,6 @@ func TestFetchMessageFunctional(t *testing.T) { assert.Equal(t, expected.GetHash(), p.GetHash()) } -func TestNamingSchema(t *testing.T) { - genSpans := func(t *testing.T, serviceOverride string) []*mocktracer.Span { - var opts []Option - if serviceOverride != "" { - opts = append(opts, WithService(serviceOverride)) - } - - mt := mocktracer.Start() - defer mt.Stop() - - messagesToWrite := []kafka.Message{ - { - Key: []byte("key1"), - Value: []byte("value1"), - }, - } - - spans, _ := genIntegrationTestSpans( - t, - mt, - func(t *testing.T, w *Writer) { - err := w.WriteMessages(context.Background(), messagesToWrite...) - require.NoError(t, err, "Expected to write message to topic") - }, - func(t *testing.T, r *Reader) { - ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) - defer cancel() - readMsg, err := r.FetchMessage(ctx) - require.NoError(t, err, "Expected to consume message") - assert.Equal(t, messagesToWrite[0].Value, readMsg.Value, "Values should be equal") - - err = r.CommitMessages(context.Background(), readMsg) - assert.NoError(t, err, "Expected CommitMessages to not return an error") - }, - opts, - opts, - ) - return spans - } - namingschematest.NewKafkaTest(genSpans)(t) -} - func BenchmarkReaderStartSpan(b *testing.B) { r := NewReader(kafka.ReaderConfig{ Brokers: []string{"localhost:9092", "localhost:9093", "localhost:9094"}, diff --git a/contrib/segmentio/kafka-go/option.go b/contrib/segmentio/kafka-go/option.go index f02e6552ef..a43d06daa0 100644 --- a/contrib/segmentio/kafka-go/option.go +++ b/contrib/segmentio/kafka-go/option.go @@ -8,12 +8,9 @@ package kafka import ( "math" - "github.com/DataDog/dd-trace-go/v2/internal" - "github.com/DataDog/dd-trace-go/v2/internal/namingschema" + "github.com/DataDog/dd-trace-go/v2/instrumentation" ) -const defaultServiceName = "kafka" - type config struct { consumerServiceName string producerServiceName string @@ -37,19 +34,15 @@ func (fn OptionFn) apply(cfg *config) { func newConfig(opts ...Option) *config { cfg := &config{ - // analyticsRate: globalconfig.AnalyticsRate(), - analyticsRate: math.NaN(), - } - if internal.BoolEnv("DD_TRACE_KAFKA_ANALYTICS_ENABLED", false) { - cfg.analyticsRate = 1.0 + analyticsRate: instr.AnalyticsRate(false), } - cfg.dataStreamsEnabled = internal.BoolEnv("DD_DATA_STREAMS_ENABLED", false) + cfg.dataStreamsEnabled = instr.DataStreamsEnabled() - cfg.consumerServiceName = namingschema.ServiceName(defaultServiceName) - cfg.producerServiceName = namingschema.ServiceNameOverrideV0(defaultServiceName, defaultServiceName) - cfg.consumerSpanName = namingschema.OpName(namingschema.KafkaInbound) - cfg.producerSpanName = namingschema.OpName(namingschema.KafkaOutbound) + cfg.consumerServiceName = instr.ServiceName(instrumentation.ComponentConsumer, nil) + cfg.producerServiceName = instr.ServiceName(instrumentation.ComponentProducer, nil) + cfg.consumerSpanName = instr.OperationName(instrumentation.ComponentConsumer, nil) + cfg.producerSpanName = instr.OperationName(instrumentation.ComponentProducer, nil) for _, opt := range opts { opt.apply(cfg) diff --git a/contrib/segmentio/kafka-go/option_test.go b/contrib/segmentio/kafka-go/option_test.go index dcc930a252..43147f6ee1 100644 --- a/contrib/segmentio/kafka-go/option_test.go +++ b/contrib/segmentio/kafka-go/option_test.go @@ -9,7 +9,7 @@ import ( "math" "testing" - "github.com/DataDog/dd-trace-go/v2/internal/globalconfig" + "github.com/DataDog/dd-trace-go/v2/instrumentation/testutils" "github.com/stretchr/testify/assert" ) @@ -22,9 +22,7 @@ func TestAnalyticsSettings(t *testing.T) { t.Run("global", func(t *testing.T) { t.Skip("global flag disabled") - rate := globalconfig.AnalyticsRate() - defer globalconfig.SetAnalyticsRate(rate) - globalconfig.SetAnalyticsRate(0.4) + testutils.SetGlobalAnalyticsRate(t, 0.4) cfg := newConfig() assert.Equal(t, 0.4, cfg.analyticsRate) @@ -36,9 +34,7 @@ func TestAnalyticsSettings(t *testing.T) { }) t.Run("override", func(t *testing.T) { - rate := globalconfig.AnalyticsRate() - defer globalconfig.SetAnalyticsRate(rate) - globalconfig.SetAnalyticsRate(0.4) + testutils.SetGlobalAnalyticsRate(t, 0.4) cfg := newConfig(WithAnalyticsRate(0.2)) assert.Equal(t, 0.2, cfg.analyticsRate) diff --git a/instrumentation/internal/namingschematest/gorilla_mux.go b/instrumentation/internal/namingschematest/gorilla_mux.go new file mode 100644 index 0000000000..131e4ba60f --- /dev/null +++ b/instrumentation/internal/namingschematest/gorilla_mux.go @@ -0,0 +1,50 @@ +package namingschematest + +import ( + "net/http" + "net/http/httptest" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + muxtrace "github.com/DataDog/dd-trace-go/contrib/gorilla/mux/v2" + "github.com/DataDog/dd-trace-go/instrumentation/internal/namingschematest/harness" + "github.com/DataDog/dd-trace-go/v2/ddtrace/mocktracer" + "github.com/DataDog/dd-trace-go/v2/instrumentation" +) + +var gorillaMux = harness.TestCase{ + Name: instrumentation.PackageGinGonicGin, + GenSpans: func(t *testing.T, serviceOverride string) []*mocktracer.Span { + var opts []muxtrace.RouterOption + if serviceOverride != "" { + opts = append(opts, muxtrace.WithService(serviceOverride)) + } + mt := mocktracer.Start() + defer mt.Stop() + + mux := muxtrace.NewRouter(opts...) + mux.Handle("/200", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte("200!\n")) + })) + req := httptest.NewRequest("GET", "/200", nil) + w := httptest.NewRecorder() + mux.ServeHTTP(w, req) + + return mt.FinishedSpans() + }, + WantServiceNameV0: harness.ServiceNameAssertions{ + Defaults: []string{"mux.router"}, + DDService: []string{harness.TestDDService}, + ServiceOverride: []string{harness.TestServiceOverride}, + }, + AssertOpV0: func(t *testing.T, spans []*mocktracer.Span) { + require.Len(t, spans, 1) + assert.Equal(t, "http.request", spans[0].OperationName()) + }, + AssertOpV1: func(t *testing.T, spans []*mocktracer.Span) { + require.Len(t, spans, 1) + assert.Equal(t, "http.server.request", spans[0].OperationName()) + }, +} diff --git a/instrumentation/internal/namingschematest/graphgophers_graphql.go b/instrumentation/internal/namingschematest/graphgophers_graphql.go new file mode 100644 index 0000000000..3588031da4 --- /dev/null +++ b/instrumentation/internal/namingschematest/graphgophers_graphql.go @@ -0,0 +1,77 @@ +package namingschematest + +import ( + "net/http" + "net/http/httptest" + "strings" + "testing" + + "github.com/graph-gophers/graphql-go" + "github.com/graph-gophers/graphql-go/relay" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + grahqltrace "github.com/DataDog/dd-trace-go/contrib/graph-gophers/graphql-go/v2" + "github.com/DataDog/dd-trace-go/instrumentation/internal/namingschematest/harness" + "github.com/DataDog/dd-trace-go/v2/ddtrace/mocktracer" + "github.com/DataDog/dd-trace-go/v2/instrumentation" +) + +type testResolver struct{} + +func (*testResolver) Hello() string { return "Hello, world!" } +func (*testResolver) HelloNonTrivial() (string, error) { return "Hello, world!", nil } + +const testServerSchema = ` + schema { + query: Query + } + type Query { + hello: String! + helloNonTrivial: String! + } +` + +func newTestServer(opts ...grahqltrace.Option) *httptest.Server { + schema := graphql.MustParseSchema(testServerSchema, new(testResolver), graphql.Tracer(grahqltrace.NewTracer(opts...))) + return httptest.NewServer(&relay.Handler{Schema: schema}) +} + +func graphGophersGraphQLGoGenSpans() harness.GenSpansFn { + return func(t *testing.T, serviceOverride string) []*mocktracer.Span { + var opts []grahqltrace.Option + if serviceOverride != "" { + opts = append(opts, grahqltrace.WithService(serviceOverride)) + } + mt := mocktracer.Start() + defer mt.Stop() + + srv := newTestServer(opts...) + defer srv.Close() + resp, err := http.Post(srv.URL, "application/json", strings.NewReader(`{"query": "{ hello }"}`)) + require.NoError(t, err) + defer resp.Body.Close() + + return mt.FinishedSpans() + } +} + +var graphGophersGraphQLGo = harness.TestCase{ + Name: instrumentation.PackageGraphGophersGraphQLGo, + GenSpans: graphGophersGraphQLGoGenSpans(), + WantServiceNameV0: harness.ServiceNameAssertions{ + Defaults: harness.RepeatString("graphql", 2), + DDService: harness.RepeatString(harness.TestDDService, 2), + ServiceOverride: harness.RepeatString(harness.TestServiceOverride, 2), + }, + AssertOpV0: func(t *testing.T, spans []*mocktracer.Span) { + require.Len(t, spans, 2) + assert.Equal(t, "graphql.field", spans[0].OperationName()) + assert.Equal(t, "graphql.request", spans[1].OperationName()) + }, + AssertOpV1: func(t *testing.T, spans []*mocktracer.Span) { + require.Len(t, spans, 2) + assert.Equal(t, "graphql.field", spans[0].OperationName()) + assert.Equal(t, "graphql.server.request", spans[1].OperationName()) + }, +} diff --git a/instrumentation/internal/namingschematest/hashicorp_consul.go b/instrumentation/internal/namingschematest/hashicorp_consul.go new file mode 100644 index 0000000000..8c2b5f7ec3 --- /dev/null +++ b/instrumentation/internal/namingschematest/hashicorp_consul.go @@ -0,0 +1,55 @@ +package namingschematest + +import ( + "testing" + + consul "github.com/hashicorp/consul/api" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + consultrace "github.com/DataDog/dd-trace-go/contrib/hashicorp/consul/v2" + "github.com/DataDog/dd-trace-go/instrumentation/internal/namingschematest/harness" + "github.com/DataDog/dd-trace-go/v2/ddtrace/mocktracer" + "github.com/DataDog/dd-trace-go/v2/instrumentation" +) + +func hashicorpConsulGenSpans() harness.GenSpansFn { + return func(t *testing.T, serviceOverride string) []*mocktracer.Span { + var opts []consultrace.ClientOption + if serviceOverride != "" { + opts = append(opts, consultrace.WithService(serviceOverride)) + } + + mt := mocktracer.Start() + defer mt.Stop() + client, err := consultrace.NewClient(consul.DefaultConfig(), opts...) + require.NoError(t, err) + kv := client.KV() + + pair := &consul.KVPair{Key: "test.key", Value: []byte("test_value")} + _, err = kv.Put(pair, nil) + require.NoError(t, err) + + spans := mt.FinishedSpans() + require.Len(t, spans, 1) + return spans + } +} + +var hashicorpConsul = harness.TestCase{ + Name: instrumentation.PackageHashicorpConsulAPI, + GenSpans: hashicorpConsulGenSpans(), + WantServiceNameV0: harness.ServiceNameAssertions{ + Defaults: []string{"consul"}, + DDService: []string{"consul"}, + ServiceOverride: []string{harness.TestServiceOverride}, + }, + AssertOpV0: func(t *testing.T, spans []*mocktracer.Span) { + require.Len(t, spans, 1) + assert.Equal(t, "consul.command", spans[0].OperationName()) + }, + AssertOpV1: func(t *testing.T, spans []*mocktracer.Span) { + require.Len(t, spans, 1) + assert.Equal(t, "consul.query", spans[0].OperationName()) + }, +} diff --git a/instrumentation/internal/namingschematest/hashicorp_vault.go b/instrumentation/internal/namingschematest/hashicorp_vault.go new file mode 100644 index 0000000000..24707141cb --- /dev/null +++ b/instrumentation/internal/namingschematest/hashicorp_vault.go @@ -0,0 +1,118 @@ +package namingschematest + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "net/http/httptest" + "testing" + + "github.com/hashicorp/vault/api" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + vaulttrace "github.com/DataDog/dd-trace-go/contrib/hashicorp/vault/v2" + "github.com/DataDog/dd-trace-go/instrumentation/internal/namingschematest/harness" + "github.com/DataDog/dd-trace-go/v2/ddtrace/mocktracer" + "github.com/DataDog/dd-trace-go/v2/instrumentation" +) + +const secretMountPath = "/ns1/ns2/secret" + +func hashicorpVaultGenSpans() harness.GenSpansFn { + return func(t *testing.T, serviceOverride string) []*mocktracer.Span { + var opts []vaulttrace.Option + if serviceOverride != "" { + opts = append(opts, vaulttrace.WithService(serviceOverride)) + } + + mt := mocktracer.Start() + defer mt.Stop() + + ts, cleanup := setupServer(t) + defer cleanup() + + client, err := api.NewClient(&api.Config{ + HttpClient: vaulttrace.NewHTTPClient(opts...), + Address: ts.URL, + }) + require.NoError(t, err) + if err != nil { + t.Fatal(err) + } + defer mountKV(client, t)() + + // Write key with namespace first + data := map[string]interface{}{"Key1": "Val1", "Key2": "Val2"} + _, err = client.Logical().Write("/some/path", data) + require.NoError(t, err) + + return mt.FinishedSpans() + } +} + +func setupServer(t *testing.T) (*httptest.Server, func()) { + storage := make(map[string]string) + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.Method { + case http.MethodPut: + slurp, err := io.ReadAll(r.Body) + if err != nil { + t.Fatal(err) + } + defer r.Body.Close() + storage[r.URL.Path] = string(slurp) + fmt.Fprintln(w, "{}") + case http.MethodGet: + val, ok := storage[r.URL.Path] + if !ok { + http.Error(w, "No data for key.", http.StatusNotFound) + return + } + secret := api.Secret{Data: make(map[string]interface{})} + json.Unmarshal([]byte(val), &secret.Data) + if err := json.NewEncoder(w).Encode(secret); err != nil { + t.Fatal(err) + } + } + })) + return ts, func() { + ts.Close() + } +} + +// mountKV mounts the K/V engine on secretMountPath and returns a function to unmount it. +// See: https://www.vaultproject.io/docs/secrets/ +func mountKV(c *api.Client, t *testing.T) func() { + secretMount := api.MountInput{ + Type: "kv", + Description: "Test KV Store", + Local: true, + } + if err := c.Sys().Mount(secretMountPath, &secretMount); err != nil { + t.Fatal(err) + } + return func() { + c.Sys().Unmount(secretMountPath) + } +} + +var hashicorpVault = harness.TestCase{ + Name: instrumentation.PackageHashicorpVaultAPI, + GenSpans: hashicorpVaultGenSpans(), + WantServiceNameV0: harness.ServiceNameAssertions{ + Defaults: harness.RepeatString("vault", 2), + DDService: harness.RepeatString("vault", 2), + ServiceOverride: harness.RepeatString(harness.TestServiceOverride, 2), + }, + AssertOpV0: func(t *testing.T, spans []*mocktracer.Span) { + require.Len(t, spans, 2) + // According to v1 tests, this should be "http.request" + assert.Equal(t, "vault.command", spans[0].OperationName()) + }, + AssertOpV1: func(t *testing.T, spans []*mocktracer.Span) { + require.Len(t, spans, 2) + assert.Equal(t, "vault.query", spans[0].OperationName()) + }, +} diff --git a/instrumentation/internal/namingschematest/ibm_sarama.go b/instrumentation/internal/namingschematest/ibm_sarama.go new file mode 100644 index 0000000000..df2e9a944c --- /dev/null +++ b/instrumentation/internal/namingschematest/ibm_sarama.go @@ -0,0 +1,98 @@ +package namingschematest + +import ( + "testing" + + saramatrace "github.com/DataDog/dd-trace-go/contrib/IBM/sarama/v2" + "github.com/DataDog/dd-trace-go/instrumentation/internal/namingschematest/harness" + "github.com/DataDog/dd-trace-go/v2/ddtrace/mocktracer" + "github.com/DataDog/dd-trace-go/v2/instrumentation" + "github.com/IBM/sarama" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func ibmSaramaGenSpans() harness.GenSpansFn { + return func(t *testing.T, serviceOverride string) []*mocktracer.Span { + var opts []saramatrace.Option + if serviceOverride != "" { + opts = append(opts, saramatrace.WithService(serviceOverride)) + } + mt := mocktracer.Start() + defer mt.Stop() + + broker := sarama.NewMockBroker(t, 1) + defer broker.Close() + + broker.SetHandlerByMap(map[string]sarama.MockResponse{ + "MetadataRequest": sarama.NewMockMetadataResponse(t). + SetBroker(broker.Addr(), broker.BrokerID()). + SetLeader("test-topic", 0, broker.BrokerID()), + "OffsetRequest": sarama.NewMockOffsetResponse(t). + SetOffset("test-topic", 0, sarama.OffsetOldest, 0). + SetOffset("test-topic", 0, sarama.OffsetNewest, 1), + "FetchRequest": sarama.NewMockFetchResponse(t, 1). + SetMessage("test-topic", 0, 0, sarama.StringEncoder("hello")), + "ProduceRequest": sarama.NewMockProduceResponse(t). + SetError("test-topic", 0, sarama.ErrNoError), + }) + cfg := sarama.NewConfig() + cfg.Version = sarama.MinVersion + cfg.Producer.Return.Successes = true + cfg.Producer.Flush.Messages = 1 + + producer, err := sarama.NewSyncProducer([]string{broker.Addr()}, cfg) + require.NoError(t, err) + producer = saramatrace.WrapSyncProducer(cfg, producer, opts...) + + c, err := sarama.NewConsumer([]string{broker.Addr()}, cfg) + require.NoError(t, err) + defer func(c sarama.Consumer) { + err := c.Close() + require.NoError(t, err) + }(c) + c = saramatrace.WrapConsumer(c, opts...) + + msg1 := &sarama.ProducerMessage{ + Topic: "test-topic", + Value: sarama.StringEncoder("test 1"), + Metadata: "test", + } + _, _, err = producer.SendMessage(msg1) + require.NoError(t, err) + + pc, err := c.ConsumePartition("test-topic", 0, 0) + if err != nil { + t.Fatal(err) + } + _ = <-pc.Messages() + err = pc.Close() + require.NoError(t, err) + // wait for the channel to be closed + <-pc.Messages() + + spans := mt.FinishedSpans() + require.Len(t, spans, 2) + return spans + } +} + +var ibmSarama = harness.TestCase{ + Name: instrumentation.PackageIBMSarama, + GenSpans: ibmSaramaGenSpans(), + WantServiceNameV0: harness.ServiceNameAssertions{ + Defaults: harness.RepeatString("kafka", 2), + DDService: []string{"kafka", harness.TestDDService}, + ServiceOverride: harness.RepeatString(harness.TestServiceOverride, 2), + }, + AssertOpV0: func(t *testing.T, spans []*mocktracer.Span) { + require.Len(t, spans, 2) + assert.Equal(t, "kafka.produce", spans[0].OperationName()) + assert.Equal(t, "kafka.consume", spans[1].OperationName()) + }, + AssertOpV1: func(t *testing.T, spans []*mocktracer.Span) { + require.Len(t, spans, 2) + assert.Equal(t, "kafka.send", spans[0].OperationName()) + assert.Equal(t, "kafka.process", spans[1].OperationName()) + }, +} diff --git a/instrumentation/internal/namingschematest/julienschmidt_httprouter.go b/instrumentation/internal/namingschematest/julienschmidt_httprouter.go new file mode 100644 index 0000000000..38add00111 --- /dev/null +++ b/instrumentation/internal/namingschematest/julienschmidt_httprouter.go @@ -0,0 +1,56 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the Apache License Version 2.0. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2024 Datadog, Inc. + +package namingschematest + +import ( + "net/http" + "net/http/httptest" + "testing" + + "github.com/julienschmidt/httprouter" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + httproutertrace "github.com/DataDog/dd-trace-go/contrib/julienschmidt/httprouter/v2" + "github.com/DataDog/dd-trace-go/instrumentation/internal/namingschematest/harness" + "github.com/DataDog/dd-trace-go/v2/ddtrace/mocktracer" + "github.com/DataDog/dd-trace-go/v2/instrumentation" +) + +var julienschmidtHTTPRouter = harness.TestCase{ + Name: instrumentation.PackageNetHTTP + "_server", + GenSpans: func(t *testing.T, serviceOverride string) []*mocktracer.Span { + var opts []httproutertrace.RouterOption + if serviceOverride != "" { + opts = append(opts, httproutertrace.WithService(serviceOverride)) + } + mt := mocktracer.Start() + defer mt.Stop() + + mux := httproutertrace.New(opts...) + mux.GET("/200", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + w.Write([]byte("OK\n")) + }) + r := httptest.NewRequest("GET", "/200", nil) + w := httptest.NewRecorder() + mux.ServeHTTP(w, r) + + return mt.FinishedSpans() + }, + WantServiceNameV0: harness.ServiceNameAssertions{ + Defaults: []string{"http.router"}, + DDService: []string{harness.TestDDService}, + ServiceOverride: []string{harness.TestServiceOverride}, + }, + AssertOpV0: func(t *testing.T, spans []*mocktracer.Span) { + require.Len(t, spans, 1) + assert.Equal(t, "http.request", spans[0].OperationName()) + }, + AssertOpV1: func(t *testing.T, spans []*mocktracer.Span) { + require.Len(t, spans, 1) + assert.Equal(t, "http.server.request", spans[0].OperationName()) + }, +} diff --git a/instrumentation/internal/namingschematest/labstack_echo_v4.go b/instrumentation/internal/namingschematest/labstack_echo_v4.go new file mode 100644 index 0000000000..d3a8a7964f --- /dev/null +++ b/instrumentation/internal/namingschematest/labstack_echo_v4.go @@ -0,0 +1,56 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the Apache License Version 2.0. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2024 Datadog, Inc. + +package namingschematest + +import ( + "net/http/httptest" + "testing" + + "github.com/labstack/echo/v4" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + echotrace "github.com/DataDog/dd-trace-go/contrib/labstack/echo.v4/v2" + "github.com/DataDog/dd-trace-go/instrumentation/internal/namingschematest/harness" + "github.com/DataDog/dd-trace-go/v2/ddtrace/mocktracer" + "github.com/DataDog/dd-trace-go/v2/instrumentation" +) + +var labstackEchoV4 = harness.TestCase{ + Name: instrumentation.PackageNetHTTP + "_server", + GenSpans: func(t *testing.T, serviceOverride string) []*mocktracer.Span { + var opts []echotrace.OptionFn + if serviceOverride != "" { + opts = append(opts, echotrace.WithService(serviceOverride)) + } + mt := mocktracer.Start() + defer mt.Stop() + + mux := echo.New() + mux.Use(echotrace.Middleware(opts...)) + mux.GET("/200", func(c echo.Context) error { + return c.NoContent(200) + }) + r := httptest.NewRequest("GET", "/200", nil) + w := httptest.NewRecorder() + mux.ServeHTTP(w, r) + + return mt.FinishedSpans() + }, + WantServiceNameV0: harness.ServiceNameAssertions{ + Defaults: []string{"http.router"}, + DDService: []string{harness.TestDDService}, + ServiceOverride: []string{harness.TestServiceOverride}, + }, + AssertOpV0: func(t *testing.T, spans []*mocktracer.Span) { + require.Len(t, spans, 1) + assert.Equal(t, "http.request", spans[0].OperationName()) + }, + AssertOpV1: func(t *testing.T, spans []*mocktracer.Span) { + require.Len(t, spans, 1) + assert.Equal(t, "http.server.request", spans[0].OperationName()) + }, +} diff --git a/instrumentation/internal/namingschematest/main_test.go b/instrumentation/internal/namingschematest/main_test.go index e3adebe98a..1e731d51e0 100644 --- a/instrumentation/internal/namingschematest/main_test.go +++ b/instrumentation/internal/namingschematest/main_test.go @@ -6,12 +6,16 @@ package namingschematest import ( + "os" "testing" "github.com/DataDog/dd-trace-go/instrumentation/internal/namingschematest/harness" ) func TestNamingSchema(t *testing.T) { + if _, ok := os.LookupEnv("INTEGRATION"); !ok { + t.Skip("🚧 Skipping integration test (INTEGRATION environment variable is not set)") + } testCases := []harness.TestCase{ gqlgen, awsSDKV1, @@ -48,6 +52,16 @@ func TestNamingSchema(t *testing.T) { tidwallBuntDB, syndtrGoLevelDB, shopifySarama, + segmentioKafkaGo, + redisGoRedisV9, + olivereElasticV5, + labstackEchoV4, + julienschmidtHTTPRouter, + ibmSarama, + hashicorpConsul, + hashicorpVault, + graphGophersGraphQLGo, + gorillaMux, } for _, tc := range testCases { harness.RunTest(t, tc) diff --git a/instrumentation/internal/namingschematest/net_http_test.go b/instrumentation/internal/namingschematest/net_http_test.go index 6a4b21e630..0b4e859146 100644 --- a/instrumentation/internal/namingschematest/net_http_test.go +++ b/instrumentation/internal/namingschematest/net_http_test.go @@ -31,7 +31,9 @@ var ( defer mt.Stop() mux := httptrace.NewServeMux(opts...) - mux.HandleFunc("/200", handler200) + mux.HandleFunc("/200", func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte("OK\n")) + }) r := httptest.NewRequest("GET", "http://localhost/200", nil) w := httptest.NewRecorder() mux.ServeHTTP(w, r) @@ -63,7 +65,9 @@ var ( mt := mocktracer.Start() defer mt.Stop() - srv := httptest.NewServer(http.HandlerFunc(handler200)) + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte("OK\n")) + })) defer srv.Close() c := httptrace.WrapClient(&http.Client{}, opts...) @@ -90,7 +94,3 @@ var ( }, } ) - -func handler200(w http.ResponseWriter, _ *http.Request) { - w.Write([]byte("OK\n")) -} diff --git a/instrumentation/internal/namingschematest/olivere_elastic_v5.go b/instrumentation/internal/namingschematest/olivere_elastic_v5.go new file mode 100644 index 0000000000..506019c7a2 --- /dev/null +++ b/instrumentation/internal/namingschematest/olivere_elastic_v5.go @@ -0,0 +1,63 @@ +package namingschematest + +import ( + "context" + "testing" + + elastictrace "github.com/DataDog/dd-trace-go/contrib/olivere/elastic.v5/v2" + "github.com/DataDog/dd-trace-go/instrumentation/internal/namingschematest/harness" + "github.com/DataDog/dd-trace-go/v2/ddtrace/mocktracer" + "github.com/DataDog/dd-trace-go/v2/instrumentation" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "gopkg.in/olivere/elastic.v5" +) + +func olivereElasticV5GenSpans() harness.GenSpansFn { + const elasticURL = "http://127.0.0.1:9201" + return func(t *testing.T, serviceOverride string) []*mocktracer.Span { + var opts []elastictrace.ClientOption + if serviceOverride != "" { + opts = append(opts, elastictrace.WithService(serviceOverride)) + } + mt := mocktracer.Start() + defer mt.Stop() + tc := elastictrace.NewHTTPClient(opts...) + client, err := elastic.NewClient( + elastic.SetURL(elasticURL), + elastic.SetHttpClient(tc), + elastic.SetSniff(false), + elastic.SetHealthcheck(false), + ) + require.NoError(t, err) + + _, err = client.Index(). + Index("twitter").Id("1"). + Type("tweet"). + BodyString(`{"user": "test", "message": "hello"}`). + Do(context.Background()) + require.NoError(t, err) + + spans := mt.FinishedSpans() + require.Len(t, spans, 1) + return spans + } +} + +var olivereElasticV5 = harness.TestCase{ + Name: instrumentation.PackageOlivereElasticV5, + GenSpans: olivereElasticV5GenSpans(), + WantServiceNameV0: harness.ServiceNameAssertions{ + Defaults: []string{"elastic.client"}, + DDService: []string{"elastic.client"}, + ServiceOverride: []string{harness.TestServiceOverride}, + }, + AssertOpV0: func(t *testing.T, spans []*mocktracer.Span) { + require.Len(t, spans, 1) + assert.Equal(t, "elasticsearch.query", spans[0].OperationName()) + }, + AssertOpV1: func(t *testing.T, spans []*mocktracer.Span) { + require.Len(t, spans, 1) + assert.Equal(t, "elasticsearch.query", spans[0].OperationName()) + }, +} diff --git a/instrumentation/internal/namingschematest/redis_goredis_v9.go b/instrumentation/internal/namingschematest/redis_goredis_v9.go new file mode 100644 index 0000000000..226689c9c5 --- /dev/null +++ b/instrumentation/internal/namingschematest/redis_goredis_v9.go @@ -0,0 +1,58 @@ +package namingschematest + +import ( + "context" + "testing" + + redistrace "github.com/DataDog/dd-trace-go/contrib/redis/go-redis.v9/v2" + "github.com/DataDog/dd-trace-go/instrumentation/internal/namingschematest/harness" + "github.com/DataDog/dd-trace-go/v2/ddtrace/mocktracer" + "github.com/DataDog/dd-trace-go/v2/instrumentation" + "github.com/redis/go-redis/v9" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func redisGoRedisV9GenSpans() harness.GenSpansFn { + return func(t *testing.T, serviceOverride string) []*mocktracer.Span { + var opts []redistrace.ClientOption + if serviceOverride != "" { + opts = append(opts, redistrace.WithService(serviceOverride)) + } + mt := mocktracer.Start() + defer mt.Stop() + + client := redistrace.NewClient(&redis.Options{Addr: "127.0.0.1:6379"}, opts...) + st := client.Set(context.Background(), "test_key", "test_value", 0) + require.NoError(t, st.Err()) + + spans := mt.FinishedSpans() + var span *mocktracer.Span + for _, s := range spans { + // pick up the redis.command span except dial + if s.OperationName() == "redis.command" { + span = s + } + } + assert.NotNil(t, span) + return []*mocktracer.Span{span} + } +} + +var redisGoRedisV9 = harness.TestCase{ + Name: instrumentation.PackageRedisGoRedisV9, + GenSpans: redisGoRedisV9GenSpans(), + WantServiceNameV0: harness.ServiceNameAssertions{ + Defaults: []string{"redis.client"}, + DDService: []string{harness.TestDDService}, + ServiceOverride: []string{harness.TestServiceOverride}, + }, + AssertOpV0: func(t *testing.T, spans []*mocktracer.Span) { + require.Len(t, spans, 1) + assert.Equal(t, "redis.command", spans[0].OperationName()) + }, + AssertOpV1: func(t *testing.T, spans []*mocktracer.Span) { + require.Len(t, spans, 1) + assert.Equal(t, "redis.command", spans[0].OperationName()) + }, +} diff --git a/instrumentation/internal/namingschematest/segmentio_kafkago.go b/instrumentation/internal/namingschematest/segmentio_kafkago.go new file mode 100644 index 0000000000..ae48761ace --- /dev/null +++ b/instrumentation/internal/namingschematest/segmentio_kafkago.go @@ -0,0 +1,118 @@ +package namingschematest + +import ( + "context" + "testing" + "time" + + segmentiotracer "github.com/DataDog/dd-trace-go/contrib/segmentio/kafka-go/v2" + "github.com/DataDog/dd-trace-go/instrumentation/internal/namingschematest/harness" + "github.com/DataDog/dd-trace-go/v2/ddtrace/mocktracer" + "github.com/DataDog/dd-trace-go/v2/instrumentation" + "github.com/segmentio/kafka-go" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +const ( + testGroupID = "gosegtest" + testTopic = "gosegtest" + testReaderMaxWait = 10 * time.Millisecond +) + +type readerOpFn func(t *testing.T, r *segmentiotracer.Reader) + +func genIntegrationTestSpans(t *testing.T, mt mocktracer.Tracer, writerOp func(t *testing.T, w *segmentiotracer.Writer), readerOp readerOpFn, writerOpts []segmentiotracer.Option, readerOpts []segmentiotracer.Option) ([]*mocktracer.Span, []kafka.Message) { + writtenMessages := []kafka.Message{} + + // add some dummy values to broker/addr to test bootstrap servers. + kw := &kafka.Writer{ + Addr: kafka.TCP("localhost:9092", "localhost:9093", "localhost:9094"), + Topic: testTopic, + RequiredAcks: kafka.RequireOne, + Completion: func(messages []kafka.Message, err error) { + writtenMessages = append(writtenMessages, messages...) + }, + } + w := segmentiotracer.WrapWriter(kw, writerOpts...) + writerOp(t, w) + err := w.Close() + require.NoError(t, err) + + r := segmentiotracer.NewReader(kafka.ReaderConfig{ + Brokers: []string{"localhost:9092", "localhost:9093", "localhost:9094"}, + GroupID: testGroupID, + Topic: testTopic, + MaxWait: testReaderMaxWait, + }, readerOpts...) + readerOp(t, r) + err = r.Close() + require.NoError(t, err) + + spans := mt.FinishedSpans() + require.Len(t, spans, 2) + // they should be linked via headers + assert.Equal(t, spans[0].TraceID(), spans[1].TraceID(), "Trace IDs should match") + return spans, writtenMessages +} + +func segmentioKafkaGoGenSpans() harness.GenSpansFn { + return func(t *testing.T, serviceOverride string) []*mocktracer.Span { + var opts []segmentiotracer.Option + if serviceOverride != "" { + opts = append(opts, segmentiotracer.WithService(serviceOverride)) + } + + mt := mocktracer.Start() + defer mt.Stop() + + messagesToWrite := []kafka.Message{ + { + Key: []byte("key1"), + Value: []byte("value1"), + }, + } + + spans, _ := genIntegrationTestSpans( + t, + mt, + func(t *testing.T, w *segmentiotracer.Writer) { + err := w.WriteMessages(context.Background(), messagesToWrite...) + require.NoError(t, err, "Expected to write message to topic") + }, + func(t *testing.T, r *segmentiotracer.Reader) { + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + readMsg, err := r.FetchMessage(ctx) + require.NoError(t, err, "Expected to consume message") + assert.Equal(t, messagesToWrite[0].Value, readMsg.Value, "Values should be equal") + + err = r.CommitMessages(context.Background(), readMsg) + assert.NoError(t, err, "Expected CommitMessages to not return an error") + }, + opts, + opts, + ) + return spans + } +} + +var segmentioKafkaGo = harness.TestCase{ + Name: instrumentation.PackageSegmentioKafkaGo, + GenSpans: segmentioKafkaGoGenSpans(), + WantServiceNameV0: harness.ServiceNameAssertions{ + Defaults: harness.RepeatString("kafka", 2), + DDService: harness.RepeatString(harness.TestDDService, 2), + ServiceOverride: harness.RepeatString(harness.TestServiceOverride, 2), + }, + AssertOpV0: func(t *testing.T, spans []*mocktracer.Span) { + require.Len(t, spans, 2) + assert.Equal(t, "kafka.produce", spans[0].OperationName()) + assert.Equal(t, "kafka.consume", spans[1].OperationName()) + }, + AssertOpV1: func(t *testing.T, spans []*mocktracer.Span) { + require.Len(t, spans, 2) + assert.Equal(t, "kafka.send", spans[0].OperationName()) + assert.Equal(t, "kafka.process", spans[1].OperationName()) + }, +} diff --git a/instrumentation/packages.go b/instrumentation/packages.go index ec3a877666..7775737bf0 100644 --- a/instrumentation/packages.go +++ b/instrumentation/packages.go @@ -45,13 +45,28 @@ const ( PackageNetHTTP Package = "net/http" PackageIBMSarama Package = "IBM/sarama" - PackageValyalaFastHTTP Package = "valyala/fasthttp" - PackageUrfaveNegroni Package = "urfave/negroni" - PackageTwitchTVTwirp Package = "twitchtv/twirp" - PackageTidwallBuntDB Package = "tidwall/buntdb" - PackageSyndtrGoLevelDB Package = "syndtr/goleveldb/leveldb" - PackageSirupsenLogrus Package = "sirupsen/logrus" - PackageShopifySarama Package = "Shopify/sarama" + PackageValyalaFastHTTP Package = "valyala/fasthttp" + PackageUrfaveNegroni Package = "urfave/negroni" + PackageTwitchTVTwirp Package = "twitchtv/twirp" + PackageTidwallBuntDB Package = "tidwall/buntdb" + PackageSyndtrGoLevelDB Package = "syndtr/goleveldb/leveldb" + PackageSirupsenLogrus Package = "sirupsen/logrus" + PackageShopifySarama Package = "Shopify/sarama" + PackageSegmentioKafkaGo Package = "segmentio/kafka-go" + PackageRedisGoRedisV9 Package = "redis/go-redis.v9" + PackageOlivereElasticV5 Package = "olivere/elastic" + PackageMiekgDNS Package = "miekg/dns" + PackageLabstackEchoV4 Package = "labstack/echo" + PackageK8SClientGo Package = "k8s.io/client-go/kubernetes" + PackageJulienschmidtHTTPRouter Package = "julienschmidt/httprouter" + PackageJmoironSQLx Package = "jmoiron/sqlx" + PackageJackcPGXV5 Package = "jackc/pgx.v5" + PackageHashicorpConsulAPI Package = "hashicorp/consul" + PackageHashicorpVaultAPI Package = "hashicorp/vault" + PackageGraphQLGoGraphQL Package = "graphql-go/graphql" + PackageGraphGophersGraphQLGo Package = "graph-gophers/graphql-go" + PackageGormIOGormV1 Package = "gorm.io/gorm.v1" + PackageGorillaMux Package = "gorilla/mux" ) type Component int @@ -524,6 +539,169 @@ var packages = map[Package]PackageInfo{ }, }, }, + PackageSegmentioKafkaGo: { + TracedPackage: "github.com/segmentio/kafka-go", + EnvVarPrefix: "KAFKA", + naming: map[Component]componentNames{ + ComponentConsumer: { + useDDServiceV0: true, + buildServiceNameV0: staticName("kafka"), + buildOpNameV0: staticName("kafka.consume"), + buildOpNameV1: staticName("kafka.process"), + }, + ComponentProducer: { + useDDServiceV0: false, + buildServiceNameV0: staticName("kafka"), + buildOpNameV0: staticName("kafka.produce"), + buildOpNameV1: staticName("kafka.send"), + }, + }, + }, + PackageRedisGoRedisV9: { + TracedPackage: "github.com/redis/go-redis/v9", + EnvVarPrefix: "REDIS", + naming: map[Component]componentNames{ + ComponentDefault: { + useDDServiceV0: true, + buildServiceNameV0: staticName("redis.client"), + buildOpNameV0: staticName("redis.command"), + buildOpNameV1: staticName("redis.command"), + }, + }, + }, + PackageOlivereElasticV5: { + TracedPackage: "gopkg.in/olivere/elastic.v5", + EnvVarPrefix: "ELASTIC", + naming: map[Component]componentNames{ + ComponentDefault: { + useDDServiceV0: false, + buildServiceNameV0: staticName("elastic.client"), + buildOpNameV0: staticName("elasticsearch.query"), + buildOpNameV1: staticName("elasticsearch.query"), + }, + }, + }, + PackageMiekgDNS: { + TracedPackage: "github.com/miekg/dns", + }, + PackageLabstackEchoV4: { + TracedPackage: "github.com/labstack/echo/v4", + EnvVarPrefix: "ECHO", + naming: map[Component]componentNames{ + ComponentServer: { + useDDServiceV0: false, + buildServiceNameV0: staticName("echo"), + buildOpNameV0: staticName("http.request"), + buildOpNameV1: staticName("http.server.request"), + }, + }, + }, + PackageK8SClientGo: { + TracedPackage: "k8s.io/client-go/kubernetes", + }, + PackageJulienschmidtHTTPRouter: { + TracedPackage: "github.com/julienschmidt/httprouter", + EnvVarPrefix: "HTTPROUTER", + naming: map[Component]componentNames{ + ComponentServer: { + useDDServiceV0: false, + buildServiceNameV0: staticName("http.router"), + buildOpNameV0: staticName("http.request"), + buildOpNameV1: staticName("http.server.request"), + }, + }, + }, + PackageJmoironSQLx: { + TracedPackage: "github.com/jmoiron/sqlx", + }, + PackageJackcPGXV5: { + TracedPackage: "github.com/jackc/pgx/v5", + naming: map[Component]componentNames{ + ComponentDefault: { + useDDServiceV0: false, + buildServiceNameV0: staticName("postgres.db"), + }, + }, + }, + PackageIBMSarama: { + TracedPackage: "github.com/IBM/sarama", + EnvVarPrefix: "SARAMA", + naming: map[Component]componentNames{ + ComponentConsumer: { + useDDServiceV0: true, + buildServiceNameV0: staticName("kafka"), + buildOpNameV0: staticName("kafka.consume"), + buildOpNameV1: staticName("kafka.process"), + }, + ComponentProducer: { + useDDServiceV0: false, + buildServiceNameV0: staticName("kafka"), + buildOpNameV0: staticName("kafka.produce"), + buildOpNameV1: staticName("kafka.send"), + }, + }, + }, + PackageHashicorpConsulAPI: { + TracedPackage: "github.com/hashicorp/consul/api", + EnvVarPrefix: "CONSUL", + naming: map[Component]componentNames{ + ComponentDefault: { + useDDServiceV0: false, + buildServiceNameV0: staticName("consul"), + buildOpNameV0: staticName("consul.command"), + buildOpNameV1: staticName("consul.query"), + }, + }, + }, + PackageHashicorpVaultAPI: { + TracedPackage: "github.com/hashicorp/vault/api", + EnvVarPrefix: "VAULT", + naming: map[Component]componentNames{ + ComponentDefault: { + useDDServiceV0: false, + buildServiceNameV0: staticName("vault"), + buildOpNameV0: staticName("vault.command"), + buildOpNameV1: staticName("vault.query"), + }, + }, + }, + PackageGraphQLGoGraphQL: { + TracedPackage: "github.com/graphql-go/graphql", + EnvVarPrefix: "GRAPHQL", + naming: map[Component]componentNames{ + ComponentDefault: { + useDDServiceV0: false, + buildServiceNameV0: staticName("graphql"), + }, + }, + }, + PackageGraphGophersGraphQLGo: { + TracedPackage: "github.com/graph-gophers/graphql-go", + EnvVarPrefix: "GRAPHQL", + naming: map[Component]componentNames{ + ComponentDefault: { + useDDServiceV0: true, + buildServiceNameV0: staticName("graphql"), + buildOpNameV0: staticName("graphql.request"), + buildOpNameV1: staticName("graphql.server.request"), + }, + }, + }, + PackageGormIOGormV1: { + TracedPackage: "gorm.io/gorm.v1", + }, + PackageGorillaMux: { + TracedPackage: "github.com/gorilla/mux", + EnvVarPrefix: "MUX", + naming: map[Component]componentNames{ + ComponentServer: { + useDDServiceV0: true, + buildServiceNameV0: staticName("mux.router"), + buildOpNameV0: staticName("http.request"), + buildOpNameV1: staticName("http.server.request"), + }, + }, + }, } func staticName(name string) func(OperationContext) string { diff --git a/instrumentation/testutils/testutils.go b/instrumentation/testutils/testutils.go index 67606639e1..a4c3ae3d8c 100644 --- a/instrumentation/testutils/testutils.go +++ b/instrumentation/testutils/testutils.go @@ -64,6 +64,11 @@ func StartAppSec(t *testing.T) { t.Cleanup(appsec.Stop) } +func StartAppSecBench(b *testing.B) { + appsec.Start() + b.Cleanup(appsec.Stop) +} + type discardLogger struct{} func (d discardLogger) Log(_ string) {}