Add mongo sanitization configuration
MODIFY
instrumentation/mongo/mongo-3.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/mongo/v3_1/MongoInstrumentationSingletons.java
instrumentation/mongo/mongo-3.1/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/mongo/v3_1/MongoInstrumentationSingletons.java
@@ -8,11 +8,20 @@ package io.opentelemetry.javaagent.instrumentation.mongo.v3_1;
import com.mongodb.event.CommandListener;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.instrumentation.mongo.v3_1.MongoTelemetry;
+import io.opentelemetry.javaagent.bootstrap.internal.CommonConfig;
+import io.opentelemetry.javaagent.bootstrap.internal.InstrumentationConfig;
public final class MongoInstrumentationSingletons {
public static final CommandListener LISTENER =
- MongoTelemetry.create(GlobalOpenTelemetry.get()).newCommandListener();
+ MongoTelemetry.builder(GlobalOpenTelemetry.get())
+ .setStatementSanitizationEnabled(
+ InstrumentationConfig.get()
+ .getBoolean(
+ "otel.instrumentation.mongo.statement-sanitizer.enabled",
+ CommonConfig.get().isStatementSanitizationEnabled()))
+ .build()
+ .newCommandListener();
public static boolean isTracingListener(CommandListener listener) {
return listener.getClass().getName().equals(LISTENER.getClass().getName());

MODIFY
instrumentation/mongo/mongo-3.1/library/src/main/java/io/opentelemetry/instrumentation/mongo/v3_1/MongoDbAttributesGetter.java
instrumentation/mongo/mongo-3.1/library/src/main/java/io/opentelemetry/instrumentation/mongo/v3_1/MongoDbAttributesGetter.java
@@ -10,7 +10,6 @@ import com.mongodb.connection.ConnectionDescription;
import com.mongodb.event.CommandStartedEvent;
import io.opentelemetry.instrumentation.api.instrumenter.db.DbClientAttributesGetter;
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
-import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
@@ -20,6 +19,8 @@ import javax.annotation.Nullable;
import org.bson.BsonArray;
import org.bson.BsonDocument;
import org.bson.BsonValue;
+import org.bson.codecs.BsonDocumentCodec;
+import org.bson.codecs.EncoderContext;
import org.bson.json.JsonWriter;
import org.bson.json.JsonWriterSettings;
@@ -36,10 +37,12 @@ class MongoDbAttributesGetter implements DbClientAttributesGetter<CommandStarted
.orElse(null);
}
+ private final boolean statementSanitizationEnabled;
private final int maxNormalizedQueryLength;
@Nullable private final JsonWriterSettings jsonWriterSettings;
- MongoDbAttributesGetter(int maxNormalizedQueryLength) {
+ MongoDbAttributesGetter(boolean statementSanitizationEnabled, int maxNormalizedQueryLength) {
+ this.statementSanitizationEnabled = statementSanitizationEnabled;
this.maxNormalizedQueryLength = maxNormalizedQueryLength;
this.jsonWriterSettings = createJsonWriterSettings(maxNormalizedQueryLength);
}
@@ -90,20 +93,24 @@ class MongoDbAttributesGetter implements DbClientAttributesGetter<CommandStarted
return event.getCommandName();
}
- // TODO(anuraaga): Migrate off of StringWriter to avoid synchronization.
- // accessible to tests
String sanitizeStatement(BsonDocument command) {
- StringWriter stringWriter = new StringWriter(128);
+ StringBuilderWriter stringWriter = new StringBuilderWriter(128);
// jsonWriterSettings is generally not null but could be due to security manager or unknown
// API incompatibilities, which we can't detect by Muzzle because we use reflection.
JsonWriter jsonWriter =
jsonWriterSettings != null
? new JsonWriter(stringWriter, jsonWriterSettings)
: new JsonWriter(stringWriter);
+
+ if (statementSanitizationEnabled) {
writeScrubbed(command, jsonWriter, /* isRoot= */ true);
+ } else {
+ new BsonDocumentCodec().encode(jsonWriter, command, EncoderContext.builder().build());
+ }
+
// If using MongoDB driver >= 3.7, the substring invocation will be a no-op due to use of
// JsonWriterSettings.Builder.maxLength in the static initializer for JSON_WRITER_SETTINGS
- StringBuffer buf = stringWriter.getBuffer();
+ StringBuilder buf = stringWriter.getBuilder();
if (buf.length() <= maxNormalizedQueryLength) {
return buf.toString();
}

MODIFY
instrumentation/mongo/mongo-3.1/library/src/main/java/io/opentelemetry/instrumentation/mongo/v3_1/MongoInstrumenterFactory.java
instrumentation/mongo/mongo-3.1/library/src/main/java/io/opentelemetry/instrumentation/mongo/v3_1/MongoInstrumenterFactory.java
@@ -21,10 +21,12 @@ class MongoInstrumenterFactory {
netAttributesExtractor = NetClientAttributesExtractor.create(new MongoNetAttributesGetter());
static Instrumenter<CommandStartedEvent, Void> createInstrumenter(
- OpenTelemetry openTelemetry, int maxNormalizedQueryLength) {
+ OpenTelemetry openTelemetry,
+ boolean statementSanitizationEnabled,
+ int maxNormalizedQueryLength) {
MongoDbAttributesGetter dbAttributesGetter =
- new MongoDbAttributesGetter(maxNormalizedQueryLength);
+ new MongoDbAttributesGetter(statementSanitizationEnabled, maxNormalizedQueryLength);
SpanNameExtractor<CommandStartedEvent> spanNameExtractor =
new MongoSpanNameExtractor(dbAttributesGetter, attributesExtractor);

MODIFY
instrumentation/mongo/mongo-3.1/library/src/main/java/io/opentelemetry/instrumentation/mongo/v3_1/MongoTelemetry.java
instrumentation/mongo/mongo-3.1/library/src/main/java/io/opentelemetry/instrumentation/mongo/v3_1/MongoTelemetry.java
@@ -28,9 +28,13 @@ public final class MongoTelemetry {
private final Instrumenter<CommandStartedEvent, Void> instrumenter;
- MongoTelemetry(OpenTelemetry openTelemetry, int maxNormalizedQueryLength) {
+ MongoTelemetry(
+ OpenTelemetry openTelemetry,
+ boolean statementSanitizationEnabled,
+ int maxNormalizedQueryLength) {
this.instrumenter =
- MongoInstrumenterFactory.createInstrumenter(openTelemetry, maxNormalizedQueryLength);
+ MongoInstrumenterFactory.createInstrumenter(
+ openTelemetry, statementSanitizationEnabled, maxNormalizedQueryLength);
}
/**

MODIFY
instrumentation/mongo/mongo-3.1/library/src/main/java/io/opentelemetry/instrumentation/mongo/v3_1/MongoTelemetryBuilder.java
instrumentation/mongo/mongo-3.1/library/src/main/java/io/opentelemetry/instrumentation/mongo/v3_1/MongoTelemetryBuilder.java
@@ -15,12 +15,24 @@ public final class MongoTelemetryBuilder {
private final OpenTelemetry openTelemetry;
+ private boolean statementSanitizationEnabled = true;
private int maxNormalizedQueryLength = DEFAULT_MAX_NORMALIZED_QUERY_LENGTH;
MongoTelemetryBuilder(OpenTelemetry openTelemetry) {
this.openTelemetry = openTelemetry;
}
+ /**
+ * Sets whether the {@code db.statement} attribute on the spans emitted by the constructed {@link
+ * MongoTelemetry} should be sanitized. If set to {@code true}, all parameters that can
+ * potentially contain sensitive information will be masked. Enabled by default.
+ */
+ public MongoTelemetryBuilder setStatementSanitizationEnabled(
+ boolean statementSanitizationEnabled) {
+ this.statementSanitizationEnabled = statementSanitizationEnabled;
+ return this;
+ }
+
/**
* Sets the max length of recorded queries after normalization. Defaults to {@value
* DEFAULT_MAX_NORMALIZED_QUERY_LENGTH}.
@@ -34,6 +46,7 @@ public final class MongoTelemetryBuilder {
* Returns a new {@link MongoTelemetry} with the settings of this {@link MongoTelemetryBuilder}.
*/
public MongoTelemetry build() {
- return new MongoTelemetry(openTelemetry, maxNormalizedQueryLength);
+ return new MongoTelemetry(
+ openTelemetry, statementSanitizationEnabled, maxNormalizedQueryLength);
}
}

ADD
instrumentation/mongo/mongo-3.1/library/src/main/java/io/opentelemetry/instrumentation/mongo/v3_1/StringBuilderWriter.java
+/*
+ * Copyright The OpenTelemetry Authors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.opentelemetry.instrumentation.mongo.v3_1;
+
+import java.io.Writer;
+
+// because StringWriter uses the synchronized StringBuffer
+class StringBuilderWriter extends Writer {
+
+ private final StringBuilder sb;
+
+ StringBuilderWriter(int initialSize) {
+ sb = new StringBuilder(initialSize);
+ }
+
+ @Override
+ public void write(char[] cbuf, int off, int len) {
+ sb.append(cbuf, off, len);
+ }
+
+ @Override
+ public void flush() {}
+
+ @Override
+ public void close() {}
+
+ public StringBuilder getBuilder() {
+ return sb;
+ }
+}

MODIFY
instrumentation/mongo/mongo-3.1/library/src/test/groovy/io/opentelemetry/instrumentation/mongo/v3_1/MongoDbAttributesGetterTest.groovy
instrumentation/mongo/mongo-3.1/library/src/test/groovy/io/opentelemetry/instrumentation/mongo/v3_1/MongoDbAttributesGetterTest.groovy
@@ -18,7 +18,7 @@ class MongoDbAttributesGetterTest extends Specification {
def 'should sanitize statements to json'() {
setup:
- def extractor = new MongoDbAttributesGetter(DEFAULT_MAX_NORMALIZED_QUERY_LENGTH)
+ def extractor = new MongoDbAttributesGetter(true, DEFAULT_MAX_NORMALIZED_QUERY_LENGTH)
expect:
sanitizeStatementAcrossVersions(extractor,
@@ -38,7 +38,7 @@ class MongoDbAttributesGetterTest extends Specification {
def 'should only preserve string value if it is the value of the first top-level key'() {
setup:
- def extractor = new MongoDbAttributesGetter(DEFAULT_MAX_NORMALIZED_QUERY_LENGTH)
+ def extractor = new MongoDbAttributesGetter(true, DEFAULT_MAX_NORMALIZED_QUERY_LENGTH)
expect:
sanitizeStatementAcrossVersions(extractor,
@@ -50,7 +50,7 @@ class MongoDbAttributesGetterTest extends Specification {
def 'should truncate simple command'() {
setup:
- def extractor = new MongoDbAttributesGetter(20)
+ def extractor = new MongoDbAttributesGetter(true, 20)
def normalized = sanitizeStatementAcrossVersions(extractor,
new BsonDocument("cmd", new BsonString("c"))
@@ -63,7 +63,7 @@ class MongoDbAttributesGetterTest extends Specification {
def 'should truncate array'() {
setup:
- def extractor = new MongoDbAttributesGetter(27)
+ def extractor = new MongoDbAttributesGetter(true, 27)
def normalized = sanitizeStatementAcrossVersions(extractor,
new BsonDocument("cmd", new BsonString("c"))

MODIFY
instrumentation/mongo/mongo-3.1/library/src/test/groovy/io/opentelemetry/instrumentation/mongo/v3_1/MongoSpanNameExtractorTest.groovy
instrumentation/mongo/mongo-3.1/library/src/test/groovy/io/opentelemetry/instrumentation/mongo/v3_1/MongoSpanNameExtractorTest.groovy
@@ -16,7 +16,7 @@ class MongoSpanNameExtractorTest extends Specification {
def 'test span name with no dbName'() {
setup:
- def nameExtractor = new MongoSpanNameExtractor(new MongoDbAttributesGetter(DEFAULT_MAX_NORMALIZED_QUERY_LENGTH), new MongoAttributesExtractor())
+ def nameExtractor = new MongoSpanNameExtractor(new MongoDbAttributesGetter(true, DEFAULT_MAX_NORMALIZED_QUERY_LENGTH), new MongoAttributesExtractor())
def event = new CommandStartedEvent(
0, null, null, command, new BsonDocument(command, new BsonInt32(1)))

MODIFY
instrumentation/mongo/mongo-3.7/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/mongo/v3_7/MongoInstrumentationSingletons.java
instrumentation/mongo/mongo-3.7/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/mongo/v3_7/MongoInstrumentationSingletons.java
@@ -8,11 +8,20 @@ package io.opentelemetry.javaagent.instrumentation.mongo.v3_7;
import com.mongodb.event.CommandListener;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.instrumentation.mongo.v3_1.MongoTelemetry;
+import io.opentelemetry.javaagent.bootstrap.internal.CommonConfig;
+import io.opentelemetry.javaagent.bootstrap.internal.InstrumentationConfig;
public final class MongoInstrumentationSingletons {
public static final CommandListener LISTENER =
- MongoTelemetry.create(GlobalOpenTelemetry.get()).newCommandListener();
+ MongoTelemetry.builder(GlobalOpenTelemetry.get())
+ .setStatementSanitizationEnabled(
+ InstrumentationConfig.get()
+ .getBoolean(
+ "otel.instrumentation.mongo.statement-sanitizer.enabled",
+ CommonConfig.get().isStatementSanitizationEnabled()))
+ .build()
+ .newCommandListener();
public static boolean isTracingListener(CommandListener listener) {
return listener.getClass().getName().equals(LISTENER.getClass().getName());

MODIFY
instrumentation/mongo/mongo-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/mongo/v4_0/MongoInstrumentationSingletons.java
instrumentation/mongo/mongo-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/mongo/v4_0/MongoInstrumentationSingletons.java
@@ -8,11 +8,20 @@ package io.opentelemetry.javaagent.instrumentation.mongo.v4_0;
import com.mongodb.event.CommandListener;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.instrumentation.mongo.v3_1.MongoTelemetry;
+import io.opentelemetry.javaagent.bootstrap.internal.CommonConfig;
+import io.opentelemetry.javaagent.bootstrap.internal.InstrumentationConfig;
public final class MongoInstrumentationSingletons {
public static final CommandListener LISTENER =
- MongoTelemetry.create(GlobalOpenTelemetry.get()).newCommandListener();
+ MongoTelemetry.builder(GlobalOpenTelemetry.get())
+ .setStatementSanitizationEnabled(
+ InstrumentationConfig.get()
+ .getBoolean(
+ "otel.instrumentation.mongo.statement-sanitizer.enabled",
+ CommonConfig.get().isStatementSanitizationEnabled()))
+ .build()
+ .newCommandListener();
public static boolean isTracingListener(CommandListener listener) {
return listener.getClass().getName().equals(LISTENER.getClass().getName());

MODIFY
instrumentation/mongo/mongo-async-3.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/mongoasync/v3_3/MongoInstrumentationSingletons.java
instrumentation/mongo/mongo-async-3.3/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/mongoasync/v3_3/MongoInstrumentationSingletons.java
@@ -8,11 +8,20 @@ package io.opentelemetry.javaagent.instrumentation.mongoasync.v3_3;
import com.mongodb.event.CommandListener;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.instrumentation.mongo.v3_1.MongoTelemetry;
+import io.opentelemetry.javaagent.bootstrap.internal.CommonConfig;
+import io.opentelemetry.javaagent.bootstrap.internal.InstrumentationConfig;
public final class MongoInstrumentationSingletons {
public static final CommandListener LISTENER =
- MongoTelemetry.create(GlobalOpenTelemetry.get()).newCommandListener();
+ MongoTelemetry.builder(GlobalOpenTelemetry.get())
+ .setStatementSanitizationEnabled(
+ InstrumentationConfig.get()
+ .getBoolean(
+ "otel.instrumentation.mongo.statement-sanitizer.enabled",
+ CommonConfig.get().isStatementSanitizationEnabled()))
+ .build()
+ .newCommandListener();
public static boolean isTracingListener(CommandListener listener) {
return listener.getClass().getName().equals(LISTENER.getClass().getName());

Add mongo sanitization configuration (#6541)