-
Notifications
You must be signed in to change notification settings - Fork 4.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add standard tags to HttpClient native trace instrumentation (#104251)
Add the following standard tags to the HTTP Request Activities started in DelegatingHandler: http.request.method http.request.method_original server.address server.port url.full error.type http.response.status_code network.protocol.version Just like in #103769, url.full is being redacted by removing UserInfo and the query string, while exposing a System.Net.Http.DisableQueryRedaction switch for opting-out from the latter.
- Loading branch information
1 parent
e733c2f
commit c7fa446
Showing
10 changed files
with
535 additions
and
125 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
121 changes: 121 additions & 0 deletions
121
src/libraries/System.Net.Http/src/System/Net/Http/DiagnosticsHelper.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using System.Collections.Generic; | ||
using System.Diagnostics; | ||
using System.Threading; | ||
|
||
namespace System.Net.Http | ||
{ | ||
internal static class DiagnosticsHelper | ||
{ | ||
internal static string GetRedactedUriString(Uri uri) | ||
{ | ||
Debug.Assert(uri.IsAbsoluteUri); | ||
|
||
if (GlobalHttpSettings.DiagnosticsHandler.DisableUriRedaction) | ||
{ | ||
return uri.AbsoluteUri; | ||
} | ||
|
||
string pathAndQuery = uri.PathAndQuery; | ||
int queryIndex = pathAndQuery.IndexOf('?'); | ||
|
||
bool redactQuery = queryIndex >= 0 && // Query is present. | ||
queryIndex < pathAndQuery.Length - 1; // Query is not empty. | ||
|
||
return (redactQuery, uri.IsDefaultPort) switch | ||
{ | ||
(true, true) => $"{uri.Scheme}://{uri.Host}{pathAndQuery.AsSpan(0, queryIndex + 1)}*", | ||
(true, false) => $"{uri.Scheme}://{uri.Host}:{uri.Port}{pathAndQuery.AsSpan(0, queryIndex + 1)}*", | ||
(false, true) => $"{uri.Scheme}://{uri.Host}{pathAndQuery}", | ||
(false, false) => $"{uri.Scheme}://{uri.Host}:{uri.Port}{pathAndQuery}" | ||
}; | ||
} | ||
|
||
internal static KeyValuePair<string, object?> GetMethodTag(HttpMethod method, out bool isUnknownMethod) | ||
{ | ||
// Return canonical names for known methods and "_OTHER" for unknown ones. | ||
HttpMethod? known = HttpMethod.GetKnownMethod(method.Method); | ||
isUnknownMethod = known is null; | ||
return new KeyValuePair<string, object?>("http.request.method", isUnknownMethod ? "_OTHER" : known!.Method); | ||
} | ||
|
||
internal static string GetProtocolVersionString(Version httpVersion) => (httpVersion.Major, httpVersion.Minor) switch | ||
{ | ||
(1, 0) => "1.0", | ||
(1, 1) => "1.1", | ||
(2, 0) => "2", | ||
(3, 0) => "3", | ||
_ => httpVersion.ToString() | ||
}; | ||
|
||
public static bool TryGetErrorType(HttpResponseMessage? response, Exception? exception, out string? errorType) | ||
{ | ||
if (response is not null) | ||
{ | ||
int statusCode = (int)response.StatusCode; | ||
|
||
// In case the status code indicates a client or a server error, return the string representation of the status code. | ||
// See the paragraph Status and the definition of 'error.type' in | ||
// https://github.com/open-telemetry/semantic-conventions/blob/2bad9afad58fbd6b33cc683d1ad1f006e35e4a5d/docs/http/http-spans.md | ||
if (statusCode >= 400 && statusCode <= 599) | ||
{ | ||
errorType = GetErrorStatusCodeString(statusCode); | ||
return true; | ||
} | ||
} | ||
|
||
if (exception is null) | ||
{ | ||
errorType = null; | ||
return false; | ||
} | ||
|
||
Debug.Assert(Enum.GetValues<HttpRequestError>().Length == 12, "We need to extend the mapping in case new values are added to HttpRequestError."); | ||
errorType = (exception as HttpRequestException)?.HttpRequestError switch | ||
{ | ||
HttpRequestError.NameResolutionError => "name_resolution_error", | ||
HttpRequestError.ConnectionError => "connection_error", | ||
HttpRequestError.SecureConnectionError => "secure_connection_error", | ||
HttpRequestError.HttpProtocolError => "http_protocol_error", | ||
HttpRequestError.ExtendedConnectNotSupported => "extended_connect_not_supported", | ||
HttpRequestError.VersionNegotiationError => "version_negotiation_error", | ||
HttpRequestError.UserAuthenticationError => "user_authentication_error", | ||
HttpRequestError.ProxyTunnelError => "proxy_tunnel_error", | ||
HttpRequestError.InvalidResponse => "invalid_response", | ||
HttpRequestError.ResponseEnded => "response_ended", | ||
HttpRequestError.ConfigurationLimitExceeded => "configuration_limit_exceeded", | ||
|
||
// Fall back to the exception type name in case of HttpRequestError.Unknown or when exception is not an HttpRequestException. | ||
_ => exception.GetType().FullName! | ||
}; | ||
return true; | ||
} | ||
|
||
private static object[]? s_boxedStatusCodes; | ||
private static string[]? s_statusCodeStrings; | ||
|
||
#pragma warning disable CA1859 // we explictly box here | ||
public static object GetBoxedStatusCode(int statusCode) | ||
{ | ||
object[] boxes = LazyInitializer.EnsureInitialized(ref s_boxedStatusCodes, static () => new object[512]); | ||
|
||
return (uint)statusCode < (uint)boxes.Length | ||
? boxes[statusCode] ??= statusCode | ||
: statusCode; | ||
} | ||
#pragma warning restore | ||
|
||
private static string GetErrorStatusCodeString(int statusCode) | ||
{ | ||
Debug.Assert(statusCode >= 400 && statusCode <= 599); | ||
|
||
string[] strings = LazyInitializer.EnsureInitialized(ref s_statusCodeStrings, static () => new string[200]); | ||
int index = statusCode - 400; | ||
return (uint)index < (uint)strings.Length | ||
? strings[index] ??= statusCode.ToString() | ||
: statusCode.ToString(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.