2525import io .opentelemetry .api .trace .StatusCode ;
2626import io .opentelemetry .api .trace .Tracer ;
2727import java .io .IOException ;
28+ import java .net .URI ;
29+ import java .net .URISyntaxException ;
30+ import java .util .Arrays ;
31+ import java .util .Collections ;
32+ import java .util .HashSet ;
33+ import java .util .Set ;
2834import org .jspecify .annotations .Nullable ;
2935
3036/**
@@ -50,6 +56,10 @@ public class HttpTracingRequestInitializer implements HttpRequestInitializer {
5056 AttributeKey .longKey ("http.response.body.size" );
5157
5258 @ VisibleForTesting static final String HTTP_RPC_SYSTEM_NAME = "http" ;
59+ private static final String REDACTED_VALUE = "REDACTED" ;
60+ private static final Set <String > SENSITIVE_QUERY_KEYS =
61+ Collections .unmodifiableSet (
62+ new HashSet <>(Arrays .asList ("AWSAccessKeyId" , "Signature" , "sig" , "X-Goog-Signature" )));
5363
5464 private final HttpRequestInitializer delegate ;
5565 private final Tracer tracer ;
@@ -128,7 +138,7 @@ private Span createHttpTraceSpan(String httpMethod, String url, String host, Int
128138 Span span =
129139 BigQueryTelemetryTracer .newSpanBuilder (tracer , httpMethod )
130140 .setAttribute (HTTP_REQUEST_METHOD , httpMethod )
131- .setAttribute (URL_FULL , url )
141+ .setAttribute (URL_FULL , sanitizeUrlFull ( url ) )
132142 .setAttribute (BigQueryTelemetryTracer .SERVER_ADDRESS , host )
133143 .setAttribute (URL_DOMAIN , resolveUrlDomain (host ))
134144 .setAttribute (BigQueryTelemetryTracer .RPC_SYSTEM_NAME , HTTP_RPC_SYSTEM_NAME )
@@ -233,4 +243,51 @@ private static void checkForUpdatedRequestMethod(
233243 span .setAttribute (HTTP_REQUEST_METHOD , actualMethod );
234244 }
235245 }
246+
247+ @ VisibleForTesting
248+ static String sanitizeUrlFull (String url ) {
249+ try {
250+ URI uri = new URI (url );
251+ String sanitizedUserInfo =
252+ uri .getRawUserInfo () != null ? REDACTED_VALUE + ":" + REDACTED_VALUE : null ;
253+ String sanitizedQuery = redactSensitiveQueryValues (uri .getRawQuery ());
254+ URI sanitizedUri =
255+ new URI (
256+ uri .getScheme (),
257+ sanitizedUserInfo ,
258+ uri .getHost (),
259+ uri .getPort (),
260+ uri .getRawPath (),
261+ sanitizedQuery ,
262+ uri .getRawFragment ());
263+ return sanitizedUri .toString ();
264+ } catch (URISyntaxException | IllegalArgumentException ex ) {
265+ return url ;
266+ }
267+ }
268+
269+ private static String redactSensitiveQueryValues (@ Nullable String rawQuery ) {
270+ if (rawQuery == null || rawQuery .isEmpty ()) {
271+ return rawQuery ;
272+ }
273+
274+ String [] params = rawQuery .split ("&" , -1 );
275+ for (int i = 0 ; i < params .length ; i ++) {
276+ String param = params [i ];
277+ int equalsIndex = param .indexOf ('=' );
278+ String key = equalsIndex >= 0 ? param .substring (0 , equalsIndex ) : param ;
279+ if (SENSITIVE_QUERY_KEYS .contains (key )) {
280+ params [i ] = key + "=" + REDACTED_VALUE ;
281+ }
282+ }
283+
284+ StringBuilder redactedQuery = new StringBuilder ();
285+ for (int i = 0 ; i < params .length ; i ++) {
286+ if (i > 0 ) {
287+ redactedQuery .append ('&' );
288+ }
289+ redactedQuery .append (params [i ]);
290+ }
291+ return redactedQuery .toString ();
292+ }
236293}
0 commit comments