Skip to content

Blazor logging scopes #62527

Open
Open
@omccully

Description

@omccully

Is there an existing issue for this?

  • I have searched the existing issues

Is your feature request related to a problem? Please describe the problem.

I am trying to add additional logging properties when logging from Blazor Server components and related services. I want to be able to log the current URL (not just the original request URL -- by default, ASP.NET Core logs the RequestPath as /blazor, which is useless). There's a lot of other situation-dependent properties that would be nice to include that are only known by the Blazor components and other services that are within the circuit's service scope (for example, which tab does the user have selected within a tab component like MudTabs).

I can set some scoped logging properties somewhat reliably by defining a IHubFilter and calling _logger.BeginScope from there. I am using Serilog, which respects the log scope data that is set (uses AsyncLocal). But from the IHubFilter, I am not able to get the data I need because it is in a different IServiceProvider scope than the Blazor circuit service scope. I'm also not sure if IHubFilter will work to add logging scope data if a render is triggered by something other than an incoming SignalR call, like a timer.

You'd think a scoped CircuitHandler would be a place to be able to start the logging scope, but the virtual methods that it contains is limited. It does not have any method that is invoked for every SignalR call. If you start a logging scope from the OnCircuitOpenedAsync, the logging scope effectively ends any future events and rerenders will be in a different async call stack (related to how AsyncLocal works).

Describe the solution you'd like

The current solution I'm using involves having a base component class that all of my components inherit from that overrides OnParametersSet() and OnAfterRender() and to check if the logging scope has started yet for the current SignalR call. This seems horribly inefficient because I'm checking AsyncLocal data for each render and for each component. It's also not 100% reliable.

I think I need something similar to IHubFilter/CircuitHandler except it can hook into any event that runs on the RendererStynchronizationContext/CircuitHost to provide a place that is completely reliable for adding logging scoped data from the circuit's scoped services.

Example of what that might look like:

builder.Services.AddScoped<IRendererListener, MyRendererListener>();
class MyRendererListener : IRendererListener
{
    // scope is the Blazor circuit's service scope
    public void OnRenderEvent(IServiceProvider scope)
    {
        scope.GetRequiredService<ILogger<MyRendererListener>>().BeginScope(scope.GetRequiredService<MyScopedLoggingData>())
    }
}

Additional context

I've been looking everywhere for a solution for this. I've explored using ASP.NET Core middleware, CircuitHandler, IHubFilter, custom component base classes, custom logger types. I haven't been able to find a good solution for this. I've looked up and down the call stacks at various points to try to figure out how I can hook in some code where I'd need to, but I haven't been able to find it. I've asked AI chat bots various questions.

Including scoped logging data like this, such as including the current URL, seems like something that should be well supported and documented. I'd appreciate any help or improvements in this area.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Needs: Author FeedbackThe author of this issue needs to respond in order for us to continue investigating this issue.area-blazorIncludes: Blazor, Razor Components

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions