// 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 { // Implements distributed tracing logic for managing the "HTTP connection_setup" and "HTTP wait_for_connection" Activities. internal static class ConnectionSetupDistributedTracing { private static readonly ActivitySource s_connectionsActivitySource = new ActivitySource(DiagnosticsHandlerLoggingStrings.ConnectionsNamespace); public static Activity? StartConnectionSetupActivity(bool isSecure, string? serverAddress, int port) { Activity? activity = null; if (s_connectionsActivitySource.HasListeners()) { // Connection activities should be new roots and not parented under whatever // request happens to be in progress when the connection is started. Activity.Current = null; activity = s_connectionsActivitySource.StartActivity(DiagnosticsHandlerLoggingStrings.ConnectionSetupActivityName); } if (activity is not null) { Debug.Assert(serverAddress is not null, "serverAddress should not be null when System.Net.Http.EnableActivityPropagation is true."); activity.DisplayName = $"HTTP connection_setup {serverAddress}:{port}"; if (activity.IsAllDataRequested) { activity.SetTag("server.address", serverAddress); activity.SetTag("server.port", port); activity.SetTag("url.scheme", isSecure ? "https" : "http"); } } return activity; } public static void StopConnectionSetupActivity(Activity activity, Exception? exception, IPEndPoint? remoteEndPoint) { Debug.Assert(activity is not null); if (exception is not null) { ReportError(activity, exception); } else { if (activity.IsAllDataRequested && remoteEndPoint is not null) { activity.SetTag("network.peer.address", remoteEndPoint.Address.ToString()); } } activity.Stop(); } public static void ReportError(Activity? activity, Exception exception) { Debug.Assert(exception is not null); if (activity is null) return; activity.SetStatus(ActivityStatusCode.Error); if (activity.IsAllDataRequested) { DiagnosticsHelper.TryGetErrorType(null, exception, out string? errorType); Debug.Assert(errorType is not null, "DiagnosticsHelper.TryGetErrorType() should succeed whenever an exception is provided."); activity.SetTag("error.type", errorType); } } public static Activity? StartWaitForConnectionActivity(HttpAuthority authority) { Activity? activity = s_connectionsActivitySource.StartActivity(DiagnosticsHandlerLoggingStrings.WaitForConnectionActivityName); activity?.DisplayName = $"HTTP wait_for_connection {authority.HostValue}:{authority.Port}"; return activity; } public static void AddConnectionLinkToRequestActivity(Activity connectionSetupActivity) { Debug.Assert(connectionSetupActivity is not null); // We only support links for request activities created by the "System.Net.Http" ActivitySource. if (GlobalHttpSettings.DiagnosticsHandler.EnableActivityPropagation && DiagnosticsHandler.s_activitySource.HasListeners()) { Activity? requestActivity = Activity.Current; if (requestActivity?.Source == DiagnosticsHandler.s_activitySource) { requestActivity.AddLink(new ActivityLink(connectionSetupActivity.Context)); } } } } } |