From c8a5c145f998d3eeae732cb312c3cd42423c4c96 Mon Sep 17 00:00:00 2001 From: Jean Bisutti Date: Mon, 27 Jan 2025 15:01:05 +0100 Subject: [PATCH 01/22] Redact query string values --- .../http/HttpClientAttributesExtractor.java | 77 ++++++++++++++++++- .../HttpClientAttributesExtractorTest.java | 77 +++++++++++++++++++ 2 files changed, 151 insertions(+), 3 deletions(-) diff --git a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java index 5769d1169c3f..8ff09cb135ab 100644 --- a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java +++ b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java @@ -17,6 +17,9 @@ import io.opentelemetry.instrumentation.api.semconv.network.internal.InternalServerAttributesExtractor; import io.opentelemetry.semconv.HttpAttributes; import io.opentelemetry.semconv.UrlAttributes; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; import java.util.function.ToIntFunction; import javax.annotation.Nullable; @@ -32,6 +35,9 @@ public final class HttpClientAttributesExtractor REQUEST, RESPONSE, HttpClientAttributesGetter> implements SpanKeyProvider { + private static final Set PARAMS_TO_REDACT = + new HashSet<>(Arrays.asList("AWSAccessKeyId", "Signature", "sig", "X-Goog-Signature")); + /** * Creates the HTTP client attributes extractor with default configuration. * @@ -54,6 +60,7 @@ public static HttpClientAttributesExtractorBuilder internalNetworkExtractor; private final InternalServerAttributesExtractor internalServerExtractor; private final ToIntFunction resendCountIncrementer; + private final boolean redactSensitiveParameters; HttpClientAttributesExtractor(HttpClientAttributesExtractorBuilder builder) { super( @@ -65,6 +72,9 @@ public static HttpClientAttributesExtractorBuilder request = new HashMap<>(); + request.put("urlFull", url); + + System.setProperty( + "otel.instrumentation.http.client.experimental.redact-sensitive-parameters", "true"); + AttributesExtractor, Map> extractor = + HttpClientAttributesExtractor.create(new TestHttpClientAttributesGetter()); + + AttributesBuilder attributes = Attributes.builder(); + extractor.onStart(attributes, Context.root(), request); + + assertThat(attributes.build()).containsOnly(entry(URL_FULL, expectedResult)); + } + + static final class StripUrlArgumentSource implements ArgumentsProvider { + + @Override + public Stream provideArguments(ExtensionContext context) { + return Stream.of( + arguments("https://user1:secret@github.com", "https://REDACTED:REDACTED@github.com"), + arguments( + "https://user1:secret@github.com/path/", + "https://REDACTED:REDACTED@github.com/path/"), + arguments( + "https://user1:secret@github.com#test.html", + "https://REDACTED:REDACTED@github.com#test.html"), + arguments( + "https://user1:secret@github.com?foo=b@r", + "https://REDACTED:REDACTED@github.com?foo=b@r"), + arguments( + "https://user1:secret@github.com/p@th?foo=b@r", + "https://REDACTED:REDACTED@github.com/p@th?foo=b@r"), + arguments("https://github.com/p@th?foo=b@r", "https://github.com/p@th?foo=b@r"), + arguments("https://github.com#t@st.html", "https://github.com#t@st.html"), + arguments("user1:secret@github.com", "user1:secret@github.com"), + arguments("https://github.com@", "https://github.com@"), + arguments( + "https://service.com?paramA=valA¶mB=valB", + "https://service.com?paramA=valA¶mB=valB"), + arguments( + "https://service.com?AWSAccessKeyId=AKIAIOSFODNN7", + "https://service.com?AWSAccessKeyId=REDACTED"), + arguments( + "https://service.com?Signature=39Up9jzHkxhuIhFE9594DJxe7w6cIRCg0V6ICGS0%3A377", + "https://service.com?Signature=REDACTED"), + arguments( + "https://service.com?sig=39Up9jzHkxhuIhFE9594DJxe7w6cIRCg0V6ICGS0", + "https://service.com?sig=REDACTED"), + arguments( + "https://service.com?X-Goog-Signature=39Up9jzHkxhuIhFE9594DJxe7w6cIRCg0V6ICGS0", + "https://service.com?X-Goog-Signature=REDACTED"), + arguments( + "https://service.com?paramA=valA&AWSAccessKeyId=AKIAIOSFODNN7¶mB=valB", + "https://service.com?paramA=valA&AWSAccessKeyId=REDACTED¶mB=valB"), + arguments( + "https://service.com?AWSAccessKeyId=AKIAIOSFODNN7¶mA=valA", + "https://service.com?AWSAccessKeyId=REDACTED¶mA=valA"), + arguments( + "https://service.com?paramA=valA&AWSAccessKeyId=AKIAIOSFODNN7", + "https://service.com?paramA=valA&AWSAccessKeyId=REDACTED"), + arguments( + "https://service.com?AWSAccessKeyId=AKIAIOSFODNN7&AWSAccessKeyId=ZGIAIOSFODNN7", + "https://service.com?AWSAccessKeyId=REDACTED&AWSAccessKeyId=REDACTED"), + arguments( + "https://service.com?AWSAccessKeyId=AKIAIOSFODNN7#ref", + "https://service.com?AWSAccessKeyId=REDACTED#ref")); + } + } + @ParameterizedTest @ArgumentsSource(ValidRequestMethodsProvider.class) void shouldExtractKnownMethods(String requestMethod) { From 641260e0d0e6054f2e923818d8780f3b196875ae Mon Sep 17 00:00:00 2001 From: Jean Bisutti Date: Wed, 29 Jan 2025 14:08:02 +0100 Subject: [PATCH 02/22] Update instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java Co-authored-by: Steve Rao --- .../api/semconv/http/HttpClientAttributesExtractor.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java index 8ff09cb135ab..ce3803de7d52 100644 --- a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java +++ b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java @@ -166,11 +166,7 @@ private static String redactUrlParameters(String urlpart) { int questionMarkIndex = urlpart.indexOf('?'); - if (questionMarkIndex == -1) { - return urlpart; - } - - if (!containsParamToRedact(urlpart)) { + if (questionMarkIndex == -1 || !containsParamToRedact(urlpart)) { return urlpart; } From e65eb6a827441fe34b35811a8f0fa13b1c981e91 Mon Sep 17 00:00:00 2001 From: Jean Bisutti Date: Wed, 29 Jan 2025 14:39:20 +0100 Subject: [PATCH 03/22] Add comments --- .../http/HttpClientAttributesExtractor.java | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java index ce3803de7d52..e312979603f3 100644 --- a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java +++ b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java @@ -170,38 +170,42 @@ private static String redactUrlParameters(String urlpart) { return urlpart; } - StringBuilder redactedParameters = new StringBuilder(); - boolean paramToRedact = false; + boolean paramToRedact = false; // To be able to skip the characters of the parameters to redact boolean paramNameDetected = false; boolean reference = false; + StringBuilder urlPartAfterQuestionMark = new StringBuilder(); + + // To build a parameter name until we reach the '=' character + // If the parameter name is a one to redact, we will redact the value StringBuilder currentParamName = new StringBuilder(); for (int i = questionMarkIndex + 1; i < urlpart.length(); i++) { char currentChar = urlpart.charAt(i); if (currentChar == '=') { paramNameDetected = true; - redactedParameters.append(currentParamName); - redactedParameters.append('='); + urlPartAfterQuestionMark.append(currentParamName); + urlPartAfterQuestionMark.append('='); if (PARAMS_TO_REDACT.contains(currentParamName.toString())) { - redactedParameters.append("REDACTED"); + urlPartAfterQuestionMark.append("REDACTED"); paramToRedact = true; } - } else if (currentChar == '&') { - redactedParameters.append('&'); + } else if (currentChar == '&') { // New parameter delimiter + urlPartAfterQuestionMark.append('&'); paramNameDetected = false; paramToRedact = false; - currentParamName.setLength(0); - } else if (currentChar == '#') { + currentParamName.setLength( + 0); // To avoid creating a new StringBuilder for each new parameter + } else if (currentChar == '#') { // Reference delimiter reference = true; - redactedParameters.append('#'); + urlPartAfterQuestionMark.append('#'); } else if (!paramNameDetected) { currentParamName.append(currentChar); } else if (!paramToRedact || reference) { - redactedParameters.append(currentChar); + urlPartAfterQuestionMark.append(currentChar); } } - return urlpart.substring(0, questionMarkIndex) + "?" + redactedParameters; + return urlpart.substring(0, questionMarkIndex) + "?" + urlPartAfterQuestionMark; } private static boolean containsParamToRedact(String urlpart) { From 417df19c61f1d8c06affdca39bc34610b03812a5 Mon Sep 17 00:00:00 2001 From: Jean Bisutti Date: Fri, 31 Jan 2025 17:57:27 +0100 Subject: [PATCH 04/22] Update instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java Co-authored-by: Lauri Tulmin --- .../api/semconv/http/HttpClientAttributesExtractor.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java index e312979603f3..c3f85bdaa3a4 100644 --- a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java +++ b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java @@ -163,9 +163,7 @@ private String stripSensitiveData(@Nullable String url) { } private static String redactUrlParameters(String urlpart) { - int questionMarkIndex = urlpart.indexOf('?'); - if (questionMarkIndex == -1 || !containsParamToRedact(urlpart)) { return urlpart; } From 65f0a33288125220ae2604784f09c7ae6ccfa0d2 Mon Sep 17 00:00:00 2001 From: Jean Bisutti Date: Tue, 11 Feb 2025 16:54:32 +0100 Subject: [PATCH 05/22] Move configuration from the stable API --- .../DefaultHttpClientInstrumenterBuilder.java | 20 ++++ .../config/internal/CommonConfig.java | 8 ++ ...erimentalHttpParamsRedactionExtractor.java | 106 ++++++++++++++++++ ...entalHttpParamsRedactionExtractorTest.java | 95 ++++++++++++++++ .../http/HttpClientAttributesExtractor.java | 75 +------------ .../HttpClientAttributesExtractorTest.java | 34 +----- ...itional-spring-configuration-metadata.json | 6 + .../AbstractOtelSpringStarterSmokeTest.java | 19 ++++ .../src/main/resources/application.yaml | 2 + 9 files changed, 260 insertions(+), 105 deletions(-) create mode 100644 instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/http/HttpClientExperimentalHttpParamsRedactionExtractor.java create mode 100644 instrumentation-api-incubator/src/test/java/io/opentelemetry/instrumentation/api/incubator/semconv/http/HttpClientExperimentalHttpParamsRedactionExtractorTest.java diff --git a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/builder/internal/DefaultHttpClientInstrumenterBuilder.java b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/builder/internal/DefaultHttpClientInstrumenterBuilder.java index a7929ae56eba..5b2ddb8f567d 100644 --- a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/builder/internal/DefaultHttpClientInstrumenterBuilder.java +++ b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/builder/internal/DefaultHttpClientInstrumenterBuilder.java @@ -10,6 +10,7 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.context.propagation.TextMapSetter; import io.opentelemetry.instrumentation.api.incubator.config.internal.CommonConfig; +import io.opentelemetry.instrumentation.api.incubator.semconv.http.HttpClientExperimentalHttpParamsRedactionExtractor; import io.opentelemetry.instrumentation.api.incubator.semconv.http.HttpClientExperimentalMetrics; import io.opentelemetry.instrumentation.api.incubator.semconv.http.HttpClientPeerServiceAttributesExtractor; import io.opentelemetry.instrumentation.api.incubator.semconv.http.HttpExperimentalAttributesExtractor; @@ -63,6 +64,7 @@ public final class DefaultHttpClientInstrumenterBuilder { private Function, ? extends SpanNameExtractor> spanNameExtractorTransformer = Function.identity(); private boolean emitExperimentalHttpClientMetrics = false; + private boolean redactSensitiveUrlParameters = false; private Consumer> builderCustomizer = b -> {}; private DefaultHttpClientInstrumenterBuilder( @@ -177,6 +179,19 @@ public DefaultHttpClientInstrumenterBuilder setKnownMethods( return this; } + /** + * Configures the instrumentation to redact sensitive URL parameters. + * + * @param redactSensitiveUrlParameters {@code true} if the sensitive URL parameters have to be + * redacted. + */ + @CanIgnoreReturnValue + public DefaultHttpClientInstrumenterBuilder setRedactSensitiveUrlParameters( + boolean redactSensitiveUrlParameters) { + this.redactSensitiveUrlParameters = redactSensitiveUrlParameters; + return this; + } + /** Sets custom {@link SpanNameExtractor} via transform function. */ @CanIgnoreReturnValue public DefaultHttpClientInstrumenterBuilder setSpanNameExtractor( @@ -225,6 +240,10 @@ public Instrumenter build() { .addAttributesExtractor(HttpExperimentalAttributesExtractor.create(attributesGetter)) .addOperationMetrics(HttpClientExperimentalMetrics.get()); } + if (redactSensitiveUrlParameters) { + builder.addAttributesExtractor( + HttpClientExperimentalHttpParamsRedactionExtractor.create(attributesGetter)); + } builderCustomizer.accept(builder); if (headerSetter != null) { @@ -248,6 +267,7 @@ public DefaultHttpClientInstrumenterBuilder configure(CommonC set( config::shouldEmitExperimentalHttpClientTelemetry, this::setEmitExperimentalHttpClientMetrics); + set(config::shouldRedactSensitiveUrlParameters, this::setRedactSensitiveUrlParameters); return this; } diff --git a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/config/internal/CommonConfig.java b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/config/internal/CommonConfig.java index 23875d7e8b5f..e6e510a29db6 100644 --- a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/config/internal/CommonConfig.java +++ b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/config/internal/CommonConfig.java @@ -31,6 +31,7 @@ public final class CommonConfig { private final boolean statementSanitizationEnabled; private final boolean emitExperimentalHttpClientTelemetry; private final boolean emitExperimentalHttpServerTelemetry; + private final boolean redactSensitiveUrlParameters; private final String loggingTraceIdKey; private final String loggingSpanIdKey; private final String loggingTraceFlagsKey; @@ -57,6 +58,9 @@ public CommonConfig(InstrumentationConfig config) { config.getBoolean("otel.instrumentation.common.db-statement-sanitizer.enabled", true); emitExperimentalHttpClientTelemetry = config.getBoolean("otel.instrumentation.http.client.emit-experimental-telemetry", false); + redactSensitiveUrlParameters = + config.getBoolean( + "otel.instrumentation.http.client.experimental.redact-sensitive-url-parameters", false); emitExperimentalHttpServerTelemetry = config.getBoolean("otel.instrumentation.http.server.emit-experimental-telemetry", false); enduserConfig = new EnduserConfig(config); @@ -111,6 +115,10 @@ public boolean shouldEmitExperimentalHttpServerTelemetry() { return emitExperimentalHttpServerTelemetry; } + public boolean shouldRedactSensitiveUrlParameters() { + return redactSensitiveUrlParameters; + } + public String getTraceIdKey() { return loggingTraceIdKey; } diff --git a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/http/HttpClientExperimentalHttpParamsRedactionExtractor.java b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/http/HttpClientExperimentalHttpParamsRedactionExtractor.java new file mode 100644 index 000000000000..137f4633cfa5 --- /dev/null +++ b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/http/HttpClientExperimentalHttpParamsRedactionExtractor.java @@ -0,0 +1,106 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.api.incubator.semconv.http; + +import static io.opentelemetry.instrumentation.api.internal.AttributesExtractorUtil.internalSet; + +import io.opentelemetry.api.common.AttributesBuilder; +import io.opentelemetry.context.Context; +import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; +import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesGetter; +import io.opentelemetry.semconv.UrlAttributes; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import javax.annotation.Nullable; + +public class HttpClientExperimentalHttpParamsRedactionExtractor + implements AttributesExtractor { + + private final HttpClientAttributesGetter attributesGetter; + + private static final Set PARAMS_TO_REDACT = + new HashSet<>(Arrays.asList("AWSAccessKeyId", "Signature", "sig", "X-Goog-Signature")); + + public HttpClientExperimentalHttpParamsRedactionExtractor( + HttpClientAttributesGetter attributesGetter) { + this.attributesGetter = attributesGetter; + } + + public static + HttpClientExperimentalHttpParamsRedactionExtractor create( + HttpClientAttributesGetter attributesGetter) { + return new HttpClientExperimentalHttpParamsRedactionExtractor<>(attributesGetter); + } + + @Override + public void onStart(AttributesBuilder attributes, Context parentContext, REQUEST request) { + String urlFull = attributesGetter.getUrlFull(request); + String redactedUrlParameters = redactUrlParameters(urlFull); + internalSet(attributes, UrlAttributes.URL_FULL, redactedUrlParameters); + } + + private static String redactUrlParameters(String url) { + int questionMarkIndex = url.indexOf('?'); + if (questionMarkIndex == -1 || !containsParamToRedact(url)) { + return url; + } + + boolean paramToRedact = false; // To be able to skip the characters of the parameters to redact + boolean paramNameDetected = false; + boolean reference = false; + + StringBuilder urlPartAfterQuestionMark = new StringBuilder(); + + // To build a parameter name until we reach the '=' character + // If the parameter name is a one to redact, we will redact the value + StringBuilder currentParamName = new StringBuilder(); + + for (int i = questionMarkIndex + 1; i < url.length(); i++) { + char currentChar = url.charAt(i); + if (currentChar == '=') { + paramNameDetected = true; + urlPartAfterQuestionMark.append(currentParamName); + urlPartAfterQuestionMark.append('='); + if (PARAMS_TO_REDACT.contains(currentParamName.toString())) { + urlPartAfterQuestionMark.append("REDACTED"); + paramToRedact = true; + } + } else if (currentChar == '&') { // New parameter delimiter + urlPartAfterQuestionMark.append('&'); + paramNameDetected = false; + paramToRedact = false; + currentParamName.setLength( + 0); // To avoid creating a new StringBuilder for each new parameter + } else if (currentChar == '#') { // Reference delimiter + reference = true; + urlPartAfterQuestionMark.append('#'); + } else if (!paramNameDetected) { + currentParamName.append(currentChar); + } else if (!paramToRedact || reference) { + urlPartAfterQuestionMark.append(currentChar); + } + } + return url.substring(0, questionMarkIndex) + "?" + urlPartAfterQuestionMark; + } + + private static boolean containsParamToRedact(String urlpart) { + for (String param : PARAMS_TO_REDACT) { + if (urlpart.contains(param)) { + return true; + } + } + return false; + } + + @Override + public void onEnd( + AttributesBuilder attributes, + Context context, + REQUEST request, + @Nullable RESPONSE response, + @Nullable Throwable error) {} +} diff --git a/instrumentation-api-incubator/src/test/java/io/opentelemetry/instrumentation/api/incubator/semconv/http/HttpClientExperimentalHttpParamsRedactionExtractorTest.java b/instrumentation-api-incubator/src/test/java/io/opentelemetry/instrumentation/api/incubator/semconv/http/HttpClientExperimentalHttpParamsRedactionExtractorTest.java new file mode 100644 index 000000000000..a2ab883dd0e3 --- /dev/null +++ b/instrumentation-api-incubator/src/test/java/io/opentelemetry/instrumentation/api/incubator/semconv/http/HttpClientExperimentalHttpParamsRedactionExtractorTest.java @@ -0,0 +1,95 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.api.incubator.semconv.http; + +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; +import static org.assertj.core.api.Assertions.entry; +import static org.junit.jupiter.params.provider.Arguments.arguments; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.common.AttributesBuilder; +import io.opentelemetry.context.Context; +import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesGetter; +import io.opentelemetry.semconv.UrlAttributes; +import java.util.stream.Stream; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; +import org.junit.jupiter.params.provider.ArgumentsSource; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class HttpClientExperimentalHttpParamsRedactionExtractorTest { + + @Mock HttpClientAttributesGetter httpClientAttributesGetter; + + @ParameterizedTest + @ArgumentsSource(StripUrlArgumentSource.class) + void shouldRedactUrlQueryParameters(String url, String expectedResult) { + + // given + when(httpClientAttributesGetter.getUrlFull(any())).thenReturn(url); + + HttpClientExperimentalHttpParamsRedactionExtractor extractor = + HttpClientExperimentalHttpParamsRedactionExtractor.create(httpClientAttributesGetter); + + AttributesBuilder attributesBuilder = Attributes.builder(); + Context context = Context.root(); + + // when + extractor.onStart(attributesBuilder, context, "request"); + + // then + Attributes attributes = attributesBuilder.build(); + assertThat(attributes).containsOnly(entry(UrlAttributes.URL_FULL, expectedResult)); + } + + static final class StripUrlArgumentSource implements ArgumentsProvider { + + @Override + public Stream provideArguments(ExtensionContext context) { + return Stream.of( + arguments("https://github.com/p@th?foo=b@r", "https://github.com/p@th?foo=b@r"), + arguments("https://github.com#t@st.html", "https://github.com#t@st.html"), + arguments("https://github.com@", "https://github.com@"), + arguments( + "https://service.com?paramA=valA¶mB=valB", + "https://service.com?paramA=valA¶mB=valB"), + arguments( + "https://service.com?AWSAccessKeyId=AKIAIOSFODNN7", + "https://service.com?AWSAccessKeyId=REDACTED"), + arguments( + "https://service.com?Signature=39Up9jzHkxhuIhFE9594DJxe7w6cIRCg0V6ICGS0%3A377", + "https://service.com?Signature=REDACTED"), + arguments( + "https://service.com?sig=39Up9jzHkxhuIhFE9594DJxe7w6cIRCg0V6ICGS0", + "https://service.com?sig=REDACTED"), + arguments( + "https://service.com?X-Goog-Signature=39Up9jzHkxhuIhFE9594DJxe7w6cIRCg0V6ICGS0", + "https://service.com?X-Goog-Signature=REDACTED"), + arguments( + "https://service.com?paramA=valA&AWSAccessKeyId=AKIAIOSFODNN7¶mB=valB", + "https://service.com?paramA=valA&AWSAccessKeyId=REDACTED¶mB=valB"), + arguments( + "https://service.com?AWSAccessKeyId=AKIAIOSFODNN7¶mA=valA", + "https://service.com?AWSAccessKeyId=REDACTED¶mA=valA"), + arguments( + "https://service.com?paramA=valA&AWSAccessKeyId=AKIAIOSFODNN7", + "https://service.com?paramA=valA&AWSAccessKeyId=REDACTED"), + arguments( + "https://service.com?AWSAccessKeyId=AKIAIOSFODNN7&AWSAccessKeyId=ZGIAIOSFODNN7", + "https://service.com?AWSAccessKeyId=REDACTED&AWSAccessKeyId=REDACTED"), + arguments( + "https://service.com?AWSAccessKeyId=AKIAIOSFODNN7#ref", + "https://service.com?AWSAccessKeyId=REDACTED#ref")); + } + } +} diff --git a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java index c3f85bdaa3a4..5769d1169c3f 100644 --- a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java +++ b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java @@ -17,9 +17,6 @@ import io.opentelemetry.instrumentation.api.semconv.network.internal.InternalServerAttributesExtractor; import io.opentelemetry.semconv.HttpAttributes; import io.opentelemetry.semconv.UrlAttributes; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; import java.util.function.ToIntFunction; import javax.annotation.Nullable; @@ -35,9 +32,6 @@ public final class HttpClientAttributesExtractor REQUEST, RESPONSE, HttpClientAttributesGetter> implements SpanKeyProvider { - private static final Set PARAMS_TO_REDACT = - new HashSet<>(Arrays.asList("AWSAccessKeyId", "Signature", "sig", "X-Goog-Signature")); - /** * Creates the HTTP client attributes extractor with default configuration. * @@ -60,7 +54,6 @@ public static HttpClientAttributesExtractorBuilder internalNetworkExtractor; private final InternalServerAttributesExtractor internalServerExtractor; private final ToIntFunction resendCountIncrementer; - private final boolean redactSensitiveParameters; HttpClientAttributesExtractor(HttpClientAttributesExtractorBuilder builder) { super( @@ -72,9 +65,6 @@ public static HttpClientAttributesExtractorBuilder request = new HashMap<>(); request.put("urlFull", url); - System.setProperty( - "otel.instrumentation.http.client.experimental.redact-sensitive-parameters", "true"); AttributesExtractor, Map> extractor = HttpClientAttributesExtractor.create(new TestHttpClientAttributesGetter()); @@ -243,37 +241,7 @@ public Stream provideArguments(ExtensionContext context) { arguments("https://github.com/p@th?foo=b@r", "https://github.com/p@th?foo=b@r"), arguments("https://github.com#t@st.html", "https://github.com#t@st.html"), arguments("user1:secret@github.com", "user1:secret@github.com"), - arguments("https://github.com@", "https://github.com@"), - arguments( - "https://service.com?paramA=valA¶mB=valB", - "https://service.com?paramA=valA¶mB=valB"), - arguments( - "https://service.com?AWSAccessKeyId=AKIAIOSFODNN7", - "https://service.com?AWSAccessKeyId=REDACTED"), - arguments( - "https://service.com?Signature=39Up9jzHkxhuIhFE9594DJxe7w6cIRCg0V6ICGS0%3A377", - "https://service.com?Signature=REDACTED"), - arguments( - "https://service.com?sig=39Up9jzHkxhuIhFE9594DJxe7w6cIRCg0V6ICGS0", - "https://service.com?sig=REDACTED"), - arguments( - "https://service.com?X-Goog-Signature=39Up9jzHkxhuIhFE9594DJxe7w6cIRCg0V6ICGS0", - "https://service.com?X-Goog-Signature=REDACTED"), - arguments( - "https://service.com?paramA=valA&AWSAccessKeyId=AKIAIOSFODNN7¶mB=valB", - "https://service.com?paramA=valA&AWSAccessKeyId=REDACTED¶mB=valB"), - arguments( - "https://service.com?AWSAccessKeyId=AKIAIOSFODNN7¶mA=valA", - "https://service.com?AWSAccessKeyId=REDACTED¶mA=valA"), - arguments( - "https://service.com?paramA=valA&AWSAccessKeyId=AKIAIOSFODNN7", - "https://service.com?paramA=valA&AWSAccessKeyId=REDACTED"), - arguments( - "https://service.com?AWSAccessKeyId=AKIAIOSFODNN7&AWSAccessKeyId=ZGIAIOSFODNN7", - "https://service.com?AWSAccessKeyId=REDACTED&AWSAccessKeyId=REDACTED"), - arguments( - "https://service.com?AWSAccessKeyId=AKIAIOSFODNN7#ref", - "https://service.com?AWSAccessKeyId=REDACTED#ref")); + arguments("https://github.com@", "https://github.com@")); } } diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json index f179b7e7f9bd..7d391ab3b52b 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -311,6 +311,12 @@ "description": "Enable the capture of experimental HTTP client telemetry. Add the http.request.body.size and http.response.body.size> attributes to spans, and record the http.client.request.size and http.client.response.size metrics.", "defaultValue": false }, + { + "name": "otel.instrumentation.http.client.experimental.redact-sensitive-parameters", + "type": "java.lang.Boolean", + "description": "Redact sensitive URL parameters. See https://opentelemetry.io/docs/specs/semconv/http/http-spans.", + "defaultValue": false + }, { "name": "otel.instrumentation.http.known-methods", "type": "java.util.List", diff --git a/smoke-tests-otel-starter/spring-boot-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelSpringStarterSmokeTest.java b/smoke-tests-otel-starter/spring-boot-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelSpringStarterSmokeTest.java index e4a85eb343f0..62c8239ba3f5 100644 --- a/smoke-tests-otel-starter/spring-boot-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelSpringStarterSmokeTest.java +++ b/smoke-tests-otel-starter/spring-boot-common/src/main/java/io/opentelemetry/spring/smoketest/AbstractOtelSpringStarterSmokeTest.java @@ -293,4 +293,23 @@ void restTemplate() { span.hasKind(SpanKind.SERVER).hasAttribute(HttpAttributes.HTTP_ROUTE, "/ping"), span -> withSpanAssert(span))); } + + @Test + void shouldRedactSomeUrlParameters() { + testing.clearAllExportedData(); + + RestTemplate restTemplate = restTemplateBuilder.rootUri("http://localhost:" + port).build(); + restTemplate.getForObject( + "/test?X-Goog-Signature=39Up9jzHkxhuIhFE9594DJxe7w6cIRCg0V6ICGS0", String.class); + + testing.waitAndAssertTraces( + traceAssert -> + traceAssert.hasSpansSatisfyingExactly( + span -> + HttpSpanDataAssert.create(span) + .assertClientGetRequest("/test?X-Goog-Signature=REDACTED"), + span -> + span.hasKind(SpanKind.SERVER) + .hasAttribute(HttpAttributes.HTTP_ROUTE, "/test"))); + } } diff --git a/smoke-tests-otel-starter/spring-boot-common/src/main/resources/application.yaml b/smoke-tests-otel-starter/spring-boot-common/src/main/resources/application.yaml index 4da76f769a0d..a557628d61e9 100644 --- a/smoke-tests-otel-starter/spring-boot-common/src/main/resources/application.yaml +++ b/smoke-tests-otel-starter/spring-boot-common/src/main/resources/application.yaml @@ -11,6 +11,8 @@ otel: http: client: emit-experimental-telemetry: true + experimental: + redact-sensitive-url-parameters: true server: emit-experimental-telemetry: true capture-request-headers: [key] From 951b0f4099fd36b9d50ef02baa520f86549565ba Mon Sep 17 00:00:00 2001 From: Jean Bisutti Date: Wed, 12 Feb 2025 12:39:01 +0100 Subject: [PATCH 06/22] Only use HttpClientAttributesExtractor and rename configuration --- .../DefaultHttpClientInstrumenterBuilder.java | 24 +++--- .../config/internal/CommonConfig.java | 10 +-- .../internal/ExperimentalParameterUtil.java | 25 +++++++ .../http/HttpClientAttributesExtractor.java | 75 ++++++++++++++++++- .../HttpClientAttributesExtractorBuilder.java | 3 + .../HttpClientAttributesExtractorTest.java | 35 ++++++++- .../src/main/resources/application.yaml | 2 +- 7 files changed, 154 insertions(+), 20 deletions(-) create mode 100644 instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/internal/ExperimentalParameterUtil.java diff --git a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/builder/internal/DefaultHttpClientInstrumenterBuilder.java b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/builder/internal/DefaultHttpClientInstrumenterBuilder.java index 5b2ddb8f567d..0bf1b7ec1ea0 100644 --- a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/builder/internal/DefaultHttpClientInstrumenterBuilder.java +++ b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/builder/internal/DefaultHttpClientInstrumenterBuilder.java @@ -10,7 +10,6 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.context.propagation.TextMapSetter; import io.opentelemetry.instrumentation.api.incubator.config.internal.CommonConfig; -import io.opentelemetry.instrumentation.api.incubator.semconv.http.HttpClientExperimentalHttpParamsRedactionExtractor; import io.opentelemetry.instrumentation.api.incubator.semconv.http.HttpClientExperimentalMetrics; import io.opentelemetry.instrumentation.api.incubator.semconv.http.HttpClientPeerServiceAttributesExtractor; import io.opentelemetry.instrumentation.api.incubator.semconv.http.HttpExperimentalAttributesExtractor; @@ -21,6 +20,7 @@ import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor; import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor; +import io.opentelemetry.instrumentation.api.internal.ExperimentalParameterUtil; import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesExtractor; import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesExtractorBuilder; import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesGetter; @@ -64,7 +64,7 @@ public final class DefaultHttpClientInstrumenterBuilder { private Function, ? extends SpanNameExtractor> spanNameExtractorTransformer = Function.identity(); private boolean emitExperimentalHttpClientMetrics = false; - private boolean redactSensitiveUrlParameters = false; + private boolean redactQueryParameters = false; private Consumer> builderCustomizer = b -> {}; private DefaultHttpClientInstrumenterBuilder( @@ -182,13 +182,12 @@ public DefaultHttpClientInstrumenterBuilder setKnownMethods( /** * Configures the instrumentation to redact sensitive URL parameters. * - * @param redactSensitiveUrlParameters {@code true} if the sensitive URL parameters have to be - * redacted. + * @param redactQueryParameters {@code true} if the sensitive URL parameters have to be redacted. */ @CanIgnoreReturnValue - public DefaultHttpClientInstrumenterBuilder setRedactSensitiveUrlParameters( - boolean redactSensitiveUrlParameters) { - this.redactSensitiveUrlParameters = redactSensitiveUrlParameters; + public DefaultHttpClientInstrumenterBuilder setRedactQueryParameters( + boolean redactQueryParameters) { + this.redactQueryParameters = redactQueryParameters; return this; } @@ -227,6 +226,10 @@ public Instrumenter build() { SpanNameExtractor spanNameExtractor = spanNameExtractorTransformer.apply(httpSpanNameExtractorBuilder.build()); + if (redactQueryParameters) { + ExperimentalParameterUtil.setRedactQueryParameters(redactQueryParameters); + } + InstrumenterBuilder builder = Instrumenter.builder( openTelemetry, instrumentationName, spanNameExtractor) @@ -240,10 +243,7 @@ public Instrumenter build() { .addAttributesExtractor(HttpExperimentalAttributesExtractor.create(attributesGetter)) .addOperationMetrics(HttpClientExperimentalMetrics.get()); } - if (redactSensitiveUrlParameters) { - builder.addAttributesExtractor( - HttpClientExperimentalHttpParamsRedactionExtractor.create(attributesGetter)); - } + builderCustomizer.accept(builder); if (headerSetter != null) { @@ -267,7 +267,7 @@ public DefaultHttpClientInstrumenterBuilder configure(CommonC set( config::shouldEmitExperimentalHttpClientTelemetry, this::setEmitExperimentalHttpClientMetrics); - set(config::shouldRedactSensitiveUrlParameters, this::setRedactSensitiveUrlParameters); + set(config::redactQueryParameters, this::setRedactQueryParameters); return this; } diff --git a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/config/internal/CommonConfig.java b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/config/internal/CommonConfig.java index e6e510a29db6..dbdd11f4a1b2 100644 --- a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/config/internal/CommonConfig.java +++ b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/config/internal/CommonConfig.java @@ -31,7 +31,7 @@ public final class CommonConfig { private final boolean statementSanitizationEnabled; private final boolean emitExperimentalHttpClientTelemetry; private final boolean emitExperimentalHttpServerTelemetry; - private final boolean redactSensitiveUrlParameters; + private final boolean redactQueryParameters; private final String loggingTraceIdKey; private final String loggingSpanIdKey; private final String loggingTraceFlagsKey; @@ -58,9 +58,9 @@ public CommonConfig(InstrumentationConfig config) { config.getBoolean("otel.instrumentation.common.db-statement-sanitizer.enabled", true); emitExperimentalHttpClientTelemetry = config.getBoolean("otel.instrumentation.http.client.emit-experimental-telemetry", false); - redactSensitiveUrlParameters = + redactQueryParameters = config.getBoolean( - "otel.instrumentation.http.client.experimental.redact-sensitive-url-parameters", false); + "otel.instrumentation.http.client.experimental.redact-query-parameters", false); emitExperimentalHttpServerTelemetry = config.getBoolean("otel.instrumentation.http.server.emit-experimental-telemetry", false); enduserConfig = new EnduserConfig(config); @@ -115,8 +115,8 @@ public boolean shouldEmitExperimentalHttpServerTelemetry() { return emitExperimentalHttpServerTelemetry; } - public boolean shouldRedactSensitiveUrlParameters() { - return redactSensitiveUrlParameters; + public boolean redactQueryParameters() { + return redactQueryParameters; } public String getTraceIdKey() { diff --git a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/internal/ExperimentalParameterUtil.java b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/internal/ExperimentalParameterUtil.java new file mode 100644 index 000000000000..40252aa39781 --- /dev/null +++ b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/internal/ExperimentalParameterUtil.java @@ -0,0 +1,25 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.api.internal; + +/** + * This class is internal and is hence not for public use. Its APIs are unstable and can change at + * any time. + */ +public class ExperimentalParameterUtil { + + private static boolean redactQueryParameters; + + private ExperimentalParameterUtil() {} + + public static boolean isRedactQueryParameters() { + return redactQueryParameters; + } + + public static void setRedactQueryParameters(boolean redactQueryParameters) { + ExperimentalParameterUtil.redactQueryParameters = redactQueryParameters; + } +} diff --git a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java index 5769d1169c3f..5d29bcbc7b69 100644 --- a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java +++ b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java @@ -17,6 +17,9 @@ import io.opentelemetry.instrumentation.api.semconv.network.internal.InternalServerAttributesExtractor; import io.opentelemetry.semconv.HttpAttributes; import io.opentelemetry.semconv.UrlAttributes; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; import java.util.function.ToIntFunction; import javax.annotation.Nullable; @@ -32,6 +35,9 @@ public final class HttpClientAttributesExtractor REQUEST, RESPONSE, HttpClientAttributesGetter> implements SpanKeyProvider { + private static final Set PARAMS_TO_REDACT = + new HashSet<>(Arrays.asList("AWSAccessKeyId", "Signature", "sig", "X-Goog-Signature")); + /** * Creates the HTTP client attributes extractor with default configuration. * @@ -54,6 +60,7 @@ public static HttpClientAttributesExtractorBuilder internalNetworkExtractor; private final InternalServerAttributesExtractor internalServerExtractor; private final ToIntFunction resendCountIncrementer; + private final boolean redactQueryParameters; HttpClientAttributesExtractor(HttpClientAttributesExtractorBuilder builder) { super( @@ -65,6 +72,7 @@ public static HttpClientAttributesExtractorBuilder { List capturedResponseHeaders = emptyList(); Set knownMethods = HttpConstants.KNOWN_METHODS; ToIntFunction resendCountIncrementer = HttpClientRequestResendCount::getAndIncrement; + boolean redactQueryParameters; HttpClientAttributesExtractorBuilder( HttpClientAttributesGetter httpAttributesGetter) { @@ -180,6 +182,7 @@ HttpClientAttributesExtractorBuilder setResendCountIncremente * @see InstrumenterBuilder#addAttributesExtractor(AttributesExtractor) */ public AttributesExtractor build() { + redactQueryParameters = ExperimentalParameterUtil.isRedactQueryParameters(); return new HttpClientAttributesExtractor<>(this); } diff --git a/instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractorTest.java b/instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractorTest.java index b16040cff47a..4305f9c6fcdb 100644 --- a/instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractorTest.java +++ b/instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractorTest.java @@ -30,6 +30,7 @@ import io.opentelemetry.api.common.AttributesBuilder; import io.opentelemetry.context.Context; import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; +import io.opentelemetry.instrumentation.api.internal.ExperimentalParameterUtil; import io.opentelemetry.instrumentation.api.internal.HttpConstants; import java.net.ConnectException; import java.util.HashMap; @@ -211,6 +212,8 @@ void stripBasicAuthTest(String url, String expectedResult) { Map request = new HashMap<>(); request.put("urlFull", url); + ExperimentalParameterUtil.setRedactQueryParameters(true); + AttributesExtractor, Map> extractor = HttpClientAttributesExtractor.create(new TestHttpClientAttributesGetter()); @@ -241,7 +244,37 @@ public Stream provideArguments(ExtensionContext context) { arguments("https://github.com/p@th?foo=b@r", "https://github.com/p@th?foo=b@r"), arguments("https://github.com#t@st.html", "https://github.com#t@st.html"), arguments("user1:secret@github.com", "user1:secret@github.com"), - arguments("https://github.com@", "https://github.com@")); + arguments("https://github.com@", "https://github.com@"), + arguments( + "https://service.com?paramA=valA¶mB=valB", + "https://service.com?paramA=valA¶mB=valB"), + arguments( + "https://service.com?AWSAccessKeyId=AKIAIOSFODNN7", + "https://service.com?AWSAccessKeyId=REDACTED"), + arguments( + "https://service.com?Signature=39Up9jzHkxhuIhFE9594DJxe7w6cIRCg0V6ICGS0%3A377", + "https://service.com?Signature=REDACTED"), + arguments( + "https://service.com?sig=39Up9jzHkxhuIhFE9594DJxe7w6cIRCg0V6ICGS0", + "https://service.com?sig=REDACTED"), + arguments( + "https://service.com?X-Goog-Signature=39Up9jzHkxhuIhFE9594DJxe7w6cIRCg0V6ICGS0", + "https://service.com?X-Goog-Signature=REDACTED"), + arguments( + "https://service.com?paramA=valA&AWSAccessKeyId=AKIAIOSFODNN7¶mB=valB", + "https://service.com?paramA=valA&AWSAccessKeyId=REDACTED¶mB=valB"), + arguments( + "https://service.com?AWSAccessKeyId=AKIAIOSFODNN7¶mA=valA", + "https://service.com?AWSAccessKeyId=REDACTED¶mA=valA"), + arguments( + "https://service.com?paramA=valA&AWSAccessKeyId=AKIAIOSFODNN7", + "https://service.com?paramA=valA&AWSAccessKeyId=REDACTED"), + arguments( + "https://service.com?AWSAccessKeyId=AKIAIOSFODNN7&AWSAccessKeyId=ZGIAIOSFODNN7", + "https://service.com?AWSAccessKeyId=REDACTED&AWSAccessKeyId=REDACTED"), + arguments( + "https://service.com?AWSAccessKeyId=AKIAIOSFODNN7#ref", + "https://service.com?AWSAccessKeyId=REDACTED#ref")); } } diff --git a/smoke-tests-otel-starter/spring-boot-common/src/main/resources/application.yaml b/smoke-tests-otel-starter/spring-boot-common/src/main/resources/application.yaml index a557628d61e9..b4d92f8dfa43 100644 --- a/smoke-tests-otel-starter/spring-boot-common/src/main/resources/application.yaml +++ b/smoke-tests-otel-starter/spring-boot-common/src/main/resources/application.yaml @@ -12,7 +12,7 @@ otel: client: emit-experimental-telemetry: true experimental: - redact-sensitive-url-parameters: true + redact-query-parameters: true server: emit-experimental-telemetry: true capture-request-headers: [key] From febf10899cf55c4d726ecda2be722f6be4bb8813 Mon Sep 17 00:00:00 2001 From: Jean Bisutti Date: Tue, 11 Feb 2025 18:06:28 +0100 Subject: [PATCH 07/22] Fix JSON metadata --- .../META-INF/additional-spring-configuration-metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 7d391ab3b52b..557bf0065450 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -312,7 +312,7 @@ "defaultValue": false }, { - "name": "otel.instrumentation.http.client.experimental.redact-sensitive-parameters", + "name": "otel.instrumentation.http.client.experimental.redact-sensitive-url-parameters", "type": "java.lang.Boolean", "description": "Redact sensitive URL parameters. See https://opentelemetry.io/docs/specs/semconv/http/http-spans.", "defaultValue": false From 53a7a0bf9a910df5f6bc1c19efbc2eebbdc4bab8 Mon Sep 17 00:00:00 2001 From: Jean Bisutti Date: Wed, 12 Feb 2025 14:48:26 +0100 Subject: [PATCH 08/22] Fix Spring metadata --- .../META-INF/additional-spring-configuration-metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 557bf0065450..6a9599c9d8d4 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -312,7 +312,7 @@ "defaultValue": false }, { - "name": "otel.instrumentation.http.client.experimental.redact-sensitive-url-parameters", + "name": "otel.instrumentation.http.client.experimental.redact-query-parameters", "type": "java.lang.Boolean", "description": "Redact sensitive URL parameters. See https://opentelemetry.io/docs/specs/semconv/http/http-spans.", "defaultValue": false From be63270585bebba7c70a936fecdd82e3e0c2c23a Mon Sep 17 00:00:00 2001 From: Jean Bisutti Date: Wed, 12 Feb 2025 17:08:18 +0100 Subject: [PATCH 09/22] Enable query redaction by default and clean up --- .../config/internal/CommonConfig.java | 2 +- ...erimentalHttpParamsRedactionExtractor.java | 106 ------------------ ...entalHttpParamsRedactionExtractorTest.java | 95 ---------------- ...itional-spring-configuration-metadata.json | 2 +- .../src/main/resources/application.yaml | 2 - 5 files changed, 2 insertions(+), 205 deletions(-) delete mode 100644 instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/http/HttpClientExperimentalHttpParamsRedactionExtractor.java delete mode 100644 instrumentation-api-incubator/src/test/java/io/opentelemetry/instrumentation/api/incubator/semconv/http/HttpClientExperimentalHttpParamsRedactionExtractorTest.java diff --git a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/config/internal/CommonConfig.java b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/config/internal/CommonConfig.java index dbdd11f4a1b2..bb64425c6da5 100644 --- a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/config/internal/CommonConfig.java +++ b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/config/internal/CommonConfig.java @@ -60,7 +60,7 @@ public CommonConfig(InstrumentationConfig config) { config.getBoolean("otel.instrumentation.http.client.emit-experimental-telemetry", false); redactQueryParameters = config.getBoolean( - "otel.instrumentation.http.client.experimental.redact-query-parameters", false); + "otel.instrumentation.http.client.experimental.redact-query-parameters", true); emitExperimentalHttpServerTelemetry = config.getBoolean("otel.instrumentation.http.server.emit-experimental-telemetry", false); enduserConfig = new EnduserConfig(config); diff --git a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/http/HttpClientExperimentalHttpParamsRedactionExtractor.java b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/http/HttpClientExperimentalHttpParamsRedactionExtractor.java deleted file mode 100644 index 137f4633cfa5..000000000000 --- a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/semconv/http/HttpClientExperimentalHttpParamsRedactionExtractor.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.instrumentation.api.incubator.semconv.http; - -import static io.opentelemetry.instrumentation.api.internal.AttributesExtractorUtil.internalSet; - -import io.opentelemetry.api.common.AttributesBuilder; -import io.opentelemetry.context.Context; -import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; -import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesGetter; -import io.opentelemetry.semconv.UrlAttributes; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import javax.annotation.Nullable; - -public class HttpClientExperimentalHttpParamsRedactionExtractor - implements AttributesExtractor { - - private final HttpClientAttributesGetter attributesGetter; - - private static final Set PARAMS_TO_REDACT = - new HashSet<>(Arrays.asList("AWSAccessKeyId", "Signature", "sig", "X-Goog-Signature")); - - public HttpClientExperimentalHttpParamsRedactionExtractor( - HttpClientAttributesGetter attributesGetter) { - this.attributesGetter = attributesGetter; - } - - public static - HttpClientExperimentalHttpParamsRedactionExtractor create( - HttpClientAttributesGetter attributesGetter) { - return new HttpClientExperimentalHttpParamsRedactionExtractor<>(attributesGetter); - } - - @Override - public void onStart(AttributesBuilder attributes, Context parentContext, REQUEST request) { - String urlFull = attributesGetter.getUrlFull(request); - String redactedUrlParameters = redactUrlParameters(urlFull); - internalSet(attributes, UrlAttributes.URL_FULL, redactedUrlParameters); - } - - private static String redactUrlParameters(String url) { - int questionMarkIndex = url.indexOf('?'); - if (questionMarkIndex == -1 || !containsParamToRedact(url)) { - return url; - } - - boolean paramToRedact = false; // To be able to skip the characters of the parameters to redact - boolean paramNameDetected = false; - boolean reference = false; - - StringBuilder urlPartAfterQuestionMark = new StringBuilder(); - - // To build a parameter name until we reach the '=' character - // If the parameter name is a one to redact, we will redact the value - StringBuilder currentParamName = new StringBuilder(); - - for (int i = questionMarkIndex + 1; i < url.length(); i++) { - char currentChar = url.charAt(i); - if (currentChar == '=') { - paramNameDetected = true; - urlPartAfterQuestionMark.append(currentParamName); - urlPartAfterQuestionMark.append('='); - if (PARAMS_TO_REDACT.contains(currentParamName.toString())) { - urlPartAfterQuestionMark.append("REDACTED"); - paramToRedact = true; - } - } else if (currentChar == '&') { // New parameter delimiter - urlPartAfterQuestionMark.append('&'); - paramNameDetected = false; - paramToRedact = false; - currentParamName.setLength( - 0); // To avoid creating a new StringBuilder for each new parameter - } else if (currentChar == '#') { // Reference delimiter - reference = true; - urlPartAfterQuestionMark.append('#'); - } else if (!paramNameDetected) { - currentParamName.append(currentChar); - } else if (!paramToRedact || reference) { - urlPartAfterQuestionMark.append(currentChar); - } - } - return url.substring(0, questionMarkIndex) + "?" + urlPartAfterQuestionMark; - } - - private static boolean containsParamToRedact(String urlpart) { - for (String param : PARAMS_TO_REDACT) { - if (urlpart.contains(param)) { - return true; - } - } - return false; - } - - @Override - public void onEnd( - AttributesBuilder attributes, - Context context, - REQUEST request, - @Nullable RESPONSE response, - @Nullable Throwable error) {} -} diff --git a/instrumentation-api-incubator/src/test/java/io/opentelemetry/instrumentation/api/incubator/semconv/http/HttpClientExperimentalHttpParamsRedactionExtractorTest.java b/instrumentation-api-incubator/src/test/java/io/opentelemetry/instrumentation/api/incubator/semconv/http/HttpClientExperimentalHttpParamsRedactionExtractorTest.java deleted file mode 100644 index a2ab883dd0e3..000000000000 --- a/instrumentation-api-incubator/src/test/java/io/opentelemetry/instrumentation/api/incubator/semconv/http/HttpClientExperimentalHttpParamsRedactionExtractorTest.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.instrumentation.api.incubator.semconv.http; - -import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; -import static org.assertj.core.api.Assertions.entry; -import static org.junit.jupiter.params.provider.Arguments.arguments; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; - -import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.api.common.AttributesBuilder; -import io.opentelemetry.context.Context; -import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesGetter; -import io.opentelemetry.semconv.UrlAttributes; -import java.util.stream.Stream; -import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.jupiter.api.extension.ExtensionContext; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.ArgumentsProvider; -import org.junit.jupiter.params.provider.ArgumentsSource; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -@ExtendWith(MockitoExtension.class) -class HttpClientExperimentalHttpParamsRedactionExtractorTest { - - @Mock HttpClientAttributesGetter httpClientAttributesGetter; - - @ParameterizedTest - @ArgumentsSource(StripUrlArgumentSource.class) - void shouldRedactUrlQueryParameters(String url, String expectedResult) { - - // given - when(httpClientAttributesGetter.getUrlFull(any())).thenReturn(url); - - HttpClientExperimentalHttpParamsRedactionExtractor extractor = - HttpClientExperimentalHttpParamsRedactionExtractor.create(httpClientAttributesGetter); - - AttributesBuilder attributesBuilder = Attributes.builder(); - Context context = Context.root(); - - // when - extractor.onStart(attributesBuilder, context, "request"); - - // then - Attributes attributes = attributesBuilder.build(); - assertThat(attributes).containsOnly(entry(UrlAttributes.URL_FULL, expectedResult)); - } - - static final class StripUrlArgumentSource implements ArgumentsProvider { - - @Override - public Stream provideArguments(ExtensionContext context) { - return Stream.of( - arguments("https://github.com/p@th?foo=b@r", "https://github.com/p@th?foo=b@r"), - arguments("https://github.com#t@st.html", "https://github.com#t@st.html"), - arguments("https://github.com@", "https://github.com@"), - arguments( - "https://service.com?paramA=valA¶mB=valB", - "https://service.com?paramA=valA¶mB=valB"), - arguments( - "https://service.com?AWSAccessKeyId=AKIAIOSFODNN7", - "https://service.com?AWSAccessKeyId=REDACTED"), - arguments( - "https://service.com?Signature=39Up9jzHkxhuIhFE9594DJxe7w6cIRCg0V6ICGS0%3A377", - "https://service.com?Signature=REDACTED"), - arguments( - "https://service.com?sig=39Up9jzHkxhuIhFE9594DJxe7w6cIRCg0V6ICGS0", - "https://service.com?sig=REDACTED"), - arguments( - "https://service.com?X-Goog-Signature=39Up9jzHkxhuIhFE9594DJxe7w6cIRCg0V6ICGS0", - "https://service.com?X-Goog-Signature=REDACTED"), - arguments( - "https://service.com?paramA=valA&AWSAccessKeyId=AKIAIOSFODNN7¶mB=valB", - "https://service.com?paramA=valA&AWSAccessKeyId=REDACTED¶mB=valB"), - arguments( - "https://service.com?AWSAccessKeyId=AKIAIOSFODNN7¶mA=valA", - "https://service.com?AWSAccessKeyId=REDACTED¶mA=valA"), - arguments( - "https://service.com?paramA=valA&AWSAccessKeyId=AKIAIOSFODNN7", - "https://service.com?paramA=valA&AWSAccessKeyId=REDACTED"), - arguments( - "https://service.com?AWSAccessKeyId=AKIAIOSFODNN7&AWSAccessKeyId=ZGIAIOSFODNN7", - "https://service.com?AWSAccessKeyId=REDACTED&AWSAccessKeyId=REDACTED"), - arguments( - "https://service.com?AWSAccessKeyId=AKIAIOSFODNN7#ref", - "https://service.com?AWSAccessKeyId=REDACTED#ref")); - } - } -} diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 6a9599c9d8d4..e339c3455df8 100644 --- a/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -315,7 +315,7 @@ "name": "otel.instrumentation.http.client.experimental.redact-query-parameters", "type": "java.lang.Boolean", "description": "Redact sensitive URL parameters. See https://opentelemetry.io/docs/specs/semconv/http/http-spans.", - "defaultValue": false + "defaultValue": true }, { "name": "otel.instrumentation.http.known-methods", diff --git a/smoke-tests-otel-starter/spring-boot-common/src/main/resources/application.yaml b/smoke-tests-otel-starter/spring-boot-common/src/main/resources/application.yaml index b4d92f8dfa43..4da76f769a0d 100644 --- a/smoke-tests-otel-starter/spring-boot-common/src/main/resources/application.yaml +++ b/smoke-tests-otel-starter/spring-boot-common/src/main/resources/application.yaml @@ -11,8 +11,6 @@ otel: http: client: emit-experimental-telemetry: true - experimental: - redact-query-parameters: true server: emit-experimental-telemetry: true capture-request-headers: [key] From da85a5efcb27e49d09be5fceaa3668086daa7c5b Mon Sep 17 00:00:00 2001 From: Jean Bisutti Date: Wed, 12 Feb 2025 17:18:57 +0100 Subject: [PATCH 10/22] Instance variable set to true to avoid confusion --- .../builder/internal/DefaultHttpClientInstrumenterBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/builder/internal/DefaultHttpClientInstrumenterBuilder.java b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/builder/internal/DefaultHttpClientInstrumenterBuilder.java index 0bf1b7ec1ea0..0170f09e4ebb 100644 --- a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/builder/internal/DefaultHttpClientInstrumenterBuilder.java +++ b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/builder/internal/DefaultHttpClientInstrumenterBuilder.java @@ -64,7 +64,7 @@ public final class DefaultHttpClientInstrumenterBuilder { private Function, ? extends SpanNameExtractor> spanNameExtractorTransformer = Function.identity(); private boolean emitExperimentalHttpClientMetrics = false; - private boolean redactQueryParameters = false; + private boolean redactQueryParameters = true; private Consumer> builderCustomizer = b -> {}; private DefaultHttpClientInstrumenterBuilder( From fa98de3cbb0cf809e235f776585acb1b1d3a981a Mon Sep 17 00:00:00 2001 From: Jean Bisutti Date: Wed, 12 Feb 2025 17:25:39 +0100 Subject: [PATCH 11/22] Re-apply feedback --- .../http/HttpClientAttributesExtractor.java | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java index 5d29bcbc7b69..421648f87d11 100644 --- a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java +++ b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java @@ -167,20 +167,17 @@ private static String redactUserInfo(String url) { private static String redactQueryParameters(String url) { int questionMarkIndex = url.indexOf('?'); - - if (questionMarkIndex == -1) { - return url; - } - - if (!containsParamToRedact(url)) { + if (questionMarkIndex == -1 || !containsParamToRedact(url)) { return url; } StringBuilder redactedParameters = new StringBuilder(); - boolean paramToRedact = false; + boolean paramToRedact = false; // To be able to skip the characters of the parameters to redact boolean paramNameDetected = false; boolean reference = false; + // To build a parameter name until we reach the '=' character + // If the parameter name is a one to redact, we will redact the value StringBuilder currentParamName = new StringBuilder(); for (int i = questionMarkIndex + 1; i < url.length(); i++) { @@ -193,12 +190,13 @@ private static String redactQueryParameters(String url) { redactedParameters.append("REDACTED"); paramToRedact = true; } - } else if (currentChar == '&') { + } else if (currentChar == '&') { // New parameter delimiter redactedParameters.append('&'); paramNameDetected = false; paramToRedact = false; - currentParamName.setLength(0); - } else if (currentChar == '#') { + currentParamName.setLength( + 0); // To avoid creating a new StringBuilder for each new parameter + } else if (currentChar == '#') { // Reference delimiter reference = true; redactedParameters.append('#'); } else if (!paramNameDetected) { From 4fc1c2defcfefcb9faf802dd018d2fac2d085fb9 Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Thu, 13 Feb 2025 16:41:19 +0200 Subject: [PATCH 12/22] make experimental option setting for redacted query params similar to other experimental options --- .../DefaultHttpClientInstrumenterBuilder.java | 9 ++--- .../api/internal/Experimental.java | 36 +++++++++++++++++++ .../internal/ExperimentalParameterUtil.java | 25 ------------- .../HttpClientAttributesExtractorBuilder.java | 8 +++-- .../HttpClientAttributesExtractorTest.java | 10 +++--- 5 files changed, 49 insertions(+), 39 deletions(-) create mode 100644 instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/internal/Experimental.java delete mode 100644 instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/internal/ExperimentalParameterUtil.java diff --git a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/builder/internal/DefaultHttpClientInstrumenterBuilder.java b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/builder/internal/DefaultHttpClientInstrumenterBuilder.java index 0170f09e4ebb..7a38491281f0 100644 --- a/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/builder/internal/DefaultHttpClientInstrumenterBuilder.java +++ b/instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/builder/internal/DefaultHttpClientInstrumenterBuilder.java @@ -20,7 +20,7 @@ import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor; import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor; import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor; -import io.opentelemetry.instrumentation.api.internal.ExperimentalParameterUtil; +import io.opentelemetry.instrumentation.api.internal.Experimental; import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesExtractor; import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesExtractorBuilder; import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesGetter; @@ -64,7 +64,6 @@ public final class DefaultHttpClientInstrumenterBuilder { private Function, ? extends SpanNameExtractor> spanNameExtractorTransformer = Function.identity(); private boolean emitExperimentalHttpClientMetrics = false; - private boolean redactQueryParameters = true; private Consumer> builderCustomizer = b -> {}; private DefaultHttpClientInstrumenterBuilder( @@ -187,7 +186,7 @@ public DefaultHttpClientInstrumenterBuilder setKnownMethods( @CanIgnoreReturnValue public DefaultHttpClientInstrumenterBuilder setRedactQueryParameters( boolean redactQueryParameters) { - this.redactQueryParameters = redactQueryParameters; + Experimental.setRedactQueryParameters(httpAttributesExtractorBuilder, redactQueryParameters); return this; } @@ -226,10 +225,6 @@ public Instrumenter build() { SpanNameExtractor spanNameExtractor = spanNameExtractorTransformer.apply(httpSpanNameExtractorBuilder.build()); - if (redactQueryParameters) { - ExperimentalParameterUtil.setRedactQueryParameters(redactQueryParameters); - } - InstrumenterBuilder builder = Instrumenter.builder( openTelemetry, instrumentationName, spanNameExtractor) diff --git a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/internal/Experimental.java b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/internal/Experimental.java new file mode 100644 index 000000000000..250cfbd5b2fb --- /dev/null +++ b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/internal/Experimental.java @@ -0,0 +1,36 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.api.internal; + +import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesExtractorBuilder; +import java.util.function.BiConsumer; +import javax.annotation.Nullable; + +/** + * This class is internal and is hence not for public use. Its APIs are unstable and can change at + * any time. + */ +public final class Experimental { + + @Nullable + private static volatile BiConsumer, Boolean> + redactHttpClientQueryParameters; + + private Experimental() {} + + public static void setRedactQueryParameters( + HttpClientAttributesExtractorBuilder builder, boolean redactQueryParameters) { + if (redactHttpClientQueryParameters != null) { + redactHttpClientQueryParameters.accept(builder, redactQueryParameters); + } + } + + public static void internalSetRedactHttpClientQueryParameters( + BiConsumer, Boolean> + redactHttpClientQueryParameters) { + Experimental.redactHttpClientQueryParameters = redactHttpClientQueryParameters; + } +} diff --git a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/internal/ExperimentalParameterUtil.java b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/internal/ExperimentalParameterUtil.java deleted file mode 100644 index 40252aa39781..000000000000 --- a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/internal/ExperimentalParameterUtil.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.instrumentation.api.internal; - -/** - * This class is internal and is hence not for public use. Its APIs are unstable and can change at - * any time. - */ -public class ExperimentalParameterUtil { - - private static boolean redactQueryParameters; - - private ExperimentalParameterUtil() {} - - public static boolean isRedactQueryParameters() { - return redactQueryParameters; - } - - public static void setRedactQueryParameters(boolean redactQueryParameters) { - ExperimentalParameterUtil.redactQueryParameters = redactQueryParameters; - } -} diff --git a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractorBuilder.java b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractorBuilder.java index 026920565fb8..db0a63a059c1 100644 --- a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractorBuilder.java +++ b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractorBuilder.java @@ -11,7 +11,7 @@ import io.opentelemetry.context.Context; import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder; -import io.opentelemetry.instrumentation.api.internal.ExperimentalParameterUtil; +import io.opentelemetry.instrumentation.api.internal.Experimental; import io.opentelemetry.instrumentation.api.internal.HttpConstants; import io.opentelemetry.instrumentation.api.semconv.network.internal.AddressAndPortExtractor; import io.opentelemetry.instrumentation.api.semconv.network.internal.InternalNetworkAttributesExtractor; @@ -40,6 +40,11 @@ public final class HttpClientAttributesExtractorBuilder { ToIntFunction resendCountIncrementer = HttpClientRequestResendCount::getAndIncrement; boolean redactQueryParameters; + static { + Experimental.internalSetRedactHttpClientQueryParameters( + (builder, redact) -> builder.redactQueryParameters = redact); + } + HttpClientAttributesExtractorBuilder( HttpClientAttributesGetter httpAttributesGetter) { this.httpAttributesGetter = httpAttributesGetter; @@ -182,7 +187,6 @@ HttpClientAttributesExtractorBuilder setResendCountIncremente * @see InstrumenterBuilder#addAttributesExtractor(AttributesExtractor) */ public AttributesExtractor build() { - redactQueryParameters = ExperimentalParameterUtil.isRedactQueryParameters(); return new HttpClientAttributesExtractor<>(this); } diff --git a/instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractorTest.java b/instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractorTest.java index 4305f9c6fcdb..eb20a70795ab 100644 --- a/instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractorTest.java +++ b/instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractorTest.java @@ -30,7 +30,7 @@ import io.opentelemetry.api.common.AttributesBuilder; import io.opentelemetry.context.Context; import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor; -import io.opentelemetry.instrumentation.api.internal.ExperimentalParameterUtil; +import io.opentelemetry.instrumentation.api.internal.Experimental; import io.opentelemetry.instrumentation.api.internal.HttpConstants; import java.net.ConnectException; import java.util.HashMap; @@ -212,10 +212,10 @@ void stripBasicAuthTest(String url, String expectedResult) { Map request = new HashMap<>(); request.put("urlFull", url); - ExperimentalParameterUtil.setRedactQueryParameters(true); - - AttributesExtractor, Map> extractor = - HttpClientAttributesExtractor.create(new TestHttpClientAttributesGetter()); + HttpClientAttributesExtractorBuilder, Map> builder = + HttpClientAttributesExtractor.builder(new TestHttpClientAttributesGetter()); + Experimental.setRedactQueryParameters(builder, true); + AttributesExtractor, Map> extractor = builder.build(); AttributesBuilder attributes = Attributes.builder(); extractor.onStart(attributes, Context.root(), request); From dd05fbbb4b5b2dd86e814f4540c1ef498f02b682 Mon Sep 17 00:00:00 2001 From: Jean Bisutti Date: Thu, 13 Feb 2025 17:29:39 +0100 Subject: [PATCH 13/22] Re-apply feedback --- .../http/HttpClientAttributesExtractor.java | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java index 421648f87d11..c5bee974cd99 100644 --- a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java +++ b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java @@ -172,9 +172,10 @@ private static String redactQueryParameters(String url) { } StringBuilder redactedParameters = new StringBuilder(); - boolean paramToRedact = false; // To be able to skip the characters of the parameters to redact - boolean paramNameDetected = false; - boolean reference = false; + boolean inRedactedParamValue = + false; // To be able to skip the characters of the parameters to redact + boolean inParamValue = false; + boolean inReference = false; // To build a parameter name until we reach the '=' character // If the parameter name is a one to redact, we will redact the value @@ -183,25 +184,25 @@ private static String redactQueryParameters(String url) { for (int i = questionMarkIndex + 1; i < url.length(); i++) { char currentChar = url.charAt(i); if (currentChar == '=') { - paramNameDetected = true; + inParamValue = true; redactedParameters.append(currentParamName); redactedParameters.append('='); if (PARAMS_TO_REDACT.contains(currentParamName.toString())) { redactedParameters.append("REDACTED"); - paramToRedact = true; + inRedactedParamValue = true; } } else if (currentChar == '&') { // New parameter delimiter redactedParameters.append('&'); - paramNameDetected = false; - paramToRedact = false; + inParamValue = false; + inRedactedParamValue = false; currentParamName.setLength( 0); // To avoid creating a new StringBuilder for each new parameter } else if (currentChar == '#') { // Reference delimiter - reference = true; + inReference = true; redactedParameters.append('#'); - } else if (!paramNameDetected) { + } else if (!inParamValue) { currentParamName.append(currentChar); - } else if (!paramToRedact || reference) { + } else if (!inRedactedParamValue || inReference) { redactedParameters.append(currentChar); } } From a5760ba807972bcfe1e1f5992fc93bd3e494f34a Mon Sep 17 00:00:00 2001 From: Trask Stalnaker Date: Thu, 13 Feb 2025 08:40:17 -0800 Subject: [PATCH 14/22] Simplify --- .../api/semconv/http/HttpClientAttributesExtractor.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java index c5bee974cd99..fa1b3d1d4159 100644 --- a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java +++ b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java @@ -175,7 +175,6 @@ private static String redactQueryParameters(String url) { boolean inRedactedParamValue = false; // To be able to skip the characters of the parameters to redact boolean inParamValue = false; - boolean inReference = false; // To build a parameter name until we reach the '=' character // If the parameter name is a one to redact, we will redact the value @@ -198,11 +197,11 @@ private static String redactQueryParameters(String url) { currentParamName.setLength( 0); // To avoid creating a new StringBuilder for each new parameter } else if (currentChar == '#') { // Reference delimiter - inReference = true; - redactedParameters.append('#'); + redactedParameters.append(url.substring(i)); + break; } else if (!inParamValue) { currentParamName.append(currentChar); - } else if (!inRedactedParamValue || inReference) { + } else if (!inRedactedParamValue) { redactedParameters.append(currentChar); } } From f37ab6de00d1ab1e4210e86dc06e0c9779ea3aef Mon Sep 17 00:00:00 2001 From: Jean Bisutti Date: Mon, 17 Feb 2025 11:47:00 +0100 Subject: [PATCH 15/22] Update instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java Co-authored-by: Lauri Tulmin --- .../api/semconv/http/HttpClientAttributesExtractor.java | 1 - 1 file changed, 1 deletion(-) diff --git a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java index fa1b3d1d4159..43c31067194b 100644 --- a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java +++ b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java @@ -165,7 +165,6 @@ private static String redactUserInfo(String url) { } private static String redactQueryParameters(String url) { - int questionMarkIndex = url.indexOf('?'); if (questionMarkIndex == -1 || !containsParamToRedact(url)) { return url; From 9ef64ab76a6b8ac0abe83df558f00c729af68cac Mon Sep 17 00:00:00 2001 From: Jean Bisutti Date: Mon, 17 Feb 2025 14:31:37 +0100 Subject: [PATCH 16/22] test method naming --- .../api/semconv/http/HttpClientAttributesExtractorTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractorTest.java b/instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractorTest.java index eb20a70795ab..40bb30692019 100644 --- a/instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractorTest.java +++ b/instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractorTest.java @@ -208,7 +208,7 @@ void normal() { @ParameterizedTest @ArgumentsSource(StripUrlArgumentSource.class) - void stripBasicAuthTest(String url, String expectedResult) { + void shouldRedactUserInfoAndQueryParameters(String url, String expectedResult) { Map request = new HashMap<>(); request.put("urlFull", url); From 4911e8346ce8e1f9490e9d126751b888990bb879 Mon Sep 17 00:00:00 2001 From: Jean Bisutti Date: Mon, 17 Feb 2025 14:40:12 +0100 Subject: [PATCH 17/22] merge --- .../smoketest/OtelSpringStarterSmokeTestController.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/smoke-tests-otel-starter/spring-boot-common/src/main/java/io/opentelemetry/spring/smoketest/OtelSpringStarterSmokeTestController.java b/smoke-tests-otel-starter/spring-boot-common/src/main/java/io/opentelemetry/spring/smoketest/OtelSpringStarterSmokeTestController.java index c4902b2d65d5..68c6fd0d199f 100644 --- a/smoke-tests-otel-starter/spring-boot-common/src/main/java/io/opentelemetry/spring/smoketest/OtelSpringStarterSmokeTestController.java +++ b/smoke-tests-otel-starter/spring-boot-common/src/main/java/io/opentelemetry/spring/smoketest/OtelSpringStarterSmokeTestController.java @@ -15,6 +15,7 @@ public class OtelSpringStarterSmokeTestController { public static final String PING = "/ping"; + public static final String TEST = "/test"; public static final String TEST_HISTOGRAM = "histogram-test-otel-spring-starter"; public static final String METER_SCOPE_NAME = "scope"; private final LongHistogram histogram; @@ -33,4 +34,9 @@ public String ping() { component.withSpanMethod("from-controller"); return "pong"; } + + @GetMapping(TEST) + public String testUrlToRedact() { + return "ok"; + } } From 5164fe544fc8ea9d2e28e97c36f84b722c3fce2f Mon Sep 17 00:00:00 2001 From: Jean Bisutti Date: Tue, 18 Feb 2025 17:31:36 +0100 Subject: [PATCH 18/22] Add scenarios with parameters without values --- .../http/HttpClientAttributesExtractor.java | 18 ++++++++++++---- .../HttpClientAttributesExtractorTest.java | 21 ++++++++++++++++--- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java index 43c31067194b..e9a31d89692e 100644 --- a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java +++ b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java @@ -173,7 +173,7 @@ private static String redactQueryParameters(String url) { StringBuilder redactedParameters = new StringBuilder(); boolean inRedactedParamValue = false; // To be able to skip the characters of the parameters to redact - boolean inParamValue = false; + boolean paramWithValue = false; // To build a parameter name until we reach the '=' character // If the parameter name is a one to redact, we will redact the value @@ -182,7 +182,7 @@ private static String redactQueryParameters(String url) { for (int i = questionMarkIndex + 1; i < url.length(); i++) { char currentChar = url.charAt(i); if (currentChar == '=') { - inParamValue = true; + paramWithValue = true; redactedParameters.append(currentParamName); redactedParameters.append('='); if (PARAMS_TO_REDACT.contains(currentParamName.toString())) { @@ -190,16 +190,26 @@ private static String redactQueryParameters(String url) { inRedactedParamValue = true; } } else if (currentChar == '&') { // New parameter delimiter + if (!paramWithValue) { // Example: https://service.com?AWSAccessKeyId=AKIAIOSFODNN7&a& + redactedParameters.append(currentParamName); + } redactedParameters.append('&'); - inParamValue = false; + paramWithValue = false; inRedactedParamValue = false; currentParamName.setLength( 0); // To avoid creating a new StringBuilder for each new parameter } else if (currentChar == '#') { // Reference delimiter + if (!paramWithValue) { // Example: + // https://service.com?&&AWSAccessKeyId=AKIAIOSFODNN7&a&b#fragment + redactedParameters.append(currentParamName); + } redactedParameters.append(url.substring(i)); break; - } else if (!inParamValue) { + } else if (!paramWithValue) { currentParamName.append(currentChar); + if (i == url.length() - 1) { // Example: https://service.com?AWSAccessKeyId=AKIAIOSFODNN7&a + redactedParameters.append(currentParamName); + } } else if (!inRedactedParamValue) { redactedParameters.append(currentChar); } diff --git a/instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractorTest.java b/instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractorTest.java index 40bb30692019..c04b78346f00 100644 --- a/instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractorTest.java +++ b/instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractorTest.java @@ -207,7 +207,7 @@ void normal() { } @ParameterizedTest - @ArgumentsSource(StripUrlArgumentSource.class) + @ArgumentsSource(UrlSourceToRedact.class) void shouldRedactUserInfoAndQueryParameters(String url, String expectedResult) { Map request = new HashMap<>(); request.put("urlFull", url); @@ -223,7 +223,7 @@ void shouldRedactUserInfoAndQueryParameters(String url, String expectedResult) { assertThat(attributes.build()).containsOnly(entry(URL_FULL, expectedResult)); } - static final class StripUrlArgumentSource implements ArgumentsProvider { + static final class UrlSourceToRedact implements ArgumentsProvider { @Override public Stream provideArguments(ExtensionContext context) { @@ -274,7 +274,22 @@ public Stream provideArguments(ExtensionContext context) { "https://service.com?AWSAccessKeyId=REDACTED&AWSAccessKeyId=REDACTED"), arguments( "https://service.com?AWSAccessKeyId=AKIAIOSFODNN7#ref", - "https://service.com?AWSAccessKeyId=REDACTED#ref")); + "https://service.com?AWSAccessKeyId=REDACTED#ref"), + arguments( + "https://service.com?AWSAccessKeyId=AKIAIOSFODNN7&aa&bb", + "https://service.com?AWSAccessKeyId=REDACTED&aa&bb"), + arguments( + "https://service.com?aa&bb&AWSAccessKeyId=AKIAIOSFODNN7", + "https://service.com?aa&bb&AWSAccessKeyId=REDACTED"), + arguments( + "https://service.com?AWSAccessKeyId=AKIAIOSFODNN7&&", + "https://service.com?AWSAccessKeyId=REDACTED&&"), + arguments( + "https://service.com?&&AWSAccessKeyId=AKIAIOSFODNN7", + "https://service.com?&&AWSAccessKeyId=REDACTED"), + arguments( + "https://service.com?AWSAccessKeyId=AKIAIOSFODNN7&a&b#fragment", + "https://service.com?AWSAccessKeyId=REDACTED&a&b#fragment")); } } From ef736e1177916cd638912ad39f5de8751c6782e5 Mon Sep 17 00:00:00 2001 From: Jean Bisutti Date: Mon, 24 Feb 2025 11:16:55 +0100 Subject: [PATCH 19/22] Alternative version --- .../http/HttpClientAttributesExtractor.java | 52 ++++++++----------- 1 file changed, 22 insertions(+), 30 deletions(-) diff --git a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java index e9a31d89692e..7867207eb551 100644 --- a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java +++ b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java @@ -170,10 +170,7 @@ private static String redactQueryParameters(String url) { return url; } - StringBuilder redactedParameters = new StringBuilder(); - boolean inRedactedParamValue = - false; // To be able to skip the characters of the parameters to redact - boolean paramWithValue = false; + StringBuilder urAfterQuestionMark = new StringBuilder(); // To build a parameter name until we reach the '=' character // If the parameter name is a one to redact, we will redact the value @@ -181,40 +178,35 @@ private static String redactQueryParameters(String url) { for (int i = questionMarkIndex + 1; i < url.length(); i++) { char currentChar = url.charAt(i); + if (currentChar == '=') { - paramWithValue = true; - redactedParameters.append(currentParamName); - redactedParameters.append('='); + urAfterQuestionMark.append('='); if (PARAMS_TO_REDACT.contains(currentParamName.toString())) { - redactedParameters.append("REDACTED"); - inRedactedParamValue = true; + urAfterQuestionMark.append("REDACTED"); + // skip over parameter value + for (; i + 1 < url.length(); i++) { + char c = url.charAt(i + 1); + if (c == '&' || c == '#') { + break; + } + } } } else if (currentChar == '&') { // New parameter delimiter - if (!paramWithValue) { // Example: https://service.com?AWSAccessKeyId=AKIAIOSFODNN7&a& - redactedParameters.append(currentParamName); - } - redactedParameters.append('&'); - paramWithValue = false; - inRedactedParamValue = false; - currentParamName.setLength( - 0); // To avoid creating a new StringBuilder for each new parameter + urAfterQuestionMark.append(currentChar); + // To avoid creating a new StringBuilder for each new parameter + currentParamName.setLength(0); } else if (currentChar == '#') { // Reference delimiter - if (!paramWithValue) { // Example: - // https://service.com?&&AWSAccessKeyId=AKIAIOSFODNN7&a&b#fragment - redactedParameters.append(currentParamName); - } - redactedParameters.append(url.substring(i)); + urAfterQuestionMark.append(url.substring(i)); break; - } else if (!paramWithValue) { - currentParamName.append(currentChar); - if (i == url.length() - 1) { // Example: https://service.com?AWSAccessKeyId=AKIAIOSFODNN7&a - redactedParameters.append(currentParamName); - } - } else if (!inRedactedParamValue) { - redactedParameters.append(currentChar); + } else { + currentParamName.append( + currentChar); // param values can be appended to currentParamName here but it's not an + // issue + urAfterQuestionMark.append(currentChar); } } - return url.substring(0, questionMarkIndex) + "?" + redactedParameters; + + return url.substring(0, questionMarkIndex) + "?" + urAfterQuestionMark; } private static boolean containsParamToRedact(String urlpart) { From bbed3b3597c01f1387356903728199c992814f98 Mon Sep 17 00:00:00 2001 From: Jean Bisutti Date: Tue, 25 Feb 2025 11:49:42 +0100 Subject: [PATCH 20/22] fix typo --- .../http/HttpClientAttributesExtractor.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java index 7867207eb551..ff9206a2c049 100644 --- a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java +++ b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java @@ -170,7 +170,7 @@ private static String redactQueryParameters(String url) { return url; } - StringBuilder urAfterQuestionMark = new StringBuilder(); + StringBuilder urlAfterQuestionMark = new StringBuilder(); // To build a parameter name until we reach the '=' character // If the parameter name is a one to redact, we will redact the value @@ -180,9 +180,9 @@ private static String redactQueryParameters(String url) { char currentChar = url.charAt(i); if (currentChar == '=') { - urAfterQuestionMark.append('='); + urlAfterQuestionMark.append('='); if (PARAMS_TO_REDACT.contains(currentParamName.toString())) { - urAfterQuestionMark.append("REDACTED"); + urlAfterQuestionMark.append("REDACTED"); // skip over parameter value for (; i + 1 < url.length(); i++) { char c = url.charAt(i + 1); @@ -192,21 +192,21 @@ private static String redactQueryParameters(String url) { } } } else if (currentChar == '&') { // New parameter delimiter - urAfterQuestionMark.append(currentChar); + urlAfterQuestionMark.append(currentChar); // To avoid creating a new StringBuilder for each new parameter currentParamName.setLength(0); } else if (currentChar == '#') { // Reference delimiter - urAfterQuestionMark.append(url.substring(i)); + urlAfterQuestionMark.append(url.substring(i)); break; } else { currentParamName.append( currentChar); // param values can be appended to currentParamName here but it's not an // issue - urAfterQuestionMark.append(currentChar); + urlAfterQuestionMark.append(currentChar); } } - return url.substring(0, questionMarkIndex) + "?" + urAfterQuestionMark; + return url.substring(0, questionMarkIndex) + "?" + urlAfterQuestionMark; } private static boolean containsParamToRedact(String urlpart) { From 1f20468e551322bbac3fa52674793e14de6b7aee Mon Sep 17 00:00:00 2001 From: Trask Stalnaker Date: Thu, 27 Feb 2025 07:33:57 -0800 Subject: [PATCH 21/22] Update instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java --- .../api/semconv/http/HttpClientAttributesExtractor.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java index ff9206a2c049..c7e3cb63c2cf 100644 --- a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java +++ b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java @@ -199,9 +199,8 @@ private static String redactQueryParameters(String url) { urlAfterQuestionMark.append(url.substring(i)); break; } else { - currentParamName.append( - currentChar); // param values can be appended to currentParamName here but it's not an - // issue + // param values can be appended to currentParamName here but it's not an issue + currentParamName.append(currentChar); urlAfterQuestionMark.append(currentChar); } } From 0195b2a57aa708050a5f817e4a9f9815a9bccb20 Mon Sep 17 00:00:00 2001 From: Jean Bisutti Date: Thu, 27 Feb 2025 17:06:42 +0100 Subject: [PATCH 22/22] spotless --- .../api/semconv/http/HttpClientAttributesExtractor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java index c7e3cb63c2cf..2227eaed7b43 100644 --- a/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java +++ b/instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java @@ -200,7 +200,7 @@ private static String redactQueryParameters(String url) { break; } else { // param values can be appended to currentParamName here but it's not an issue - currentParamName.append(currentChar); + currentParamName.append(currentChar); urlAfterQuestionMark.append(currentChar); } }