dd-trace-go icon indicating copy to clipboard operation
dd-trace-go copied to clipboard

[BUG]: MongoDB query span tag should be truncated

Open colinking opened this issue 6 months ago • 2 comments

Tracer Version(s)

v2.0.0

Go Version(s)

1.24.4

Bug Report

The MongoDB command is directly serialized as the mongodb.query span tag, without any truncation. We've run into situations at Rippling where this command can be quite large (e.g. writing 100 1MB documents via a BulkWrite call produces a 100MB mongodb.query span tag).

There is prior art for truncating raw queries, e.g. the ElasticSearch module truncates request/response tags to 5KB. Alternatively, the SQL modules like pgx don't truncate, but those queries would rarely include raw data and therefore should be much smaller in size (in theory).

I'd propose making this configurable and can open a PR if the DataDog team is interested (draft PR here).

Reproduction Code

The following code instruments a MongoDB update and logs the spans. You'll see a large span in the logs.

package main

import (
	"context"
	"runtime"
	"strings"
	"testing"

	mongotrace "github.com/DataDog/dd-trace-go/contrib/go.mongodb.org/mongo-driver/v2/mongo"
	ddotel "github.com/DataDog/dd-trace-go/v2/ddtrace/opentelemetry"
	"github.com/DataDog/dd-trace-go/v2/ddtrace/tracer"
	"github.com/rs/zerolog"
	"github.com/stretchr/testify/require"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

type logAdapter struct{ Logger *zerolog.Logger }

var _ tracer.Logger = &logAdapter{}

func (l *logAdapter) Log(msg string) {
	l.Logger.Info().Msg(msg)
}

func TestRepro(t *testing.T) {
	logger := zerolog.New(zerolog.NewTestWriter(t))
	tp := ddotel.NewTracerProvider(
		tracer.WithLogger(&logAdapter{Logger: &logger}),
		tracer.WithDebugMode(true),
		tracer.WithLogStartup(false),
	)

	tr := tp.Tracer("demo")
	ctx, span := tr.Start(context.Background(), "HandleEvent")
	defer span.End()

	opts := options.Client().ApplyURI("mongodb://localhost:9572/?replicaSet=rs0&directConnection=true")
	opts.Monitor = mongotrace.NewMonitor(
		mongotrace.WithService("testing"),
	)

	client, err := mongo.Connect(t.Context(), opts)
	require.NoError(t, err)
	db := client.Database("tests")
	col := db.Collection("test_collection")

	n := 100

	models := make([]mongo.WriteModel, 0, n)
	for range n {
		models = append(models, mongo.NewUpdateManyModel().
			SetFilter(bson.D{{Key: "_id", Value: "68536ec8d906742797f5705a"}}).
			SetUpdate(bson.D{{Key: "$set", Value: map[string]any{"value": strings.Repeat("1", 1000)}}}).
			SetUpsert(true),
		)
	}

	_, err = col.BulkWrite(ctx, models, options.BulkWrite().SetOrdered(false))
	require.NoError(t, err)

	runtime.GC()
	var m runtime.MemStats
	runtime.ReadMemStats(&m)
	logger.Info().Msgf("Memory: %v", m.Alloc)
}

Error Logs

n/a

Go Env Output

n/a

colinking avatar Jun 20 '25 04:06 colinking

Thanks for reaching out and for the contribution, @colinking. Please open the PR in our repository and our IDM team will review it.

darccio avatar Jun 20 '25 07:06 darccio

Thanks @darccio. I've opened a PR here: https://github.com/DataDog/dd-trace-go/pull/3679

colinking avatar Jun 20 '25 17:06 colinking