问题
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?
回答1:
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.)
回答2:
Thanks to Nicholas Blumhardt for a good starting point. I just have a small tweak.
my class:
public class Dummy
{
public string Field = "the field";
public string Property { get; set; } = "the property";
}
log call:
Log.Information("Dummy = {@Dummy}", new Dummy());
IDestructuringPolicy implementation includes both fields and properties:
internal class IncludePublicFieldsPolicy : IDestructuringPolicy
{
public bool TryDestructure(object value, ILogEventPropertyValueFactory propertyValueFactory, out LogEventPropertyValue result)
{
var typeInfo = value.GetType().GetTypeInfo();
var fieldsWithValues = typeInfo
.DeclaredFields
.Where(f => f.IsPublic)
.Select(f =>
{
var val = f.GetValue(value);
var propval = propertyValueFactory.CreatePropertyValue(val);
var ret = new LogEventProperty(f.Name, propval);
return ret;
})
;
var propertiesWithValues = typeInfo
.DeclaredProperties
.Where(f => f.CanRead)
.Select(f =>
{
var val = f.GetValue(value);
var propval = propertyValueFactory.CreatePropertyValue(val);
var ret = new LogEventProperty(f.Name, propval);
return ret;
})
;
result = new StructureValue(fieldsWithValues.Union(propertiesWithValues));
return true;
}
}
来源:https://stackoverflow.com/questions/46152092/serilog-serializing-fields