Skip to content

Commit 6c1244f

Browse files
Refactor connection endpoint tagging to use shared utility
Co-authored-by: BrennanConroy <[email protected]>
1 parent dbd9f49 commit 6c1244f

File tree

5 files changed

+140
-51
lines changed

5 files changed

+140
-51
lines changed

src/Servers/Kestrel/Core/src/Internal/Infrastructure/KestrelMetrics.cs

Lines changed: 1 addition & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -321,43 +321,7 @@ private void TlsHandshakeStopCore(ConnectionMetricsContext metricsContext, long
321321

322322
private static void InitializeConnectionTags(ref TagList tags, in ConnectionMetricsContext metricsContext)
323323
{
324-
var localEndpoint = metricsContext.ConnectionContext.LocalEndPoint;
325-
if (localEndpoint is IPEndPoint localIPEndPoint)
326-
{
327-
tags.Add("server.address", localIPEndPoint.Address.ToString());
328-
tags.Add("server.port", localIPEndPoint.Port);
329-
330-
switch (localIPEndPoint.Address.AddressFamily)
331-
{
332-
case AddressFamily.InterNetwork:
333-
tags.Add("network.type", "ipv4");
334-
break;
335-
case AddressFamily.InterNetworkV6:
336-
tags.Add("network.type", "ipv6");
337-
break;
338-
}
339-
340-
// There isn't an easy way to detect whether QUIC is the underlying transport.
341-
// This code assumes that a multiplexed connection is QUIC.
342-
// Improve in the future if there are additional multiplexed connection types.
343-
var transport = metricsContext.ConnectionContext is not MultiplexedConnectionContext ? "tcp" : "udp";
344-
tags.Add("network.transport", transport);
345-
}
346-
else if (localEndpoint is UnixDomainSocketEndPoint udsEndPoint)
347-
{
348-
tags.Add("server.address", udsEndPoint.ToString());
349-
tags.Add("network.transport", "unix");
350-
}
351-
else if (localEndpoint is NamedPipeEndPoint namedPipeEndPoint)
352-
{
353-
tags.Add("server.address", namedPipeEndPoint.ToString());
354-
tags.Add("network.transport", "pipe");
355-
}
356-
else if (localEndpoint != null)
357-
{
358-
tags.Add("server.address", localEndpoint.ToString());
359-
tags.Add("network.transport", localEndpoint.AddressFamily.ToString());
360-
}
324+
ConnectionEndpointTags.AddConnectionEndpointTags(ref tags, metricsContext.ConnectionContext);
361325
}
362326

363327
public ConnectionMetricsContext CreateContext(BaseConnectionContext connection)

src/Servers/Kestrel/Core/src/Microsoft.AspNetCore.Server.Kestrel.Core.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
<Compile Include="$(SharedSourceRoot)Obsoletions.cs" LinkBase="Shared" />
3838
<Compile Include="$(RepoRoot)src\Shared\TaskToApm.cs" Link="Internal\TaskToApm.cs" />
3939
<Compile Include="$(SharedSourceRoot)Metrics\MetricsExtensions.cs" />
40+
<Compile Include="$(SharedSourceRoot)ConnectionEndpointTags.cs" />
4041
</ItemGroup>
4142

4243
<ItemGroup>
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Diagnostics;
5+
using System.Net;
6+
using System.Net.Sockets;
7+
using Microsoft.AspNetCore.Connections;
8+
using Microsoft.AspNetCore.Connections.Features;
9+
using Microsoft.AspNetCore.Http.Features;
10+
11+
#nullable enable
12+
13+
internal static class ConnectionEndpointTags
14+
{
15+
/// <summary>
16+
/// Adds connection endpoint tags to a TagList using IConnectionEndPointFeature.
17+
/// </summary>
18+
/// <param name="tags">The TagList to add tags to.</param>
19+
/// <param name="features">The feature collection to get endpoint information from.</param>
20+
public static void AddConnectionEndpointTags(ref TagList tags, IFeatureCollection features)
21+
{
22+
var endpointFeature = features.Get<IConnectionEndPointFeature>();
23+
if (endpointFeature is null)
24+
{
25+
return;
26+
}
27+
28+
var localEndpoint = endpointFeature.LocalEndPoint;
29+
if (localEndpoint is IPEndPoint localIPEndPoint)
30+
{
31+
tags.Add("server.address", localIPEndPoint.Address.ToString());
32+
tags.Add("server.port", localIPEndPoint.Port);
33+
34+
switch (localIPEndPoint.Address.AddressFamily)
35+
{
36+
case AddressFamily.InterNetwork:
37+
tags.Add("network.type", "ipv4");
38+
break;
39+
case AddressFamily.InterNetworkV6:
40+
tags.Add("network.type", "ipv6");
41+
break;
42+
}
43+
44+
// There isn't an easy way to detect whether QUIC is the underlying transport.
45+
// This code assumes that a multiplexed connection is QUIC.
46+
// Improve in the future if there are additional multiplexed connection types.
47+
// Note: We can't determine transport from features alone, so we default to "tcp"
48+
tags.Add("network.transport", "tcp");
49+
}
50+
else if (localEndpoint is UnixDomainSocketEndPoint udsEndPoint)
51+
{
52+
tags.Add("server.address", udsEndPoint.ToString());
53+
tags.Add("network.transport", "unix");
54+
}
55+
else if (localEndpoint is NamedPipeEndPoint namedPipeEndPoint)
56+
{
57+
tags.Add("server.address", namedPipeEndPoint.ToString());
58+
tags.Add("network.transport", "pipe");
59+
}
60+
else if (localEndpoint != null)
61+
{
62+
tags.Add("server.address", localEndpoint.ToString());
63+
tags.Add("network.transport", localEndpoint.AddressFamily.ToString());
64+
}
65+
}
66+
67+
/// <summary>
68+
/// Adds connection endpoint tags to a TagList using IConnectionEndPointFeature.
69+
/// </summary>
70+
/// <param name="tags">The TagList to add tags to.</param>
71+
/// <param name="connectionContext">The connection context to get endpoint information from.</param>
72+
public static void AddConnectionEndpointTags(ref TagList tags, BaseConnectionContext connectionContext)
73+
{
74+
var endpointFeature = connectionContext.Features.Get<IConnectionEndPointFeature>();
75+
if (endpointFeature is null)
76+
{
77+
return;
78+
}
79+
80+
var localEndpoint = endpointFeature.LocalEndPoint;
81+
if (localEndpoint is IPEndPoint localIPEndPoint)
82+
{
83+
tags.Add("server.address", localIPEndPoint.Address.ToString());
84+
tags.Add("server.port", localIPEndPoint.Port);
85+
86+
switch (localIPEndPoint.Address.AddressFamily)
87+
{
88+
case AddressFamily.InterNetwork:
89+
tags.Add("network.type", "ipv4");
90+
break;
91+
case AddressFamily.InterNetworkV6:
92+
tags.Add("network.type", "ipv6");
93+
break;
94+
}
95+
96+
// There isn't an easy way to detect whether QUIC is the underlying transport.
97+
// This code assumes that a multiplexed connection is QUIC.
98+
// Improve in the future if there are additional multiplexed connection types.
99+
var transport = connectionContext is not MultiplexedConnectionContext ? "tcp" : "udp";
100+
tags.Add("network.transport", transport);
101+
}
102+
else if (localEndpoint is UnixDomainSocketEndPoint udsEndPoint)
103+
{
104+
tags.Add("server.address", udsEndPoint.ToString());
105+
tags.Add("network.transport", "unix");
106+
}
107+
else if (localEndpoint is NamedPipeEndPoint namedPipeEndPoint)
108+
{
109+
tags.Add("server.address", namedPipeEndPoint.ToString());
110+
tags.Add("network.transport", "pipe");
111+
}
112+
else if (localEndpoint != null)
113+
{
114+
tags.Add("server.address", localEndpoint.ToString());
115+
tags.Add("network.transport", localEndpoint.AddressFamily.ToString());
116+
}
117+
}
118+
}

src/SignalR/server/Core/src/Internal/DefaultHubDispatcher.cs

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ public override async Task OnConnectedAsync(HubConnectionContext connection)
9292
// OnConnectedAsync won't work with client results (ISingleClientProxy.InvokeAsync)
9393
InitializeHub(hub, connection, invokeAllowed: false);
9494

95-
activity = StartActivity(SignalRServerActivitySource.OnConnected, ActivityKind.Internal, linkedActivity: null, scope.ServiceProvider, nameof(hub.OnConnectedAsync), headers: null, _logger);
95+
activity = StartActivity(SignalRServerActivitySource.OnConnected, ActivityKind.Internal, linkedActivity: null, scope.ServiceProvider, nameof(hub.OnConnectedAsync), headers: null, _logger, connection);
9696

9797
if (_onConnectedMiddleware != null)
9898
{
@@ -127,7 +127,7 @@ public override async Task OnDisconnectedAsync(HubConnectionContext connection,
127127
{
128128
InitializeHub(hub, connection);
129129

130-
activity = StartActivity(SignalRServerActivitySource.OnDisconnected, ActivityKind.Internal, linkedActivity: null, scope.ServiceProvider, nameof(hub.OnDisconnectedAsync), headers: null, _logger);
130+
activity = StartActivity(SignalRServerActivitySource.OnDisconnected, ActivityKind.Internal, linkedActivity: null, scope.ServiceProvider, nameof(hub.OnDisconnectedAsync), headers: null, _logger, connection);
131131

132132
if (_onDisconnectedMiddleware != null)
133133
{
@@ -404,7 +404,7 @@ static async Task ExecuteInvocation(DefaultHubDispatcher<THub> dispatcher,
404404

405405
// Use hubMethodInvocationMessage.Target instead of methodExecutor.MethodInfo.Name
406406
// We want to take HubMethodNameAttribute into account which will be the same as what the invocation target is
407-
var activity = StartActivity(SignalRServerActivitySource.InvocationIn, ActivityKind.Server, connection.OriginalActivity, scope.ServiceProvider, hubMethodInvocationMessage.Target, hubMethodInvocationMessage.Headers, logger);
407+
var activity = StartActivity(SignalRServerActivitySource.InvocationIn, ActivityKind.Server, connection.OriginalActivity, scope.ServiceProvider, hubMethodInvocationMessage.Target, hubMethodInvocationMessage.Headers, logger, connection);
408408

409409
object? result;
410410
try
@@ -522,7 +522,7 @@ private async Task StreamAsync(string invocationId, HubConnectionContext connect
522522
Activity.Current = null;
523523
}
524524

525-
var activity = StartActivity(SignalRServerActivitySource.InvocationIn, ActivityKind.Server, connection.OriginalActivity, scope.ServiceProvider, hubMethodInvocationMessage.Target, hubMethodInvocationMessage.Headers, _logger);
525+
var activity = StartActivity(SignalRServerActivitySource.InvocationIn, ActivityKind.Server, connection.OriginalActivity, scope.ServiceProvider, hubMethodInvocationMessage.Target, hubMethodInvocationMessage.Headers, _logger, connection);
526526

527527
try
528528
{
@@ -829,7 +829,7 @@ public override IReadOnlyList<Type> GetParameterTypes(string methodName)
829829

830830
// Starts an Activity for a Hub method invocation and sets up all the tags and other state.
831831
// Make sure to call Activity.Stop() once the Hub method completes, and consider calling SetActivityError on exception.
832-
private static Activity? StartActivity(string operationName, ActivityKind kind, Activity? linkedActivity, IServiceProvider serviceProvider, string methodName, IDictionary<string, string>? headers, ILogger logger)
832+
private static Activity? StartActivity(string operationName, ActivityKind kind, Activity? linkedActivity, IServiceProvider serviceProvider, string methodName, IDictionary<string, string>? headers, ILogger logger, HubConnectionContext? connection = null)
833833
{
834834
var activitySource = serviceProvider.GetService<SignalRServerActivitySource>()?.ActivitySource;
835835
if (activitySource is null)
@@ -843,15 +843,20 @@ public override IReadOnlyList<Type> GetParameterTypes(string methodName)
843843
return null;
844844
}
845845

846-
IEnumerable<KeyValuePair<string, object?>> tags =
847-
[
848-
new("rpc.method", methodName),
849-
new("rpc.system", "signalr"),
850-
new("rpc.service", _fullHubName),
851-
// See https://github.com/dotnet/aspnetcore/blob/027c60168383421750f01e427e4f749d0684bc02/src/Servers/Kestrel/Core/src/Internal/Infrastructure/KestrelMetrics.cs#L308
852-
// And https://github.com/dotnet/aspnetcore/issues/43786
853-
//new("server.address", ...),
854-
];
846+
var tagList = new TagList
847+
{
848+
{ "rpc.method", methodName },
849+
{ "rpc.system", "signalr" },
850+
{ "rpc.service", _fullHubName }
851+
};
852+
853+
// Add connection endpoint tags if connection is available
854+
if (connection is not null)
855+
{
856+
ConnectionEndpointTags.AddConnectionEndpointTags(ref tagList, connection.Features);
857+
}
858+
859+
IEnumerable<KeyValuePair<string, object?>> tags = tagList;
855860
IEnumerable<ActivityLink>? links = (linkedActivity is not null) ? [new ActivityLink(linkedActivity.Context)] : null;
856861

857862
Activity? activity;

src/SignalR/server/Core/src/Microsoft.AspNetCore.SignalR.Core.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
<Compile Include="$(SharedSourceRoot)ThrowHelpers\ArgumentNullThrowHelper.cs" LinkBase="Shared" />
2323
<Compile Include="$(SharedSourceRoot)CallerArgument\CallerArgumentExpressionAttribute.cs" LinkBase="Shared" />
2424
<Compile Include="$(SharedSourceRoot)Diagnostics\ActivityCreator.cs" />
25+
<Compile Include="$(SharedSourceRoot)ConnectionEndpointTags.cs" />
2526
</ItemGroup>
2627

2728
<ItemGroup>

0 commit comments

Comments
 (0)