Goran
Goran

Reputation: 6518

Serilog in the blazor wasm hosted project

I am trying out for the first time Serilog, and I am having trouble understanding how it parses data during serialization. I am using Serilog.Sinks.Http in order to pass exception information from Client (Blazor wazm hosted) to Server (ASP.NET Core 6.0).

The way I understood it, Serilog.AspNetCore can only be used on the server side, which I was able to configure successfully. However, on client side I need a library that can serialize through HTTP.

So I found Serilog.Sinks.Http. First I experienced a problem on the Serilog registration part: I could not find a way to insert a Serilog provider on the client side, as I was able on the server side. That means that on server side Serilog is nicely integrated into MS Logging infrastructure, and on the client it is not. I was only able to register it in DI container. But it is completely disconnected from MS logging framework. So, two questions:

Q1) Is it possible to register Serilog as a custom provider in a blazor wasm hosted project, so that it can integrate with MS framework? This is the code I have now:

builder.Logging.Services.AddScoped<Serilog.ILogger>(_ =>
new LoggerConfiguration()
  .WriteTo.Http(requestUri: uri)
  .CreateLogger()
  .ForContext<Program>());

Q2) How can I control the serialization part? Basically what I am interested in, is to either pass a whole exception object with some additional data, or pass my custom entity, and then log this entity on the server side. I know I can establish connection with normal web api call, but as far as I understand, Serilog has advanced buffering system, where it is able to store messages and then resend them when connection is reactivated, for example.

I tried something like this:

Logger.Error( exception, someMessage);

Then I get a weird JSON structure on the Server side, I do not know what to do with it. Here is an example where I throw AccessViolationException. I recognize the first #events# part, I have seen it in some example on the github, where they used LogEvents for mapping:

 public class LogEvents { public LogEvent[] Events { get; set; } = null!; }

But I just could not make it to work with my custom object (more data):

 {{
  "events": [
     {
       "Timestamp": "2021-12-20T19:04:25.822+01:00",
       "Level": "Error",
       "MessageTemplate": "Exception while bla bla bla",
       "RenderedMessage": "Exception while bla bla bla",
       "Exception": "System.AccessViolationException: bla bla at bla bla",
       "Properties": {
         "SourceContext": "Program"
       }
     }
   ]
 }}
 ChildrenTokens: Count = 1
 Count: 1
 First: {"events": [
   {
     "Timestamp": "2021-12-20T19:04:25.822+01:00",
     "Level": "Error",
     "MessageTemplate": "Exception while bla bla bla",
     "RenderedMessage": "Exception while bla bla bla",
     "Exception": "System.AccessViolationException: bla bla at bla bla",
     "Properties": {
       "SourceContext": "Program"
     }
   }
 ]}
 HasValues: true
 Last: {"events": [
   {
     "Timestamp": "2021-12-20T19:04:25.822+01:00",
     "Level": "Error",
     "MessageTemplate": "Exception while bla bla bla",
     "RenderedMessage": "Exception while bla bla bla",
     "Exception": "System.AccessViolationException: bla bla at bla bla",
     "Properties": {
       "SourceContext": "Program"
     }
   }
 ]}
 Next: null
 Parent: null
 Path: ""
 Previous: null
 Root: {{
   "events": [
     {
       "Timestamp": "2021-12-20T19:04:25.822+01:00",
       "Level": "Error",
       "MessageTemplate": "Exception while bla bla bla",
       "RenderedMessage": "Exception while bla bla bla",
       "Exception": "System.AccessViolationException: bla bla at bla bla",
       "Properties": {
         "SourceContext": "Program"
       }
     }
   ]
 }}
 Type: Object
 Results View: Expanding the Results View will enumerate the IEnumerable
 Dynamic View: Expanding the Dynamic View will get the dynamic members for the object

Upvotes: 1

Views: 2252

Answers (1)

John Goudy
John Goudy

Reputation: 341

In order to get Blazor WASM client Serilog information passed to the server for processing I followed https://nblumhardt.com/2019/11/serilog-blazor/ which uses Serilog.Sinks.BrowserHttp and Serilog.AspNetCore.Ingestion which are both pre-release Nuget packages.

As per a comment on that link, I also found it necessary to supply the endpointUrl parameter as:

.WriteTo.BrowserHttp(endpointUrl: builder.HostEnvironment.BaseAddress+"ingest"

In the client Program.cs

var levelSwitch = new LoggingLevelSwitch();

string LogTemplate = "{Timestamp:yyyy-MM-dd HH:mm:ss.fff} [{Level:u3}]  {Message,-120:j}     {NewLine}{Exception}";

Log.Logger = new LoggerConfiguration()
    .MinimumLevel.ControlledBy(levelSwitch)
    .Enrich.WithProperty("InstanceId", Guid.NewGuid().ToString("n"))
    .WriteTo.BrowserHttp(endpointUrl: builder.HostEnvironment.BaseAddress + "ingest", controlLevelSwitch: levelSwitch)
    .WriteTo.BrowserConsole(outputTemplate: LogTemplate)
    .CreateLogger();

In the server Program.cs

app.UseSerilogIngestion();
app.UseSerilogRequestLogging();

It works with .NET6.

Upvotes: 2

Related Questions