diff --git a/instrumentation-api-semconv/build.gradle.kts b/instrumentation-api-semconv/build.gradle.kts index 852fed4416..be4d3b62e9 100644 --- a/instrumentation-api-semconv/build.gradle.kts +++ b/instrumentation-api-semconv/build.gradle.kts @@ -38,22 +38,4 @@ tasks { sourcesJar { dependsOn("generateJflex") } - - val testStatementSanitizerConfig by registering(Test::class) { - filter { - includeTestsMatching("StatementSanitizationConfigTest") - } - include("**/StatementSanitizationConfigTest.*") - jvmArgs("-Dotel.instrumentation.common.db-statement-sanitizer.enabled=false") - } - - test { - filter { - excludeTestsMatching("StatementSanitizationConfigTest") - } - } - - check { - dependsOn(testStatementSanitizerConfig) - } } diff --git a/instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/db/RedisCommandSanitizer.java b/instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/db/RedisCommandSanitizer.java index f729c0c533..98e94b3c58 100644 --- a/instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/db/RedisCommandSanitizer.java +++ b/instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/db/RedisCommandSanitizer.java @@ -8,10 +8,6 @@ package io.opentelemetry.instrumentation.api.db; import static java.util.Arrays.asList; import static java.util.Collections.unmodifiableMap; -import io.opentelemetry.instrumentation.api.db.RedisCommandSanitizer.CommandSanitizer.CommandAndNumArgs; -import io.opentelemetry.instrumentation.api.db.RedisCommandSanitizer.CommandSanitizer.Eval; -import io.opentelemetry.instrumentation.api.db.RedisCommandSanitizer.CommandSanitizer.KeepAllArgs; -import io.opentelemetry.instrumentation.api.db.RedisCommandSanitizer.CommandSanitizer.MultiKeyValue; import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.List; @@ -353,8 +349,18 @@ public final class RedisCommandSanitizer { SANITIZERS = unmodifiableMap(sanitizers); } - public static String sanitize(String command, List args) { - if (!StatementSanitizationConfig.isStatementSanitizationEnabled()) { + public static RedisCommandSanitizer create(boolean statementSanitizationEnabled) { + return new RedisCommandSanitizer(statementSanitizationEnabled); + } + + private final boolean statementSanitizationEnabled; + + private RedisCommandSanitizer(boolean statementSanitizationEnabled) { + this.statementSanitizationEnabled = statementSanitizationEnabled; + } + + public String sanitize(String command, List args) { + if (!statementSanitizationEnabled) { return KeepAllArgs.INSTANCE.sanitize(command, args); } return SANITIZERS @@ -362,107 +368,105 @@ public final class RedisCommandSanitizer { .sanitize(command, args); } - public interface CommandSanitizer { + interface CommandSanitizer { String sanitize(String command, List args); + } - static String argToString(Object arg) { - if (arg instanceof byte[]) { - return new String((byte[]) arg, StandardCharsets.UTF_8); - } else { - return String.valueOf(arg); - } - } - - enum KeepAllArgs implements CommandSanitizer { - INSTANCE; - - @Override - public String sanitize(String command, List args) { - StringBuilder sanitized = new StringBuilder(command); - for (Object arg : args) { - sanitized.append(" ").append(argToString(arg)); - } - return sanitized.toString(); - } - } - - // keeps only a chosen number of arguments - // example for num=2: CMD arg1 arg2 ? ? - class CommandAndNumArgs implements CommandSanitizer { - private final int numOfArgsToKeep; - - public CommandAndNumArgs(int numOfArgsToKeep) { - this.numOfArgsToKeep = numOfArgsToKeep; - } - - @Override - public String sanitize(String command, List args) { - StringBuilder sanitized = new StringBuilder(command); - for (int i = 0; i < numOfArgsToKeep && i < args.size(); ++i) { - sanitized.append(" ").append(argToString(args.get(i))); - } - for (int i = numOfArgsToKeep; i < args.size(); ++i) { - sanitized.append(" ?"); - } - return sanitized.toString(); - } - } - - // keeps only chosen number of arguments and then every second one - // example for num=2: CMD arg1 arg2 key1 ? key2 ? - class MultiKeyValue implements CommandSanitizer { - private final int numOfArgsBeforeKeyValue; - - public MultiKeyValue(int numOfArgsBeforeKeyValue) { - this.numOfArgsBeforeKeyValue = numOfArgsBeforeKeyValue; - } - - @Override - public String sanitize(String command, List args) { - StringBuilder sanitized = new StringBuilder(command); - // append all "initial" arguments before key-value pairs start - for (int i = 0; i < numOfArgsBeforeKeyValue && i < args.size(); ++i) { - sanitized.append(" ").append(argToString(args.get(i))); - } - - // loop over keys only - for (int i = numOfArgsBeforeKeyValue; i < args.size(); i += 2) { - sanitized.append(" ").append(argToString(args.get(i))).append(" ?"); - } - return sanitized.toString(); - } - } - - enum Eval implements CommandSanitizer { - INSTANCE; - - @Override - public String sanitize(String command, List args) { - StringBuilder sanitized = new StringBuilder(command); - - // get the number of keys passed from the command itself (second arg) - int numberOfKeys = 0; - if (args.size() > 2) { - try { - numberOfKeys = Integer.parseInt(argToString(args.get(1))); - } catch (NumberFormatException ignored) { - // Ignore - } - } - - int i = 0; - // log the script, number of keys and all keys - for (; i < (numberOfKeys + 2) && i < args.size(); ++i) { - sanitized.append(" ").append(argToString(args.get(i))); - } - // mask the rest - for (; i < args.size(); ++i) { - sanitized.append(" ?"); - } - return sanitized.toString(); + enum KeepAllArgs implements CommandSanitizer { + INSTANCE; + + @Override + public String sanitize(String command, List args) { + StringBuilder sanitized = new StringBuilder(command); + for (Object arg : args) { + sanitized.append(" ").append(argToString(arg)); } + return sanitized.toString(); } } - private RedisCommandSanitizer() {} + // keeps only a chosen number of arguments + // example for num=2: CMD arg1 arg2 ? ? + static final class CommandAndNumArgs implements CommandSanitizer { + private final int numOfArgsToKeep; + + CommandAndNumArgs(int numOfArgsToKeep) { + this.numOfArgsToKeep = numOfArgsToKeep; + } + + @Override + public String sanitize(String command, List args) { + StringBuilder sanitized = new StringBuilder(command); + for (int i = 0; i < numOfArgsToKeep && i < args.size(); ++i) { + sanitized.append(" ").append(argToString(args.get(i))); + } + for (int i = numOfArgsToKeep; i < args.size(); ++i) { + sanitized.append(" ?"); + } + return sanitized.toString(); + } + } + + // keeps only chosen number of arguments and then every second one + // example for num=2: CMD arg1 arg2 key1 ? key2 ? + static final class MultiKeyValue implements CommandSanitizer { + private final int numOfArgsBeforeKeyValue; + + MultiKeyValue(int numOfArgsBeforeKeyValue) { + this.numOfArgsBeforeKeyValue = numOfArgsBeforeKeyValue; + } + + @Override + public String sanitize(String command, List args) { + StringBuilder sanitized = new StringBuilder(command); + // append all "initial" arguments before key-value pairs start + for (int i = 0; i < numOfArgsBeforeKeyValue && i < args.size(); ++i) { + sanitized.append(" ").append(argToString(args.get(i))); + } + + // loop over keys only + for (int i = numOfArgsBeforeKeyValue; i < args.size(); i += 2) { + sanitized.append(" ").append(argToString(args.get(i))).append(" ?"); + } + return sanitized.toString(); + } + } + + enum Eval implements CommandSanitizer { + INSTANCE; + + @Override + public String sanitize(String command, List args) { + StringBuilder sanitized = new StringBuilder(command); + + // get the number of keys passed from the command itself (second arg) + int numberOfKeys = 0; + if (args.size() > 2) { + try { + numberOfKeys = Integer.parseInt(argToString(args.get(1))); + } catch (NumberFormatException ignored) { + // Ignore + } + } + + int i = 0; + // log the script, number of keys and all keys + for (; i < (numberOfKeys + 2) && i < args.size(); ++i) { + sanitized.append(" ").append(argToString(args.get(i))); + } + // mask the rest + for (; i < args.size(); ++i) { + sanitized.append(" ?"); + } + return sanitized.toString(); + } + } + + static String argToString(Object arg) { + if (arg instanceof byte[]) { + return new String((byte[]) arg, StandardCharsets.UTF_8); + } else { + return String.valueOf(arg); + } + } } diff --git a/instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/db/SqlStatementSanitizer.java b/instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/db/SqlStatementSanitizer.java index 077645442c..a9175364a8 100644 --- a/instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/db/SqlStatementSanitizer.java +++ b/instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/db/SqlStatementSanitizer.java @@ -5,7 +5,6 @@ package io.opentelemetry.instrumentation.api.db; -import static io.opentelemetry.instrumentation.api.db.StatementSanitizationConfig.isStatementSanitizationEnabled; import static io.opentelemetry.instrumentation.api.internal.SupportabilityMetrics.CounterNames.SQL_STATEMENT_SANITIZER_CACHE_MISS; import com.google.auto.value.AutoValue; @@ -23,12 +22,22 @@ public final class SqlStatementSanitizer { private static final Cache sqlToStatementInfoCache = Cache.bounded(1000); - public static SqlStatementInfo sanitize(@Nullable String statement) { + public static SqlStatementSanitizer create(boolean statementSanitizationEnabled) { + return new SqlStatementSanitizer(statementSanitizationEnabled); + } + + private final boolean statementSanitizationEnabled; + + private SqlStatementSanitizer(boolean statementSanitizationEnabled) { + this.statementSanitizationEnabled = statementSanitizationEnabled; + } + + public SqlStatementInfo sanitize(@Nullable String statement) { return sanitize(statement, SqlDialect.DEFAULT); } - public static SqlStatementInfo sanitize(@Nullable String statement, SqlDialect dialect) { - if (!isStatementSanitizationEnabled() || statement == null) { + public SqlStatementInfo sanitize(@Nullable String statement, SqlDialect dialect) { + if (!statementSanitizationEnabled || statement == null) { return SqlStatementInfo.create(statement, null, null); } return sqlToStatementInfoCache.computeIfAbsent( @@ -50,6 +59,4 @@ public final class SqlStatementSanitizer { abstract SqlDialect getDialect(); } - - private SqlStatementSanitizer() {} } diff --git a/instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/db/StatementSanitizationConfig.java b/instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/db/StatementSanitizationConfig.java deleted file mode 100644 index 17665024b7..0000000000 --- a/instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/db/StatementSanitizationConfig.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.instrumentation.api.db; - -import io.opentelemetry.instrumentation.api.config.Config; - -/** DB statement sanitization is always enabled by default, you have to manually disable it. */ -final class StatementSanitizationConfig { - - private static final boolean STATEMENT_SANITIZATION_ENABLED = - Config.get().getBoolean("otel.instrumentation.common.db-statement-sanitizer.enabled", true); - - static boolean isStatementSanitizationEnabled() { - return STATEMENT_SANITIZATION_ENABLED; - } - - private StatementSanitizationConfig() {} -} diff --git a/instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/db/DbClientSpanNameExtractor.java b/instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/db/DbClientSpanNameExtractor.java index 6612554436..00afa6d5c5 100644 --- a/instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/db/DbClientSpanNameExtractor.java +++ b/instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/db/DbClientSpanNameExtractor.java @@ -82,6 +82,9 @@ public abstract class DbClientSpanNameExtractor implements SpanNameExtr private static final class SqlClientSpanNameExtractor extends DbClientSpanNameExtractor { + // a dedicated sanitizer just for extracting the operation and table name + private static final SqlStatementSanitizer sanitizer = SqlStatementSanitizer.create(true); + private final SqlClientAttributesGetter getter; private SqlClientSpanNameExtractor(SqlClientAttributesGetter getter) { @@ -91,8 +94,7 @@ public abstract class DbClientSpanNameExtractor implements SpanNameExtr @Override public String extract(REQUEST request) { String dbName = getter.name(request); - SqlStatementInfo sanitizedStatement = - SqlStatementSanitizer.sanitize(getter.rawStatement(request)); + SqlStatementInfo sanitizedStatement = sanitizer.sanitize(getter.rawStatement(request)); return computeSpanName( dbName, sanitizedStatement.getOperation(), sanitizedStatement.getTable()); } diff --git a/instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/db/SqlClientAttributesExtractor.java b/instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/db/SqlClientAttributesExtractor.java index d98ef1ea28..09147303ae 100644 --- a/instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/db/SqlClientAttributesExtractor.java +++ b/instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/db/SqlClientAttributesExtractor.java @@ -44,19 +44,22 @@ public final class SqlClientAttributesExtractor } private final AttributeKey dbTableAttribute; + private final SqlStatementSanitizer sanitizer; SqlClientAttributesExtractor( - SqlClientAttributesGetter getter, AttributeKey dbTableAttribute) { + SqlClientAttributesGetter getter, + AttributeKey dbTableAttribute, + SqlStatementSanitizer sanitizer) { super(getter); this.dbTableAttribute = dbTableAttribute; + this.sanitizer = sanitizer; } @Override public void onStart(AttributesBuilder attributes, Context parentContext, REQUEST request) { super.onStart(attributes, parentContext, request); - SqlStatementInfo sanitizedStatement = - SqlStatementSanitizer.sanitize(getter.rawStatement(request)); + SqlStatementInfo sanitizedStatement = sanitizer.sanitize(getter.rawStatement(request)); internalSet(attributes, SemanticAttributes.DB_STATEMENT, sanitizedStatement.getFullStatement()); internalSet(attributes, SemanticAttributes.DB_OPERATION, sanitizedStatement.getOperation()); internalSet(attributes, dbTableAttribute, sanitizedStatement.getTable()); diff --git a/instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/db/SqlClientAttributesExtractorBuilder.java b/instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/db/SqlClientAttributesExtractorBuilder.java index 9b872f2901..666ffec204 100644 --- a/instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/db/SqlClientAttributesExtractorBuilder.java +++ b/instrumentation-api-semconv/src/main/java/io/opentelemetry/instrumentation/api/instrumenter/db/SqlClientAttributesExtractorBuilder.java @@ -8,6 +8,7 @@ package io.opentelemetry.instrumentation.api.instrumenter.db; import static java.util.Objects.requireNonNull; import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.instrumentation.api.db.SqlStatementSanitizer; import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; /** A builder of {@link SqlClientAttributesExtractor}. */ @@ -15,6 +16,7 @@ public final class SqlClientAttributesExtractorBuilder { final SqlClientAttributesGetter getter; AttributeKey dbTableAttribute = SemanticAttributes.DB_SQL_TABLE; + boolean statementSanitizationEnabled = true; SqlClientAttributesExtractorBuilder(SqlClientAttributesGetter getter) { this.getter = getter; @@ -34,11 +36,23 @@ public final class SqlClientAttributesExtractorBuilder { return this; } + /** + * Sets whether the {@code db.statement} attribute extracted by the constructed {@link + * SqlClientAttributesExtractor} should be sanitized. If set to {@code true}, all parameters that + * can potentially contain sensitive information will be masked. Enabled by default. + */ + public SqlClientAttributesExtractorBuilder setStatementSanitizationEnabled( + boolean statementSanitizationEnabled) { + this.statementSanitizationEnabled = statementSanitizationEnabled; + return this; + } + /** * Returns a new {@link SqlClientAttributesExtractor} with the settings of this {@link * SqlClientAttributesExtractorBuilder}. */ public SqlClientAttributesExtractor build() { - return new SqlClientAttributesExtractor<>(getter, dbTableAttribute); + return new SqlClientAttributesExtractor<>( + getter, dbTableAttribute, SqlStatementSanitizer.create(statementSanitizationEnabled)); } } diff --git a/instrumentation-api-semconv/src/test/groovy/io/opentelemetry/instrumentation/api/db/RedisCommandSanitizerTest.groovy b/instrumentation-api-semconv/src/test/groovy/io/opentelemetry/instrumentation/api/db/RedisCommandSanitizerTest.groovy index 9f110e1a0d..3a66f3d65a 100644 --- a/instrumentation-api-semconv/src/test/groovy/io/opentelemetry/instrumentation/api/db/RedisCommandSanitizerTest.groovy +++ b/instrumentation-api-semconv/src/test/groovy/io/opentelemetry/instrumentation/api/db/RedisCommandSanitizerTest.groovy @@ -12,7 +12,7 @@ class RedisCommandSanitizerTest extends Specification { @Unroll def "should sanitize #expected"() { when: - def sanitized = RedisCommandSanitizer.sanitize(command, args) + def sanitized = RedisCommandSanitizer.create(true).sanitize(command, args) then: sanitized == expected @@ -90,7 +90,7 @@ class RedisCommandSanitizerTest extends Specification { def args = ["arg1", "arg 2"] when: - def sanitized = RedisCommandSanitizer.sanitize(command, args) + def sanitized = RedisCommandSanitizer.create(true).sanitize(command, args) then: sanitized == command + " " + args.join(" ") @@ -140,7 +140,7 @@ class RedisCommandSanitizerTest extends Specification { def "should mask all arguments of an unknown command"() { when: - def sanitized = RedisCommandSanitizer.sanitize("NEWAUTH", ["password", "secret"]) + def sanitized = RedisCommandSanitizer.create(true).sanitize("NEWAUTH", ["password", "secret"]) then: sanitized == "NEWAUTH ? ?" diff --git a/instrumentation-api-semconv/src/test/groovy/io/opentelemetry/instrumentation/api/db/SqlStatementSanitizerTest.groovy b/instrumentation-api-semconv/src/test/groovy/io/opentelemetry/instrumentation/api/db/SqlStatementSanitizerTest.groovy index a126b2a312..a21418ef2f 100644 --- a/instrumentation-api-semconv/src/test/groovy/io/opentelemetry/instrumentation/api/db/SqlStatementSanitizerTest.groovy +++ b/instrumentation-api-semconv/src/test/groovy/io/opentelemetry/instrumentation/api/db/SqlStatementSanitizerTest.groovy @@ -12,7 +12,7 @@ class SqlStatementSanitizerTest extends Specification { def "normalize #originalSql"() { setup: - def actualSanitized = SqlStatementSanitizer.sanitize(originalSql) + def actualSanitized = SqlStatementSanitizer.create(true).sanitize(originalSql) expect: actualSanitized.getFullStatement() == sanitizedSql @@ -79,7 +79,7 @@ class SqlStatementSanitizerTest extends Specification { def "normalize couchbase #originalSql"() { setup: - def actualSanitized = SqlStatementSanitizer.sanitize(originalSql, SqlDialect.COUCHBASE) + def actualSanitized = SqlStatementSanitizer.create(true).sanitize(originalSql, SqlDialect.COUCHBASE) expect: actualSanitized.getFullStatement() == sanitizedSql @@ -99,7 +99,7 @@ class SqlStatementSanitizerTest extends Specification { @Unroll def "should simplify #sql"() { expect: - SqlStatementSanitizer.sanitize(sql) == expected + SqlStatementSanitizer.create(true).sanitize(sql) == expected where: sql | expected @@ -169,14 +169,14 @@ class SqlStatementSanitizerTest extends Specification { expect: def sanitizedQuery = query.replace('=123', '=?').substring(0, AutoSqlSanitizer.LIMIT) - SqlStatementSanitizer.sanitize(query) == SqlStatementInfo.create(sanitizedQuery, "SELECT", "table") + SqlStatementSanitizer.create(true).sanitize(query) == SqlStatementInfo.create(sanitizedQuery, "SELECT", "table") } def "lots and lots of ticks don't cause stack overflow or long runtimes"() { setup: String s = "'" for (int i = 0; i < 10000; i++) { - assert SqlStatementSanitizer.sanitize(s) != null + assert SqlStatementSanitizer.create(true).sanitize(s) != null s += "'" } } @@ -187,7 +187,7 @@ class SqlStatementSanitizerTest extends Specification { for (int i = 0; i < 10000; i++) { s += String.valueOf(i) } - assert "?" == SqlStatementSanitizer.sanitize(s).getFullStatement() + assert "?" == SqlStatementSanitizer.create(true).sanitize(s).getFullStatement() } def "very long numbers at end of table name don't cause problem"() { @@ -196,7 +196,7 @@ class SqlStatementSanitizerTest extends Specification { for (int i = 0; i < 10000; i++) { s += String.valueOf(i) } - assert s.substring(0, AutoSqlSanitizer.LIMIT) == SqlStatementSanitizer.sanitize(s).getFullStatement() + assert s.substring(0, AutoSqlSanitizer.LIMIT) == SqlStatementSanitizer.create(true).sanitize(s).getFullStatement() } def "test 32k truncation"() { @@ -205,7 +205,7 @@ class SqlStatementSanitizerTest extends Specification { for (int i = 0; i < 10000; i++) { s.append("SELECT * FROM TABLE WHERE FIELD = 1234 AND ") } - String sanitized = SqlStatementSanitizer.sanitize(s.toString()).getFullStatement() + String sanitized = SqlStatementSanitizer.create(true).sanitize(s.toString()).getFullStatement() System.out.println(sanitized.length()) assert sanitized.length() <= AutoSqlSanitizer.LIMIT assert !sanitized.contains("1234") @@ -219,7 +219,7 @@ class SqlStatementSanitizerTest extends Specification { for (int c = 0; c < 1000; c++) { sb.append((char) r.nextInt((int) Character.MAX_VALUE)) } - SqlStatementSanitizer.sanitize(sb.toString()) + SqlStatementSanitizer.create(true).sanitize(sb.toString()) } } } diff --git a/instrumentation-api-semconv/src/test/java/io/opentelemetry/instrumentation/api/db/StatementSanitizationConfigTest.java b/instrumentation-api-semconv/src/test/java/io/opentelemetry/instrumentation/api/db/StatementSanitizationConfigTest.java deleted file mode 100644 index 30a6e20490..0000000000 --- a/instrumentation-api-semconv/src/test/java/io/opentelemetry/instrumentation/api/db/StatementSanitizationConfigTest.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.instrumentation.api.db; - -import static org.junit.jupiter.api.Assertions.assertFalse; - -import org.junit.jupiter.api.Test; - -public class StatementSanitizationConfigTest { - - @Test - void shouldGetFalse() { - assertFalse(StatementSanitizationConfig.isStatementSanitizationEnabled()); - } -} diff --git a/instrumentation/apache-camel-2.20/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachecamel/decorators/DbSpanDecorator.java b/instrumentation/apache-camel-2.20/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachecamel/decorators/DbSpanDecorator.java index 65d029ef0b..f831cf8b61 100644 --- a/instrumentation/apache-camel-2.20/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachecamel/decorators/DbSpanDecorator.java +++ b/instrumentation/apache-camel-2.20/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachecamel/decorators/DbSpanDecorator.java @@ -25,6 +25,7 @@ package io.opentelemetry.javaagent.instrumentation.apachecamel.decorators; import io.opentelemetry.api.common.AttributesBuilder; import io.opentelemetry.instrumentation.api.db.SqlStatementSanitizer; +import io.opentelemetry.javaagent.bootstrap.internal.CommonConfig; import io.opentelemetry.javaagent.instrumentation.apachecamel.CamelDirection; import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; import java.net.URI; @@ -34,6 +35,9 @@ import org.apache.camel.Exchange; class DbSpanDecorator extends BaseSpanDecorator { + private static final SqlStatementSanitizer sanitizer = + SqlStatementSanitizer.create(CommonConfig.get().isStatementSanitizationEnabled()); + private final String component; private final String system; @@ -65,19 +69,19 @@ class DbSpanDecorator extends BaseSpanDecorator { case "cql": Object cqlObj = exchange.getIn().getHeader("CamelCqlQuery"); if (cqlObj != null) { - return SqlStatementSanitizer.sanitize(cqlObj.toString()).getFullStatement(); + return sanitizer.sanitize(cqlObj.toString()).getFullStatement(); } return null; case "jdbc": Object body = exchange.getIn().getBody(); if (body instanceof String) { - return SqlStatementSanitizer.sanitize((String) body).getFullStatement(); + return sanitizer.sanitize((String) body).getFullStatement(); } return null; case "sql": Object sqlquery = exchange.getIn().getHeader("CamelSqlQuery"); if (sqlquery instanceof String) { - return SqlStatementSanitizer.sanitize((String) sqlquery).getFullStatement(); + return sanitizer.sanitize((String) sqlquery).getFullStatement(); } return null; default: diff --git a/instrumentation/cassandra/cassandra-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/cassandra/v3_0/CassandraSingletons.java b/instrumentation/cassandra/cassandra-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/cassandra/v3_0/CassandraSingletons.java index 01f4599bb1..24ca24b9c7 100644 --- a/instrumentation/cassandra/cassandra-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/cassandra/v3_0/CassandraSingletons.java +++ b/instrumentation/cassandra/cassandra-3.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/cassandra/v3_0/CassandraSingletons.java @@ -12,6 +12,7 @@ import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor; import io.opentelemetry.instrumentation.api.instrumenter.db.DbClientSpanNameExtractor; import io.opentelemetry.instrumentation.api.instrumenter.db.SqlClientAttributesExtractor; import io.opentelemetry.instrumentation.api.instrumenter.net.NetClientAttributesExtractor; +import io.opentelemetry.javaagent.bootstrap.internal.CommonConfig; import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; public final class CassandraSingletons { @@ -32,6 +33,8 @@ public final class CassandraSingletons { .addAttributesExtractor( SqlClientAttributesExtractor.builder(attributesGetter) .setTableAttribute(SemanticAttributes.DB_CASSANDRA_TABLE) + .setStatementSanitizationEnabled( + CommonConfig.get().isStatementSanitizationEnabled()) .build()) .addAttributesExtractor( NetClientAttributesExtractor.create(new CassandraNetAttributesGetter())) diff --git a/instrumentation/cassandra/cassandra-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/cassandra/v4_0/CassandraSingletons.java b/instrumentation/cassandra/cassandra-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/cassandra/v4_0/CassandraSingletons.java index eaa03855ea..8e2e692767 100644 --- a/instrumentation/cassandra/cassandra-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/cassandra/v4_0/CassandraSingletons.java +++ b/instrumentation/cassandra/cassandra-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/cassandra/v4_0/CassandraSingletons.java @@ -12,6 +12,7 @@ import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor; import io.opentelemetry.instrumentation.api.instrumenter.db.DbClientSpanNameExtractor; import io.opentelemetry.instrumentation.api.instrumenter.db.SqlClientAttributesExtractor; import io.opentelemetry.instrumentation.api.instrumenter.net.NetClientAttributesExtractor; +import io.opentelemetry.javaagent.bootstrap.internal.CommonConfig; import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; public final class CassandraSingletons { @@ -31,6 +32,8 @@ public final class CassandraSingletons { .addAttributesExtractor( SqlClientAttributesExtractor.builder(attributesGetter) .setTableAttribute(SemanticAttributes.DB_CASSANDRA_TABLE) + .setStatementSanitizationEnabled( + CommonConfig.get().isStatementSanitizationEnabled()) .build()) .addAttributesExtractor( NetClientAttributesExtractor.create(new CassandraNetAttributesGetter())) diff --git a/instrumentation/couchbase/couchbase-2-common/javaagent-unit-tests/build.gradle.kts b/instrumentation/couchbase/couchbase-2-common/javaagent-unit-tests/build.gradle.kts index d91fd2027c..08e327b8b0 100644 --- a/instrumentation/couchbase/couchbase-2-common/javaagent-unit-tests/build.gradle.kts +++ b/instrumentation/couchbase/couchbase-2-common/javaagent-unit-tests/build.gradle.kts @@ -7,6 +7,7 @@ dependencies { testImplementation("org.spockframework:spock-core") testImplementation(project(":instrumentation-api-semconv")) + testImplementation(project(":javaagent-extension-api")) testImplementation(project(":instrumentation:couchbase:couchbase-2-common:javaagent")) testImplementation("com.couchbase.client:java-client:2.5.0") } diff --git a/instrumentation/couchbase/couchbase-2-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/CouchbaseQuerySanitizer.java b/instrumentation/couchbase/couchbase-2-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/CouchbaseQuerySanitizer.java index 10c6a533d1..222d1b2e2f 100644 --- a/instrumentation/couchbase/couchbase-2-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/CouchbaseQuerySanitizer.java +++ b/instrumentation/couchbase/couchbase-2-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/couchbase/v2_0/CouchbaseQuerySanitizer.java @@ -8,12 +8,17 @@ package io.opentelemetry.javaagent.instrumentation.couchbase.v2_0; import io.opentelemetry.instrumentation.api.db.SqlDialect; import io.opentelemetry.instrumentation.api.db.SqlStatementInfo; import io.opentelemetry.instrumentation.api.db.SqlStatementSanitizer; +import io.opentelemetry.javaagent.bootstrap.internal.CommonConfig; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import javax.annotation.Nullable; public final class CouchbaseQuerySanitizer { + + private static final SqlStatementSanitizer sanitizer = + SqlStatementSanitizer.create(CommonConfig.get().isStatementSanitizationEnabled()); + @Nullable private static final Class QUERY_CLASS; @Nullable private static final Class STATEMENT_CLASS; @Nullable private static final Class N1QL_QUERY_CLASS; @@ -116,7 +121,7 @@ public final class CouchbaseQuerySanitizer { } private static SqlStatementInfo sanitizeString(String query) { - return SqlStatementSanitizer.sanitize(query, SqlDialect.COUCHBASE); + return sanitizer.sanitize(query, SqlDialect.COUCHBASE); } private CouchbaseQuerySanitizer() {} diff --git a/instrumentation/geode-1.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/geode/GeodeDbAttributesGetter.java b/instrumentation/geode-1.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/geode/GeodeDbAttributesGetter.java index f93ce70303..cc0304c5d5 100644 --- a/instrumentation/geode-1.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/geode/GeodeDbAttributesGetter.java +++ b/instrumentation/geode-1.4/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/geode/GeodeDbAttributesGetter.java @@ -7,11 +7,15 @@ package io.opentelemetry.javaagent.instrumentation.geode; import io.opentelemetry.instrumentation.api.db.SqlStatementSanitizer; import io.opentelemetry.instrumentation.api.instrumenter.db.DbClientAttributesGetter; +import io.opentelemetry.javaagent.bootstrap.internal.CommonConfig; import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; import javax.annotation.Nullable; final class GeodeDbAttributesGetter implements DbClientAttributesGetter { + private static final SqlStatementSanitizer sanitizer = + SqlStatementSanitizer.create(CommonConfig.get().isStatementSanitizationEnabled()); + @Override public String system(GeodeRequest request) { return SemanticAttributes.DbSystemValues.GEODE; @@ -38,7 +42,7 @@ final class GeodeDbAttributesGetter implements DbClientAttributesGetter { + private static final RedisCommandSanitizer sanitizer = + RedisCommandSanitizer.create(CommonConfig.get().isStatementSanitizationEnabled()); + @Override public String system(JedisRequest request) { return SemanticAttributes.DbSystemValues.REDIS; @@ -35,7 +39,7 @@ final class JedisDbAttributesGetter implements DbClientAttributesGetter args) { return new AutoValue_JedisRequest(connection, command, args); @@ -39,6 +43,6 @@ public abstract class JedisRequest { } public String getStatement() { - return RedisCommandSanitizer.sanitize(getOperation(), getArgs()); + return sanitizer.sanitize(getOperation(), getArgs()); } } diff --git a/instrumentation/jedis/jedis-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jedis/v4_0/JedisRequest.java b/instrumentation/jedis/jedis-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jedis/v4_0/JedisRequest.java index 0980942592..6de09a4ea1 100644 --- a/instrumentation/jedis/jedis-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jedis/v4_0/JedisRequest.java +++ b/instrumentation/jedis/jedis-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/jedis/v4_0/JedisRequest.java @@ -7,6 +7,7 @@ package io.opentelemetry.javaagent.instrumentation.jedis.v4_0; import com.google.auto.value.AutoValue; import io.opentelemetry.instrumentation.api.db.RedisCommandSanitizer; +import io.opentelemetry.javaagent.bootstrap.internal.CommonConfig; import java.net.Socket; import java.net.SocketAddress; import java.nio.charset.StandardCharsets; @@ -20,6 +21,9 @@ import redis.clients.jedis.commands.ProtocolCommand; @AutoValue public abstract class JedisRequest { + private static final RedisCommandSanitizer sanitizer = + RedisCommandSanitizer.create(CommonConfig.get().isStatementSanitizationEnabled()); + public static JedisRequest create(ProtocolCommand command, List args) { return new AutoValue_JedisRequest(command, args); } @@ -54,7 +58,7 @@ public abstract class JedisRequest { } public String getStatement() { - return RedisCommandSanitizer.sanitize(getOperation(), getArgs()); + return sanitizer.sanitize(getOperation(), getArgs()); } private SocketAddress remoteSocketAddress; diff --git a/instrumentation/lettuce/lettuce-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/LettuceDbAttributesGetter.java b/instrumentation/lettuce/lettuce-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/LettuceDbAttributesGetter.java index 09aea5fd9a..f1a55c8192 100644 --- a/instrumentation/lettuce/lettuce-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/LettuceDbAttributesGetter.java +++ b/instrumentation/lettuce/lettuce-5.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/lettuce/v5_0/LettuceDbAttributesGetter.java @@ -9,6 +9,7 @@ import io.lettuce.core.protocol.RedisCommand; import io.opentelemetry.instrumentation.api.db.RedisCommandSanitizer; import io.opentelemetry.instrumentation.api.instrumenter.db.DbClientAttributesGetter; import io.opentelemetry.instrumentation.lettuce.common.LettuceArgSplitter; +import io.opentelemetry.javaagent.bootstrap.internal.CommonConfig; import io.opentelemetry.semconv.trace.attributes.SemanticAttributes; import java.util.Collections; import java.util.List; @@ -16,6 +17,9 @@ import javax.annotation.Nullable; final class LettuceDbAttributesGetter implements DbClientAttributesGetter> { + private static final RedisCommandSanitizer sanitizer = + RedisCommandSanitizer.create(CommonConfig.get().isStatementSanitizationEnabled()); + @Override public String system(RedisCommand request) { return SemanticAttributes.DbSystemValues.REDIS; @@ -46,7 +50,7 @@ final class LettuceDbAttributesGetter implements DbClientAttributesGetter events; @@ -174,9 +178,10 @@ final class OpenTelemetryTracing implements Tracing { @Nullable private Span span; @Nullable private String args; - OpenTelemetrySpan(Context context, SpanBuilder spanBuilder) { + OpenTelemetrySpan(Context context, SpanBuilder spanBuilder, RedisCommandSanitizer sanitizer) { this.context = context; this.spanBuilder = spanBuilder; + this.sanitizer = sanitizer; } @Override @@ -319,7 +324,7 @@ final class OpenTelemetryTracing implements Tracing { private void finish(Span span) { if (name != null) { - String statement = RedisCommandSanitizer.sanitize(name, splitArgs(args)); + String statement = sanitizer.sanitize(name, splitArgs(args)); span.setAttribute(SemanticAttributes.DB_STATEMENT, statement); } span.end(); diff --git a/instrumentation/redisson/redisson-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/redisson/RedissonRequest.java b/instrumentation/redisson/redisson-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/redisson/RedissonRequest.java index 828fde96db..4a3d1e6518 100644 --- a/instrumentation/redisson/redisson-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/redisson/RedissonRequest.java +++ b/instrumentation/redisson/redisson-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/redisson/RedissonRequest.java @@ -11,6 +11,7 @@ import static java.util.Collections.singletonList; import com.google.auto.value.AutoValue; import io.netty.buffer.ByteBuf; import io.opentelemetry.instrumentation.api.db.RedisCommandSanitizer; +import io.opentelemetry.javaagent.bootstrap.internal.CommonConfig; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; @@ -27,6 +28,9 @@ import org.redisson.client.protocol.CommandsData; @AutoValue public abstract class RedissonRequest { + private static final RedisCommandSanitizer sanitizer = + RedisCommandSanitizer.create(CommonConfig.get().isStatementSanitizationEnabled()); + public static RedissonRequest create(InetSocketAddress address, Object command) { return new AutoValue_RedissonRequest(address, command); } @@ -98,7 +102,7 @@ public abstract class RedissonRequest { args.add(param); } } - return RedisCommandSanitizer.sanitize(command.getCommand().getName(), args); + return sanitizer.sanitize(command.getCommand().getName(), args); } @Nullable diff --git a/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/bootstrap/internal/CommonConfig.java b/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/bootstrap/internal/CommonConfig.java index 42bba18764..7072f64809 100644 --- a/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/bootstrap/internal/CommonConfig.java +++ b/javaagent-extension-api/src/main/java/io/opentelemetry/javaagent/bootstrap/internal/CommonConfig.java @@ -28,6 +28,7 @@ public final class CommonConfig { private final List clientResponseHeaders; private final List serverRequestHeaders; private final List serverResponseHeaders; + private final boolean statementSanitizationEnabled; CommonConfig(InstrumentationConfig config) { peerServiceMapping = @@ -40,6 +41,8 @@ public final class CommonConfig { config.getList("otel.instrumentation.http.capture-headers.server.request", emptyList()); serverResponseHeaders = config.getList("otel.instrumentation.http.capture-headers.server.response", emptyList()); + statementSanitizationEnabled = + config.getBoolean("otel.instrumentation.common.db-statement-sanitizer.enabled", true); } public Map getPeerServiceMapping() { @@ -61,4 +64,8 @@ public final class CommonConfig { public List getServerResponseHeaders() { return serverResponseHeaders; } + + public boolean isStatementSanitizationEnabled() { + return statementSanitizationEnabled; + } }