I have a small application that is receiving messages from a service bus, which can send through several different types of events for different users. Based on the type of event, a different function is called. I'm logging information in each of these functions.
I currently have this:
var logger = new LoggerConfiguration()
.MinimumLevel.Information()
.WriteTo.Console(outputTemplate:
"[{Timestamp:HH:mm:ss} {Level:u3}] {Message}{NewLine}{Exception}")
.WriteTo.Loggly()
.CreateLogger();
...
// logging an event
Log.Information("{UserId} {Event} - Here is my message", "123", "Test Event");
That works fine, but since for this application, every single log will contain both the UserId and Event data in the logs, I figured I could add them to my output template to make my logging code a little cleaner. So I've tried this:
var logger = new LoggerConfiguration()
.MinimumLevel.Information()
.WriteTo.Console(outputTemplate:
"[{Timestamp:HH:mm:ss} {Level:u3}] {UserId} {Event} - {Message}{NewLine}{Exception}")
.WriteTo.Loggly()
.CreateLogger();
...
// logging an event
Log.Information("Here is my message", "123", "Test Event");
Log.Information("Here is my message", new { UserId = "123", Event = "Test Event"});
Neither of those work though, all it outputs is my message, it doesn't pass through the UserId or Event that I passed into it.
Am I doing this wrong? Or is there even a way to do it at all?
If you want to add properties that aren't part of the message template, then you need to enrich the log context. That means adding the FromLogContext enricher, and adding your properties to your logged event a bit differently.
Log.Logger = new LoggerConfiguration()
.Enrich.FromLogContext()
.MinimumLevel.Information()
.WriteTo.Console(outputTemplate:
"[{Timestamp:HH:mm:ss} {Level:u3}] {UserId} {Event} - {Message}{NewLine}{Exception}")
.CreateLogger();
using (LogContext.PushProperty("UserId", "123"))
using (LogContext.PushProperty("Event", "Test Event"))
{
Log.Information("Here is my message about order {OrderNumber}", 567);
Log.Information("Here is my message about product {ProductId}", "SomeProduct");
}
You can learn more about enrichment in the documentation.
Now I'm not sure about Loggly. I've never used it before. But you don't even need to modify the output template if you're using Seq (which is from the creators of Serilog and works best with it). Properties added will automatically be available for each event.
As Nicholas Blumhardt pointed out via comment, if you just need to one-off add a property to a single logged event, you can do that as well. I sometimes do this when I have a lot of properties for events that don't necessarily need to show up in the message, and only apply to this single event.
Log
.ForContext("OrderNumber", orderNumber)
.ForContext("UserId", user.Id)
.Information("Order submitted");