Skip to content

[BUG]: MongoDB query span tag should be truncated #3672

@colinking

Description

@colinking

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

Metadata

Metadata

Assignees

Labels

enhancementquick change/addition that does not need full team approval

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions