Skip to content

Commit e222ecb

Browse files
[Instrumentation.Http][Instrumentation.AspNetCore] Fix url.full and url.query attribute values (open-telemetry#5532)
1 parent 0bbebb5 commit e222ecb

22 files changed

+359
-15
lines changed

OpenTelemetry.sln

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{A49299
270270
src\Shared\PeerServiceResolver.cs = src\Shared\PeerServiceResolver.cs
271271
src\Shared\PeriodicExportingMetricReaderHelper.cs = src\Shared\PeriodicExportingMetricReaderHelper.cs
272272
src\Shared\PooledList.cs = src\Shared\PooledList.cs
273+
src\Shared\RedactionHelper.cs = src\Shared\RedactionHelper.cs
273274
src\Shared\RequestMethodHelper.cs = src\Shared\RequestMethodHelper.cs
274275
src\Shared\ResourceSemanticConventions.cs = src\Shared\ResourceSemanticConventions.cs
275276
src\Shared\SemanticConventions.cs = src\Shared\SemanticConventions.cs

src/OpenTelemetry.Instrumentation.AspNetCore/AspNetCoreTraceInstrumentationOptions.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,14 @@ internal AspNetCoreTraceInstrumentationOptions(IConfiguration configuration)
3232
{
3333
this.EnableGrpcAspNetCoreSupport = enableGrpcInstrumentation;
3434
}
35+
36+
if (configuration.TryGetBoolValue(
37+
AspNetCoreInstrumentationEventSource.Log,
38+
"OTEL_DOTNET_EXPERIMENTAL_ASPNETCORE_DISABLE_URL_QUERY_REDACTION",
39+
out var disableUrlQueryRedaction))
40+
{
41+
this.DisableUrlQueryRedaction = disableUrlQueryRedaction;
42+
}
3543
}
3644

3745
/// <summary>
@@ -94,4 +102,14 @@ internal AspNetCoreTraceInstrumentationOptions(IConfiguration configuration)
94102
/// https://github.com/open-telemetry/semantic-conventions/blob/main/docs/rpc/rpc-spans.md.
95103
/// </remarks>
96104
internal bool EnableGrpcAspNetCoreSupport { get; set; }
105+
106+
/// <summary>
107+
/// Gets or sets a value indicating whether the url query value should be redacted or not.
108+
/// </summary>
109+
/// <remarks>
110+
/// The query parameter values are redacted with value set as Redacted.
111+
/// e.g. `?key1=value1` is set as `?key1=Redacted`.
112+
/// The redaction can be disabled by setting this property to <see langword="true" />.
113+
/// </remarks>
114+
internal bool DisableUrlQueryRedaction { get; set; }
97115
}

src/OpenTelemetry.Instrumentation.AspNetCore/CHANGELOG.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
# Changelog
22

3-
## Unreleased
3+
## 1.8.1
4+
5+
Released 2024-Apr-12
6+
7+
* **Breaking Change**: Fixed tracing instrumentation so that by default any
8+
values detected in the query string component of requests are replaced with
9+
the text `Redacted` when building the `url.query` tag. For example,
10+
`?key1=value1&key2=value2` becomes `?key1=Redacted&key2=Redacted`. You can
11+
disable this redaction by setting the environment variable
12+
`OTEL_DOTNET_EXPERIMENTAL_ASPNETCORE_DISABLE_URL_QUERY_REDACTION` to `true`.
13+
([#5532](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5532))
414

515
## 1.8.0
616

src/OpenTelemetry.Instrumentation.AspNetCore/Implementation/HttpInListener.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,8 +193,14 @@ public void OnStartActivity(Activity activity, object payload)
193193

194194
if (request.QueryString.HasValue)
195195
{
196-
// QueryString should be sanitized. see: https://github.com/open-telemetry/opentelemetry-dotnet/issues/4571
197-
activity.SetTag(SemanticConventions.AttributeUrlQuery, request.QueryString.Value);
196+
if (this.options.DisableUrlQueryRedaction)
197+
{
198+
activity.SetTag(SemanticConventions.AttributeUrlQuery, request.QueryString.Value);
199+
}
200+
else
201+
{
202+
activity.SetTag(SemanticConventions.AttributeUrlQuery, RedactionHelper.GetRedactedQueryString(request.QueryString.Value));
203+
}
198204
}
199205

200206
RequestMethodHelper.SetHttpMethodTag(activity, request.Method);

src/OpenTelemetry.Instrumentation.AspNetCore/OpenTelemetry.Instrumentation.AspNetCore.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
<Compile Include="$(RepoRoot)\src\OpenTelemetry.Instrumentation.GrpcNetClient\GrpcTagHelper.cs" Link="Includes\GrpcTagHelper.cs" />
1818
<Compile Include="$(RepoRoot)\src\OpenTelemetry.Instrumentation.GrpcNetClient\StatusCanonicalCode.cs" Link="Includes\StatusCanonicalCode.cs" />
1919
<Compile Include="$(RepoRoot)\src\Shared\Guard.cs" Link="Includes\Guard.cs" />
20+
<Compile Include="$(RepoRoot)\src\Shared\RedactionHelper.cs" Link="Includes\RedactionHelper.cs" />
2021
<Compile Include="$(RepoRoot)\src\Shared\RequestMethodHelper.cs" Link="Includes\RequestMethodHelper.cs" />
2122
<Compile Include="$(RepoRoot)\src\Shared\Shims\NullableAttributes.cs" Link="Includes\Shims\NullableAttributes.cs" />
2223
<Compile Include="$(RepoRoot)\src\Shared\Options\*.cs" Link="Includes\Options\%(Filename).cs" />

src/OpenTelemetry.Instrumentation.AspNetCore/README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,11 @@ for more details about each individual attribute:
7575
* `server.address`
7676
* `server.port`
7777
* `url.path`
78-
* `url.query`
78+
* `url.query` - By default, the values in the query component are replaced with
79+
the text `Redacted`. For example, `?key1=value1&key2=value2` becomes
80+
`?key1=Redacted&key2=Redacted`. You can disable this redaction by setting the
81+
environment variable
82+
`OTEL_DOTNET_EXPERIMENTAL_ASPNETCORE_DISABLE_URL_QUERY_REDACTION` to `true`.
7983
* `url.scheme`
8084

8185
[Enrich Api](#enrich) can be used if any additional attributes are

src/OpenTelemetry.Instrumentation.Http/CHANGELOG.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
# Changelog
22

3-
## Unreleased
3+
## 1.8.1
4+
5+
Released 2024-Apr-12
6+
7+
* **Breaking Change**: Fixed tracing instrumentation so that by default any
8+
values detected in the query string component of requests are replaced with
9+
the text `Redacted` when building the `url.full` tag. For example,
10+
`?key1=value1&key2=value2` becomes `?key1=Redacted&key2=Redacted`. You can
11+
disable this redaction by setting the environment variable
12+
`OTEL_DOTNET_EXPERIMENTAL_HTTPCLIENT_DISABLE_URL_QUERY_REDACTION` to `true`.
13+
([#5532](https://github.com/open-telemetry/opentelemetry-dotnet/pull/5532))
414

515
## 1.8.0
616

src/OpenTelemetry.Instrumentation.Http/HttpClientInstrumentationTracerProviderBuilderExtensions.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ public static TracerProviderBuilder AddHttpClientInstrumentation(
5959
{
6060
services.Configure(name, configureHttpClientTraceInstrumentationOptions);
6161
}
62+
63+
services.RegisterOptionsFactory(configuration => new HttpClientTraceInstrumentationOptions(configuration));
6264
});
6365

6466
#if NETFRAMEWORK

src/OpenTelemetry.Instrumentation.Http/HttpClientTraceInstrumentationOptions.cs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33

44
using System.Diagnostics;
55
using System.Net;
6+
using System.Runtime.CompilerServices;
67
#if NETFRAMEWORK
78
using System.Net.Http;
89
#endif
9-
using System.Runtime.CompilerServices;
10+
using Microsoft.Extensions.Configuration;
1011
using OpenTelemetry.Instrumentation.Http.Implementation;
1112

1213
namespace OpenTelemetry.Instrumentation.Http;
@@ -16,6 +17,27 @@ namespace OpenTelemetry.Instrumentation.Http;
1617
/// </summary>
1718
public class HttpClientTraceInstrumentationOptions
1819
{
20+
/// <summary>
21+
/// Initializes a new instance of the <see cref="HttpClientTraceInstrumentationOptions"/> class.
22+
/// </summary>
23+
public HttpClientTraceInstrumentationOptions()
24+
: this(new ConfigurationBuilder().AddEnvironmentVariables().Build())
25+
{
26+
}
27+
28+
internal HttpClientTraceInstrumentationOptions(IConfiguration configuration)
29+
{
30+
Debug.Assert(configuration != null, "configuration was null");
31+
32+
if (configuration.TryGetBoolValue(
33+
HttpInstrumentationEventSource.Log,
34+
"OTEL_DOTNET_EXPERIMENTAL_HTTPCLIENT_DISABLE_URL_QUERY_REDACTION",
35+
out var disableUrlQueryRedaction))
36+
{
37+
this.DisableUrlQueryRedaction = disableUrlQueryRedaction;
38+
}
39+
}
40+
1941
/// <summary>
2042
/// Gets or sets a filter function that determines whether or not to
2143
/// collect telemetry on a per request basis.
@@ -125,6 +147,16 @@ public class HttpClientTraceInstrumentationOptions
125147
/// </remarks>
126148
public bool RecordException { get; set; }
127149

150+
/// <summary>
151+
/// Gets or sets a value indicating whether the url query value should be redacted or not.
152+
/// </summary>
153+
/// <remarks>
154+
/// The query parameter values are redacted with value set as Redacted.
155+
/// e.g. `?key1=value1` is set as `?key1=Redacted`.
156+
/// The redaction can be disabled by setting this property to <see langword="true" />.
157+
/// </remarks>
158+
internal bool DisableUrlQueryRedaction { get; set; }
159+
128160
[MethodImpl(MethodImplOptions.AggressiveInlining)]
129161
internal bool EventFilterHttpRequestMessage(string activityName, object arg1)
130162
{

src/OpenTelemetry.Instrumentation.Http/Implementation/HttpHandlerDiagnosticListener.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ public void OnStartActivity(Activity activity, object payload)
149149
activity.SetTag(SemanticConventions.AttributeServerAddress, request.RequestUri.Host);
150150
activity.SetTag(SemanticConventions.AttributeServerPort, request.RequestUri.Port);
151151

152-
activity.SetTag(SemanticConventions.AttributeUrlFull, HttpTagHelper.GetUriTagValueFromRequestUri(request.RequestUri));
152+
activity.SetTag(SemanticConventions.AttributeUrlFull, HttpTagHelper.GetUriTagValueFromRequestUri(request.RequestUri, this.options.DisableUrlQueryRedaction));
153153

154154
try
155155
{

src/OpenTelemetry.Instrumentation.Http/Implementation/HttpInstrumentationEventSource.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// SPDX-License-Identifier: Apache-2.0
33

44
using System.Diagnostics.Tracing;
5+
using Microsoft.Extensions.Configuration;
56
using OpenTelemetry.Internal;
67

78
namespace OpenTelemetry.Instrumentation.Http.Implementation;
@@ -10,7 +11,7 @@ namespace OpenTelemetry.Instrumentation.Http.Implementation;
1011
/// EventSource events emitted from the project.
1112
/// </summary>
1213
[EventSource(Name = "OpenTelemetry-Instrumentation-Http")]
13-
internal sealed class HttpInstrumentationEventSource : EventSource
14+
internal sealed class HttpInstrumentationEventSource : EventSource, IConfigurationExtensionsLogger
1415
{
1516
public static HttpInstrumentationEventSource Log = new();
1617

@@ -100,4 +101,15 @@ public void UnknownErrorProcessingEvent(string handlerName, string eventName, st
100101
{
101102
this.WriteEvent(7, handlerName, eventName, ex);
102103
}
104+
105+
[Event(8, Message = "Configuration key '{0}' has an invalid value: '{1}'", Level = EventLevel.Warning)]
106+
public void InvalidConfigurationValue(string key, string value)
107+
{
108+
this.WriteEvent(8, key, value);
109+
}
110+
111+
void IConfigurationExtensionsLogger.LogInvalidConfigurationValue(string key, string value)
112+
{
113+
this.InvalidConfigurationValue(key, value);
114+
}
103115
}

src/OpenTelemetry.Instrumentation.Http/Implementation/HttpTagHelper.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// Copyright The OpenTelemetry Authors
22
// SPDX-License-Identifier: Apache-2.0
33

4+
using OpenTelemetry.Internal;
5+
46
namespace OpenTelemetry.Instrumentation.Http.Implementation;
57

68
/// <summary>
@@ -12,15 +14,18 @@ internal static class HttpTagHelper
1214
/// Gets the OpenTelemetry standard uri tag value for a span based on its request <see cref="Uri"/>.
1315
/// </summary>
1416
/// <param name="uri"><see cref="Uri"/>.</param>
17+
/// <param name="disableQueryRedaction">Indicates whether query parameter should be redacted or not.</param>
1518
/// <returns>Span uri value.</returns>
16-
public static string GetUriTagValueFromRequestUri(Uri uri)
19+
public static string GetUriTagValueFromRequestUri(Uri uri, bool disableQueryRedaction)
1720
{
18-
if (string.IsNullOrEmpty(uri.UserInfo))
21+
if (string.IsNullOrEmpty(uri.UserInfo) && disableQueryRedaction)
1922
{
2023
return uri.OriginalString;
2124
}
2225

23-
return string.Concat(uri.Scheme, Uri.SchemeDelimiter, uri.Authority, uri.PathAndQuery, uri.Fragment);
26+
var query = disableQueryRedaction ? uri.Query : RedactionHelper.GetRedactedQueryString(uri.Query);
27+
28+
return string.Concat(uri.Scheme, Uri.SchemeDelimiter, uri.Authority, uri.AbsolutePath, query, uri.Fragment);
2429
}
2530

2631
public static string GetProtocolVersionString(Version httpVersion) => (httpVersion.Major, httpVersion.Minor) switch

src/OpenTelemetry.Instrumentation.Http/Implementation/HttpWebRequestActivitySource.netfx.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ private static void AddRequestTagsAndInstrumentRequest(HttpWebRequest request, A
105105
activity.SetTag(SemanticConventions.AttributeServerAddress, request.RequestUri.Host);
106106
activity.SetTag(SemanticConventions.AttributeServerPort, request.RequestUri.Port);
107107

108-
activity.SetTag(SemanticConventions.AttributeUrlFull, HttpTagHelper.GetUriTagValueFromRequestUri(request.RequestUri));
108+
activity.SetTag(SemanticConventions.AttributeUrlFull, HttpTagHelper.GetUriTagValueFromRequestUri(request.RequestUri, tracingOptions.DisableUrlQueryRedaction));
109109

110110
try
111111
{

src/OpenTelemetry.Instrumentation.Http/OpenTelemetry.Instrumentation.Http.csproj

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,12 @@
1212
</PropertyGroup>
1313

1414
<ItemGroup>
15+
<Compile Include="$(RepoRoot)\src\Shared\Configuration\*.cs" Link="Includes\Configuration\%(Filename).cs" />
16+
<Compile Include="$(RepoRoot)\src\Shared\EnvironmentVariables\*.cs" Link="Includes\EnvironmentVariables\%(Filename).cs" />
1517
<Compile Include="$(RepoRoot)\src\Shared\Guard.cs" Link="Includes\Guard.cs" />
1618
<Compile Include="$(RepoRoot)\src\Shared\Shims\NullableAttributes.cs" Link="Includes\Shims\NullableAttributes.cs" />
19+
<Compile Include="$(RepoRoot)\src\Shared\Options\*.cs" Link="Includes\Options\%(Filename).cs" />
20+
<Compile Include="$(RepoRoot)\src\Shared\RedactionHelper.cs" Link="Includes\RedactionHelper.cs" />
1721
<Compile Include="$(RepoRoot)\src\Shared\RequestMethodHelper.cs" Link="Includes\RequestMethodHelper.cs" />
1822
</ItemGroup>
1923

@@ -29,6 +33,7 @@
2933
<ItemGroup>
3034
<Reference Include="System.Net.Http" Condition="'$(TargetFramework)' == '$(NetFrameworkMinimumSupportedVersion)'" />
3135
<PackageReference Include="Microsoft.Extensions.Options" />
36+
<PackageReference Include="Microsoft.Extensions.Configuration" />
3237
</ItemGroup>
3338

3439
</Project>

src/OpenTelemetry.Instrumentation.Http/README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,11 @@ for more details about each individual attribute:
6868
* `network.protocol.version`
6969
* `server.address`
7070
* `server.port`
71-
* `url.full`
71+
* `url.full` - By default, the values in the query component of the url are
72+
replaced with the text `Redacted`. For example, `?key1=value1&key2=value2`
73+
becomes `?key1=Redacted&key2=Redacted`. You can disable this redaction by
74+
setting the environment variable
75+
`OTEL_DOTNET_EXPERIMENTAL_HTTPCLIENT_DISABLE_URL_QUERY_REDACTION` to `true`.
7276

7377
[Enrich Api](#enrich-httpclient-api) can be used if any additional attributes are
7478
required on activity.

src/Shared/RedactionHelper.cs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
#nullable enable
5+
6+
using System.Text;
7+
8+
namespace OpenTelemetry.Internal;
9+
10+
internal class RedactionHelper
11+
{
12+
private static readonly string RedactedText = "Redacted";
13+
14+
public static string? GetRedactedQueryString(string query)
15+
{
16+
int length = query.Length;
17+
int index = 0;
18+
19+
// Preallocate some size to avoid re-sizing multiple times.
20+
// Since the size will increase, allocating twice as much.
21+
// TODO: Check to see if we can borrow from https://github.com/dotnet/runtime/blob/main/src/libraries/Common/src/System/Text/ValueStringBuilder.cs
22+
// to improve perf.
23+
StringBuilder queryBuilder = new(2 * length);
24+
while (index < query.Length)
25+
{
26+
// Check if the character is = for redacting value.
27+
if (query[index] == '=')
28+
{
29+
// Append =
30+
queryBuilder.Append('=');
31+
index++;
32+
33+
// Append redactedText in place of original value.
34+
queryBuilder.Append(RedactedText);
35+
36+
// Move until end of this key/value pair.
37+
while (index < length && query[index] != '&')
38+
{
39+
index++;
40+
}
41+
42+
// End of key/value.
43+
if (index < length && query[index] == '&')
44+
{
45+
queryBuilder.Append(query[index]);
46+
}
47+
}
48+
else
49+
{
50+
// Keep adding to the result
51+
queryBuilder.Append(query[index]);
52+
}
53+
54+
index++;
55+
}
56+
57+
return queryBuilder.ToString();
58+
}
59+
}

0 commit comments

Comments
 (0)