Based on @Donald Byrd's answer, I have created a more optimized version. There's no need to recreate the entire structure—just ignore default or empty values.
public class CompactJsonExtantFormatter : CompactJsonFormatter
{
/// <inheritdoc />
public CompactJsonExtantFormatter(JsonValueFormatter? valueFormatter = null) :
base(valueFormatter ?? new JsonExtantValueFormatter(typeTagName: "$type"))
{ }
}
/// <inheritdoc />
public class JsonExtantValueFormatter : JsonValueFormatter
{
private readonly string? _typeTagName;
/// <inheritdoc />
public JsonExtantValueFormatter(string typeTagName) :
base(typeTagName)
{
_typeTagName = typeTagName;
}
/// <inheritdoc />
protected override bool VisitStructureValue(TextWriter state, StructureValue structure)
{
state.Write('{');
char? delim = null;
foreach (var prop in structure.Properties)
{
if (IsDefaultValue(prop.Value))
continue;
if (delim != null)
state.Write(delim.Value);
delim = ',';
WriteQuotedJsonString(prop.Name, state);
state.Write(':');
Visit(state, prop.Value);
}
if (_typeTagName != null && structure.TypeTag != null)
{
if (delim != null)
state.Write(delim.Value);
WriteQuotedJsonString(_typeTagName, state);
state.Write(':');
WriteQuotedJsonString(structure.TypeTag, state);
}
state.Write('}');
return false;
}
private static bool IsDefaultValue(LogEventPropertyValue value)
{
return value switch
{
ScalarValue { Value: null } => true,
ScalarValue { Value: string s } when string.IsNullOrEmpty(s) => true,
ScalarValue { Value: 0 } => true,
ScalarValue { Value: 0L } => true,
ScalarValue { Value: 0.0 } => true,
ScalarValue { Value: 0.0f } => true,
ScalarValue { Value: 0m } => true,
ScalarValue { Value: false } => true,
SequenceValue seq => seq.Elements.Count == 0,
DictionaryValue seq => seq.Elements.Count == 0,
StructureValue structVal => structVal.Properties.Count == 0,
_ => false
};
}
}