From 4869b03aba25ee3301b594df3c9dffccced88fc8 Mon Sep 17 00:00:00 2001 From: Adam Chester Date: Mon, 2 May 2016 17:03:21 +1000 Subject: [PATCH] Allow destructuring/transforming reflection types, 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. --- .../Parameters/PropertyValueConverter.cs | 6 +- ...flectionTypesScalarDestructuringPolicy.cs} | 6 +- .../Serilog.Tests/LoggerConfigurationTests.cs | 71 +++++++++++++++++++ .../Parameters/PropertyValueConverterTests.cs | 10 ++- 4 files changed, 86 insertions(+), 7 deletions(-) rename src/Serilog/Policies/{ReflectionTypesScalarConversionPolicy.cs => ReflectionTypesScalarDestructuringPolicy.cs} (80%) diff --git a/src/Serilog/Parameters/PropertyValueConverter.cs b/src/Serilog/Parameters/PropertyValueConverter.cs index c805ead9f..beeabcac0 100644 --- a/src/Serilog/Parameters/PropertyValueConverter.cs +++ b/src/Serilog/Parameters/PropertyValueConverter.cs @@ -61,13 +61,13 @@ public PropertyValueConverter(int maximumDestructuringDepth, IEnumerable a new NullableScalarConversionPolicy(), new EnumScalarConversionPolicy(), new ByteArrayScalarConversionPolicy(), - new ReflectionTypesScalarConversionPolicy() }; _destructuringPolicies = additionalDestructuringPolicies - .Concat(new [] + .Concat(new IDestructuringPolicy [] { - new DelegateDestructuringPolicy() + new DelegateDestructuringPolicy(), + new ReflectionTypesScalarDestructuringPolicy() }) .ToArray(); } diff --git a/src/Serilog/Policies/ReflectionTypesScalarConversionPolicy.cs b/src/Serilog/Policies/ReflectionTypesScalarDestructuringPolicy.cs similarity index 80% rename from src/Serilog/Policies/ReflectionTypesScalarConversionPolicy.cs rename to src/Serilog/Policies/ReflectionTypesScalarDestructuringPolicy.cs index 0d8996bd2..5b2d944c8 100644 --- a/src/Serilog/Policies/ReflectionTypesScalarConversionPolicy.cs +++ b/src/Serilog/Policies/ReflectionTypesScalarDestructuringPolicy.cs @@ -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. @@ -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. diff --git a/test/Serilog.Tests/LoggerConfigurationTests.cs b/test/Serilog.Tests/LoggerConfigurationTests.cs index 7c5c22e14..92e148754 100644 --- a/test/Serilog.Tests/LoggerConfigurationTests.cs +++ b/test/Serilog.Tests/LoggerConfigurationTests.cs @@ -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; @@ -109,6 +110,76 @@ public void SpecifyingThatATypeIsScalarCausesItToBeLoggedAsScalarEvenWhenDestruc Assert.IsType(prop); } + [Fact] + public void DestructuringSystemTypeGivesScalarByDefault() + { + var events = new List(); + 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(prop); + Assert.Equal(thisType, sv.LiteralValue()); + } + + class ProjectedDestructuringPolicy : IDestructuringPolicy + { + readonly Func _canApply; + readonly Func _projection; + + public ProjectedDestructuringPolicy(Func canApply, Func 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(); + 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(prop); + Assert.Equal(thisType.AssemblyQualifiedName, sv.LiteralValue()); + } + [Fact] public void TransformationsAreAppliedToEventProperties() { diff --git a/test/Serilog.Tests/Parameters/PropertyValueConverterTests.cs b/test/Serilog.Tests/Parameters/PropertyValueConverterTests.cs index 4fca562ad..f935855b4 100644 --- a/test/Serilog.Tests/Parameters/PropertyValueConverterTests.cs +++ b/test/Serilog.Tests/Parameters/PropertyValueConverterTests.cs @@ -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