Search code examples
c#.netserilogseqseq-logging

Serilog serializing fields


If I have the following class

public class Customer
{
    public string Name;
}

and then have the following log command in Serilog

Log.Logger = new LoggerConfiguration()
    .WriteTo.Console()
    .WriteTo.Seq("http://localhost:5341")
    .CreateLogger();

var item = new Customer();
item.Name = "John";
Serilog.Log.Information("Customer {@item}", item);

The log just displays in Seq as

Customer {}

If I change the Name field to a property it works but I would prefer not to do that at this stage. Is there any way around it?


Solution

  • To do this just for the one type (recommended), you can use:

    .Destructure.ByTransforming<Customer>(c => new { c.Name })
    

    If you want to include public fields for all types, or those matching some kind of condition, you can plug in a policy to do it:

    class IncludePublicFieldsPolicy : IDestructuringPolicy
    {
        public bool TryDestructure(
            object value,
            ILogEventPropertyValueFactory propertyValueFactory,
            out LogEventPropertyValue result)
        {
            if (!(value is SomeBaseType))
            {
                result = null;
                return false;
            }
    
            var fieldsWithValues = value.GetType().GetTypeInfo().DeclaredFields
                .Where(f => f.IsPublic)
                .Select(f => new LogEventProperty(f.Name,
                   propertyValueFactory.CreatePropertyValue(f.GetValue(value))));
    
            result = new StructureValue(fieldsWithValues);
            return true;
        }
    }
    

    The example scopes this down to look at objects derived from SomeBaseType only.

    You can plug it in with:

    .Destructure.With<IncludePublicFieldsPolicy>()
    

    (I think it's likely to require some tweaking, but should be a good starting point.)