diff --git a/Serilog.sln.DotSettings b/Serilog.sln.DotSettings index 77a52ea2d..a84b8ae38 100644 --- a/Serilog.sln.DotSettings +++ b/Serilog.sln.DotSettings @@ -2,10 +2,13 @@ True + True True True False SOLUTION + DO_NOT_SHOW + DO_NOT_SHOW DO_NOT_SHOW ERROR DO_NOT_SHOW @@ -16,6 +19,7 @@ ERROR WARNING ERROR + HINT ERROR ERROR ERROR @@ -27,8 +31,9 @@ ERROR DO_NOT_SHOW DO_NOT_SHOW - HINT + DO_NOT_SHOW DO_NOT_SHOW + HINT DO_NOT_SHOW HINT ERROR @@ -103,6 +108,7 @@ DO_NOT_SHOW SUGGESTION ERROR + HINT ERROR ERROR ERROR @@ -111,6 +117,8 @@ <?xml version="1.0" encoding="utf-16"?><Profile name="Format My Code Using &quot;Particular&quot; conventions"><CSMakeFieldReadonly>True</CSMakeFieldReadonly><CSUseVar><BehavourStyle>CAN_CHANGE_TO_IMPLICIT</BehavourStyle><LocalVariableStyle>ALWAYS_IMPLICIT</LocalVariableStyle><ForeachVariableStyle>ALWAYS_IMPLICIT</ForeachVariableStyle></CSUseVar><CSOptimizeUsings><OptimizeUsings>True</OptimizeUsings><EmbraceInRegion>False</EmbraceInRegion><RegionName></RegionName></CSOptimizeUsings><CSReformatCode>True</CSReformatCode><CSReorderTypeMembers>True</CSReorderTypeMembers><JsInsertSemicolon>True</JsInsertSemicolon><JsReformatCode>True</JsReformatCode><CssReformatCode>True</CssReformatCode><CSArrangeThisQualifier>True</CSArrangeThisQualifier><RemoveCodeRedundancies>True</RemoveCodeRedundancies><CSUseAutoProperty>True</CSUseAutoProperty><HtmlReformatCode>True</HtmlReformatCode><CSShortenReferences>True</CSShortenReferences><CSharpFormatDocComments>True</CSharpFormatDocComments><CssAlphabetizeProperties>True</CssAlphabetizeProperties></Profile> Default: Reformat Code Format My Code Using "Particular" conventions + Implicit + Implicit False DO_NOT_CHANGE DO_NOT_CHANGE @@ -477,10 +485,13 @@ II.2.12 <HandlesEvent /> True Automatic property True + False False False + AD DB DTC + GT ID NSB SLA diff --git a/src/Serilog/Parameters/DepthLimiter.cs b/src/Serilog/Capturing/DepthLimiter.cs similarity index 98% rename from src/Serilog/Parameters/DepthLimiter.cs rename to src/Serilog/Capturing/DepthLimiter.cs index 6785198ab..005a3be55 100644 --- a/src/Serilog/Parameters/DepthLimiter.cs +++ b/src/Serilog/Capturing/DepthLimiter.cs @@ -19,7 +19,7 @@ using Serilog.Events; using Serilog.Parsing; -namespace Serilog.Parameters +namespace Serilog.Capturing { partial class PropertyValueConverter { diff --git a/src/Serilog/Parameters/GetablePropertyFinder.cs b/src/Serilog/Capturing/GetablePropertyFinder.cs similarity index 98% rename from src/Serilog/Parameters/GetablePropertyFinder.cs rename to src/Serilog/Capturing/GetablePropertyFinder.cs index e7304547f..9c0f74e06 100644 --- a/src/Serilog/Parameters/GetablePropertyFinder.cs +++ b/src/Serilog/Capturing/GetablePropertyFinder.cs @@ -17,7 +17,7 @@ using System.Linq; using System.Reflection; -namespace Serilog.Parameters +namespace Serilog.Capturing { static class GetablePropertyFinder { diff --git a/src/Serilog/Parameters/MessageTemplateProcessor.cs b/src/Serilog/Capturing/MessageTemplateProcessor.cs similarity index 92% rename from src/Serilog/Parameters/MessageTemplateProcessor.cs rename to src/Serilog/Capturing/MessageTemplateProcessor.cs index 780fed64d..974f6fe8a 100644 --- a/src/Serilog/Parameters/MessageTemplateProcessor.cs +++ b/src/Serilog/Capturing/MessageTemplateProcessor.cs @@ -18,11 +18,11 @@ using Serilog.Events; using Serilog.Parsing; -namespace Serilog.Parameters +namespace Serilog.Capturing { class MessageTemplateProcessor : ILogEventPropertyFactory { - readonly IMessageTemplateParser _parser = new MessageTemplateCache(new MessageTemplateParser()); + readonly MessageTemplateCache _parser = new MessageTemplateCache(new MessageTemplateParser()); readonly PropertyBinder _propertyBinder; readonly PropertyValueConverter _propertyValueConverter; diff --git a/src/Serilog/Parameters/PropertyBinder.cs b/src/Serilog/Capturing/PropertyBinder.cs similarity index 99% rename from src/Serilog/Parameters/PropertyBinder.cs rename to src/Serilog/Capturing/PropertyBinder.cs index 1461f61c5..23ebd6047 100644 --- a/src/Serilog/Parameters/PropertyBinder.cs +++ b/src/Serilog/Capturing/PropertyBinder.cs @@ -19,7 +19,7 @@ using Serilog.Events; using Serilog.Parsing; -namespace Serilog.Parameters +namespace Serilog.Capturing { // Performance relevant - on the hot path when creating log events from existing templates. class PropertyBinder diff --git a/src/Serilog/Parameters/PropertyValueConverter.cs b/src/Serilog/Capturing/PropertyValueConverter.cs similarity index 99% rename from src/Serilog/Parameters/PropertyValueConverter.cs rename to src/Serilog/Capturing/PropertyValueConverter.cs index 325799a63..d244271c9 100644 --- a/src/Serilog/Parameters/PropertyValueConverter.cs +++ b/src/Serilog/Capturing/PropertyValueConverter.cs @@ -24,7 +24,7 @@ using Serilog.Policies; using System.Runtime.CompilerServices; -namespace Serilog.Parameters +namespace Serilog.Capturing { // Values in Serilog are simplified down into a lowest-common-denominator internal // type system so that there is a better chance of code written with one sink in @@ -351,7 +351,7 @@ IEnumerable GetProperties(object value) if (_propagateExceptions) throw; - propValue = "The property accessor threw an exception: " + ex.InnerException.GetType().Name; + propValue = "The property accessor threw an exception: " + ex.InnerException?.GetType().Name; } yield return new LogEventProperty(prop.Name, _depthLimiter.CreatePropertyValue(propValue, Destructuring.Destructure)); } diff --git a/src/Serilog/Context/LogContext.cs b/src/Serilog/Context/LogContext.cs index b4ebd2e37..8d2657134 100644 --- a/src/Serilog/Context/LogContext.cs +++ b/src/Serilog/Context/LogContext.cs @@ -20,7 +20,6 @@ using Serilog.Events; #if ASYNCLOCAL -using System.Collections.Generic; using System.Threading; #elif REMOTING using System.Runtime.Remoting; diff --git a/src/Serilog/Core/Logger.cs b/src/Serilog/Core/Logger.cs index 141b6363d..b9207c31d 100644 --- a/src/Serilog/Core/Logger.cs +++ b/src/Serilog/Core/Logger.cs @@ -14,10 +14,10 @@ using System; using System.Collections.Generic; +using Serilog.Capturing; using Serilog.Core.Enrichers; using Serilog.Debugging; using Serilog.Events; -using Serilog.Parameters; #pragma warning disable Serilog004 // Constant MessageTemplate verifier diff --git a/src/Serilog/Core/Pipeline/MessageTemplateCache.cs b/src/Serilog/Core/Pipeline/MessageTemplateCache.cs index 0688ee0e1..459a224a5 100644 --- a/src/Serilog/Core/Pipeline/MessageTemplateCache.cs +++ b/src/Serilog/Core/Pipeline/MessageTemplateCache.cs @@ -13,9 +13,13 @@ // limitations under the License. using System; -using System.Collections.Generic; using Serilog.Events; + +#if HASHTABLE using System.Collections; +#else +using System.Collections.Generic; +#endif namespace Serilog.Core.Pipeline { diff --git a/src/Serilog/Data/LogEventPropertyValueVisitor.cs b/src/Serilog/Data/LogEventPropertyValueVisitor.cs index dd1ae1687..d4bea708c 100644 --- a/src/Serilog/Data/LogEventPropertyValueVisitor.cs +++ b/src/Serilog/Data/LogEventPropertyValueVisitor.cs @@ -15,6 +15,8 @@ using System; using Serilog.Events; +// ReSharper disable VirtualMemberNeverOverridden.Global + namespace Serilog.Data { /// @@ -40,7 +42,6 @@ public abstract class LogEventPropertyValueVisitor /// Operation state. /// The value to visit. /// The result of visiting . - // ReSharper disable once VirtualMemberNeverOverriden.Global protected virtual TResult Visit(TState state, LogEventPropertyValue value) { if (value == null) throw new ArgumentNullException(nameof(value)); @@ -103,7 +104,6 @@ protected virtual TResult Visit(TState state, LogEventPropertyValue value) /// The value to visit. /// The result of visiting . // ReSharper disable once UnusedParameter.Global - // ReSharper disable once VirtualMemberNeverOverriden.Global protected virtual TResult VisitUnsupportedValue(TState state, LogEventPropertyValue value) { if (value == null) throw new ArgumentNullException(nameof(value)); diff --git a/src/Serilog/Events/MessageTemplate.cs b/src/Serilog/Events/MessageTemplate.cs index bb75f7234..b1664aeea 100644 --- a/src/Serilog/Events/MessageTemplate.cs +++ b/src/Serilog/Events/MessageTemplate.cs @@ -18,6 +18,7 @@ using System.Linq; using Serilog.Debugging; using Serilog.Parsing; +using Serilog.Rendering; namespace Serilog.Events { @@ -35,15 +36,14 @@ public class MessageTemplate readonly MessageTemplateToken[] _tokens; - // Optimisation for when the template is bound to - // property values. - /// /// Construct a message template using manually-defined text and property tokens. /// /// The text and property tokens defining the template. public MessageTemplate(IEnumerable tokens) + // ReSharper disable PossibleMultipleEnumeration : this(string.Join("", tokens), tokens) + // ReSharper enable PossibleMultipleEnumeration { } @@ -91,7 +91,7 @@ public MessageTemplate(string text, IEnumerable tokens) /// /// Similar to , but faster. /// - static TResult[] GetElementsOfTypeToArray(object[] tokens) + static TResult[] GetElementsOfTypeToArray(MessageTemplateToken[] tokens) where TResult: class { var result = new List(tokens.Length / 2); @@ -125,6 +125,8 @@ public override string ToString() /// public IEnumerable Tokens => _tokens; + internal MessageTemplateToken[] TokenArray => _tokens; + internal PropertyToken[] NamedProperties { get; } internal PropertyToken[] PositionalProperties { get; } @@ -156,10 +158,9 @@ public string Render(IReadOnlyDictionary properti /// Supplies culture-specific formatting information, or null. public void Render(IReadOnlyDictionary properties, TextWriter output, IFormatProvider formatProvider = null) { - foreach (var token in _tokens) - { - token.Render(properties, output, formatProvider); - } + if (properties == null) throw new ArgumentNullException(nameof(properties)); + if (output == null) throw new ArgumentNullException(nameof(output)); + MessageTemplateRenderer.Render(this, properties, output, null, formatProvider); } } } diff --git a/src/Serilog/Events/ScalarValue.cs b/src/Serilog/Events/ScalarValue.cs index e5b280d6f..01f514fe5 100644 --- a/src/Serilog/Events/ScalarValue.cs +++ b/src/Serilog/Events/ScalarValue.cs @@ -46,16 +46,21 @@ public ScalarValue(object value) /// A format provider to apply to the value, or null to use the default. /// . public override void Render(TextWriter output, string format = null, IFormatProvider formatProvider = null) + { + Render(Value, output, format, formatProvider); + } + + internal static void Render(object value, TextWriter output, string format = null, IFormatProvider formatProvider = null) { if (output == null) throw new ArgumentNullException(nameof(output)); - if (Value == null) + if (value == null) { output.Write("null"); return; } - var s = Value as string; + var s = value as string; if (s != null) { if (format != "l") @@ -76,19 +81,19 @@ public override void Render(TextWriter output, string format = null, IFormatProv var custom = (ICustomFormatter)formatProvider.GetFormat(typeof(ICustomFormatter)); if (custom != null) { - output.Write(custom.Format(format, Value, formatProvider)); + output.Write(custom.Format(format, value, formatProvider)); return; } } - var f = Value as IFormattable; + var f = value as IFormattable; if (f != null) { output.Write(f.ToString(format, formatProvider ?? CultureInfo.InvariantCulture)); } else { - output.Write(Value.ToString()); + output.Write(value.ToString()); } } diff --git a/src/Serilog/Formatting/Display/LevelOutputFormat.cs b/src/Serilog/Formatting/Display/LevelOutputFormat.cs new file mode 100644 index 000000000..76f9b3d5e --- /dev/null +++ b/src/Serilog/Formatting/Display/LevelOutputFormat.cs @@ -0,0 +1,97 @@ +// Copyright 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. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using Serilog.Events; +using Serilog.Rendering; + +namespace Serilog.Formatting.Display +{ + /// + /// Implements the {Level} element. + /// can now have a fixed width applied to it, as well as casing rules. + /// Width is set through formats like "u3" (uppercase three chars), + /// "w1" (one lowercase char), or "t4" (title case four chars). + /// + static class LevelOutputFormat + { + static readonly string[][] _titleCaseLevelMap = { + new []{ "V", "Vb", "Vrb", "Verb" }, + new []{ "D", "De", "Dbg", "Dbug" }, + new []{ "I", "In", "Inf", "Info" }, + new []{ "W", "Wn", "Wrn", "Warn" }, + new []{ "E", "Er", "Err", "Eror" }, + new []{ "F", "Fa", "Ftl", "Fatl" } + }; + + static readonly string[][] _lowercaseLevelMap = { + new []{ "v", "vb", "vrb", "verb" }, + new []{ "d", "de", "dbg", "dbug" }, + new []{ "i", "in", "inf", "info" }, + new []{ "w", "wn", "wrn", "warn" }, + new []{ "e", "er", "err", "eror" }, + new []{ "f", "fa", "ftl", "fatl" } + }; + + static readonly string[][] _uppercaseLevelMap = { + new []{ "V", "VB", "VRB", "VERB" }, + new []{ "D", "DE", "DBG", "DBUG" }, + new []{ "I", "IN", "INF", "INFO" }, + new []{ "W", "WN", "WRN", "WARN" }, + new []{ "E", "ER", "ERR", "EROR" }, + new []{ "F", "FA", "FTL", "FATL" } + }; + + public static string GetLevelMoniker(LogEventLevel value, string format = null) + { + if (format == null || format.Length != 2 && format.Length != 3) + return Casing.Format(value.ToString(), format); + + // Using int.Parse() here requires allocating a string to exclude the first character prefix. + // Junk like "wxy" will be accepted but produce benign results. + var width = format[1] - '0'; + if (format.Length == 3) + { + width *= 10; + width += format[2] - '0'; + } + + if (width < 1) + return string.Empty; + + if (width > 4) + { + var stringValue = value.ToString(); + if (stringValue.Length > width) + stringValue = stringValue.Substring(0, width); + return Casing.Format(stringValue); + } + + var index = (int)value; + if (index >= 0 && index <= (int) LogEventLevel.Fatal) + { + switch (format[0]) + { + case 'w': + return _lowercaseLevelMap[index][width - 1]; + case 'u': + return _uppercaseLevelMap[index][width - 1]; + case 't': + return _titleCaseLevelMap[index][width - 1]; + } + } + + return Casing.Format(value.ToString(), format); + } + } +} \ No newline at end of file diff --git a/src/Serilog/Formatting/Display/LogEventLevelValue.cs b/src/Serilog/Formatting/Display/LogEventLevelValue.cs deleted file mode 100644 index d850722c3..000000000 --- a/src/Serilog/Formatting/Display/LogEventLevelValue.cs +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright 2013-2015 Serilog Contributors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -using System; -using System.IO; - -using Serilog.Events; - -namespace Serilog.Formatting.Display -{ - // Allows for the specific handling of the {Level} element. - // can now have a fixed width applied to it, as well as casing rules. - // Width is set through formats like "u3" (uppercase three chars), - // "w1" (one lowercase char), or "t4" (title case four chars). - class LogEventLevelValue : LogEventPropertyValue - { - readonly LogEventLevel _value; - - static readonly string[][] _titleCaseLevelMap = { - new []{ "V", "Vb", "Vrb", "Verb" }, - new []{ "D", "De", "Dbg", "Dbug" }, - new []{ "I", "In", "Inf", "Info" }, - new []{ "W", "Wn", "Wrn", "Warn" }, - new []{ "E", "Er", "Err", "Eror" }, - new []{ "F", "Fa", "Ftl", "Fatl" } - }; - - static readonly string[][] _lowercaseLevelMap = { - new []{ "v", "vb", "vrb", "verb" }, - new []{ "d", "de", "dbg", "dbug" }, - new []{ "i", "in", "inf", "info" }, - new []{ "w", "wn", "wrn", "warn" }, - new []{ "e", "er", "err", "eror" }, - new []{ "f", "fa", "ftl", "fatl" } - }; - - static readonly string[][] _uppercaseLevelMap = { - new []{ "V", "VB", "VRB", "VERB" }, - new []{ "D", "DE", "DBG", "DBUG" }, - new []{ "I", "IN", "INF", "INFO" }, - new []{ "W", "WN", "WRN", "WARN" }, - new []{ "E", "ER", "ERR", "EROR" }, - new []{ "F", "FA", "FTL", "FATL" } - }; - - public LogEventLevelValue(LogEventLevel value) - { - _value = value; - } - - /// - /// This method will apply only upper or lower case formatting, not fixed width - /// - public override void Render(TextWriter output, string format = null, IFormatProvider formatProvider = null) - { - if (format != null && (format.Length == 2 || format.Length == 3)) - { - // Using int.Parse() here requires allocating a string to exclude the first character prefix. - // Junk like "wxy" will be accepted but produce benign results. - var width = format[1] - '0'; - if (format.Length == 3) - { - width *= 10; - width += format[2] - '0'; - } - - if (width < 1) - return; - - if (width > 4) - { - var value = _value.ToString(); - if (value.Length > width) - value = value.Substring(0, width); - output.Write(Casing.Format(value)); - return; - } - - var index = (int)_value; - if (index >= 0 && index <= (int) LogEventLevel.Fatal) - { - switch (format[0]) - { - case 'w': - output.Write(_lowercaseLevelMap[index][width - 1]); - return; - case 'u': - output.Write(_uppercaseLevelMap[index][width - 1]); - return; - case 't': - output.Write(_titleCaseLevelMap[index][width - 1]); - return; - } - } - } - - output.Write(Casing.Format(_value.ToString(), format)); - } - } -} \ No newline at end of file diff --git a/src/Serilog/Formatting/Display/MessageTemplateTextFormatter.cs b/src/Serilog/Formatting/Display/MessageTemplateTextFormatter.cs index 0c1ae7f8d..ac45223db 100644 --- a/src/Serilog/Formatting/Display/MessageTemplateTextFormatter.cs +++ b/src/Serilog/Formatting/Display/MessageTemplateTextFormatter.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. @@ -13,10 +13,10 @@ // limitations under the License. using System; -using System.Collections.Generic; using System.IO; using Serilog.Events; using Serilog.Parsing; +using Serilog.Rendering; namespace Serilog.Formatting.Display { @@ -58,42 +58,70 @@ public void Format(LogEvent logEvent, TextWriter output) if (logEvent == null) throw new ArgumentNullException(nameof(logEvent)); if (output == null) throw new ArgumentNullException(nameof(output)); - // This could be lazier: the output properties include - // everything from the log event, but often we won't need any more than - // just the standard timestamp/message etc. - var outputProperties = OutputProperties.GetOutputProperties(logEvent, _outputTemplate); - foreach (var token in _outputTemplate.Tokens) { - var pt = token as PropertyToken; - if (pt == null) + if (token is TextToken tt) { - token.Render(outputProperties, output, _formatProvider); + MessageTemplateRenderer.RenderTextToken(tt, output); continue; } - // First variation from normal rendering - if a property is missing, - // don't render anything (message templates render the raw token here). - LogEventPropertyValue propertyValue; - if (!outputProperties.TryGetValue(pt.PropertyName, out propertyValue)) - continue; - - // Second variation; if the value is a scalar string, use literal - // rendering and support some additional formats: 'u' for uppercase - // and 'w' for lowercase. - var sv = propertyValue as ScalarValue; - if (sv != null && sv.Value is string) + var pt = (PropertyToken)token; + if (pt.PropertyName == OutputProperties.LevelPropertyName) { - var overridden = new Dictionary - { - { pt.PropertyName, new LiteralStringValue((string) sv.Value) } - }; - - token.Render(overridden, output, _formatProvider); + var moniker = LevelOutputFormat.GetLevelMoniker(logEvent.Level, pt.Format); + Padding.Apply(output, moniker, pt.Alignment); + } + else if (pt.PropertyName == OutputProperties.NewLinePropertyName) + { + Padding.Apply(output, Environment.NewLine, pt.Alignment); + } + else if (pt.PropertyName == OutputProperties.ExceptionPropertyName) + { + var exception = logEvent.Exception == null ? "" : logEvent.Exception + Environment.NewLine; + Padding.Apply(output, exception, pt.Alignment); } else { - token.Render(outputProperties, output, _formatProvider); + // In this block, `writer` may be used to buffer output so that + // padding can be applied. + var writer = pt.Alignment.HasValue ? new StringWriter() : output; + + if (pt.PropertyName == OutputProperties.MessagePropertyName) + { + MessageTemplateRenderer.Render(logEvent.MessageTemplate, logEvent.Properties, writer, pt.Format, _formatProvider); + } + else if (pt.PropertyName == OutputProperties.TimestampPropertyName) + { + ScalarValue.Render(logEvent.Timestamp, writer, pt.Format, _formatProvider); + } + else if (pt.PropertyName == OutputProperties.PropertiesPropertyName) + { + PropertiesOutputFormat.Render(logEvent.MessageTemplate, logEvent.Properties, _outputTemplate, writer, _formatProvider); + } + else + { + // If a property is missing, don't render anything (message templates render the raw token here). + LogEventPropertyValue propertyValue; + if (!logEvent.Properties.TryGetValue(pt.PropertyName, out propertyValue)) + continue; + + // If the value is a scalar string, support some additional formats: 'u' for uppercase + // and 'w' for lowercase. + var sv = propertyValue as ScalarValue; + if (sv?.Value is string literalString) + { + var cased = Casing.Format(literalString, pt.Format); + writer.Write(cased); + } + else + { + propertyValue.Render(output, pt.Format, _formatProvider); + } + } + + if (pt.Alignment.HasValue) + Padding.Apply(output, ((StringWriter)writer).ToString(), pt.Alignment); } } } diff --git a/src/Serilog/Formatting/Display/LiteralStringValue.cs b/src/Serilog/Formatting/Display/Obsolete/LiteralStringValue.cs similarity index 86% rename from src/Serilog/Formatting/Display/LiteralStringValue.cs rename to src/Serilog/Formatting/Display/Obsolete/LiteralStringValue.cs index 82f172536..e7bc44023 100644 --- a/src/Serilog/Formatting/Display/LiteralStringValue.cs +++ b/src/Serilog/Formatting/Display/Obsolete/LiteralStringValue.cs @@ -15,19 +15,20 @@ using System; using System.IO; using Serilog.Events; +using Serilog.Rendering; -namespace Serilog.Formatting.Display +namespace Serilog.Formatting.Display.Obsolete { // A special case (non-null) string value for use in output // templates. Does not apply "quoted" formatting by default. + [Obsolete("Not used by the current output formatting implementation.")] class LiteralStringValue : LogEventPropertyValue { readonly string _value; public LiteralStringValue(string value) { - if (value == null) throw new ArgumentNullException(nameof(value)); - _value = value; + _value = value ?? throw new ArgumentNullException(nameof(value)); } public override void Render(TextWriter output, string format = null, IFormatProvider formatProvider = null) diff --git a/src/Serilog/Formatting/Display/Obsolete/LogEventLevelValue.cs b/src/Serilog/Formatting/Display/Obsolete/LogEventLevelValue.cs new file mode 100644 index 000000000..293990f5a --- /dev/null +++ b/src/Serilog/Formatting/Display/Obsolete/LogEventLevelValue.cs @@ -0,0 +1,40 @@ +// Copyright 2013-2015 Serilog Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; +using System.IO; + +using Serilog.Events; + +namespace Serilog.Formatting.Display.Obsolete +{ + [Obsolete("Not used by the current output formatting implementation.")] + class LogEventLevelValue : LogEventPropertyValue + { + readonly LogEventLevel _value; + + public LogEventLevelValue(LogEventLevel value) + { + _value = value; + } + + /// + /// This method will apply only upper or lower case formatting, not fixed width + /// + public override void Render(TextWriter output, string format = null, IFormatProvider formatProvider = null) + { + output.Write(LevelOutputFormat.GetLevelMoniker(_value, format)); + } + } +} diff --git a/src/Serilog/Formatting/Display/Obsolete/LogEventPropertiesValue.cs b/src/Serilog/Formatting/Display/Obsolete/LogEventPropertiesValue.cs new file mode 100644 index 000000000..a0b089152 --- /dev/null +++ b/src/Serilog/Formatting/Display/Obsolete/LogEventPropertiesValue.cs @@ -0,0 +1,41 @@ +// Copyright 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. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; +using System.Collections.Generic; +using System.IO; +using Serilog.Events; + +namespace Serilog.Formatting.Display.Obsolete +{ + [Obsolete("Not used by the current output formatting implementation.")] + class LogEventPropertiesValue : LogEventPropertyValue + { + readonly MessageTemplate _template; + readonly IReadOnlyDictionary _properties; + readonly MessageTemplate _outputTemplate; + + public LogEventPropertiesValue(MessageTemplate template, IReadOnlyDictionary properties, MessageTemplate outputTemplate) + { + _template = template; + _properties = properties; + _outputTemplate = outputTemplate; + } + + public override void Render(TextWriter output, string format = null, IFormatProvider formatProvider = null) + { + PropertiesOutputFormat.Render(_template, _properties, _outputTemplate, output, formatProvider); + } + } +} \ No newline at end of file diff --git a/src/Serilog/Formatting/Display/LogEventPropertyMessageValue.cs b/src/Serilog/Formatting/Display/Obsolete/LogEventPropertyMessageValue.cs similarity index 91% rename from src/Serilog/Formatting/Display/LogEventPropertyMessageValue.cs rename to src/Serilog/Formatting/Display/Obsolete/LogEventPropertyMessageValue.cs index f021962cd..9507a7fb2 100644 --- a/src/Serilog/Formatting/Display/LogEventPropertyMessageValue.cs +++ b/src/Serilog/Formatting/Display/Obsolete/LogEventPropertyMessageValue.cs @@ -17,8 +17,9 @@ using System.IO; using Serilog.Events; -namespace Serilog.Formatting.Display +namespace Serilog.Formatting.Display.Obsolete { + [Obsolete("Not used by the current output formatting implementation.")] class LogEventPropertyMessageValue : LogEventPropertyValue { readonly MessageTemplate _template; diff --git a/src/Serilog/Formatting/Display/OutputProperties.cs b/src/Serilog/Formatting/Display/OutputProperties.cs index 14065c4db..c1b2cf8c8 100644 --- a/src/Serilog/Formatting/Display/OutputProperties.cs +++ b/src/Serilog/Formatting/Display/OutputProperties.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. @@ -16,6 +16,9 @@ using System.Collections.Generic; using System.Linq; using Serilog.Events; +using Serilog.Formatting.Display.Obsolete; + +#pragma warning disable 618 namespace Serilog.Formatting.Display { @@ -62,7 +65,7 @@ public static class OutputProperties /// /// The log event. /// A dictionary with properties representing the log event. - [Obsolete("Pass the full output template using the other overload.")] + [Obsolete("These implementation details of output formatting will not be exposed in a future version.")] public static IReadOnlyDictionary GetOutputProperties(LogEvent logEvent) { return GetOutputProperties(logEvent, MessageTemplate.Empty); @@ -74,7 +77,7 @@ public static IReadOnlyDictionary GetOutputProper /// The log event. /// The output template. /// A dictionary with properties representing the log event. - public static IReadOnlyDictionary GetOutputProperties(LogEvent logEvent, MessageTemplate outputTemplate) + internal static IReadOnlyDictionary GetOutputProperties(LogEvent logEvent, MessageTemplate outputTemplate) { var result = logEvent.Properties.ToDictionary(kvp => kvp.Key, kvp => kvp.Value); @@ -94,4 +97,4 @@ public static IReadOnlyDictionary GetOutputProper return result; } } -} \ No newline at end of file +} diff --git a/src/Serilog/Formatting/Display/Padding.cs b/src/Serilog/Formatting/Display/Padding.cs deleted file mode 100644 index de6744f34..000000000 --- a/src/Serilog/Formatting/Display/Padding.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System.IO; - -using Serilog.Parsing; - -namespace Serilog.Formatting.Display -{ - static class Padding - { - /// - /// Writes the provided value to the output, applying direction-based padding when is provided. - /// - public static void Apply(TextWriter output, string value, Alignment? alignment) - { - if (!alignment.HasValue) - { - output.Write(value); - return; - } - - var pad = alignment.Value.Width - value.Length; - - if (alignment.Value.Direction == AlignmentDirection.Right) - output.Write(new string(' ', pad)); - - output.Write(value); - - if (alignment.Value.Direction == AlignmentDirection.Left) - output.Write(new string(' ', pad)); - } - } -} \ No newline at end of file diff --git a/src/Serilog/Formatting/Display/LogEventPropertiesValue.cs b/src/Serilog/Formatting/Display/PropertiesOutputFormat.cs similarity index 66% rename from src/Serilog/Formatting/Display/LogEventPropertiesValue.cs rename to src/Serilog/Formatting/Display/PropertiesOutputFormat.cs index 1e47f0ee7..ac2b5b807 100644 --- a/src/Serilog/Formatting/Display/LogEventPropertiesValue.cs +++ b/src/Serilog/Formatting/Display/PropertiesOutputFormat.cs @@ -1,4 +1,4 @@ -// Copyright 2017 Serilog Contributors +// Copyright 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. @@ -19,32 +19,21 @@ namespace Serilog.Formatting.Display { - class LogEventPropertiesValue : LogEventPropertyValue + static class PropertiesOutputFormat { - readonly MessageTemplate _template; - readonly IReadOnlyDictionary _properties; - readonly MessageTemplate _outputTemplate; - - public LogEventPropertiesValue(MessageTemplate template, IReadOnlyDictionary properties, MessageTemplate outputTemplate) - { - _template = template; - _properties = properties; - _outputTemplate = outputTemplate; - } - - public override void Render(TextWriter output, string format = null, IFormatProvider formatProvider = null) + public static void Render(MessageTemplate template, IReadOnlyDictionary properties, MessageTemplate outputTemplate, TextWriter output, IFormatProvider formatProvider = null) { output.Write('{'); var delim = ""; - foreach (var kvp in _properties) + foreach (var kvp in properties) { - if (TemplateContainsPropertyName(_template, kvp.Key)) + if (TemplateContainsPropertyName(template, kvp.Key)) { continue; } - if (TemplateContainsPropertyName(_outputTemplate, kvp.Key)) + if (TemplateContainsPropertyName(outputTemplate, kvp.Key)) { continue; } diff --git a/src/Serilog/Formatting/Json/JsonFormatter.cs b/src/Serilog/Formatting/Json/JsonFormatter.cs index aded1eb29..5e762ad7c 100644 --- a/src/Serilog/Formatting/Json/JsonFormatter.cs +++ b/src/Serilog/Formatting/Json/JsonFormatter.cs @@ -21,6 +21,7 @@ using System.Linq; using Serilog.Events; using Serilog.Parsing; +using Serilog.Rendering; namespace Serilog.Formatting.Json { @@ -207,7 +208,7 @@ protected virtual void WriteRenderingsValues(IGrouping[] WriteJsonProperty("Format", format.Format, ref eldelim, output); var sw = new StringWriter(); - format.Render(properties, sw); + MessageTemplateRenderer.RenderPropertyToken(format, properties, sw, _formatProvider, true, false); WriteJsonProperty("Rendering", sw.ToString(), ref eldelim, output); output.Write("}"); diff --git a/src/Serilog/Formatting/Raw/RawFormatter.cs b/src/Serilog/Formatting/Raw/RawFormatter.cs index 95ad05e3b..6138c190e 100644 --- a/src/Serilog/Formatting/Raw/RawFormatter.cs +++ b/src/Serilog/Formatting/Raw/RawFormatter.cs @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +using System; using System.IO; using Serilog.Events; @@ -20,6 +21,7 @@ namespace Serilog.Formatting.Raw /// /// Formats log events as a raw dump of the message template and properties. /// + [Obsolete("A JSON-based formatter such as `Serilog.Formatting.Compact.CompactJsonFormatter` is recommended for this task.")] public class RawFormatter : ITextFormatter { /// diff --git a/src/Serilog/LoggerConfiguration.cs b/src/Serilog/LoggerConfiguration.cs index bc39b5e4b..f24e2dc6c 100644 --- a/src/Serilog/LoggerConfiguration.cs +++ b/src/Serilog/LoggerConfiguration.cs @@ -15,12 +15,12 @@ using System; using System.Collections.Generic; using System.Linq; +using Serilog.Capturing; using Serilog.Configuration; using Serilog.Core; using Serilog.Core.Enrichers; using Serilog.Core.Sinks; using Serilog.Events; -using Serilog.Parameters; namespace Serilog { diff --git a/src/Serilog/Parsing/MessageTemplateToken.cs b/src/Serilog/Parsing/MessageTemplateToken.cs index 52a3abcb2..a7cc83ba1 100644 --- a/src/Serilog/Parsing/MessageTemplateToken.cs +++ b/src/Serilog/Parsing/MessageTemplateToken.cs @@ -50,6 +50,7 @@ protected MessageTemplateToken(int startIndex) /// Properties that may be represented by the token. /// Output for the rendered string. /// Supplies culture-specific formatting information, or null. + // ReSharper disable once UnusedMemberInSuper.Global public abstract void Render(IReadOnlyDictionary properties, TextWriter output, IFormatProvider formatProvider = null); } } \ No newline at end of file diff --git a/src/Serilog/Parsing/PropertyToken.cs b/src/Serilog/Parsing/PropertyToken.cs index ef4db7c3a..01dcc2109 100644 --- a/src/Serilog/Parsing/PropertyToken.cs +++ b/src/Serilog/Parsing/PropertyToken.cs @@ -18,14 +18,14 @@ using System.Globalization; using System.IO; using Serilog.Events; -using Serilog.Formatting.Display; +using Serilog.Rendering; namespace Serilog.Parsing { /// /// A message template token representing a log event property. /// - public class PropertyToken : MessageTemplateToken + public sealed class PropertyToken : MessageTemplateToken { readonly string _rawText; readonly int? _position; @@ -57,12 +57,10 @@ public PropertyToken(string propertyName, string rawText, string formatObsolete, public PropertyToken(string propertyName, string rawText, string format = null, Alignment? alignment = null, Destructuring destructuring = Destructuring.Default, int startIndex = -1) : base(startIndex) { - if (propertyName == null) throw new ArgumentNullException(nameof(propertyName)); - if (rawText == null) throw new ArgumentNullException(nameof(rawText)); - PropertyName = propertyName; + PropertyName = propertyName ?? throw new ArgumentNullException(nameof(propertyName)); Format = format; Destructuring = destructuring; - _rawText = rawText; + _rawText = rawText ?? throw new ArgumentNullException(nameof(rawText)); Alignment = alignment; int position; @@ -89,30 +87,7 @@ public override void Render(IReadOnlyDictionary p if (properties == null) throw new ArgumentNullException(nameof(properties)); if (output == null) throw new ArgumentNullException(nameof(output)); - LogEventPropertyValue propertyValue; - if (!properties.TryGetValue(PropertyName, out propertyValue)) - { - output.Write(_rawText); - return; - } - - if (!Alignment.HasValue) - { - propertyValue.Render(output, Format, formatProvider); - return; - } - - var valueOutput = new StringWriter(); - propertyValue.Render(valueOutput, Format, formatProvider); - var value = valueOutput.ToString(); - - if (value.Length >= Alignment.Value.Width) - { - output.Write(value); - return; - } - - Padding.Apply(output, value, Alignment.Value); + MessageTemplateRenderer.RenderPropertyToken(this, properties, output, formatProvider, false, false); } /// @@ -140,6 +115,8 @@ public override void Render(IReadOnlyDictionary p /// public bool IsPositional => _position.HasValue; + internal string RawText => _rawText; + /// /// Try to get the integer value represented by the property name. /// diff --git a/src/Serilog/Parsing/TextToken.cs b/src/Serilog/Parsing/TextToken.cs index 9035d57d1..493a1b56d 100644 --- a/src/Serilog/Parsing/TextToken.cs +++ b/src/Serilog/Parsing/TextToken.cs @@ -16,13 +16,14 @@ using System.Collections.Generic; using System.IO; using Serilog.Events; +using Serilog.Rendering; namespace Serilog.Parsing { /// /// A message template token representing literal text. /// - public class TextToken : MessageTemplateToken + public sealed class TextToken : MessageTemplateToken { /// /// Construct a . @@ -32,8 +33,7 @@ public class TextToken : MessageTemplateToken /// public TextToken(string text, int startIndex = -1) : base(startIndex) { - if (text == null) throw new ArgumentNullException(nameof(text)); - Text = text; + Text = text ?? throw new ArgumentNullException(nameof(text)); } /// @@ -50,7 +50,7 @@ public TextToken(string text, int startIndex = -1) : base(startIndex) public override void Render(IReadOnlyDictionary properties, TextWriter output, IFormatProvider formatProvider = null) { if (output == null) throw new ArgumentNullException(nameof(output)); - output.Write(Text); + MessageTemplateRenderer.RenderTextToken(this, output); } /// diff --git a/src/Serilog/Formatting/Display/Casing.cs b/src/Serilog/Rendering/Casing.cs similarity index 53% rename from src/Serilog/Formatting/Display/Casing.cs rename to src/Serilog/Rendering/Casing.cs index b024e8b87..62aa022f5 100644 --- a/src/Serilog/Formatting/Display/Casing.cs +++ b/src/Serilog/Rendering/Casing.cs @@ -1,4 +1,18 @@ -namespace Serilog.Formatting.Display +// 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. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Serilog.Rendering { static class Casing { diff --git a/src/Serilog/Rendering/MessageTemplateRenderer.cs b/src/Serilog/Rendering/MessageTemplateRenderer.cs new file mode 100644 index 000000000..090e39e98 --- /dev/null +++ b/src/Serilog/Rendering/MessageTemplateRenderer.cs @@ -0,0 +1,109 @@ +// 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. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.CompilerServices; +using Serilog.Events; +using Serilog.Formatting.Json; +using Serilog.Parsing; + +namespace Serilog.Rendering +{ + static class MessageTemplateRenderer + { + static JsonValueFormatter JsonValueFormatter = new JsonValueFormatter("$type"); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Render(MessageTemplate messageTemplate, IReadOnlyDictionary properties, TextWriter output, string format = null, IFormatProvider formatProvider = null) + { + bool isLiteral = false, isJson = false; + + if (format != null) + { + for (var i = 0; i < format.Length; ++i) + { + if (format[i] == 'l') + isLiteral = true; + else if (format[i] == 'j') + isJson = true; + } + } + + for (var ti = 0; ti < messageTemplate.TokenArray.Length; ++ti) + { + var token = messageTemplate.TokenArray[ti]; + if (token is TextToken tt) + { + RenderTextToken(tt, output); + } + else + { + var pt = (PropertyToken) token; + RenderPropertyToken(pt, properties, output, formatProvider, isLiteral, isJson); + } + } + } + + public static void RenderTextToken(TextToken tt, TextWriter output) + { + output.Write(tt.Text); + } + + public static void RenderPropertyToken(PropertyToken pt, IReadOnlyDictionary properties, TextWriter output, IFormatProvider formatProvider, bool isLiteral, bool isJson) + { + LogEventPropertyValue propertyValue; + if (!properties.TryGetValue(pt.PropertyName, out propertyValue)) + { + output.Write(pt.RawText); + return; + } + + if (!pt.Alignment.HasValue) + { + RenderValue(propertyValue, isLiteral, isJson, output, pt.Format, formatProvider); + return; + } + + var valueOutput = new StringWriter(); + RenderValue(propertyValue, isLiteral, isJson, valueOutput, pt.Format, formatProvider); + var value = valueOutput.ToString(); + + if (value.Length >= pt.Alignment.Value.Width) + { + output.Write(value); + return; + } + + Padding.Apply(output, value, pt.Alignment.Value); + } + + static void RenderValue(LogEventPropertyValue propertyValue, bool literal, bool json, TextWriter output, string format, IFormatProvider formatProvider) + { + if (literal && propertyValue is ScalarValue sv && sv.Value is string str) + { + output.Write(str); + } + else if (json) + { + JsonValueFormatter.Format(propertyValue, output); + } + else + { + propertyValue.Render(output, format, formatProvider); + } + } + } +} diff --git a/src/Serilog/Rendering/Padding.cs b/src/Serilog/Rendering/Padding.cs new file mode 100644 index 000000000..23ea8206e --- /dev/null +++ b/src/Serilog/Rendering/Padding.cs @@ -0,0 +1,53 @@ +// 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. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System.IO; +using Serilog.Parsing; + +namespace Serilog.Rendering +{ + static class Padding + { + static readonly char[] PaddingChars = new string(' ', 80).ToCharArray(); + + /// + /// Writes the provided value to the output, applying direction-based padding when is provided. + /// + public static void Apply(TextWriter output, string value, Alignment? alignment) + { + if (!alignment.HasValue || value.Length >= alignment.Value.Width) + { + output.Write(value); + return; + } + + var pad = alignment.Value.Width - value.Length; + + if (alignment.Value.Direction == AlignmentDirection.Left) + output.Write(value); + + if (pad <= PaddingChars.Length) + { + output.Write(PaddingChars, 0, pad); + } + else + { + output.Write(new string(' ', pad)); + } + + if (alignment.Value.Direction == AlignmentDirection.Right) + output.Write(value); + } + } +} \ No newline at end of file diff --git a/src/Serilog/Serilog.csproj b/src/Serilog/Serilog.csproj index ad479c83b..0e6af3504 100644 --- a/src/Serilog/Serilog.csproj +++ b/src/Serilog/Serilog.csproj @@ -18,6 +18,8 @@ false true + True + diff --git a/test/Serilog.PerformanceTests/LevelControlBenchmark.cs b/test/Serilog.PerformanceTests/LevelControlBenchmark.cs index 899212357..6f29e9883 100644 --- a/test/Serilog.PerformanceTests/LevelControlBenchmark.cs +++ b/test/Serilog.PerformanceTests/LevelControlBenchmark.cs @@ -1,11 +1,7 @@ using BenchmarkDotNet.Attributes; -using BenchmarkDotNet.Running; -using Serilog; using Serilog.Core; using Serilog.Events; -using System; using Serilog.PerformanceTests.Support; -using Xunit; namespace Serilog.PerformanceTests { diff --git a/test/Serilog.PerformanceTests/LogContextEnrichmentBenchmark.cs b/test/Serilog.PerformanceTests/LogContextEnrichmentBenchmark.cs index c353fccfb..e7ea19867 100644 --- a/test/Serilog.PerformanceTests/LogContextEnrichmentBenchmark.cs +++ b/test/Serilog.PerformanceTests/LogContextEnrichmentBenchmark.cs @@ -1,10 +1,6 @@ using BenchmarkDotNet.Attributes; -using BenchmarkDotNet.Running; -using Serilog; using Serilog.Context; -using System; using Serilog.PerformanceTests.Support; -using Xunit; using Serilog.Events; namespace Serilog.PerformanceTests diff --git a/test/Serilog.PerformanceTests/MessageTemplateParsingBenchmark.cs b/test/Serilog.PerformanceTests/MessageTemplateParsingBenchmark.cs index d9c3fcfe3..e5ae2fd9b 100644 --- a/test/Serilog.PerformanceTests/MessageTemplateParsingBenchmark.cs +++ b/test/Serilog.PerformanceTests/MessageTemplateParsingBenchmark.cs @@ -1,19 +1,12 @@ using BenchmarkDotNet.Attributes; -using BenchmarkDotNet.Running; -using Serilog; -using Serilog.Events; using Serilog.Parsing; -using System; -using System.Linq; -using System.Collections; -using System.Collections.Generic; -using Xunit; namespace Serilog.PerformanceTests { /// /// Tests the cost of parsing various message templates. /// + [MemoryDiagnoser] public class MessageTemplateParsingBenchmark { MessageTemplateParser _parser; diff --git a/test/Serilog.PerformanceTests/MessageTemplateRenderingBenchmark.cs b/test/Serilog.PerformanceTests/MessageTemplateRenderingBenchmark.cs index 76023f421..486b79e8d 100644 --- a/test/Serilog.PerformanceTests/MessageTemplateRenderingBenchmark.cs +++ b/test/Serilog.PerformanceTests/MessageTemplateRenderingBenchmark.cs @@ -8,6 +8,7 @@ namespace Serilog.PerformanceTests /// /// Determines the cost of rendering a message template. /// + [MemoryDiagnoser] public class MessageTemplateRenderingBenchmark { static readonly LogEvent NoProperties = @@ -17,14 +18,7 @@ public class MessageTemplateRenderingBenchmark Some.InformationEvent("Processed {@Position} for {Task} in {Elapsed:000} ms", new { Latitude = 25, Longitude = 134 }, "Benchmark", 34); - readonly StringWriter _output = new StringWriter(); - - [Setup] - public void Setup() - { - _output.GetStringBuilder().Length = 0; - _output.GetStringBuilder().Capacity = 1024; // Only a few dozen chars actually needed here. - } + readonly TextWriter _output = new NullTextWriter(); [Benchmark] public void TemplateWithNoProperties() diff --git a/test/Serilog.PerformanceTests/NestedLoggerLatencyBenchmark.cs b/test/Serilog.PerformanceTests/NestedLoggerLatencyBenchmark.cs index 537a60371..578fd6de3 100644 --- a/test/Serilog.PerformanceTests/NestedLoggerLatencyBenchmark.cs +++ b/test/Serilog.PerformanceTests/NestedLoggerLatencyBenchmark.cs @@ -1,9 +1,5 @@ using BenchmarkDotNet.Attributes; -using BenchmarkDotNet.Running; -using Serilog; -using System; using Serilog.PerformanceTests.Support; -using Xunit; using Serilog.Events; namespace Serilog.PerformanceTests diff --git a/test/Serilog.PerformanceTests/OutputTemplateRenderingBenchmark.cs b/test/Serilog.PerformanceTests/OutputTemplateRenderingBenchmark.cs index cae6a892d..60310df85 100644 --- a/test/Serilog.PerformanceTests/OutputTemplateRenderingBenchmark.cs +++ b/test/Serilog.PerformanceTests/OutputTemplateRenderingBenchmark.cs @@ -11,20 +11,14 @@ namespace Serilog.PerformanceTests /// Determines the cost of rendering an event out to one of the typical text targets, /// like the console or a text file. /// + [MemoryDiagnoser] public class OutputTemplateRenderingBenchmark { const string DefaultFileOutputTemplate = "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] {Message}{NewLine}{Exception}"; static readonly LogEvent HelloWorldEvent = Some.InformationEvent("Hello, {Name}", "World"); static readonly MessageTemplateTextFormatter Formatter = new MessageTemplateTextFormatter(DefaultFileOutputTemplate, CultureInfo.InvariantCulture); - readonly StringWriter _output = new StringWriter(); - - [Setup] - public void Setup() - { - _output.GetStringBuilder().Length = 0; - _output.GetStringBuilder().Capacity = 1024; // Only a few dozen chars actually needed here. - } + readonly TextWriter _output = new NullTextWriter(); [Benchmark] public void FormatToOutput() diff --git a/test/Serilog.PerformanceTests/PipelineBenchmark.cs b/test/Serilog.PerformanceTests/PipelineBenchmark.cs index 6812f2345..784dd97a8 100644 --- a/test/Serilog.PerformanceTests/PipelineBenchmark.cs +++ b/test/Serilog.PerformanceTests/PipelineBenchmark.cs @@ -14,22 +14,15 @@ // limitations under the License. using BenchmarkDotNet.Attributes; -using BenchmarkDotNet.Running; -using Serilog; -using Serilog.Events; -using Serilog.Parsing; using System; -using System.Linq; -using System.Collections; -using System.Collections.Generic; using Serilog.PerformanceTests.Support; -using Xunit; namespace Serilog.PerformanceTests { /// /// Tests the cost of writing through the logging pipeline. /// + [MemoryDiagnoser] public class PipelineBenchmark { ILogger _log; diff --git a/test/Serilog.PerformanceTests/Support/NullTextWriter.cs b/test/Serilog.PerformanceTests/Support/NullTextWriter.cs new file mode 100644 index 000000000..680eac502 --- /dev/null +++ b/test/Serilog.PerformanceTests/Support/NullTextWriter.cs @@ -0,0 +1,160 @@ +using System; +using System.IO; +using System.Text; + +namespace Serilog.PerformanceTests.Support +{ + class NullTextWriter : TextWriter + { + public override void Write(char value) + { + } + + public override Encoding Encoding { get; } = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false); + + public override void Write(bool value) + { + } + + public override void Write(char[] buffer) + { + } + + public override void Write(char[] buffer, int index, int count) + { + } + + public override void Write(decimal value) + { + } + + public override void Write(double value) + { + } + + public override void Write(int value) + { + } + + public override void Write(long value) + { + } + + public override void Write(object value) + { + } + + public override void Write(float value) + { + } + + public override void Write(string value) + { + } + + public override void Write(string format, object arg0) + { + } + + public override void Write(string format, object arg0, object arg1) + { + } + + public override void Write(string format, object arg0, object arg1, object arg2) + { + } + + public override void Write(string format, params object[] arg) + { + } + + public override void Write(uint value) + { + } + + public override void Write(ulong value) + { + } + + public override string ToString() + { + return String.Empty; + } + + public override void Flush() + { + } + + public override void WriteLine() + { + } + + public override void WriteLine(bool value) + { + } + + public override void WriteLine(char value) + { + } + + public override void WriteLine(char[] buffer) + { + } + + public override void WriteLine(char[] buffer, int index, int count) + { + } + + public override void WriteLine(decimal value) + { + } + + public override void WriteLine(double value) + { + } + + public override void WriteLine(int value) + { + } + + public override void WriteLine(long value) + { + } + + public override void WriteLine(object value) + { + } + + public override void WriteLine(float value) + { + } + + public override void WriteLine(string value) + { + } + + public override void WriteLine(string format, object arg0) + { + } + + public override void WriteLine(string format, object arg0, object arg1) + { + } + + public override void WriteLine(string format, object arg0, object arg1, object arg2) + { + } + + public override void WriteLine(string format, params object[] arg) + { + } + + public override void WriteLine(uint value) + { + } + + public override void WriteLine(ulong value) + { + } + } +} diff --git a/test/Serilog.PerformanceTests/Support/Some.cs b/test/Serilog.PerformanceTests/Support/Some.cs index e1284b02c..655eedd7e 100644 --- a/test/Serilog.PerformanceTests/Support/Some.cs +++ b/test/Serilog.PerformanceTests/Support/Some.cs @@ -1,4 +1,4 @@ -using System; +using System; using Serilog.Events; namespace Serilog.PerformanceTests.Support diff --git a/test/Serilog.Tests/Parameters/PropertyValueConverterTests.cs b/test/Serilog.Tests/Capturing/PropertyValueConverterTests.cs similarity index 99% rename from test/Serilog.Tests/Parameters/PropertyValueConverterTests.cs rename to test/Serilog.Tests/Capturing/PropertyValueConverterTests.cs index 732b737ad..6534a35ef 100644 --- a/test/Serilog.Tests/Parameters/PropertyValueConverterTests.cs +++ b/test/Serilog.Tests/Capturing/PropertyValueConverterTests.cs @@ -1,20 +1,20 @@ using System; using System.Collections.Generic; using System.Linq; +using Serilog.Capturing; using System.Threading.Tasks; using System.Threading; -using Xunit; using Serilog.Core; using Serilog.Events; -using Serilog.Parameters; using Serilog.Parsing; using Serilog.Tests.Support; +using Xunit; // ReSharper disable UnusedAutoPropertyAccessor.Global, UnusedParameter.Local -namespace Serilog.Tests.Parameters +namespace Serilog.Tests.Capturing { public class PropertyValueConverterTests { diff --git a/test/Serilog.Tests/Core/LogEventPropertyCapturingTests.cs b/test/Serilog.Tests/Core/LogEventPropertyCapturingTests.cs index 07c19f093..8e9f05837 100644 --- a/test/Serilog.Tests/Core/LogEventPropertyCapturingTests.cs +++ b/test/Serilog.Tests/Core/LogEventPropertyCapturingTests.cs @@ -1,10 +1,10 @@ using System; using System.Linq; using System.Collections.Generic; +using Serilog.Capturing; using Serilog.Core; using Serilog.Debugging; using Serilog.Events; -using Serilog.Parameters; using Serilog.Parsing; using Serilog.Tests.Support; using Xunit; diff --git a/test/Serilog.Tests/Core/MessageTemplateTests.cs b/test/Serilog.Tests/Core/MessageTemplateTests.cs index b76185d36..8ae5cdb33 100755 --- a/test/Serilog.Tests/Core/MessageTemplateTests.cs +++ b/test/Serilog.Tests/Core/MessageTemplateTests.cs @@ -3,9 +3,9 @@ using System.IO; using System.Linq; using System.Text; +using Serilog.Capturing; using Xunit; using Serilog.Core; -using Serilog.Parameters; using MessageTemplateParser = Serilog.Parsing.MessageTemplateParser; namespace Serilog.Tests.Core diff --git a/test/Serilog.Tests/Core/SecondaryLoggerSinkTests.cs b/test/Serilog.Tests/Core/SecondaryLoggerSinkTests.cs index 0408235ed..c84007bf7 100644 --- a/test/Serilog.Tests/Core/SecondaryLoggerSinkTests.cs +++ b/test/Serilog.Tests/Core/SecondaryLoggerSinkTests.cs @@ -1,5 +1,4 @@ -using System; -using Serilog.Tests.Support; +using Serilog.Tests.Support; using Xunit; using Serilog.Core; using Serilog.Events; @@ -37,9 +36,10 @@ public void WhenOwnedByCallerSecondaryLoggerIsNotDisposed() .WriteTo.Sink(secondary) .CreateLogger(); - ((IDisposable)new LoggerConfiguration() + new LoggerConfiguration() .WriteTo.Logger(secondaryLogger) - .CreateLogger()).Dispose(); + .CreateLogger() + .Dispose(); Assert.False(secondary.IsDisposed); } @@ -49,9 +49,10 @@ public void WhenOwnedByPrimaryLoggerSecondaryIsDisposed() { var secondary = new DisposeTrackingSink(); - ((IDisposable)new LoggerConfiguration() + new LoggerConfiguration() .WriteTo.Logger(lc => lc.WriteTo.Sink(secondary)) - .CreateLogger()).Dispose(); + .CreateLogger() + .Dispose(); Assert.True(secondary.IsDisposed); } diff --git a/test/Serilog.Tests/Events/LogEventPropertyValueTests.cs b/test/Serilog.Tests/Events/LogEventPropertyValueTests.cs index 534351075..76d9dfe9f 100644 --- a/test/Serilog.Tests/Events/LogEventPropertyValueTests.cs +++ b/test/Serilog.Tests/Events/LogEventPropertyValueTests.cs @@ -15,10 +15,10 @@ using System; using System.Globalization; using System.Linq; +using Serilog.Capturing; using Xunit; using Serilog.Core; using Serilog.Events; -using Serilog.Parameters; using Serilog.Parsing; using Serilog.Tests.Support; diff --git a/test/Serilog.Tests/Formatting/Display/MessageTemplateTextFormatterTests.cs b/test/Serilog.Tests/Formatting/Display/MessageTemplateTextFormatterTests.cs index 052ee267c..c5e4a3d82 100644 --- a/test/Serilog.Tests/Formatting/Display/MessageTemplateTextFormatterTests.cs +++ b/test/Serilog.Tests/Formatting/Display/MessageTemplateTextFormatterTests.cs @@ -218,5 +218,34 @@ public void DoNotDuplicatePropertiesAlreadyRenderedInOutputTemplate() formatter.Format(evt, sw); Assert.Equal("42 {Bar: 42}", sw.ToString()); } + + [Theory] + [InlineData("", "Hello, \"World\"!")] + [InlineData(":j", "Hello, \"World\"!")] + [InlineData(":l", "Hello, World!")] + [InlineData(":lj", "Hello, World!")] + [InlineData(":jl", "Hello, World!")] + public void AppliesLiteralFormattingToMessageStringsWhenSpecified(string format, string expected) + { + var formatter = new MessageTemplateTextFormatter("{Message" + format + "}", null); + var evt = DelegatingSink.GetLogEvent(l => l.Information("Hello, {Name}!", "World")); + var sw = new StringWriter(); + formatter.Format(evt, sw); + Assert.Equal(expected, sw.ToString()); + } + + [Theory] + [InlineData("", "{ Name: \"World\" }")] + [InlineData(":j", "{\"Name\":\"World\"}")] + [InlineData(":lj", "{\"Name\":\"World\"}")] + [InlineData(":jl", "{\"Name\":\"World\"}")] + public void AppliesJsonFormattingToMessageStructuresWhenSpecified(string format, string expected) + { + var formatter = new MessageTemplateTextFormatter("{Message" + format + "}", null); + var evt = DelegatingSink.GetLogEvent(l => l.Information("{@Obj}", new {Name = "World"})); + var sw = new StringWriter(); + formatter.Format(evt, sw); + Assert.Equal(expected, sw.ToString()); + } } } diff --git a/test/Serilog.Tests/Formatting/Json/JsonValueFormatterTests.cs b/test/Serilog.Tests/Formatting/Json/JsonValueFormatterTests.cs index 45e22324a..84aca1af5 100644 --- a/test/Serilog.Tests/Formatting/Json/JsonValueFormatterTests.cs +++ b/test/Serilog.Tests/Formatting/Json/JsonValueFormatterTests.cs @@ -1,11 +1,8 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; using Serilog.Events; using Serilog.Formatting.Json; -using Serilog.Tests.Events; -using Serilog.Tests.Support; using Xunit; namespace Serilog.Tests.Formatting.Json diff --git a/test/Serilog.Tests/LoggerConfigurationTests.cs b/test/Serilog.Tests/LoggerConfigurationTests.cs index 61808a6aa..b94d28570 100644 --- a/test/Serilog.Tests/LoggerConfigurationTests.cs +++ b/test/Serilog.Tests/LoggerConfigurationTests.cs @@ -1,11 +1,8 @@ using System; -using System.IO; using System.Collections.Generic; using System.Linq; using System.Reflection; -using System.Runtime.InteropServices.ComTypes; using Xunit; -using Serilog.Configuration; using Serilog.Core; using Serilog.Core.Filters; using Serilog.Debugging; @@ -120,7 +117,7 @@ public void DestructuringSystemTypeGivesScalarByDefault() .WriteTo.Sink(sink) .CreateLogger(); - var thisType = this.GetType(); + var thisType = GetType(); logger.Information("{@thisType}", thisType); var ev = events.Single(); @@ -171,7 +168,7 @@ public void DestructuringIsPossibleForSystemTypeDerivedProperties() .WriteTo.Sink(sink) .CreateLogger(); - var thisType = this.GetType(); + var thisType = GetType(); logger.Information("{@thisType}", thisType); var ev = events.Single(); @@ -495,7 +492,7 @@ public void HigherMinimumLevelOverridesArePropagated() .CreateLogger(); logger.Write(Some.InformationEvent()); - logger.ForContext(Serilog.Core.Constants.SourceContextPropertyName, "Microsoft.AspNet.Something").Write(Some.InformationEvent()); + logger.ForContext(Constants.SourceContextPropertyName, "Microsoft.AspNet.Something").Write(Some.InformationEvent()); logger.ForContext().Write(Some.InformationEvent()); Assert.Equal(2, sink.Events.Count); @@ -513,7 +510,7 @@ public void LowerMinimumLevelOverridesArePropagated() .CreateLogger(); logger.Write(Some.InformationEvent()); - logger.ForContext(Serilog.Core.Constants.SourceContextPropertyName, "Microsoft.AspNet.Something").Write(Some.InformationEvent()); + logger.ForContext(Constants.SourceContextPropertyName, "Microsoft.AspNet.Something").Write(Some.InformationEvent()); logger.ForContext().Write(Some.InformationEvent()); Assert.Equal(1, sink.Events.Count); @@ -523,7 +520,7 @@ public void LowerMinimumLevelOverridesArePropagated() public void ExceptionsThrownBySinksAreNotPropagated() { var logger = new LoggerConfiguration() - .WriteTo.Sink(new DelegatingSink(e => { throw new Exception("Boom!"); })) + .WriteTo.Sink(new DelegatingSink(e => throw new Exception("Boom!"))) .CreateLogger(); logger.Write(Some.InformationEvent()); diff --git a/test/Serilog.Tests/MethodOverloadConventionTests.cs b/test/Serilog.Tests/MethodOverloadConventionTests.cs index c634f46e0..1c03f55f6 100644 --- a/test/Serilog.Tests/MethodOverloadConventionTests.cs +++ b/test/Serilog.Tests/MethodOverloadConventionTests.cs @@ -10,6 +10,10 @@ using System.Text.RegularExpressions; using Xunit; using Xunit.Sdk; +// ReSharper disable PossibleMultipleEnumeration +// ReSharper disable UnusedMember.Local +// ReSharper disable UnusedParameter.Local +// ReSharper disable AssignNullToNotNullAttribute namespace Serilog.Tests { @@ -97,10 +101,9 @@ public void ValidateWriteEventLogMethods(Type loggerType) Assert.True(writeMethod.IsPublic); Assert.Equal(writeMethod.ReturnType, typeof(void)); - LogEventLevel level = LogEventLevel.Information; + var level = LogEventLevel.Information; CollectingSink sink; - var logger = GetLogger(loggerType, out sink); InvokeMethod(writeMethod, logger, new object[] { Some.LogEvent(DateTimeOffset.Now, level) }); @@ -108,8 +111,8 @@ public void ValidateWriteEventLogMethods(Type loggerType) //handle silent logger special case i.e. no result validation if (loggerType == typeof(SilentLogger)) return; - else - EvaluateSingleResult(level, sink); + + EvaluateSingleResult(level, sink); } [Theory] @@ -158,12 +161,10 @@ public void ValidateForContextMethods(Type loggerType) { report.AppendLine($"{testMethod.Name} Invocation Failure on: {method} with: {xunitException.UserMessage}"); } - - continue; } } - Assert.True(signatureMatchAndInvokeSuccess, $"{method} did not match any known method or failed invoke\n" + report.ToString()); + Assert.True(signatureMatchAndInvokeSuccess, $"{method} did not match any known method or failed invoke\n" + report); } } @@ -185,7 +186,7 @@ public void ValidateBindMessageTemplateMethods(Type loggerType) Assert.Equal(messageTemplateAttr.MessageTemplateParameterName, MessageTemplate); var parameters = method.GetParameters(); - int index = 0; + var index = 0; Assert.Equal(parameters[index].Name, "messageTemplate"); Assert.Equal(parameters[index].ParameterType, typeof(string)); @@ -203,7 +204,6 @@ public void ValidateBindMessageTemplateMethods(Type loggerType) Assert.Equal(parameters[index].Name, "boundProperties"); Assert.Equal(parameters[index].ParameterType, typeof(IEnumerable).MakeByRefType()); Assert.True(parameters[index].IsOut); - index++; var logger = GetLogger(loggerType); @@ -242,7 +242,7 @@ public void ValidateBindPropertyMethods(Type loggerType) Assert.True(method.IsPublic); var parameters = method.GetParameters(); - int index = 0; + var index = 0; Assert.Equal(parameters[index].Name, "propertyName"); Assert.Equal(parameters[index].ParameterType, typeof(string)); @@ -343,7 +343,7 @@ void ForContextMethod0(MethodInfo method) { e.Data.Add("IsSignatureAssertionFailure", true); - throw e; + throw; } var logger = GetLogger(method.DeclaringType); @@ -375,7 +375,7 @@ void ForContextMethod1(MethodInfo method) { e.Data.Add("IsSignatureAssertionFailure", true); - throw e; + throw; } var logger = GetLogger(method.DeclaringType); @@ -396,7 +396,7 @@ void ForContextMethod2(MethodInfo method) var parameters = method.GetParameters(); Assert.Equal(parameters.Length, 3); - int index = 0; + var index = 0; Assert.Equal(parameters[index].Name, "propertyName"); Assert.Equal(parameters[index].ParameterType, typeof(string)); @@ -414,7 +414,7 @@ void ForContextMethod2(MethodInfo method) { e.Data.Add("IsSignatureAssertionFailure", true); - throw e; + throw; } var logger = GetLogger(method.DeclaringType); @@ -464,12 +464,12 @@ void ForContextMethod3(MethodInfo method) { e.Data.Add("IsSignatureAssertionFailure", true); - throw e; + throw; } var logger = GetLogger(method.DeclaringType); - var enrichedLogger = InvokeMethod(method, logger, null, new Type[] { typeof(object) }); + var enrichedLogger = InvokeMethod(method, logger, null, new[] { typeof(object) }); Assert.NotNull(enrichedLogger); Assert.True(enrichedLogger is ILogger); @@ -493,7 +493,7 @@ void ForContextMethod4(MethodInfo method) { e.Data.Add("IsSignatureAssertionFailure", true); - throw e; + throw; } var logger = GetLogger(method.DeclaringType); @@ -566,7 +566,7 @@ void ValidateConventionForMethodSet( { try { - Action invokeTestMethod = null; + Action invokeTestMethod; if (testInvokeResults) invokeTestMethod = InvokeConventionMethodAndTest; @@ -592,19 +592,17 @@ void ValidateConventionForMethodSet( { report.AppendLine($"{testMethod.Name} Invocation Failure on: {method} with: {xunitException.UserMessage}"); } - - continue; } } - Assert.True(signatureMatchAndInvokeSuccess, $"{method} did not match any known convention or failed invoke\n" + report.ToString()); + Assert.True(signatureMatchAndInvokeSuccess, $"{method} did not match any known convention or failed invoke\n" + report); } } // Method0 (string messageTemplate) : void void ValidateMethod0(MethodInfo method, Action invokeMethod) { - VerifyMethodSignature(method, expectedArgCount: 1); + VerifyMethodSignature(method); var parameters = new object[] { "message" }; @@ -616,7 +614,7 @@ void ValidateMethod1(MethodInfo method, Action inv { VerifyMethodSignature(method, isGeneric: true, expectedArgCount: 2); - var typeArgs = new Type[] { typeof(string) }; + var typeArgs = new[] { typeof(string) }; var parameters = new object[] { "message", "value0" }; @@ -628,7 +626,7 @@ void ValidateMethod2(MethodInfo method, Action inv { VerifyMethodSignature(method, isGeneric: true, expectedArgCount: 3); - var typeArgs = new Type[] { typeof(string), typeof(string) }; + var typeArgs = new[] { typeof(string), typeof(string) }; var parameters = new object[] { @@ -643,7 +641,7 @@ void ValidateMethod3(MethodInfo method, Action inv { VerifyMethodSignature(method, isGeneric: true, expectedArgCount: 4); - var typeArgs = new Type[] { typeof(string), typeof(string), typeof(string) }; + var typeArgs = new[] { typeof(string), typeof(string), typeof(string) }; var parameters = new object[] { @@ -681,7 +679,7 @@ void ValidateMethod6(MethodInfo method, Action inv { VerifyMethodSignature(method, hasExceptionArg: true, isGeneric: true, expectedArgCount: 3); - var typeArgs = new Type[] { typeof(string) }; + var typeArgs = new[] { typeof(string) }; var parameters = new object[] { @@ -696,7 +694,7 @@ void ValidateMethod7(MethodInfo method, Action inv { VerifyMethodSignature(method, hasExceptionArg: true, isGeneric: true, expectedArgCount: 4); - var typeArgs = new Type[] { typeof(string), typeof(string) }; + var typeArgs = new[] { typeof(string), typeof(string) }; var parameters = new object[] { @@ -711,7 +709,7 @@ void ValidateMethod8(MethodInfo method, Action inv { VerifyMethodSignature(method, hasExceptionArg: true, isGeneric: true, expectedArgCount: 5); - var typeArgs = new Type[] { typeof(string), typeof(string), typeof(string) }; + var typeArgs = new[] { typeof(string), typeof(string), typeof(string) }; var parameters = new object[] { @@ -726,7 +724,7 @@ void ValidateMethod9(MethodInfo method, Action inv { VerifyMethodSignature(method, hasExceptionArg: true, expectedArgCount: 3); - object[] parameters = new object[] + var parameters = new object[] { new Exception("test"), "Processed {value0}, {value1}, {value2}", new object[] { "value0", "value1", "value2" } @@ -786,7 +784,7 @@ static void VerifyMethodSignature(MethodInfo method, bool hasExceptionArg = fals { var parameters = method.GetParameters(); - int index = 0; + var index = 0; if (method.Name == Write) { @@ -822,7 +820,7 @@ static void VerifyMethodSignature(MethodInfo method, bool hasExceptionArg = fals //multiple generic argument convention T0...Tx : T0 propertyValue0... Tx propertyValueX if (genericTypeArgs.Length > 1) { - for (int i = 0; i < genericTypeArgs.Length; i++, index++) + for (var i = 0; i < genericTypeArgs.Length; i++, index++) { Assert.Equal(genericTypeArgs[i].Name, $"T{i}"); @@ -867,7 +865,7 @@ static void VerifyMethodSignature(MethodInfo method, bool hasExceptionArg = fals // mark xunit assertion failures e.Data.Add("IsSignatureAssertionFailure", true); - throw e; + throw; } } @@ -881,13 +879,14 @@ static object InvokeMethod( { if (method.IsGenericMethod) return method.MakeGenericMethod(typeArgs).Invoke(null, parameters); - else - return method.Invoke(null, parameters); + + return method.Invoke(null, parameters); } - else if (method.IsGenericMethod) + + if (method.IsGenericMethod) return method.MakeGenericMethod(typeArgs).Invoke(instance, parameters); - else - return method.Invoke(instance, parameters); + + return method.Invoke(instance, parameters); } static void EvaluateSingleResult(LogEventLevel level, CollectingSink results) @@ -920,7 +919,8 @@ static ILogger GetLogger(Type loggerType, out CollectingSink sink, LogEventLevel .WriteTo.Sink(sink) .CreateLogger(); } - else if (loggerType == typeof(Log)) + + if (loggerType == typeof(Log)) { sink = new CollectingSink(); @@ -933,10 +933,11 @@ static ILogger GetLogger(Type loggerType, out CollectingSink sink, LogEventLevel return null; } - else if (loggerType == typeof(SilentLogger)) + + if (loggerType == typeof(SilentLogger)) return new SilentLogger(); - else - throw new ArgumentException($"Logger Type of {loggerType} is not supported"); + + throw new ArgumentException($"Logger Type of {loggerType} is not supported"); } } } \ No newline at end of file diff --git a/test/Serilog.Tests/Settings/KeyValuePairSettingsTests.cs b/test/Serilog.Tests/Settings/KeyValuePairSettingsTests.cs index ffb974378..9725f0374 100644 --- a/test/Serilog.Tests/Settings/KeyValuePairSettingsTests.cs +++ b/test/Serilog.Tests/Settings/KeyValuePairSettingsTests.cs @@ -6,12 +6,9 @@ using Serilog.Events; using Serilog.Settings.KeyValuePairs; using Serilog.Tests.Support; -using Serilog.Enrichers; using TestDummies; using Serilog.Configuration; using Serilog.Formatting; -using Serilog.Formatting.Json; -using Serilog.Tests.Formatting.Json; namespace Serilog.Tests.Settings { @@ -142,7 +139,7 @@ public void TestMinimumLevelOverrides() .WriteTo.Sink(new DelegatingSink(e => evt = e)) .CreateLogger(); - var systemLogger = log.ForContext(); + var systemLogger = log.ForContext(); systemLogger.Write(Some.InformationEvent()); Assert.Null(evt); diff --git a/test/Serilog.Tests/Settings/SettingValueConversionsTests.cs b/test/Serilog.Tests/Settings/SettingValueConversionsTests.cs index 0fca5ec32..3ee1bc118 100644 --- a/test/Serilog.Tests/Settings/SettingValueConversionsTests.cs +++ b/test/Serilog.Tests/Settings/SettingValueConversionsTests.cs @@ -46,7 +46,7 @@ public void ValuesConvertToEnumMembers() [Fact] public void StringValuesConvertToDefaultInstancesIfTargetIsInterface() { - var result = (object)SettingValueConversions.ConvertToType("Serilog.Formatting.Json.JsonFormatter", typeof(ITextFormatter)); + var result = SettingValueConversions.ConvertToType("Serilog.Formatting.Json.JsonFormatter", typeof(ITextFormatter)); Assert.IsType(result); } } diff --git a/test/Serilog.Tests/Support/DisposableLogger.cs b/test/Serilog.Tests/Support/DisposableLogger.cs index 1c46e6132..aa465c1d1 100644 --- a/test/Serilog.Tests/Support/DisposableLogger.cs +++ b/test/Serilog.Tests/Support/DisposableLogger.cs @@ -5,7 +5,7 @@ namespace Serilog.Tests.Support { - public class DisposableLogger : Serilog.ILogger, IDisposable + public class DisposableLogger : ILogger, IDisposable { public bool Disposed { get; set; } diff --git a/test/Serilog.Tests/Support/LogEventPropertyStructuralEqualityComparer.cs b/test/Serilog.Tests/Support/LogEventPropertyStructuralEqualityComparer.cs index e1162ed8f..8b6135bd6 100644 --- a/test/Serilog.Tests/Support/LogEventPropertyStructuralEqualityComparer.cs +++ b/test/Serilog.Tests/Support/LogEventPropertyStructuralEqualityComparer.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using Serilog.Events; @@ -11,7 +10,7 @@ class LogEventPropertyStructuralEqualityComparer : IEqualityComparer valueEqualityComparer = null) { - this._valueEqualityComparer = + _valueEqualityComparer = valueEqualityComparer ?? new LogEventPropertyValueComparer(EqualityComparer.Default); } diff --git a/test/Serilog.Tests/Support/LogEventPropertyValueComparer.cs b/test/Serilog.Tests/Support/LogEventPropertyValueComparer.cs index 232b1cf96..b6e57d7f1 100644 --- a/test/Serilog.Tests/Support/LogEventPropertyValueComparer.cs +++ b/test/Serilog.Tests/Support/LogEventPropertyValueComparer.cs @@ -11,7 +11,7 @@ class LogEventPropertyValueComparer : IEqualityComparer public LogEventPropertyValueComparer(IEqualityComparer objectEqualityComparer = null) { - this._objectEqualityComparer = objectEqualityComparer ?? EqualityComparer.Default; + _objectEqualityComparer = objectEqualityComparer ?? EqualityComparer.Default; } public bool Equals(LogEventPropertyValue x, LogEventPropertyValue y) diff --git a/test/Serilog.Tests/Support/StringSink.cs b/test/Serilog.Tests/Support/StringSink.cs index e7102af69..5bb088467 100644 --- a/test/Serilog.Tests/Support/StringSink.cs +++ b/test/Serilog.Tests/Support/StringSink.cs @@ -1,5 +1,4 @@ -using System; -using System.Globalization; +using System.Globalization; using System.IO; using Serilog.Core; using Serilog.Events; diff --git a/test/TestDummies/DummyThreadIdEnricher.cs b/test/TestDummies/DummyThreadIdEnricher.cs index 142c15282..4ba740eb7 100644 --- a/test/TestDummies/DummyThreadIdEnricher.cs +++ b/test/TestDummies/DummyThreadIdEnricher.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Serilog.Core; +using Serilog.Core; using Serilog.Events; namespace TestDummies diff --git a/test/TestDummies/Properties/AssemblyInfo.cs b/test/TestDummies/Properties/AssemblyInfo.cs index 1f1fc4f85..89032973b 100644 --- a/test/TestDummies/Properties/AssemblyInfo.cs +++ b/test/TestDummies/Properties/AssemblyInfo.cs @@ -1,5 +1,4 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following