0

I'm working to set up distributed tracing for my application. One of the connections in the application is a WebSocket connection using SignalR. Both ends of the SignalR connection are asp.net core applications. One is a Windows service (the client) and the other runs under a web server (the server).

Communication will be sourced from both directions so I'll have TraceIds originating with requests on both sides of the connection. Does SignalR have a facility for passing this Trace information back and forth? I have searched all over and there is almost no information about SignalR supporting W3C Trace Contexts or even a custom implemented tracing system like .net core pre 2.0.

I have tried creating a new Activity when making a request on the server side but I don't think any trace information is making it to the client. I may not be looking in the right place, but when I check System.Diagnostics.Activity.CurrentActivity on the client I only get null even though on the server I had the following Activity at the time I made the call.

System.Diagnostics.Activity.Current
{System.Diagnostics.Activity}
    ActivityTraceFlags: None
    Baggage: {System.Collections.Generic.KeyValuePair<string, string>[0]}
    Context: {System.Diagnostics.ActivityContext}
    DisplayName: "Microsoft.AspNetCore.Hosting.HttpRequestIn"
    Duration: {00:00:00}
    Events: {System.Diagnostics.ActivityEvent[0]}
    Id: "00-eb7a4125a171a6438a44ddda5a637cd0-f7c16b0bb8512443-00"
    IdFormat: W3C
    IsAllDataRequested: true
    Kind: Internal
    Links: {System.Diagnostics.ActivityLink[0]}
    OperationName: "Microsoft.AspNetCore.Hosting.HttpRequestIn"
    Parent: null
    ParentId: null
    ParentSpanId: {0000000000000000}
    Recorded: false
    RootId: "eb7a4125a171a6438a44ddda5a637cd0"
    Source: {System.Diagnostics.ActivitySource}
    SpanId: {f7c16b0bb8512443}
    StartTimeUtc: {7/13/2021 11:26:13 PM}
    TagObjects: {System.Collections.Generic.KeyValuePair<string, object>[0]}
    Tags: {System.Collections.Generic.KeyValuePair<string, string>[0]}
    TraceId: {eb7a4125a171a6438a44ddda5a637cd0}
    TraceStateString: null

I hope someone out there can shed some light on this.

Thanks!

-=-=-=-= Edit -=-=-=-=

It looks like at least some level of W3C context tracing is supported by SignalR when hosted in a Blazor app. Not sure what to make of that though. https://github.com/dotnet/aspnetcore/issues/29846

omatase
  • 1,551
  • 1
  • 18
  • 42

2 Answers2

0

Logging and tracing are really two names for the same technique.

  1. You can use the logging system to collect diagnostic information to help solve the problem.
  2. Logging and diagnostics in ASP.NET Core SignalR
  3. .NET Core logging and tracing

If you want to implement distributed tracing, you can enable Application Insights for ASP.NET Core applications.

  1. Application Insights for ASP.NET Core applications
  2. .NET distributed tracing
Yihui Sun
  • 755
  • 3
  • 5
  • thanks but I'm looking for a logging platform-agnostic solution because I'm not using AI. I know that I can manually do my tracing but I'm interesting in knowing if the SignalR team has already solved the problem. I'm guessing they have not though. However, I did find an article showing that at least some level of W3C context tracing is occuring in SignalR when hosted inside Blazor. I'm not sure what to make of that. https://github.com/dotnet/aspnetcore/issues/29846 – omatase Jul 14 '21 at 15:31
0

After much research, not only does SignalR have little to no extensibility options for the message invocation lifecycle (the only one available appears to be HubFilters) but it also doesn't support W3C Trace Contexts at all. I've taken to implement this myself, but it's a big undertaking so I'm holding off to see if MS starts supporting this in the next 8 - 12 months. Here's hoping.

More on my musings on how this would have to be implemented manually...

HubFilters

These only offer an extensibility touch point when a message is coming from one of the connected clients. Before the method invocation requested by the client takes place you have an opportunity to inspect the message coming from the client and can take actions against all messages in a central location. There seems to be no such extensibility options for messages being sent to a client, being received by a client or being sent from a client. In order to inject code at these points you have to do it manually by wrapping all of your function invocations in another function.

Header and Querystring Support

SignalR does let you add headers and data to the query string, but since Websocket communication doesn't occur over the HTTP protocol there isn't a way to pass data specific to each message using these headers.

Conclusion

If you want to support the same functionality you get from a W3C Trace Contexts implementation in SignalR with websockets, you'll need to pass a common object (I called mine SignalRContext) in every request to and from the client or server. This object can be used to pass along, at a minimum, a TraceId to help tie all of your application tracing together.

omatase
  • 1,551
  • 1
  • 18
  • 42