Serilog field names for properties not used in message template

c#, logging, serilog

Solution

Anonymous types achieve what you have above with a lot less code:

logger
    .ForContext("Operation", new {operationTypeId, otherId, anotherId}, true)
    .Debug("Recalculation performed for operation {OperationId}", operationId);

Or alternatively by including everything in the event:

logger.Debug("Recalculation performed for operation {@Operation}", new {
        Id = operationId, TypeId = operationTypeId, OtherId = otherId, 
        AnotherId = anotherId
    });

If you find there are a lot of messages in which you want to include the same properties, you may be better off pushing them onto the `LogContext`:

using (LogContext.PushProperty("OperationId", operationId))
{
    logger.Debug("Recalculation performed");

    // ...etc...

    logger.Debug("Something else");
}

In this case, both events will have an `OperationId` associated with them. You can push multiple properties onto the log context. Just make sure to add `Enrich.FromLogContext()` to your `LoggerConfiguration` to use this style.

Problem

I am testing out Serilog and am having some issues field names. I want to add log entry with one field included in the message template and the other fields just stored in the log for querying against. I would like to do something simple like this: ``` logger.Debug("Recalculation performed for operation {OperationId}", operationId, operationTypeId, otherId, anotherId); ``` But this results in the field names not being given friendly names because they are not in the message template: ``` { "@timestamp":"2016-10-20T16:57:02.0623798+01:00", "level":"Debug", "messageTemplate":"Recalculation performed for operation {OperationId}", "fields":{ "OperationId":1024, "__1":16, "__2":32, "__3":256, "SourceContext":"SerilogTest.Worker" } } ``` I know that I can put all of the fields into a class and use the ForContext method to include them in the log entry: ``` internal class OperationData { public int OperationId { get; set; } public int OperationTypeId { get; set; } public int OtherId { get; set; } public int AnotherId { get; set; } } var operationData = new OperationData { OperationId = 1024, OperationTypeId = 16, OtherId = 32, AnotherId = 256 }; var operationLogger = logger.ForContext("OperationData", operationData, destructureObjects: true); operationLogger.Debug("Recalculation performed for operation {OperationId}", operationData.OperationId); ``` This kind of gets me the result I am looking for: ``` { "@timestamp":"2016-10-20T18:00:35.4956991+01:00", "level":"Debug", "messageTemplate":"Recalculation performed for operation {OperationId}", "fields":{ "OperationId":1024, "OperationData":{ "_typeTag":"RecalulationResult", "OperationId":1024, "OperationTypeId":16, "OtherId":32, "AnotherId":256 }, "SourceContext":"SerilogTest.Worker" } } ``` BUT, it seems like a lot of effort to go through just to have friendly field names. I have to create a new logger instance, have a type to include all of the relevant fields for the log message and then do the log. Is there an easier way of naming the fields than this?

Original source