Ed Landau
Ed Landau

Reputation: 998

Serilog: Can I add a property without adding to the message?

I have a WIndows .NET app, and starting to use Serilog. I initialize this like this:

Log.Logger = new LoggerConfiguration()
  .MinimumLevel.Verbose()
.Enrich.With(new ThreadIdEnricher())
.Enrich.WithProperty("BuildId", Guid.NewGuid()) // One Guid per run.
.Enrich.FromLogContext()
.WriteTo.RollingFile(@"C:\QRT\Logs\QRT-LOG.txt", LogEventLevel.Verbose)
.WriteTo.Seq("http://localhost:5341" )
.WriteTo.Console(outputTemplate:"{Source} BLAHBLAH {Message:lj}")
.WriteTo.File(new CompactJsonFormatter(), "C:/QRT/Logs/log.json")
.CreateLogger();

And I use it like this:

_log = Log.ForContext<GameBase>()
.ForContext("InstrumentID", InstrumentId);
_log.Verbose("This is an order: {orderID} / {order}", order.OrderID, order);

I'd like my OrderID to be displayed in the message and I'd like the order object to be included as a property (so that I can access it when I dig into this event in Seq) but I do not want the message itself to contain the object (too big). Is there a way to do this?

Or so I need something like this:

using (var __log = _log.PushProperty("order", order)
{
  __log.Verbose ("Hit {orderID}", orderID);
}

Seems like a lot of code...

Upvotes: 3

Views: 2443

Answers (3)

ElasticCode
ElasticCode

Reputation: 7875

You can add anther ForContext to your logger for order object the same way you add InstrumentID and it will be included as a property

_log = Log.ForContext<GameBase>()
    .ForContext("InstrumentID", InstrumentId)
    .ForContext("Order", order, true);

_log.Verbose("This is an order: {orderID}", order.OrderID);

Upvotes: 3

Nicholas Blumhardt
Nicholas Blumhardt

Reputation: 31877

_log.ForContext("order", order, true).Verbose("Hit {orderID}", orderID);

The true here tells Serilog to serialized ("destructure") order instead of calling its ToString() method.

Upvotes: 2

Ruben Bartelink
Ruben Bartelink

Reputation: 61893

Yes, but there are weird tricks involved


eta example:

class ScalarValueEnricher : ILogEventEnricher
{
    readonly LogEventProperty _prop;

    public ScalarValueEnricher(string name, object value)
    {
        _prop = new LogEventProperty(name, new ScalarValue(value));
    }

    public void Enrich(LogEvent evt, ILogEventPropertyFactory _)
    {
         evt.AddPropertyIfAbsent(_prop);
    }
}

consumed like so:

var _log = Log.ForContext<GameBase>()
    .ForContext("InstrumentID", InstrumentId);

_log.ForContext(new ScalarEnricher("order",order)).Verbose("Hit: {orderID}", order.OrderID);

You can also of course make temporaries from _log.ForContext(new ScalarEnricher("order",order)) where that's cleaner/clearer/more efficient.

Upvotes: 0

Related Questions