-
Notifications
You must be signed in to change notification settings - Fork 4.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Activities for Http Connections, Dns, Sockets and SslStream #103922
Merged
antonfirsov
merged 50 commits into
dotnet:main
from
antonfirsov:connection-activities-05
Jul 13, 2024
Merged
Changes from all commits
Commits
Show all changes
50 commits
Select commit
Hold shift + click to select a range
4e740d0
Activities for Http Connection, Dns, Sockets and Tls
antonfirsov 3945fe4
address review feedback
antonfirsov f40ce38
Merge branch 'main' into connection-activities-05
antonfirsov 08bc611
resolve conflicts
antonfirsov e2cf15e
get rid of finally block
antonfirsov e963ed2
Merge branch 'main' into connection-activities-05
antonfirsov 133c7b7
Merge branch 'main' into connection-activities-05
antonfirsov 5119f9c
System.Net.NameResolution: record tags and ActivityStatusCode
antonfirsov 4b1ffa8
set DNS activity DisplayName
antonfirsov 5e0e971
Socket Activity tags
antonfirsov 4988004
emit attributes on SslStream Activity
antonfirsov 7777b68
connection setup activity graph
antonfirsov fd60820
emit tags on http connection activities
antonfirsov b730434
Merge branch 'connection-activities-05' of https://github.com/antonfi…
antonfirsov 4ce1499
fix MacOS failure
antonfirsov ecce03b
adjustments
antonfirsov c109253
Merge branch 'main' into connection-activities-05
antonfirsov dc563ad
consolidate connection setup Activity error handling into a single ca…
antonfirsov c099441
address more review feedback
antonfirsov 17e62a0
merge stuff
antonfirsov 2d8bee3
emit the link on the request span instead of wait_for_connection
antonfirsov 55b1eea
Merge branch 'main' into connection-activities-05
antonfirsov 9995e27
adjust System.Net.NameResolution
antonfirsov c2c7c87
adjust System.Net.Sockets naming, add UDS test
antonfirsov 8acab55
replace the _connectActivity field with a CWT
antonfirsov afe1648
Adjust SslStream tracing
antonfirsov 96f1f18
ActivityKind
antonfirsov a9cd814
adjust HTTP Activities
antonfirsov f4548ff
Merge branch 'main' into connection-activities-05
antonfirsov 576842c
SocketsHttpHandler_DiagnosticsTest_Http3
antonfirsov f04ab6e
WIP h3
antonfirsov 7b94039
adjust to main
antonfirsov 1c5e772
implement H/3 connection diagnostics
antonfirsov 3d6911c
Merge branch 'main' into connection-activities-05
antonfirsov 8c008e1
actually use the same ActivitySource for ConnectionSetup & WaitForCon…
antonfirsov e829df2
*handshake
antonfirsov 7c94ae8
Update src/libraries/System.Net.NameResolution/src/System/Net/NameRes…
antonfirsov 92afed7
Merge branch 'connection-activities-05' of https://github.com/antonfi…
antonfirsov 06896bf
fix H3 logic based on feedback
antonfirsov b455d17
ConnectionSetupDiagnostics -> ConnectionSetupDistributedTracing
antonfirsov 0d231ba
Merge branch 'main' into connection-activities-05
antonfirsov 56e8cb3
suggestion
antonfirsov 870eae5
suggestion
antonfirsov de774dd
suggestion
antonfirsov 284734b
Merge branch 'main' into connection-activities-05
antonfirsov b1ef7f3
implement 'network.transport'
antonfirsov d99734f
SslStream: move Activity management code to NetSecurityTelemetry
antonfirsov ae587f7
readd assertion and add comment
antonfirsov 9443cd2
Merge branch 'main' into connection-activities-05
antonfirsov c9a5ad2
Merge branch 'main' into connection-activities-05
antonfirsov File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
136 changes: 136 additions & 0 deletions
136
src/libraries/Common/tests/System/Net/ActivityRecorder.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,136 @@ | ||
// 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.Linq; | ||
using System.Text; | ||
using Xunit; | ||
|
||
namespace System.Net.Test.Common | ||
{ | ||
internal class ActivityRecorder : IDisposable | ||
{ | ||
private string _activitySourceName; | ||
private string _activityName; | ||
|
||
private readonly ActivityListener _listener; | ||
private List<Activity> _finishedActivities = new(); | ||
|
||
public Predicate<Activity> Filter { get; set; } = _ => true; | ||
public bool VerifyParent { get; set; } = true; | ||
public Activity ExpectedParent { get; set; } | ||
|
||
public int Started { get; private set; } | ||
public int Stopped { get; private set; } | ||
public Activity LastStartedActivity { get; private set; } | ||
public Activity LastFinishedActivity { get; private set; } | ||
public IEnumerable<Activity> FinishedActivities => _finishedActivities; | ||
|
||
public ActivityRecorder(string activitySourceName, string activityName) | ||
{ | ||
_activitySourceName = activitySourceName; | ||
_activityName = activityName; | ||
_listener = new ActivityListener | ||
{ | ||
ShouldListenTo = (activitySource) => activitySource.Name == _activitySourceName, | ||
Sample = (ref ActivityCreationOptions<ActivityContext> options) => ActivitySamplingResult.AllData, | ||
ActivityStarted = (activity) => { | ||
if (activity.OperationName == _activityName && Filter(activity)) | ||
{ | ||
if (VerifyParent) | ||
{ | ||
Assert.Same(ExpectedParent, activity.Parent); | ||
} | ||
|
||
Started++; | ||
LastStartedActivity = activity; | ||
} | ||
}, | ||
ActivityStopped = (activity) => { | ||
if (activity.OperationName == _activityName && Filter(activity)) | ||
{ | ||
if (VerifyParent) | ||
{ | ||
Assert.Same(ExpectedParent, activity.Parent); | ||
} | ||
|
||
Stopped++; | ||
LastFinishedActivity = activity; | ||
_finishedActivities.Add(activity); | ||
} | ||
} | ||
}; | ||
|
||
ActivitySource.AddActivityListener(_listener); | ||
} | ||
|
||
public void Dispose() => _listener.Dispose(); | ||
|
||
public void VerifyActivityRecorded(int times) | ||
{ | ||
Assert.Equal(times, Started); | ||
Assert.Equal(times, Stopped); | ||
} | ||
|
||
public Activity VerifyActivityRecordedOnce() | ||
{ | ||
VerifyActivityRecorded(1); | ||
return LastFinishedActivity; | ||
} | ||
} | ||
|
||
internal static class ActivityAssert | ||
{ | ||
public static KeyValuePair<string, object> HasTag(Activity activity, string name) | ||
{ | ||
KeyValuePair<string, object> tag = activity.TagObjects.SingleOrDefault(t => t.Key == name); | ||
if (tag.Key is null) | ||
{ | ||
Assert.Fail($"The Activity tags should contain {name}."); | ||
} | ||
return tag; | ||
} | ||
|
||
public static void HasTag<T>(Activity activity, string name, T expectedValue) | ||
{ | ||
KeyValuePair<string, object> tag = HasTag(activity, name); | ||
Assert.Equal(expectedValue, (T)tag.Value); | ||
} | ||
|
||
public static void HasTag<T>(Activity activity, string name, Func<T, bool> verifyValue) | ||
{ | ||
T? value = (T?)activity.TagObjects.SingleOrDefault(t => t.Key == name).Value; | ||
Assert.False(value is null, $"The Activity tags should contain {name}."); | ||
Assert.True(verifyValue(value)); | ||
} | ||
|
||
public static void HasNoTag(Activity activity, string name) | ||
{ | ||
bool contains = activity.TagObjects.Any(t => t.Key == name); | ||
Assert.False(contains, $"The Activity tags should not contain {name}."); | ||
} | ||
|
||
public static void FinishedInOrder(Activity first, Activity second) | ||
{ | ||
Assert.True(first.StartTimeUtc + first.Duration < second.StartTimeUtc + second.Duration, $"{first.OperationName} should stop before {second.OperationName}"); | ||
} | ||
|
||
public static string CamelToSnake(string camel) | ||
{ | ||
if (string.IsNullOrEmpty(camel)) return camel; | ||
StringBuilder bld = new(); | ||
bld.Append(char.ToLower(camel[0])); | ||
for (int i = 1; i < camel.Length; i++) | ||
{ | ||
char c = camel[i]; | ||
if (char.IsUpper(c)) | ||
{ | ||
bld.Append('_'); | ||
} | ||
bld.Append(char.ToLower(c)); | ||
} | ||
return bld.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
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
98 changes: 98 additions & 0 deletions
98
...rc/System/Net/Http/SocketsHttpHandler/ConnectionPool/ConnectionSetupDistributedTracing.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,98 @@ | ||
// 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, HttpAuthority authority) | ||
{ | ||
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) | ||
{ | ||
activity.DisplayName = $"HTTP connection_setup {authority.HostValue}:{authority.Port}"; | ||
if (activity.IsAllDataRequested) | ||
{ | ||
activity.SetTag("server.address", authority.HostValue); | ||
activity.SetTag("server.port", authority.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); | ||
if (activity is not null) | ||
{ | ||
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 (DiagnosticsHandler.s_activitySource.HasListeners()) | ||
{ | ||
Activity? requestActivity = Activity.Current; | ||
if (requestActivity?.Source == DiagnosticsHandler.s_activitySource) | ||
{ | ||
requestActivity.AddLink(new ActivityLink(connectionSetupActivity.Context)); | ||
} | ||
} | ||
} | ||
} | ||
} |
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.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Experimental?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It turned out that our solution results is an unexpected volume of span links for tools like Azure Monitor, blowing up their UI, see open-telemetry/opentelemetry-specification#4130.
We need to work with OTel and Azure Monitor to introduce a standard way for categorizing links so visualization tools can distinguish them. The plan is to drive this work forward in order to stabilize the feature in .NET 10.