Skip to content

Commit

Permalink
Allow destructuring/transforming reflection types,
Browse files Browse the repository at this point in the history
by changing ReflectionTypesScalarConversionPolicy to ReflectionTypesScalarDestructuringPolicy, custom IDestructuringPolicy implementations can then destructure or transform reflection types. Reflection types aren't very 'scalar' in the sense that they can be transformed in many useful ways.
  • Loading branch information
adamchester committed May 2, 2016
1 parent 0d2dac5 commit 4869b03
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 7 deletions.
6 changes: 3 additions & 3 deletions src/Serilog/Parameters/PropertyValueConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,13 @@ public PropertyValueConverter(int maximumDestructuringDepth, IEnumerable<Type> a
new NullableScalarConversionPolicy(),
new EnumScalarConversionPolicy(),
new ByteArrayScalarConversionPolicy(),
new ReflectionTypesScalarConversionPolicy()
};

_destructuringPolicies = additionalDestructuringPolicies
.Concat(new []
.Concat(new IDestructuringPolicy []
{
new DelegateDestructuringPolicy()
new DelegateDestructuringPolicy(),
new ReflectionTypesScalarDestructuringPolicy()
})
.ToArray();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2013-2015 Serilog Contributors
// Copyright 2013-2016 Serilog Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -19,9 +19,9 @@

namespace Serilog.Policies
{
class ReflectionTypesScalarConversionPolicy : IScalarConversionPolicy
class ReflectionTypesScalarDestructuringPolicy : IDestructuringPolicy
{
public bool TryConvertToScalar(object value, ILogEventPropertyValueFactory propertyValueFactory, out ScalarValue result)
public bool TryDestructure(object value, ILogEventPropertyValueFactory propertyValueFactory, out LogEventPropertyValue result)
{
// These types and their subclasses are property-laden and deep;
// most sinks will convert them to strings.
Expand Down
71 changes: 71 additions & 0 deletions test/Serilog.Tests/LoggerConfigurationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Xunit;
using Serilog.Core;
using Serilog.Core.Filters;
Expand Down Expand Up @@ -109,6 +110,76 @@ public void SpecifyingThatATypeIsScalarCausesItToBeLoggedAsScalarEvenWhenDestruc
Assert.IsType<ScalarValue>(prop);
}

[Fact]
public void DestructuringSystemTypeGivesScalarByDefault()
{
var events = new List<LogEvent>();
var sink = new DelegatingSink(events.Add);

var logger = new LoggerConfiguration()
.WriteTo.Sink(sink)
.CreateLogger();

var thisType = this.GetType();
logger.Information("{@thisType}", thisType);

var ev = events.Single();
var prop = ev.Properties["thisType"];
var sv = Assert.IsAssignableFrom<ScalarValue>(prop);
Assert.Equal(thisType, sv.LiteralValue());
}

class ProjectedDestructuringPolicy : IDestructuringPolicy
{
readonly Func<Type, bool> _canApply;
readonly Func<object, object> _projection;

public ProjectedDestructuringPolicy(Func<Type, bool> canApply, Func<object, object> projection)
{
if (canApply == null) throw new ArgumentNullException(nameof(canApply));
if (projection == null) throw new ArgumentNullException(nameof(projection));
_canApply = canApply;
_projection = projection;
}

public bool TryDestructure(object value, ILogEventPropertyValueFactory propertyValueFactory, out LogEventPropertyValue result)
{
if (value == null) throw new ArgumentNullException(nameof(value));

if (!_canApply(value.GetType()))
{
result = null;
return false;
}

var projected = _projection(value);
result = propertyValueFactory.CreatePropertyValue(projected, true);
return true;
}
}

[Fact]
public void DestructuringIsPossibleForSystemTypeDerivedProperties()
{
var events = new List<LogEvent>();
var sink = new DelegatingSink(events.Add);

var logger = new LoggerConfiguration()
.Destructure.With(new ProjectedDestructuringPolicy(
canApply: t => typeof(Type).GetTypeInfo().IsAssignableFrom(t.GetTypeInfo()),
projection: o => ((Type)o).AssemblyQualifiedName))
.WriteTo.Sink(sink)
.CreateLogger();

var thisType = this.GetType();
logger.Information("{@thisType}", thisType);

var ev = events.Single();
var prop = ev.Properties["thisType"];
var sv = Assert.IsAssignableFrom<ScalarValue>(prop);
Assert.Equal(thisType.AssemblyQualifiedName, sv.LiteralValue());
}

[Fact]
public void TransformationsAreAppliedToEventProperties()
{
Expand Down
10 changes: 9 additions & 1 deletion test/Serilog.Tests/Parameters/PropertyValueConverterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,15 @@ public void FailsGracefullyWhenGettersThrow()
public void SurvivesDestructuringASystemType()
{
var pv = _converter.CreatePropertyValue(typeof(string), Destructuring.Destructure);
Assert.Equal(typeof(string), pv.LiteralValue());
Assert.Equal(typeof(string), pv.LiteralValue());
}

[Fact]
public void SurvivesDestructuringMethodBase()
{
var theMethod = System.Reflection.MethodBase.GetCurrentMethod();
var pv = _converter.CreatePropertyValue(theMethod, Destructuring.Destructure);
Assert.Equal(theMethod, pv.LiteralValue());
}

public class BaseWithProps
Expand Down

0 comments on commit 4869b03

Please sign in to comment.