diff --git a/ddtrace/tracer/tracer.go b/ddtrace/tracer/tracer.go index ccc52bbc17..abc44d0619 100644 --- a/ddtrace/tracer/tracer.go +++ b/ddtrace/tracer/tracer.go @@ -347,6 +347,17 @@ func newTracer(opts ...StartOption) *tracer { t.abandonedSpansDebugger = newAbandonedSpansDebugger() t.abandonedSpansDebugger.Start(t.config.spanTimeout) } + for name, conf := range c.integrations { + if !conf.Instrumented { + continue + } + v := conf.Version + if v == "" { + v = "unknown" + } + t.statsd.Incr("datadog.tracer.integrations", []string{"integration:" + name, "integration_version:" + v}, 1) + } + t.wg.Add(1) go func() { defer t.wg.Done() diff --git a/ddtrace/tracer/tracer_test.go b/ddtrace/tracer/tracer_test.go index 555c71080d..133b724e02 100644 --- a/ddtrace/tracer/tracer_test.go +++ b/ddtrace/tracer/tracer_test.go @@ -255,6 +255,34 @@ func TestTracerStart(t *testing.T) { tr.Stop() tr.Stop() }) + + t.Run("integration_health_metric", func(t *testing.T) { + assert := assert.New(t) + defer clearIntegrationsForTests() + var tg statsdtest.TestStatsdClient + + ok := MarkIntegrationImported("github.com/go-chi/chi") + assert.True(ok) + tr, _, _, stop := startTestTracer(t, withStatsdClient(&tg)) + defer stop() + + tg.Wait(assert, 1, 100*time.Millisecond) + + conf, ok := tr.config.integrations["chi"] + assert.True(ok) + assert.True(conf.Instrumented) + + counts := tg.Counts() + assert.Equal(int64(1), counts["datadog.tracer.integrations"]) + + calls := tg.IncrCalls() + for _, c := range statsdtest.FilterCallsByName(calls, "datadog.tracer.integrations") { + assert.EqualValues(c.GetTags(), []string{"integration:chi", "integration_version:unknown"}) + return + } + assert.Fail("expected integration to have appropriate tags") + + }) } func TestTracerLogFile(t *testing.T) { diff --git a/internal/statsdtest/statsdtest.go b/internal/statsdtest/statsdtest.go index 8845e6465c..af41d118fe 100644 --- a/internal/statsdtest/statsdtest.go +++ b/internal/statsdtest/statsdtest.go @@ -55,6 +55,10 @@ func (tg *TestStatsdClient) addCount(name string, value int64) { tg.counts[name] += value } +func (tc *TestStatsdCall) GetTags() []string { + return tc.tags +} + func (tg *TestStatsdClient) Gauge(name string, value float64, tags []string, rate float64) error { return tg.addMetric(callTypeGauge, tags, TestStatsdCall{ name: name, @@ -214,6 +218,16 @@ func (tg *TestStatsdClient) CallsByName() map[string]int { return counts } +func FilterCallsByName(calls []TestStatsdCall, name string) []TestStatsdCall { + var matches []TestStatsdCall + for _, c := range calls { + if c.name == name { + matches = append(matches, c) + } + } + return matches +} + func (tg *TestStatsdClient) Counts() map[string]int64 { tg.mu.RLock() defer tg.mu.RUnlock()