Skip to content

Commit 9c6deda

Browse files
committed
Only use HttpClientAttributesExtractor and rename configuration
1 parent 6b069fd commit 9c6deda

File tree

7 files changed

+154
-20
lines changed

7 files changed

+154
-20
lines changed

instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/builder/internal/DefaultHttpClientInstrumenterBuilder.java

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
import io.opentelemetry.api.common.AttributeKey;
1111
import io.opentelemetry.context.propagation.TextMapSetter;
1212
import io.opentelemetry.instrumentation.api.incubator.config.internal.CommonConfig;
13-
import io.opentelemetry.instrumentation.api.incubator.semconv.http.HttpClientExperimentalHttpParamsRedactionExtractor;
1413
import io.opentelemetry.instrumentation.api.incubator.semconv.http.HttpClientExperimentalMetrics;
1514
import io.opentelemetry.instrumentation.api.incubator.semconv.http.HttpClientPeerServiceAttributesExtractor;
1615
import io.opentelemetry.instrumentation.api.incubator.semconv.http.HttpExperimentalAttributesExtractor;
@@ -21,6 +20,7 @@
2120
import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor;
2221
import io.opentelemetry.instrumentation.api.instrumenter.SpanNameExtractor;
2322
import io.opentelemetry.instrumentation.api.instrumenter.SpanStatusExtractor;
23+
import io.opentelemetry.instrumentation.api.internal.ExperimentalParameterUtil;
2424
import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesExtractor;
2525
import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesExtractorBuilder;
2626
import io.opentelemetry.instrumentation.api.semconv.http.HttpClientAttributesGetter;
@@ -64,7 +64,7 @@ public final class DefaultHttpClientInstrumenterBuilder<REQUEST, RESPONSE> {
6464
private Function<SpanNameExtractor<? super REQUEST>, ? extends SpanNameExtractor<? super REQUEST>>
6565
spanNameExtractorTransformer = Function.identity();
6666
private boolean emitExperimentalHttpClientMetrics = false;
67-
private boolean redactSensitiveUrlParameters = false;
67+
private boolean redactQueryParameters = false;
6868
private Consumer<InstrumenterBuilder<REQUEST, RESPONSE>> builderCustomizer = b -> {};
6969

7070
private DefaultHttpClientInstrumenterBuilder(
@@ -182,13 +182,12 @@ public DefaultHttpClientInstrumenterBuilder<REQUEST, RESPONSE> setKnownMethods(
182182
/**
183183
* Configures the instrumentation to redact sensitive URL parameters.
184184
*
185-
* @param redactSensitiveUrlParameters {@code true} if the sensitive URL parameters have to be
186-
* redacted.
185+
* @param redactQueryParameters {@code true} if the sensitive URL parameters have to be redacted.
187186
*/
188187
@CanIgnoreReturnValue
189-
public DefaultHttpClientInstrumenterBuilder<REQUEST, RESPONSE> setRedactSensitiveUrlParameters(
190-
boolean redactSensitiveUrlParameters) {
191-
this.redactSensitiveUrlParameters = redactSensitiveUrlParameters;
188+
public DefaultHttpClientInstrumenterBuilder<REQUEST, RESPONSE> setRedactQueryParameters(
189+
boolean redactQueryParameters) {
190+
this.redactQueryParameters = redactQueryParameters;
192191
return this;
193192
}
194193

@@ -227,6 +226,10 @@ public Instrumenter<REQUEST, RESPONSE> build() {
227226
SpanNameExtractor<? super REQUEST> spanNameExtractor =
228227
spanNameExtractorTransformer.apply(httpSpanNameExtractorBuilder.build());
229228

229+
if (redactQueryParameters) {
230+
ExperimentalParameterUtil.setRedactQueryParameters(redactQueryParameters);
231+
}
232+
230233
InstrumenterBuilder<REQUEST, RESPONSE> builder =
231234
Instrumenter.<REQUEST, RESPONSE>builder(
232235
openTelemetry, instrumentationName, spanNameExtractor)
@@ -240,10 +243,7 @@ public Instrumenter<REQUEST, RESPONSE> build() {
240243
.addAttributesExtractor(HttpExperimentalAttributesExtractor.create(attributesGetter))
241244
.addOperationMetrics(HttpClientExperimentalMetrics.get());
242245
}
243-
if (redactSensitiveUrlParameters) {
244-
builder.addAttributesExtractor(
245-
HttpClientExperimentalHttpParamsRedactionExtractor.create(attributesGetter));
246-
}
246+
247247
builderCustomizer.accept(builder);
248248

249249
if (headerSetter != null) {
@@ -267,7 +267,7 @@ public DefaultHttpClientInstrumenterBuilder<REQUEST, RESPONSE> configure(CommonC
267267
set(
268268
config::shouldEmitExperimentalHttpClientTelemetry,
269269
this::setEmitExperimentalHttpClientMetrics);
270-
set(config::shouldRedactSensitiveUrlParameters, this::setRedactSensitiveUrlParameters);
270+
set(config::redactQueryParameters, this::setRedactQueryParameters);
271271
return this;
272272
}
273273

instrumentation-api-incubator/src/main/java/io/opentelemetry/instrumentation/api/incubator/config/internal/CommonConfig.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public final class CommonConfig {
3131
private final boolean statementSanitizationEnabled;
3232
private final boolean emitExperimentalHttpClientTelemetry;
3333
private final boolean emitExperimentalHttpServerTelemetry;
34-
private final boolean redactSensitiveUrlParameters;
34+
private final boolean redactQueryParameters;
3535
private final String loggingTraceIdKey;
3636
private final String loggingSpanIdKey;
3737
private final String loggingTraceFlagsKey;
@@ -58,9 +58,9 @@ public CommonConfig(InstrumentationConfig config) {
5858
config.getBoolean("otel.instrumentation.common.db-statement-sanitizer.enabled", true);
5959
emitExperimentalHttpClientTelemetry =
6060
config.getBoolean("otel.instrumentation.http.client.emit-experimental-telemetry", false);
61-
redactSensitiveUrlParameters =
61+
redactQueryParameters =
6262
config.getBoolean(
63-
"otel.instrumentation.http.client.experimental.redact-sensitive-url-parameters", false);
63+
"otel.instrumentation.http.client.experimental.redact-query-parameters", false);
6464
emitExperimentalHttpServerTelemetry =
6565
config.getBoolean("otel.instrumentation.http.server.emit-experimental-telemetry", false);
6666
enduserConfig = new EnduserConfig(config);
@@ -115,8 +115,8 @@ public boolean shouldEmitExperimentalHttpServerTelemetry() {
115115
return emitExperimentalHttpServerTelemetry;
116116
}
117117

118-
public boolean shouldRedactSensitiveUrlParameters() {
119-
return redactSensitiveUrlParameters;
118+
public boolean redactQueryParameters() {
119+
return redactQueryParameters;
120120
}
121121

122122
public String getTraceIdKey() {
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.instrumentation.api.internal;
7+
8+
/**
9+
* This class is internal and is hence not for public use. Its APIs are unstable and can change at
10+
* any time.
11+
*/
12+
public class ExperimentalParameterUtil {
13+
14+
private static boolean redactQueryParameters;
15+
16+
private ExperimentalParameterUtil() {}
17+
18+
public static boolean isRedactQueryParameters() {
19+
return redactQueryParameters;
20+
}
21+
22+
public static void setRedactQueryParameters(boolean redactQueryParameters) {
23+
ExperimentalParameterUtil.redactQueryParameters = redactQueryParameters;
24+
}
25+
}

instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractor.java

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
import io.opentelemetry.instrumentation.api.semconv.network.internal.InternalServerAttributesExtractor;
1818
import io.opentelemetry.semconv.HttpAttributes;
1919
import io.opentelemetry.semconv.UrlAttributes;
20+
import java.util.Arrays;
21+
import java.util.HashSet;
22+
import java.util.Set;
2023
import java.util.function.ToIntFunction;
2124
import javax.annotation.Nullable;
2225

@@ -32,6 +35,9 @@ public final class HttpClientAttributesExtractor<REQUEST, RESPONSE>
3235
REQUEST, RESPONSE, HttpClientAttributesGetter<REQUEST, RESPONSE>>
3336
implements SpanKeyProvider {
3437

38+
private static final Set<String> PARAMS_TO_REDACT =
39+
new HashSet<>(Arrays.asList("AWSAccessKeyId", "Signature", "sig", "X-Goog-Signature"));
40+
3541
/**
3642
* Creates the HTTP client attributes extractor with default configuration.
3743
*
@@ -54,6 +60,7 @@ public static <REQUEST, RESPONSE> HttpClientAttributesExtractorBuilder<REQUEST,
5460
private final InternalNetworkAttributesExtractor<REQUEST, RESPONSE> internalNetworkExtractor;
5561
private final InternalServerAttributesExtractor<REQUEST> internalServerExtractor;
5662
private final ToIntFunction<Context> resendCountIncrementer;
63+
private final boolean redactQueryParameters;
5764

5865
HttpClientAttributesExtractor(HttpClientAttributesExtractorBuilder<REQUEST, RESPONSE> builder) {
5966
super(
@@ -65,6 +72,7 @@ public static <REQUEST, RESPONSE> HttpClientAttributesExtractorBuilder<REQUEST,
6572
internalNetworkExtractor = builder.buildNetworkExtractor();
6673
internalServerExtractor = builder.buildServerExtractor();
6774
resendCountIncrementer = builder.resendCountIncrementer;
75+
redactQueryParameters = builder.redactQueryParameters;
6876
}
6977

7078
@Override
@@ -104,11 +112,21 @@ public SpanKey internalGetSpanKey() {
104112
}
105113

106114
@Nullable
107-
private static String stripSensitiveData(@Nullable String url) {
115+
private String stripSensitiveData(@Nullable String url) {
108116
if (url == null || url.isEmpty()) {
109117
return url;
110118
}
111119

120+
url = redactUserInfo(url);
121+
122+
if (redactQueryParameters) {
123+
url = redactQueryParameters(url);
124+
}
125+
126+
return url;
127+
}
128+
129+
private static String redactUserInfo(String url) {
112130
int schemeEndIndex = url.indexOf(':');
113131

114132
if (schemeEndIndex == -1) {
@@ -145,4 +163,59 @@ private static String stripSensitiveData(@Nullable String url) {
145163
}
146164
return url.substring(0, schemeEndIndex + 3) + "REDACTED:REDACTED" + url.substring(atIndex);
147165
}
166+
167+
private static String redactQueryParameters(String url) {
168+
169+
int questionMarkIndex = url.indexOf('?');
170+
171+
if (questionMarkIndex == -1) {
172+
return url;
173+
}
174+
175+
if (!containsParamToRedact(url)) {
176+
return url;
177+
}
178+
179+
StringBuilder redactedParameters = new StringBuilder();
180+
boolean paramToRedact = false;
181+
boolean paramNameDetected = false;
182+
boolean reference = false;
183+
184+
StringBuilder currentParamName = new StringBuilder();
185+
186+
for (int i = questionMarkIndex + 1; i < url.length(); i++) {
187+
char currentChar = url.charAt(i);
188+
if (currentChar == '=') {
189+
paramNameDetected = true;
190+
redactedParameters.append(currentParamName);
191+
redactedParameters.append('=');
192+
if (PARAMS_TO_REDACT.contains(currentParamName.toString())) {
193+
redactedParameters.append("REDACTED");
194+
paramToRedact = true;
195+
}
196+
} else if (currentChar == '&') {
197+
redactedParameters.append('&');
198+
paramNameDetected = false;
199+
paramToRedact = false;
200+
currentParamName.setLength(0);
201+
} else if (currentChar == '#') {
202+
reference = true;
203+
redactedParameters.append('#');
204+
} else if (!paramNameDetected) {
205+
currentParamName.append(currentChar);
206+
} else if (!paramToRedact || reference) {
207+
redactedParameters.append(currentChar);
208+
}
209+
}
210+
return url.substring(0, questionMarkIndex) + "?" + redactedParameters;
211+
}
212+
213+
private static boolean containsParamToRedact(String urlpart) {
214+
for (String param : PARAMS_TO_REDACT) {
215+
if (urlpart.contains(param)) {
216+
return true;
217+
}
218+
}
219+
return false;
220+
}
148221
}

instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractorBuilder.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import io.opentelemetry.context.Context;
1212
import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor;
1313
import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder;
14+
import io.opentelemetry.instrumentation.api.internal.ExperimentalParameterUtil;
1415
import io.opentelemetry.instrumentation.api.internal.HttpConstants;
1516
import io.opentelemetry.instrumentation.api.semconv.network.internal.AddressAndPortExtractor;
1617
import io.opentelemetry.instrumentation.api.semconv.network.internal.InternalNetworkAttributesExtractor;
@@ -37,6 +38,7 @@ public final class HttpClientAttributesExtractorBuilder<REQUEST, RESPONSE> {
3738
List<String> capturedResponseHeaders = emptyList();
3839
Set<String> knownMethods = HttpConstants.KNOWN_METHODS;
3940
ToIntFunction<Context> resendCountIncrementer = HttpClientRequestResendCount::getAndIncrement;
41+
boolean redactQueryParameters;
4042

4143
HttpClientAttributesExtractorBuilder(
4244
HttpClientAttributesGetter<REQUEST, RESPONSE> httpAttributesGetter) {
@@ -180,6 +182,7 @@ HttpClientAttributesExtractorBuilder<REQUEST, RESPONSE> setResendCountIncremente
180182
* @see InstrumenterBuilder#addAttributesExtractor(AttributesExtractor)
181183
*/
182184
public AttributesExtractor<REQUEST, RESPONSE> build() {
185+
redactQueryParameters = ExperimentalParameterUtil.isRedactQueryParameters();
183186
return new HttpClientAttributesExtractor<>(this);
184187
}
185188

instrumentation-api/src/test/java/io/opentelemetry/instrumentation/api/semconv/http/HttpClientAttributesExtractorTest.java

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import io.opentelemetry.api.common.AttributesBuilder;
3131
import io.opentelemetry.context.Context;
3232
import io.opentelemetry.instrumentation.api.instrumenter.AttributesExtractor;
33+
import io.opentelemetry.instrumentation.api.internal.ExperimentalParameterUtil;
3334
import io.opentelemetry.instrumentation.api.internal.HttpConstants;
3435
import java.net.ConnectException;
3536
import java.util.HashMap;
@@ -211,6 +212,8 @@ void stripBasicAuthTest(String url, String expectedResult) {
211212
Map<String, String> request = new HashMap<>();
212213
request.put("urlFull", url);
213214

215+
ExperimentalParameterUtil.setRedactQueryParameters(true);
216+
214217
AttributesExtractor<Map<String, String>, Map<String, String>> extractor =
215218
HttpClientAttributesExtractor.create(new TestHttpClientAttributesGetter());
216219

@@ -241,7 +244,37 @@ public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
241244
arguments("https://github.com/p@th?foo=b@r", "https://github.com/p@th?foo=b@r"),
242245
arguments("https://github.com#[email protected]", "https://github.com#[email protected]"),
243246
arguments("user1:[email protected]", "user1:[email protected]"),
244-
arguments("https://github.com@", "https://github.com@"));
247+
arguments("https://github.com@", "https://github.com@"),
248+
arguments(
249+
"https://service.com?paramA=valA&paramB=valB",
250+
"https://service.com?paramA=valA&paramB=valB"),
251+
arguments(
252+
"https://service.com?AWSAccessKeyId=AKIAIOSFODNN7",
253+
"https://service.com?AWSAccessKeyId=REDACTED"),
254+
arguments(
255+
"https://service.com?Signature=39Up9jzHkxhuIhFE9594DJxe7w6cIRCg0V6ICGS0%3A377",
256+
"https://service.com?Signature=REDACTED"),
257+
arguments(
258+
"https://service.com?sig=39Up9jzHkxhuIhFE9594DJxe7w6cIRCg0V6ICGS0",
259+
"https://service.com?sig=REDACTED"),
260+
arguments(
261+
"https://service.com?X-Goog-Signature=39Up9jzHkxhuIhFE9594DJxe7w6cIRCg0V6ICGS0",
262+
"https://service.com?X-Goog-Signature=REDACTED"),
263+
arguments(
264+
"https://service.com?paramA=valA&AWSAccessKeyId=AKIAIOSFODNN7&paramB=valB",
265+
"https://service.com?paramA=valA&AWSAccessKeyId=REDACTED&paramB=valB"),
266+
arguments(
267+
"https://service.com?AWSAccessKeyId=AKIAIOSFODNN7&paramA=valA",
268+
"https://service.com?AWSAccessKeyId=REDACTED&paramA=valA"),
269+
arguments(
270+
"https://service.com?paramA=valA&AWSAccessKeyId=AKIAIOSFODNN7",
271+
"https://service.com?paramA=valA&AWSAccessKeyId=REDACTED"),
272+
arguments(
273+
"https://service.com?AWSAccessKeyId=AKIAIOSFODNN7&AWSAccessKeyId=ZGIAIOSFODNN7",
274+
"https://service.com?AWSAccessKeyId=REDACTED&AWSAccessKeyId=REDACTED"),
275+
arguments(
276+
"https://service.com?AWSAccessKeyId=AKIAIOSFODNN7#ref",
277+
"https://service.com?AWSAccessKeyId=REDACTED#ref"));
245278
}
246279
}
247280

smoke-tests-otel-starter/spring-boot-common/src/main/resources/application.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ otel:
1212
client:
1313
emit-experimental-telemetry: true
1414
experimental:
15-
redact-sensitive-url-parameters: true
15+
redact-query-parameters: true
1616
server:
1717
emit-experimental-telemetry: true
1818
capture-request-headers: [key]

0 commit comments

Comments
 (0)