So, I'm attempting to include Serilog in my application at the moment, and was wondering about the following:
Is it possible to add an object so my Azure Tablestorage sink will pick it up and write it out completely to JSON in the respective "Data" column, without adding it to the plain text message?
My initial approach was this:
m_logger.Information("{message} @{context}", message, context);
And this is what my question originates from. This worked, but I'd like to keep the message itself human readable and keep metadata from the context in a separate column.
So, my second attempt now looks like this:
using (LogContext.PushProperty("context", context))
{
m_logger.Information("{message}", message);
}
Given, I added this to my logger config: .Enrich.FromLogContext()
Now this kind of works, the object does not appear in the message anymore and is actually added to the Data, but instead of completely writing it out to JSON, this is what I end up with in my Data column on the Tablestorage endpoint:
{"Timestamp":"2019-09-01T08:52:29.4835746+02:00","Level":"Information","MessageTemplate":"{message}","Properties":{"message":"Login happened","context":"MooMed.Core.DataTypes.Session.Context"}}
So, it seems like this internally merely calls .ToString()
.
I'd now like to know whether there is a built in way to recursively jsonify the object, or if I have to (seemingly) just override .ToString()
in my Context
class?
Unless you explicitly tell Serilog to destructure your context data it will simply use the ToString
representation. In your initial approach you're telling Serilog to destructure by using the @
symbol (although I assume you used it inside the curly braces rather than outside, i.e. {@context}
rather than @{context}
otherwise this shouldn't have worked).
When using LogContext
you can tell Serilog to destructure the object by passing a flag when pusing a property:
using (LogContext.PushProperty("context", context, destructureObjects: true))
{
// ...
}
I assume you're aware that this will add the context to all messages logged inside the using
block, including any that occur further down the call stack. As an alternative, you can also create a temporary logger enriched with this context data if you want more control over which messages the context gets added to. This is done using the ILogger.ForContext
method:
var enrichedLogger = m_logger.ForContext("context", context, destructureObjects: true);
// Use `enrichedLogger` instead of `m_logger` whenever you want context data included.
enrichedLogger.Information("This message has context data attached!");
m_logger.Information("This message does not have context data attached.");
You can also use the same approach above to add context to a single message:
m_logger.ForContext("context", context, destructureObjects: true)
.Information("This message has context data attached!")