From a20143b9a340309f97a0ac90e90960d3bf753f76 Mon Sep 17 00:00:00 2001 From: Christian Mauduit Date: Tue, 9 Jul 2024 10:31:46 +0200 Subject: [PATCH] [contrib/gocql] reporting both cluster and datacenter (#2577) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Rodrigo Arguello Co-authored-by: Dario Castañé --- .github/workflows/unit-integration-tests.yml | 2 +- contrib/gocql/gocql/gocql.go | 10 ++- contrib/gocql/gocql/gocql_test.go | 69 +++++++++++++++++++- contrib/gocql/gocql/option.go | 12 ++++ ddtrace/ext/db.go | 3 + docker-compose.yaml | 2 +- go.mod | 2 +- 7 files changed, 94 insertions(+), 6 deletions(-) diff --git a/.github/workflows/unit-integration-tests.yml b/.github/workflows/unit-integration-tests.yml index b44dccefc2..81d027f00d 100644 --- a/.github/workflows/unit-integration-tests.yml +++ b/.github/workflows/unit-integration-tests.yml @@ -82,7 +82,7 @@ jobs: DD_POOL_TRACE_CHECK_FAILURES: true DD_DISABLE_ERROR_RESPONSES: true cassandra: - image: cassandra:3.7 + image: cassandra:3.11 env: JVM_OPTS: "-Xms750m -Xmx750m" ports: diff --git a/contrib/gocql/gocql/gocql.go b/contrib/gocql/gocql/gocql.go index fd39fe454e..03a84c6002 100644 --- a/contrib/gocql/gocql/gocql.go +++ b/contrib/gocql/gocql/gocql.go @@ -250,7 +250,15 @@ func (tq *Query) Iter() *Iter { if tIter.Host() != nil { tIter.span.SetTag(ext.TargetHost, tIter.Iter.Host().HostID()) tIter.span.SetTag(ext.TargetPort, strconv.Itoa(tIter.Iter.Host().Port())) - tIter.span.SetTag(ext.CassandraCluster, tIter.Iter.Host().DataCenter()) + + cluster := tIter.Iter.Host().ClusterName() + dc := tIter.Iter.Host().DataCenter() + if tq.config.clusterTagLegacyMode { + tIter.span.SetTag(ext.CassandraCluster, dc) + } else { + tIter.span.SetTag(ext.CassandraCluster, cluster) + } + tIter.span.SetTag(ext.CassandraDatacenter, dc) } return tIter } diff --git a/contrib/gocql/gocql/gocql_test.go b/contrib/gocql/gocql/gocql_test.go index 73a6ba3275..1ff7ea21ee 100644 --- a/contrib/gocql/gocql/gocql_test.go +++ b/contrib/gocql/gocql/gocql_test.go @@ -105,7 +105,8 @@ func TestErrorWrapper(t *testing.T) { if iter.Host() != nil { assert.Equal(span.Tag(ext.TargetPort), "9042") assert.Equal(span.Tag(ext.TargetHost), iter.Host().HostID()) - assert.Equal(span.Tag(ext.CassandraCluster), "datacenter1") + assert.Equal(span.Tag(ext.CassandraCluster), "Test Cluster") + assert.Equal(span.Tag(ext.CassandraDatacenter), "datacenter1") } } @@ -152,7 +153,71 @@ func TestChildWrapperSpan(t *testing.T) { if iter.Host() != nil { assert.Equal(childSpan.Tag(ext.TargetPort), "9042") assert.Equal(childSpan.Tag(ext.TargetHost), iter.Host().HostID()) - assert.Equal(childSpan.Tag(ext.CassandraCluster), "datacenter1") + assert.Equal(childSpan.Tag(ext.CassandraCluster), "Test Cluster") + assert.Equal(childSpan.Tag(ext.CassandraDatacenter), "datacenter1") + } +} + +func TestCompatMode(t *testing.T) { + genSpans := func(t *testing.T) []mocktracer.Span { + mt := mocktracer.Start() + defer mt.Stop() + + cluster := newCassandraCluster() + session, err := cluster.CreateSession() + require.NoError(t, err) + + q := session.Query("SELECT * FROM trace.person").WithContext(context.Background()) + tq := WrapQuery(q, WithServiceName("TestServiceName")) + iter := tq.Iter() + err = iter.Close() + require.NoError(t, err) + + spans := mt.FinishedSpans() + require.Len(t, spans, 1) + return spans + } + testCases := []struct { + name string + gocqlCompat string + wantCluster string + }{ + { + name: "== v1.65", + gocqlCompat: "v1.65", + wantCluster: "datacenter1", + }, + { + name: "< v1.65", + gocqlCompat: "v1.64", + wantCluster: "datacenter1", + }, + { + name: "> v1.65", + gocqlCompat: "v1.66", + wantCluster: "Test Cluster", + }, + { + name: "empty", + gocqlCompat: "", + wantCluster: "Test Cluster", + }, + { + name: "bad version", + gocqlCompat: "bad-version", + wantCluster: "Test Cluster", + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + t.Setenv("DD_TRACE_GOCQL_COMPAT", tc.gocqlCompat) + spans := genSpans(t) + s := spans[0] + assert.Equal(t, s.Tag(ext.TargetPort), "9042") + assert.NotEmpty(t, s.Tag(ext.TargetHost)) + assert.Equal(t, tc.wantCluster, s.Tag(ext.CassandraCluster)) + assert.Equal(t, "datacenter1", s.Tag(ext.CassandraDatacenter)) + }) } } diff --git a/contrib/gocql/gocql/option.go b/contrib/gocql/gocql/option.go index baee715fb4..c0df25d2b2 100644 --- a/contrib/gocql/gocql/option.go +++ b/contrib/gocql/gocql/option.go @@ -7,8 +7,12 @@ package gocql import ( "math" + "os" + + "golang.org/x/mod/semver" "gopkg.in/DataDog/dd-trace-go.v1/internal" + "gopkg.in/DataDog/dd-trace-go.v1/internal/log" "gopkg.in/DataDog/dd-trace-go.v1/internal/namingschema" ) @@ -21,6 +25,7 @@ type queryConfig struct { analyticsRate float64 errCheck func(err error) bool customTags map[string]interface{} + clusterTagLegacyMode bool } // WrapOption represents an option that can be passed to WrapQuery. @@ -37,6 +42,13 @@ func defaultConfig() *queryConfig { } else { cfg.analyticsRate = math.NaN() } + if compatMode := os.Getenv("DD_TRACE_GOCQL_COMPAT"); compatMode != "" { + if semver.IsValid(compatMode) { + cfg.clusterTagLegacyMode = semver.Compare(semver.MajorMinor(compatMode), "v1.65") <= 0 + } else { + log.Warn("ignoring DD_TRACE_GOCQL_COMPAT: invalid version %q", compatMode) + } + } cfg.errCheck = func(error) bool { return true } return cfg } diff --git a/ddtrace/ext/db.go b/ddtrace/ext/db.go index 8074342d17..f729f237b0 100644 --- a/ddtrace/ext/db.go +++ b/ddtrace/ext/db.go @@ -73,6 +73,9 @@ const ( // CassandraCluster specifies the tag name that is used to set the cluster. CassandraCluster = "cassandra.cluster" + // CassandraDatacenter specifies the tag name that is used to set the datacenter. + CassandraDatacenter = "cassandra.datacenter" + // CassandraRowCount specifies the tag name to use when settings the row count. CassandraRowCount = "cassandra.row_count" diff --git a/docker-compose.yaml b/docker-compose.yaml index 1657755709..4548bea1c5 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,7 +1,7 @@ version: "3.3" # optional since v1.27.0 services: cassandra: - image: cassandra:3.7 + image: cassandra:3.11 environment: JVM_OPTS: "-Xms750m -Xmx750m" ports: diff --git a/go.mod b/go.mod index eceec377d2..aa54410ff0 100644 --- a/go.mod +++ b/go.mod @@ -96,6 +96,7 @@ require ( go.opentelemetry.io/otel v1.20.0 go.opentelemetry.io/otel/trace v1.20.0 go.uber.org/atomic v1.11.0 + golang.org/x/mod v0.14.0 golang.org/x/net v0.23.0 golang.org/x/oauth2 v0.9.0 golang.org/x/sys v0.20.0 @@ -260,7 +261,6 @@ require ( golang.org/x/arch v0.4.0 // indirect golang.org/x/crypto v0.21.0 // indirect golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect - golang.org/x/mod v0.14.0 // indirect golang.org/x/sync v0.5.0 // indirect golang.org/x/term v0.18.0 // indirect golang.org/x/text v0.14.0 // indirect