diff --git a/results/net46/AllocationsBenchmark-report-github.md b/results/net46/AllocationsBenchmark-report-github.md
new file mode 100644
index 000000000..d40893e56
--- /dev/null
+++ b/results/net46/AllocationsBenchmark-report-github.md
@@ -0,0 +1,18 @@
+``` ini
+
+BenchmarkDotNet=v0.10.6, OS=Windows 10 Redstone 1 (10.0.14393)
+Processor=Intel Core i7-4790 CPU 3.60GHz (Haswell), ProcessorCount=8
+Frequency=3507500 Hz, Resolution=285.1033 ns, Timer=TSC
+ [Host] : Clr 4.0.30319.42000, 32bit LegacyJIT-v4.7.2053.0
+ DefaultJob : Clr 4.0.30319.42000, 32bit LegacyJIT-v4.7.2053.0
+
+
+```
+ | Method | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated |
+ |--------------------- |-------------:|-----------:|-----------:|-------:|---------:|-------:|----------:|
+ | LogEmpty | 9.749 ns | 0.0346 ns | 0.0324 ns | 1.00 | 0.00 | - | 0 B |
+ | LogEmptyWithEnricher | 103.460 ns | 0.1742 ns | 0.1629 ns | 10.61 | 0.04 | 0.0066 | 28 B |
+ | LogScalar | 478.723 ns | 0.6996 ns | 0.6201 ns | 49.11 | 0.17 | 0.0591 | 248 B |
+ | LogDictionary | 3,867.137 ns | 13.5751 ns | 12.6982 ns | 396.67 | 1.79 | 0.3128 | 1324 B |
+ | LogSequence | 1,309.241 ns | 1.4345 ns | 1.3418 ns | 134.30 | 0.45 | 0.1144 | 484 B |
+ | LogAnonymous | 6,128.421 ns | 11.3529 ns | 10.6195 ns | 628.62 | 2.28 | 0.4654 | 1960 B |
diff --git a/results/netcoreapp1.1/AllocationsBenchmark-report-github.md b/results/netcoreapp1.1/AllocationsBenchmark-report-github.md
new file mode 100644
index 000000000..369846ee3
--- /dev/null
+++ b/results/netcoreapp1.1/AllocationsBenchmark-report-github.md
@@ -0,0 +1,19 @@
+``` ini
+
+BenchmarkDotNet=v0.10.6, OS=Windows 10 Redstone 1 (10.0.14393)
+Processor=Intel Core i7-4790 CPU 3.60GHz (Haswell), ProcessorCount=8
+Frequency=3507500 Hz, Resolution=285.1033 ns, Timer=TSC
+dotnet cli version=2.0.0-preview1-005977
+ [Host] : .NET Core 4.6.25211.01, 64bit RyuJIT
+ DefaultJob : .NET Core 4.6.25211.01, 64bit RyuJIT
+
+
+```
+ | Method | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated |
+ |--------------------- |-------------:|-----------:|-----------:|-------:|---------:|-------:|----------:|
+ | LogEmpty | 8.652 ns | 0.0230 ns | 0.0215 ns | 1.00 | 0.00 | - | 0 B |
+ | LogEmptyWithEnricher | 104.790 ns | 0.4970 ns | 0.4405 ns | 12.11 | 0.06 | 0.0132 | 56 B |
+ | LogScalar | 432.424 ns | 0.6263 ns | 0.5858 ns | 49.98 | 0.14 | 0.1030 | 432 B |
+ | LogDictionary | 3,887.068 ns | 4.4649 ns | 3.7284 ns | 449.26 | 1.16 | 0.5417 | 2296 B |
+ | LogSequence | 1,428.896 ns | 3.6324 ns | 3.2200 ns | 165.15 | 0.53 | 0.2079 | 880 B |
+ | LogAnonymous | 6,694.431 ns | 22.4848 ns | 21.0323 ns | 773.73 | 3.00 | 0.8392 | 3528 B |
diff --git a/src/Serilog/Core/IScalarConversionPolicy.cs b/src/Serilog/Core/IScalarConversionPolicy.cs
index f4e9ed2b5..a7fd7466a 100644
--- a/src/Serilog/Core/IScalarConversionPolicy.cs
+++ b/src/Serilog/Core/IScalarConversionPolicy.cs
@@ -12,9 +12,8 @@ interface IScalarConversionPolicy
/// If supported, convert the provided value into an immutable scalar.
///
/// The value to convert.
- /// Recursively apply policies to convert additional values.
/// The converted value, or null.
/// True if the value could be converted under this policy.
- bool TryConvertToScalar(object value, ILogEventPropertyValueFactory propertyValueFactory, out ScalarValue result);
+ bool TryConvertToScalar(object value, out ScalarValue result);
}
}
\ No newline at end of file
diff --git a/src/Serilog/Parameters/DepthLimiter.cs b/src/Serilog/Parameters/DepthLimiter.cs
index e51b23794..6785198ab 100644
--- a/src/Serilog/Parameters/DepthLimiter.cs
+++ b/src/Serilog/Parameters/DepthLimiter.cs
@@ -1,4 +1,4 @@
-// Copyright 2013-2015 Serilog Contributors
+// Copyright 2013-2017 Serilog Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+using System;
+
using Serilog.Core;
using Serilog.Debugging;
using Serilog.Events;
@@ -23,32 +25,50 @@ partial class PropertyValueConverter
{
class DepthLimiter : ILogEventPropertyValueFactory
{
+ [ThreadStatic]
+ static int _currentDepth;
+
readonly int _maximumDestructuringDepth;
- readonly int _currentDepth;
readonly PropertyValueConverter _propertyValueConverter;
- public DepthLimiter(int currentDepth, int maximumDepth, PropertyValueConverter propertyValueConverter)
+ public DepthLimiter(int maximumDepth, PropertyValueConverter propertyValueConverter)
{
_maximumDestructuringDepth = maximumDepth;
- _currentDepth = currentDepth;
_propertyValueConverter = propertyValueConverter;
}
+ public void SetCurrentDepth(int depth)
+ {
+ _currentDepth = depth;
+ }
+
public LogEventPropertyValue CreatePropertyValue(object value, Destructuring destructuring)
{
- return DefaultIfMaximumDepth() ??
- _propertyValueConverter.CreatePropertyValue(value, destructuring, _currentDepth + 1);
+ var storedDepth = _currentDepth;
+
+ var result = DefaultIfMaximumDepth(storedDepth) ??
+ _propertyValueConverter.CreatePropertyValue(value, destructuring, storedDepth + 1);
+
+ _currentDepth = storedDepth;
+
+ return result;
}
- public LogEventPropertyValue CreatePropertyValue(object value, bool destructureObjects = false)
+ LogEventPropertyValue ILogEventPropertyValueFactory.CreatePropertyValue(object value, bool destructureObjects)
{
- return DefaultIfMaximumDepth() ??
- _propertyValueConverter.CreatePropertyValue(value, destructureObjects, _currentDepth + 1);
+ var storedDepth = _currentDepth;
+
+ var result = DefaultIfMaximumDepth(storedDepth) ??
+ _propertyValueConverter.CreatePropertyValue(value, destructureObjects, storedDepth + 1);
+
+ _currentDepth = storedDepth;
+
+ return result;
}
- LogEventPropertyValue DefaultIfMaximumDepth()
+ LogEventPropertyValue DefaultIfMaximumDepth(int depth)
{
- if (_currentDepth == _maximumDestructuringDepth)
+ if (depth == _maximumDestructuringDepth)
{
SelfLog.WriteLine("Maximum destructuring depth reached.");
return new ScalarValue(null);
diff --git a/src/Serilog/Parameters/PropertyValueConverter.cs b/src/Serilog/Parameters/PropertyValueConverter.cs
old mode 100755
new mode 100644
index 657836dba..325799a63
--- a/src/Serilog/Parameters/PropertyValueConverter.cs
+++ b/src/Serilog/Parameters/PropertyValueConverter.cs
@@ -1,4 +1,4 @@
-// Copyright 2013-2015 Serilog Contributors
+// Copyright 2013-2017 Serilog Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -45,7 +45,7 @@ partial class PropertyValueConverter : ILogEventPropertyFactory, ILogEventProper
readonly IDestructuringPolicy[] _destructuringPolicies;
readonly IScalarConversionPolicy[] _scalarConversionPolicies;
- readonly int _maximumDestructuringDepth;
+ readonly DepthLimiter _depthLimiter;
readonly int _maximumStringLength;
readonly int _maximumCollectionCount;
readonly bool _propagateExceptions;
@@ -63,8 +63,7 @@ public PropertyValueConverter(
if (maximumDestructuringDepth < 0) throw new ArgumentOutOfRangeException(nameof(maximumDestructuringDepth));
if (maximumStringLength < 2) throw new ArgumentOutOfRangeException(nameof(maximumStringLength));
if (maximumCollectionCount < 1) throw new ArgumentOutOfRangeException(nameof(maximumCollectionCount));
-
- _maximumDestructuringDepth = maximumDestructuringDepth;
+
_propagateExceptions = propagateExceptions;
_maximumStringLength = maximumStringLength;
_maximumCollectionCount = maximumCollectionCount;
@@ -72,7 +71,6 @@ public PropertyValueConverter(
_scalarConversionPolicies = new IScalarConversionPolicy[]
{
new SimpleScalarConversionPolicy(BuiltInScalarTypes.Concat(additionalScalarTypes)),
- new NullableScalarConversionPolicy(),
new EnumScalarConversionPolicy(),
new ByteArrayScalarConversionPolicy()
};
@@ -84,6 +82,8 @@ public PropertyValueConverter(
new ReflectionTypesScalarDestructuringPolicy()
})
.ToArray();
+
+ _depthLimiter = new DepthLimiter(maximumDestructuringDepth, this);
}
public LogEventProperty CreateProperty(string name, object value, bool destructureObjects = false)
@@ -134,21 +134,19 @@ LogEventPropertyValue CreatePropertyValue(object value, Destructuring destructur
}
var valueType = value.GetType();
- var limiter = new DepthLimiter(depth, _maximumDestructuringDepth, this);
+ _depthLimiter.SetCurrentDepth(depth);
if (destructuring == Destructuring.Destructure)
{
- var stringValue = value as string;
- if (stringValue != null)
+ if (value is string stringValue)
{
value = TruncateIfNecessary(stringValue);
}
}
foreach (var scalarConversionPolicy in _scalarConversionPolicies)
- {
- ScalarValue converted;
- if (scalarConversionPolicy.TryConvertToScalar(value, limiter, out converted))
+ {
+ if (scalarConversionPolicy.TryConvertToScalar(value, out var converted))
return converted;
}
@@ -156,37 +154,26 @@ LogEventPropertyValue CreatePropertyValue(object value, Destructuring destructur
{
foreach (var destructuringPolicy in _destructuringPolicies)
{
- LogEventPropertyValue result;
- if (destructuringPolicy.TryDestructure(value, limiter, out result))
+ if (destructuringPolicy.TryDestructure(value, _depthLimiter, out var result))
return result;
}
}
- if (TryConvertEnumerable(value, destructuring, valueType, limiter, out var enumerableResult))
+ if (TryConvertEnumerable(value, destructuring, valueType, out var enumerableResult))
return enumerableResult;
- if (TryConvertValueTuple(value, destructuring, valueType, limiter, out var tupleResult))
+ if (TryConvertValueTuple(value, destructuring, valueType, out var tupleResult))
return tupleResult;
- if (destructuring == Destructuring.Destructure)
- {
- var type = value.GetType();
- var typeTag = type.Name;
- if (typeTag.Length <= 0 || IsCompilerGeneratedType(type))
- {
- typeTag = null;
- }
-
- return new StructureValue(GetProperties(value, limiter), typeTag);
- }
+ if (TryConvertCompilerGeneratedType(value, destructuring, valueType, out var compilerGeneratedResult))
+ return compilerGeneratedResult;
return new ScalarValue(value.ToString());
- }
+ }
- bool TryConvertEnumerable(object value, Destructuring destructuring, Type valueType, DepthLimiter limiter, out LogEventPropertyValue result)
+ bool TryConvertEnumerable(object value, Destructuring destructuring, Type valueType, out LogEventPropertyValue result)
{
- var enumerable = value as IEnumerable;
- if (enumerable != null)
+ if (value is IEnumerable enumerable)
{
// Only dictionaries with 'scalar' keys are permitted, as
// more complex keys may not serialize to unique values for
@@ -196,35 +183,54 @@ bool TryConvertEnumerable(object value, Destructuring destructuring, Type valueT
// Only actual dictionaries are supported, as arbitrary types
// can implement multiple IDictionary interfaces and thus introduce
// multiple different interpretations.
- if (IsValueTypeDictionary(valueType))
+ if (TryGetDictionary(value, valueType, out var dictionary))
{
- var typeInfo = typeof(KeyValuePair<,>).MakeGenericType(valueType.GenericTypeArguments).GetTypeInfo();
- var keyProperty = typeInfo.GetDeclaredProperty("Key");
- var valueProperty = typeInfo.GetDeclaredProperty("Value");
-
- result = new DictionaryValue(enumerable
- .Cast