From 7112d6b032e6bdd5b7594465926cc5de48b41b16 Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Fri, 3 Feb 2017 11:15:55 +1000 Subject: [PATCH 01/58] Dev version bump [Skip CI] --- src/Serilog/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Serilog/project.json b/src/Serilog/project.json index 4d8c226fb..810666497 100644 --- a/src/Serilog/project.json +++ b/src/Serilog/project.json @@ -1,5 +1,5 @@ { - "version": "2.4.0-*", + "version": "2.4.1-*", "description": "Simple .NET logging with fully-structured events", "authors": [ "Serilog Contributors" ], From e5b1f51ff075e4591ffec0a287ccad9cc24ca85b Mon Sep 17 00:00:00 2001 From: Adam Chester Date: Sat, 4 Feb 2017 08:29:59 +1000 Subject: [PATCH 02/58] Tooling RC3 --- Serilog.sln | 97 +++++++++++++------ appveyor.yml | 4 +- build.sh | 19 ++-- global.json | 2 +- src/Serilog/Serilog.csproj | 45 +++++++++ src/Serilog/Serilog.xproj | 17 ---- src/Serilog/project.json | 65 ------------- .../Serilog.PerformanceTests.csproj | 30 ++++++ .../Serilog.PerformanceTests.xproj | 21 ---- test/Serilog.PerformanceTests/project.json | 30 ------ test/Serilog.Tests/Serilog.Tests.csproj | 41 ++++++++ test/Serilog.Tests/Serilog.Tests.xproj | 21 ---- .../Settings/KeyValuePairSettingsTests.cs | 26 ----- test/Serilog.Tests/project.json | 39 -------- test/TestDummies/TestDummies.csproj | 24 +++++ test/TestDummies/TestDummies.xproj | 21 ---- test/TestDummies/project.json | 15 --- 17 files changed, 217 insertions(+), 300 deletions(-) create mode 100644 src/Serilog/Serilog.csproj delete mode 100644 src/Serilog/Serilog.xproj delete mode 100644 src/Serilog/project.json create mode 100644 test/Serilog.PerformanceTests/Serilog.PerformanceTests.csproj delete mode 100644 test/Serilog.PerformanceTests/Serilog.PerformanceTests.xproj delete mode 100755 test/Serilog.PerformanceTests/project.json create mode 100644 test/Serilog.Tests/Serilog.Tests.csproj delete mode 100644 test/Serilog.Tests/Serilog.Tests.xproj delete mode 100644 test/Serilog.Tests/project.json create mode 100644 test/TestDummies/TestDummies.csproj delete mode 100644 test/TestDummies/TestDummies.xproj delete mode 100644 test/TestDummies/project.json diff --git a/Serilog.sln b/Serilog.sln index 32d2b0d9b..e61cd6e07 100644 --- a/Serilog.sln +++ b/Serilog.sln @@ -1,12 +1,7 @@ - Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 +# Visual Studio 15 +VisualStudioVersion = 15.0.26127.3 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{037440DE-440B-4129-9F7A-09B42D00397E}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{0D135C0C-A60B-454A-A2F4-CD74A30E04B0}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "assets", "assets", "{E9D1B5E1-DEB9-4A04-8BAB-24EC7240ADAF}" ProjectSection(SolutionItems) = preProject .editorconfig = .editorconfig @@ -22,44 +17,84 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "assets", "assets", "{E9D1B5 assets\Serilog.snk = assets\Serilog.snk EndProjectSection EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Serilog", "src\Serilog\Serilog.xproj", "{803CD13A-D54B-4CEC-A55F-E22AE3D93B3C}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{791D4267-0D6F-4FDF-80F2-11F4E793B0F2}" +EndProject +Project("{13B669BE-BB05-4DDF-9536-439F39A36129}") = "Serilog", "src\Serilog\Serilog.csproj", "{AB00B377-9F1E-4D4B-B6B0-B95F53BCAEF1}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{290A2775-7CA0-4F81-9DDC-32E28C3A7565}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Serilog.Tests", "test\Serilog.Tests\Serilog.Tests.xproj", "{3C2D8E01-5580-426A-BDD9-EC59CD98E618}" +Project("{13B669BE-BB05-4DDF-9536-439F39A36129}") = "TestDummies", "test\TestDummies\TestDummies.csproj", "{37EF0B5E-0363-4A47-AF3E-51FA6E79E3CF}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "TestDummies", "test\TestDummies\TestDummies.xproj", "{2BB12CE5-C867-43BD-AE5D-253FE3248C7F}" +Project("{13B669BE-BB05-4DDF-9536-439F39A36129}") = "Serilog.Tests", "test\Serilog.Tests\Serilog.Tests.csproj", "{B11B911D-977A-42CE-900A-596CF59F6FFA}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Serilog.PerformanceTests", "test\Serilog.PerformanceTests\Serilog.PerformanceTests.xproj", "{D7A37F73-BBA3-4DAE-9648-1A753A86F968}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Serilog.PerformanceTests", "test\Serilog.PerformanceTests\Serilog.PerformanceTests.csproj", "{B4AC7ED9-517B-47E9-BB49-15F8A8478E62}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {803CD13A-D54B-4CEC-A55F-E22AE3D93B3C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {803CD13A-D54B-4CEC-A55F-E22AE3D93B3C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {803CD13A-D54B-4CEC-A55F-E22AE3D93B3C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {803CD13A-D54B-4CEC-A55F-E22AE3D93B3C}.Release|Any CPU.Build.0 = Release|Any CPU - {3C2D8E01-5580-426A-BDD9-EC59CD98E618}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3C2D8E01-5580-426A-BDD9-EC59CD98E618}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3C2D8E01-5580-426A-BDD9-EC59CD98E618}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3C2D8E01-5580-426A-BDD9-EC59CD98E618}.Release|Any CPU.Build.0 = Release|Any CPU - {2BB12CE5-C867-43BD-AE5D-253FE3248C7F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2BB12CE5-C867-43BD-AE5D-253FE3248C7F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2BB12CE5-C867-43BD-AE5D-253FE3248C7F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2BB12CE5-C867-43BD-AE5D-253FE3248C7F}.Release|Any CPU.Build.0 = Release|Any CPU - {D7A37F73-BBA3-4DAE-9648-1A753A86F968}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D7A37F73-BBA3-4DAE-9648-1A753A86F968}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D7A37F73-BBA3-4DAE-9648-1A753A86F968}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D7A37F73-BBA3-4DAE-9648-1A753A86F968}.Release|Any CPU.Build.0 = Release|Any CPU + {AB00B377-9F1E-4D4B-B6B0-B95F53BCAEF1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AB00B377-9F1E-4D4B-B6B0-B95F53BCAEF1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AB00B377-9F1E-4D4B-B6B0-B95F53BCAEF1}.Debug|x64.ActiveCfg = Debug|x64 + {AB00B377-9F1E-4D4B-B6B0-B95F53BCAEF1}.Debug|x64.Build.0 = Debug|x64 + {AB00B377-9F1E-4D4B-B6B0-B95F53BCAEF1}.Debug|x86.ActiveCfg = Debug|x86 + {AB00B377-9F1E-4D4B-B6B0-B95F53BCAEF1}.Debug|x86.Build.0 = Debug|x86 + {AB00B377-9F1E-4D4B-B6B0-B95F53BCAEF1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AB00B377-9F1E-4D4B-B6B0-B95F53BCAEF1}.Release|Any CPU.Build.0 = Release|Any CPU + {AB00B377-9F1E-4D4B-B6B0-B95F53BCAEF1}.Release|x64.ActiveCfg = Release|x64 + {AB00B377-9F1E-4D4B-B6B0-B95F53BCAEF1}.Release|x64.Build.0 = Release|x64 + {AB00B377-9F1E-4D4B-B6B0-B95F53BCAEF1}.Release|x86.ActiveCfg = Release|x86 + {AB00B377-9F1E-4D4B-B6B0-B95F53BCAEF1}.Release|x86.Build.0 = Release|x86 + {37EF0B5E-0363-4A47-AF3E-51FA6E79E3CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {37EF0B5E-0363-4A47-AF3E-51FA6E79E3CF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {37EF0B5E-0363-4A47-AF3E-51FA6E79E3CF}.Debug|x64.ActiveCfg = Debug|x64 + {37EF0B5E-0363-4A47-AF3E-51FA6E79E3CF}.Debug|x64.Build.0 = Debug|x64 + {37EF0B5E-0363-4A47-AF3E-51FA6E79E3CF}.Debug|x86.ActiveCfg = Debug|x86 + {37EF0B5E-0363-4A47-AF3E-51FA6E79E3CF}.Debug|x86.Build.0 = Debug|x86 + {37EF0B5E-0363-4A47-AF3E-51FA6E79E3CF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {37EF0B5E-0363-4A47-AF3E-51FA6E79E3CF}.Release|Any CPU.Build.0 = Release|Any CPU + {37EF0B5E-0363-4A47-AF3E-51FA6E79E3CF}.Release|x64.ActiveCfg = Release|x64 + {37EF0B5E-0363-4A47-AF3E-51FA6E79E3CF}.Release|x64.Build.0 = Release|x64 + {37EF0B5E-0363-4A47-AF3E-51FA6E79E3CF}.Release|x86.ActiveCfg = Release|x86 + {37EF0B5E-0363-4A47-AF3E-51FA6E79E3CF}.Release|x86.Build.0 = Release|x86 + {B11B911D-977A-42CE-900A-596CF59F6FFA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B11B911D-977A-42CE-900A-596CF59F6FFA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B11B911D-977A-42CE-900A-596CF59F6FFA}.Debug|x64.ActiveCfg = Debug|x64 + {B11B911D-977A-42CE-900A-596CF59F6FFA}.Debug|x64.Build.0 = Debug|x64 + {B11B911D-977A-42CE-900A-596CF59F6FFA}.Debug|x86.ActiveCfg = Debug|x86 + {B11B911D-977A-42CE-900A-596CF59F6FFA}.Debug|x86.Build.0 = Debug|x86 + {B11B911D-977A-42CE-900A-596CF59F6FFA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B11B911D-977A-42CE-900A-596CF59F6FFA}.Release|Any CPU.Build.0 = Release|Any CPU + {B11B911D-977A-42CE-900A-596CF59F6FFA}.Release|x64.ActiveCfg = Release|x64 + {B11B911D-977A-42CE-900A-596CF59F6FFA}.Release|x64.Build.0 = Release|x64 + {B11B911D-977A-42CE-900A-596CF59F6FFA}.Release|x86.ActiveCfg = Release|x86 + {B11B911D-977A-42CE-900A-596CF59F6FFA}.Release|x86.Build.0 = Release|x86 + {B4AC7ED9-517B-47E9-BB49-15F8A8478E62}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B4AC7ED9-517B-47E9-BB49-15F8A8478E62}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B4AC7ED9-517B-47E9-BB49-15F8A8478E62}.Debug|x64.ActiveCfg = Debug|x64 + {B4AC7ED9-517B-47E9-BB49-15F8A8478E62}.Debug|x64.Build.0 = Debug|x64 + {B4AC7ED9-517B-47E9-BB49-15F8A8478E62}.Debug|x86.ActiveCfg = Debug|x86 + {B4AC7ED9-517B-47E9-BB49-15F8A8478E62}.Debug|x86.Build.0 = Debug|x86 + {B4AC7ED9-517B-47E9-BB49-15F8A8478E62}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B4AC7ED9-517B-47E9-BB49-15F8A8478E62}.Release|Any CPU.Build.0 = Release|Any CPU + {B4AC7ED9-517B-47E9-BB49-15F8A8478E62}.Release|x64.ActiveCfg = Release|x64 + {B4AC7ED9-517B-47E9-BB49-15F8A8478E62}.Release|x64.Build.0 = Release|x64 + {B4AC7ED9-517B-47E9-BB49-15F8A8478E62}.Release|x86.ActiveCfg = Release|x86 + {B4AC7ED9-517B-47E9-BB49-15F8A8478E62}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {803CD13A-D54B-4CEC-A55F-E22AE3D93B3C} = {037440DE-440B-4129-9F7A-09B42D00397E} - {3C2D8E01-5580-426A-BDD9-EC59CD98E618} = {0D135C0C-A60B-454A-A2F4-CD74A30E04B0} - {2BB12CE5-C867-43BD-AE5D-253FE3248C7F} = {0D135C0C-A60B-454A-A2F4-CD74A30E04B0} - {D7A37F73-BBA3-4DAE-9648-1A753A86F968} = {0D135C0C-A60B-454A-A2F4-CD74A30E04B0} + {AB00B377-9F1E-4D4B-B6B0-B95F53BCAEF1} = {791D4267-0D6F-4FDF-80F2-11F4E793B0F2} + {37EF0B5E-0363-4A47-AF3E-51FA6E79E3CF} = {290A2775-7CA0-4F81-9DDC-32E28C3A7565} + {B11B911D-977A-42CE-900A-596CF59F6FFA} = {290A2775-7CA0-4F81-9DDC-32E28C3A7565} + {B4AC7ED9-517B-47E9-BB49-15F8A8478E62} = {290A2775-7CA0-4F81-9DDC-32E28C3A7565} EndGlobalSection EndGlobal diff --git a/appveyor.yml b/appveyor.yml index 185375dde..a6fda6025 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -4,9 +4,9 @@ image: Visual Studio 2015 configuration: Release install: - ps: mkdir -Force ".\build\" | Out-Null - - ps: Invoke-WebRequest "https://raw.githubusercontent.com/dotnet/cli/rel/1.0.0-preview2/scripts/obtain/dotnet-install.ps1" -OutFile ".\build\installcli.ps1" + - ps: Invoke-WebRequest "https://raw.githubusercontent.com/dotnet/cli/rel/1.0.0-rc3/scripts/obtain/dotnet-install.ps1" -OutFile ".\build\installcli.ps1" - ps: $env:DOTNET_INSTALL_DIR = "$pwd\.dotnetcli" - - ps: '& .\build\installcli.ps1 -InstallDir "$env:DOTNET_INSTALL_DIR" -NoPath -Version 1.0.0-preview2-003121' + - ps: '& .\build\installcli.ps1 -InstallDir "$env:DOTNET_INSTALL_DIR" -NoPath -Version 1.0.0-rc3-004530' - ps: $env:Path = "$env:DOTNET_INSTALL_DIR;$env:Path" build_script: - ps: ./Build.ps1 diff --git a/build.sh b/build.sh index ff84facad..0d185a815 100755 --- a/build.sh +++ b/build.sh @@ -1,17 +1,14 @@ #!/bin/bash dotnet restore -for path in src/*/project.json; do - dirname="$(dirname "${path}")" - dotnet build ${dirname} -c Release +for path in src/**/*.csproj; do + dotnet build -c Release ${path} done -for path in test/Serilog.Tests/project.json; do - dirname="$(dirname "${path}")" - dotnet build ${dirname} -f netcoreapp1.0 -c Release - dotnet test ${dirname} -f netcoreapp1.0 -c Release +for path in test/**/*.csproj; do + dotnet build -f netcoreapp1.0 -c Release ${path} + dotnet test -f netcoreapp1.0 -c Release ${path} done -for path in test/Serilog.PerformanceTests/project.json; do - dirname="$(dirname "${path}")" - dotnet build ${dirname} -f netcoreapp1.0 -c Release -done \ No newline at end of file +for path in test/Serilog.PerformanceTests/Serilog.PerformanceTests.csproj; do + dotnet build -f netcoreapp1.0 -c Release ${path} +done diff --git a/global.json b/global.json index a2b2a4152..e5f27bb8f 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "projects": [ "src", "test" ], "sdk": { - "version": "1.0.0-preview2-003121" + "version": "1.0.0-rc3-004530" } } diff --git a/src/Serilog/Serilog.csproj b/src/Serilog/Serilog.csproj new file mode 100644 index 000000000..7b38f1573 --- /dev/null +++ b/src/Serilog/Serilog.csproj @@ -0,0 +1,45 @@ + + + + Simple .NET logging with fully-structured events + 2.4.1 + Serilog Contributors + net45;net46;netstandard1.0;netstandard1.3 + true + Serilog + ../../assets/Serilog.snk + true + true + Serilog + serilog;logging;semantic;structured + http://serilog.net/images/serilog-nuget.png + http://serilog.net + http://www.apache.org/licenses/LICENSE-2.0 + false + + + + + + + + + + + + + + + + + $(DefineConstants);REMOTING;HASHTABLE + + + + $(DefineConstants);ASYNCLOCAL + + + + + + diff --git a/src/Serilog/Serilog.xproj b/src/Serilog/Serilog.xproj deleted file mode 100644 index 865914c3d..000000000 --- a/src/Serilog/Serilog.xproj +++ /dev/null @@ -1,17 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 803cd13a-d54b-4cec-a55f-e22ae3d93b3c - Serilog - .\obj - .\bin\ - - 2.0 - - - diff --git a/src/Serilog/project.json b/src/Serilog/project.json deleted file mode 100644 index 810666497..000000000 --- a/src/Serilog/project.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "version": "2.4.1-*", - - "description": "Simple .NET logging with fully-structured events", - "authors": [ "Serilog Contributors" ], - - "packOptions": { - "tags": [ "serilog", "logging", "semantic", "structured" ], - "projectUrl": "http://serilog.net", - "licenseUrl": "http://www.apache.org/licenses/LICENSE-2.0", - "iconUrl": "http://serilog.net/images/serilog-nuget.png" - }, - - "buildOptions": { - "keyFile": "../../assets/Serilog.snk", - "xmlDoc": true - }, - - "frameworks": { - "net4.5": { - "buildOptions": { - "define": [ "REMOTING", "HASHTABLE" ] - } - }, - "net4.6": { - "buildOptions": { - "define": [ "ASYNCLOCAL", "HASHTABLE" ] - } - }, - "netstandard1.0": { - "dependencies": { - "Microsoft.CSharp": "4.0.1", - "System.Collections": "4.0.11", - "System.Dynamic.Runtime": "4.0.11", - "System.Globalization": "4.0.11", - "System.Linq": "4.1.0", - "System.Reflection": "4.1.0", - "System.Reflection.Extensions": "4.0.1", - "System.Runtime": "4.1.0", - "System.Runtime.Extensions": "4.1.0", - "System.Text.RegularExpressions": "4.1.0", - "System.Threading": "4.0.11" - } - }, - "netstandard1.3": { - "buildOptions": { - "define": [ "ASYNCLOCAL", "HASHTABLE" ] - }, - "dependencies": { - "Microsoft.CSharp": "4.0.1", - "System.Collections": "4.0.11", - "System.Collections.NonGeneric": "4.0.1", - "System.Dynamic.Runtime": "4.0.11", - "System.Globalization": "4.0.11", - "System.Linq": "4.1.0", - "System.Reflection": "4.1.0", - "System.Reflection.Extensions": "4.0.1", - "System.Runtime": "4.1.0", - "System.Runtime.Extensions": "4.1.0", - "System.Text.RegularExpressions": "4.1.0", - "System.Threading": "4.0.11" - } - } - } -} diff --git a/test/Serilog.PerformanceTests/Serilog.PerformanceTests.csproj b/test/Serilog.PerformanceTests/Serilog.PerformanceTests.csproj new file mode 100644 index 000000000..39d94dfaf --- /dev/null +++ b/test/Serilog.PerformanceTests/Serilog.PerformanceTests.csproj @@ -0,0 +1,30 @@ + + + netcoreapp1.0;net452 + Serilog.PerformanceTests + ../../assets/Serilog.snk + true + true + Serilog.PerformanceTests + true + $(PackageTargetFallback);dnxcore50;portable-net45+win8 + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/Serilog.PerformanceTests/Serilog.PerformanceTests.xproj b/test/Serilog.PerformanceTests/Serilog.PerformanceTests.xproj deleted file mode 100644 index e84267546..000000000 --- a/test/Serilog.PerformanceTests/Serilog.PerformanceTests.xproj +++ /dev/null @@ -1,21 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - d7a37f73-bba3-4dae-9648-1a753a86f968 - Serilog.PerformanceTests - .\obj - .\bin\ - - - 2.0 - - - - - - \ No newline at end of file diff --git a/test/Serilog.PerformanceTests/project.json b/test/Serilog.PerformanceTests/project.json deleted file mode 100755 index 70bc3da6f..000000000 --- a/test/Serilog.PerformanceTests/project.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "testRunner": "xunit", - - "dependencies": { - "Serilog": { "target": "project" }, - "xunit": "2.1.0", - "dotnet-test-xunit": "1.0.0-rc2-build10025", - "BenchmarkDotNet": "0.9.9" - }, - "buildOptions": { - "keyFile": "../../assets/Serilog.snk" - }, - "frameworks": { - "netcoreapp1.0": { - "dependencies": { - "Microsoft.NETCore.App": { - "type": "platform", - "version": "1.0.0" - }, - "System.Collections": "4.0.11" - }, - "imports": [ - "dnxcore50", - "portable-net45+win8" - ] - }, - "net4.5.2": { - } - } -} diff --git a/test/Serilog.Tests/Serilog.Tests.csproj b/test/Serilog.Tests/Serilog.Tests.csproj new file mode 100644 index 000000000..f8676504b --- /dev/null +++ b/test/Serilog.Tests/Serilog.Tests.csproj @@ -0,0 +1,41 @@ + + + netcoreapp1.0;net452;net46 + Serilog.Tests + ../../assets/Serilog.snk + true + true + Serilog.Tests + true + $(PackageTargetFallback);dnxcore50;portable-net45+win8 + + + + + + + + + + + + + + + + + + + $(DefineConstants);APPDOMAIN;REMOTING;GETCURRENTMETHOD + + + $(DefineConstants);ASYNCLOCAL + + + + + + + + + \ No newline at end of file diff --git a/test/Serilog.Tests/Serilog.Tests.xproj b/test/Serilog.Tests/Serilog.Tests.xproj deleted file mode 100644 index f620d4de3..000000000 --- a/test/Serilog.Tests/Serilog.Tests.xproj +++ /dev/null @@ -1,21 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 3c2d8e01-5580-426a-bdd9-ec59cd98e618 - Serilog.Tests - .\obj - .\bin\ - - - 2.0 - - - - - - \ No newline at end of file diff --git a/test/Serilog.Tests/Settings/KeyValuePairSettingsTests.cs b/test/Serilog.Tests/Settings/KeyValuePairSettingsTests.cs index 7b57984e8..b1aed92b9 100644 --- a/test/Serilog.Tests/Settings/KeyValuePairSettingsTests.cs +++ b/test/Serilog.Tests/Settings/KeyValuePairSettingsTests.cs @@ -126,31 +126,5 @@ public void AuditSinksAreConfigured() Assert.Equal(1, DummyRollingFileAuditSink.Emitted.Count); } - [Fact] - public void TestMinimumLevelOverrides() { - var settings = new Dictionary - { - ["minimum-level:override:Microsoft"] = "Warning", - }; - - LogEvent evt = null; - - var log = new LoggerConfiguration() - .ReadFrom.KeyValuePairs(settings) - .WriteTo.Sink(new DelegatingSink(e => evt = e)) - .CreateLogger(); - - var microsoftLogger = log.ForContext(); - microsoftLogger.Write(Some.InformationEvent()); - - Assert.Null(evt); - - microsoftLogger.Warning("Bad things"); - Assert.NotNull(evt); - - evt = null; - log.Write(Some.InformationEvent()); - Assert.NotNull(evt); - } } } diff --git a/test/Serilog.Tests/project.json b/test/Serilog.Tests/project.json deleted file mode 100644 index f148cd108..000000000 --- a/test/Serilog.Tests/project.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "testRunner": "xunit", - - "dependencies": { - "Serilog": { "target": "project" }, - "TestDummies": { "target": "project" }, - "xunit": "2.1.0", - "dotnet-test-xunit": "1.0.0-rc2-build10025" - }, - - "buildOptions": { - "keyFile": "../../assets/Serilog.snk" - }, - "frameworks": { - "netcoreapp1.0": { - "define": [ "ASYNCLOCAL" ], - "dependencies": { - "Microsoft.NETCore.App": { - "type": "platform", - "version": "1.0.0" - } - }, - "imports": [ - "dnxcore50", - "portable-net45+win8" - ] - }, - "net4.5.2": { - "buildOptions": { - "define": [ "APPDOMAIN", "REMOTING", "GETCURRENTMETHOD" ] - } - }, - "net4.6": { - "buildOptions": { - "define": [ "ASYNCLOCAL", "APPDOMAIN", "GETCURRENTMETHOD" ] - } - } - } -} diff --git a/test/TestDummies/TestDummies.csproj b/test/TestDummies/TestDummies.csproj new file mode 100644 index 000000000..5f8ab00dc --- /dev/null +++ b/test/TestDummies/TestDummies.csproj @@ -0,0 +1,24 @@ + + + + net452;netstandard1.3 + TestDummies + ../../assets/Serilog.snk + true + true + TestDummies + false + false + false + + + + + + + + + + + + diff --git a/test/TestDummies/TestDummies.xproj b/test/TestDummies/TestDummies.xproj deleted file mode 100644 index 491d7aa12..000000000 --- a/test/TestDummies/TestDummies.xproj +++ /dev/null @@ -1,21 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - 2bb12ce5-c867-43bd-ae5d-253fe3248c7f - TestDummies - .\obj - .\bin\ - v4.5.2 - - - - 2.0 - - - diff --git a/test/TestDummies/project.json b/test/TestDummies/project.json deleted file mode 100644 index 6d498ef45..000000000 --- a/test/TestDummies/project.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "buildOptions": { - "keyFile": "../../assets/Serilog.snk" - }, - - "dependencies": { - "NETStandard.Library": "1.6.0", - "Serilog": { "target": "project" } - }, - - "frameworks": { - "net4.5.2": { }, - "netstandard1.3": {} - } -} From e89d7cb81210bc91036ce9b832aab56501922841 Mon Sep 17 00:00:00 2001 From: Adam Chester Date: Sat, 11 Feb 2017 12:17:48 +1000 Subject: [PATCH 03/58] Tooling RC4-004771 --- .travis.yml | 4 ++-- Serilog.sln | 3 ++- appveyor.yml | 4 ++-- global.json | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 562d018d5..1565b4526 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,10 +5,10 @@ matrix: - os: linux # Ubuntu 14.04 dist: trusty sudo: required - dotnet: 1.0.0-preview2-003121 + dotnet: 1.0.0-rc4-004771 - os: osx # OSX 10.11 osx_image: xcode7.2 - dotnet: 1.0.0-preview2-003121 + dotnet: 1.0.0-rc4-004771 script: - ./build.sh \ No newline at end of file diff --git a/Serilog.sln b/Serilog.sln index e61cd6e07..086baa1a7 100644 --- a/Serilog.sln +++ b/Serilog.sln @@ -1,10 +1,11 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26127.3 +VisualStudioVersion = 15.0.26206.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "assets", "assets", "{E9D1B5E1-DEB9-4A04-8BAB-24EC7240ADAF}" ProjectSection(SolutionItems) = preProject .editorconfig = .editorconfig + .travis.yml = .travis.yml appveyor.yml = appveyor.yml Build.ps1 = Build.ps1 build.sh = build.sh diff --git a/appveyor.yml b/appveyor.yml index a6fda6025..8ddc4e07f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -4,9 +4,9 @@ image: Visual Studio 2015 configuration: Release install: - ps: mkdir -Force ".\build\" | Out-Null - - ps: Invoke-WebRequest "https://raw.githubusercontent.com/dotnet/cli/rel/1.0.0-rc3/scripts/obtain/dotnet-install.ps1" -OutFile ".\build\installcli.ps1" + - ps: Invoke-WebRequest "https://raw.githubusercontent.com/dotnet/cli/rel/1.0.0-rc4/scripts/obtain/dotnet-install.ps1" -OutFile ".\build\installcli.ps1" - ps: $env:DOTNET_INSTALL_DIR = "$pwd\.dotnetcli" - - ps: '& .\build\installcli.ps1 -InstallDir "$env:DOTNET_INSTALL_DIR" -NoPath -Version 1.0.0-rc3-004530' + - ps: '& .\build\installcli.ps1 -InstallDir "$env:DOTNET_INSTALL_DIR" -NoPath -Version 1.0.0-rc4-004771' - ps: $env:Path = "$env:DOTNET_INSTALL_DIR;$env:Path" build_script: - ps: ./Build.ps1 diff --git a/global.json b/global.json index e5f27bb8f..490585a9d 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "projects": [ "src", "test" ], "sdk": { - "version": "1.0.0-rc3-004530" + "version": "1.0.0-rc4-004771" } } From b0b5eee5c367867ddab20391a3c9ee149afeec62 Mon Sep 17 00:00:00 2001 From: Adam Chester Date: Sat, 11 Feb 2017 12:18:19 +1000 Subject: [PATCH 04/58] Bring back `TestMinimumLevelOverrides` --- .../Settings/KeyValuePairSettingsTests.cs | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/test/Serilog.Tests/Settings/KeyValuePairSettingsTests.cs b/test/Serilog.Tests/Settings/KeyValuePairSettingsTests.cs index b1aed92b9..ffb974378 100644 --- a/test/Serilog.Tests/Settings/KeyValuePairSettingsTests.cs +++ b/test/Serilog.Tests/Settings/KeyValuePairSettingsTests.cs @@ -24,7 +24,7 @@ public void FindsConfigurationAssemblies() // The core Serilog assembly is always considered Assert.Equal(1, configurationAssemblies.Count); - } + } [Fact] public void PropertyEnrichmentIsApplied() @@ -126,5 +126,34 @@ public void AuditSinksAreConfigured() Assert.Equal(1, DummyRollingFileAuditSink.Emitted.Count); } + [Fact] + public void TestMinimumLevelOverrides() + { + var settings = new Dictionary + + { + ["minimum-level:override:System"] = "Warning", + }; + + LogEvent evt = null; + + var log = new LoggerConfiguration() + .ReadFrom.KeyValuePairs(settings) + .WriteTo.Sink(new DelegatingSink(e => evt = e)) + .CreateLogger(); + + var systemLogger = log.ForContext(); + systemLogger.Write(Some.InformationEvent()); + + Assert.Null(evt); + + systemLogger.Warning("Bad things"); + Assert.NotNull(evt); + + evt = null; + log.Write(Some.InformationEvent()); + Assert.NotNull(evt); + } + } } From 079a2265d08f465a168672df19998cc8a691588d Mon Sep 17 00:00:00 2001 From: Adam Chester Date: Sat, 11 Feb 2017 12:23:44 +1000 Subject: [PATCH 05/58] Remove `rc4` from the dotnet cli install script path --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 8ddc4e07f..5ac0604c9 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -4,7 +4,7 @@ image: Visual Studio 2015 configuration: Release install: - ps: mkdir -Force ".\build\" | Out-Null - - ps: Invoke-WebRequest "https://raw.githubusercontent.com/dotnet/cli/rel/1.0.0-rc4/scripts/obtain/dotnet-install.ps1" -OutFile ".\build\installcli.ps1" + - ps: Invoke-WebRequest "https://raw.githubusercontent.com/dotnet/cli/rel/1.0.0/scripts/obtain/dotnet-install.ps1" -OutFile ".\build\installcli.ps1" - ps: $env:DOTNET_INSTALL_DIR = "$pwd\.dotnetcli" - ps: '& .\build\installcli.ps1 -InstallDir "$env:DOTNET_INSTALL_DIR" -NoPath -Version 1.0.0-rc4-004771' - ps: $env:Path = "$env:DOTNET_INSTALL_DIR;$env:Path" From ee98b3e77ac6202fa90c59a501fa42aab34dd897 Mon Sep 17 00:00:00 2001 From: Adam Chester Date: Tue, 14 Feb 2017 20:38:20 +1000 Subject: [PATCH 06/58] Fix `netstandard1.3` defines and references --- src/Serilog/Serilog.csproj | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Serilog/Serilog.csproj b/src/Serilog/Serilog.csproj index 7b38f1573..8315519dc 100644 --- a/src/Serilog/Serilog.csproj +++ b/src/Serilog/Serilog.csproj @@ -39,7 +39,12 @@ $(DefineConstants);ASYNCLOCAL + + $(DefineConstants);ASYNCLOCAL;HASHTABLE + + + From 6087532764e364516226b63fc6ee510f5d3dc222 Mon Sep 17 00:00:00 2001 From: Adam Chester Date: Tue, 14 Feb 2017 20:38:53 +1000 Subject: [PATCH 07/58] travis: use `osx_image` = `xcode7.3`, because `xcode7.2` is deprecated --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 1565b4526..7170ffafe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ matrix: sudo: required dotnet: 1.0.0-rc4-004771 - os: osx # OSX 10.11 - osx_image: xcode7.2 + osx_image: xcode7.3 dotnet: 1.0.0-rc4-004771 script: From 273c191623015e2a5b31005abe3e03bce22ee58b Mon Sep 17 00:00:00 2001 From: Adam Chester Date: Tue, 14 Feb 2017 20:56:56 +1000 Subject: [PATCH 08/58] Adjust codcov test command --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 5ac0604c9..180e92536 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -12,7 +12,7 @@ build_script: - ps: ./Build.ps1 test_script: - nuget.exe install OpenCover -ExcludeVersion - - OpenCover\tools\OpenCover.Console.exe -register:user -filter:"+[Serilog]*" -target:"dotnet.exe" "-targetargs:test test\Serilog.Tests" -returntargetcode -hideskipped:All -output:coverage.xml + - OpenCover\tools\OpenCover.Console.exe -register:user -filter:"+[Serilog]*" -target:"dotnet.exe" "-targetargs:test test\Serilog.Tests\Serilog.Tests.csproj" -returntargetcode -hideskipped:All -output:coverage.xml - "SET PATH=C:\\Python34;C:\\Python34\\Scripts;%PATH%" - pip install codecov - codecov -f "coverage.xml" From df69837d6ce6e2c09597b58726194e5d7f294c19 Mon Sep 17 00:00:00 2001 From: Adam Chester Date: Sun, 5 Mar 2017 08:11:55 +1000 Subject: [PATCH 09/58] Fix travis build, remove OpenCover --- .travis.yml | 6 ++++-- appveyor.yml | 6 ------ build.cmd | 1 + build.sh | 8 ++++++++ 4 files changed, 13 insertions(+), 8 deletions(-) create mode 100644 build.cmd diff --git a/.travis.yml b/.travis.yml index 7170ffafe..15fad5c21 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,10 +5,12 @@ matrix: - os: linux # Ubuntu 14.04 dist: trusty sudo: required - dotnet: 1.0.0-rc4-004771 + dotnet: 1.0.0-preview2-003121 + CLI_VERSION: 1.0.0-rc4-004771 - os: osx # OSX 10.11 osx_image: xcode7.3 - dotnet: 1.0.0-rc4-004771 + dotnet: 1.0.0-preview2-003121 + CLI_VERSION: 1.0.0-rc4-004771 script: - ./build.sh \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml index 180e92536..af782b38a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -10,12 +10,6 @@ install: - ps: $env:Path = "$env:DOTNET_INSTALL_DIR;$env:Path" build_script: - ps: ./Build.ps1 -test_script: - - nuget.exe install OpenCover -ExcludeVersion - - OpenCover\tools\OpenCover.Console.exe -register:user -filter:"+[Serilog]*" -target:"dotnet.exe" "-targetargs:test test\Serilog.Tests\Serilog.Tests.csproj" -returntargetcode -hideskipped:All -output:coverage.xml - - "SET PATH=C:\\Python34;C:\\Python34\\Scripts;%PATH%" - - pip install codecov - - codecov -f "coverage.xml" artifacts: - path: artifacts/Serilog.*.nupkg deploy: diff --git a/build.cmd b/build.cmd new file mode 100644 index 000000000..29af91cd3 --- /dev/null +++ b/build.cmd @@ -0,0 +1 @@ +@powershell .\Build.ps1 %* \ No newline at end of file diff --git a/build.sh b/build.sh index 0d185a815..546235185 100755 --- a/build.sh +++ b/build.sh @@ -1,5 +1,13 @@ #!/bin/bash +export DOTNET_INSTALL_DIR="$PWD/.dotnetcli" +DotnetCliVersion=${CLI_VERSION:="1.0.0-rc4-004771"} +install_script_url=https://raw.githubusercontent.com/dotnet/cli/rel/1.0.0/scripts/obtain/dotnet-install.sh +curl -sSL $install_script_url | bash /dev/stdin --version "$DotnetCliVersion" --install-dir "$DOTNET_INSTALL_DIR" +export PATH="$DOTNET_INSTALL_DIR:$PATH" + +dotnet --info dotnet restore + for path in src/**/*.csproj; do dotnet build -c Release ${path} done From 1dfb049b23517aa69ebddb92e64a64161324ace9 Mon Sep 17 00:00:00 2001 From: Adam Chester Date: Sun, 5 Mar 2017 08:18:05 +1000 Subject: [PATCH 10/58] Stop using beta test libraries --- .../Serilog.PerformanceTests.csproj | 6 +++--- test/Serilog.Tests/Serilog.Tests.csproj | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/Serilog.PerformanceTests/Serilog.PerformanceTests.csproj b/test/Serilog.PerformanceTests/Serilog.PerformanceTests.csproj index 39d94dfaf..4aff922fa 100644 --- a/test/Serilog.PerformanceTests/Serilog.PerformanceTests.csproj +++ b/test/Serilog.PerformanceTests/Serilog.PerformanceTests.csproj @@ -13,9 +13,9 @@ - - - + + + diff --git a/test/Serilog.Tests/Serilog.Tests.csproj b/test/Serilog.Tests/Serilog.Tests.csproj index f8676504b..dfa074061 100644 --- a/test/Serilog.Tests/Serilog.Tests.csproj +++ b/test/Serilog.Tests/Serilog.Tests.csproj @@ -14,10 +14,10 @@ - + - - + + From b2b95aa4c97f09e73d2309fe5420e151ef8a6eab Mon Sep 17 00:00:00 2001 From: Adam Chester Date: Sun, 5 Mar 2017 08:30:11 +1000 Subject: [PATCH 11/58] Improve travis(osx/linux) build --- .gitignore | 1 + build.sh | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 8ff53697f..bcaad9494 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,7 @@ bld/ [Bb]in/ [Oo]bj/ BenchmarkDotNet.Artifacts/ +.dotnetcli/ # Visual Studio 2015 cache/options directory .vs/ diff --git a/build.sh b/build.sh index 546235185..829d1d287 100755 --- a/build.sh +++ b/build.sh @@ -9,14 +9,14 @@ dotnet --info dotnet restore for path in src/**/*.csproj; do - dotnet build -c Release ${path} + dotnet build -f netstandard1.0 -c Release ${path} + dotnet build -f netstandard1.3 -c Release ${path} done -for path in test/**/*.csproj; do - dotnet build -f netcoreapp1.0 -c Release ${path} +for path in test/Serilog.Tests/*.csproj; do dotnet test -f netcoreapp1.0 -c Release ${path} done -for path in test/Serilog.PerformanceTests/Serilog.PerformanceTests.csproj; do - dotnet build -f netcoreapp1.0 -c Release ${path} -done +# for path in test/Serilog.PerformanceTests/Serilog.PerformanceTests.csproj; do +# dotnet test -f netcoreapp1.0 -c Release ${path} +# done From 76f599e2fc08926f1bc948e8d8ca9381888613cc Mon Sep 17 00:00:00 2001 From: Adam Chester Date: Sun, 5 Mar 2017 11:22:17 +1000 Subject: [PATCH 12/58] Produce symbol packages again --- Build.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Build.ps1 b/Build.ps1 index 55db40f54..27729c8e1 100644 --- a/Build.ps1 +++ b/Build.ps1 @@ -24,7 +24,7 @@ foreach ($src in ls src/*) { echo "build: Packaging project in $src" & dotnet build -c Release --version-suffix=$buildSuffix - & dotnet pack -c Release -o ..\..\artifacts --version-suffix=$suffix --no-build + & dotnet pack -c Release --include-symbols -o ..\..\artifacts --version-suffix=$suffix --no-build if($LASTEXITCODE -ne 0) { exit 1 } Pop-Location From 33ae3ec1b98f2c221932e643fe411f88b31a817f Mon Sep 17 00:00:00 2001 From: Adam Chester Date: Sun, 5 Mar 2017 11:29:15 +1000 Subject: [PATCH 13/58] Perf tests: BDN 0.10.3 + netcoreapp1.1 --- Build.ps1 | 16 ++++++++-------- build.sh | 8 ++++---- .../Serilog.PerformanceTests.csproj | 8 +++++--- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/Build.ps1 b/Build.ps1 index 27729c8e1..648b06823 100644 --- a/Build.ps1 +++ b/Build.ps1 @@ -30,24 +30,24 @@ foreach ($src in ls src/*) { Pop-Location } -foreach ($test in ls test/*.PerformanceTests) { +foreach ($test in ls test/*.Tests) { Push-Location $test - echo "build: Building performance test project in $test" + echo "build: Testing project in $test" - & dotnet build -c Release - if($LASTEXITCODE -ne 0) { exit 2 } + & dotnet test -c Release + if($LASTEXITCODE -ne 0) { exit 3 } Pop-Location } -foreach ($test in ls test/*.Tests) { +foreach ($test in ls test/*.PerformanceTests) { Push-Location $test - echo "build: Testing project in $test" + echo "build: Building performance test project in $test" - & dotnet test -c Release - if($LASTEXITCODE -ne 0) { exit 3 } + & dotnet build -c Release + if($LASTEXITCODE -ne 0) { exit 2 } Pop-Location } diff --git a/build.sh b/build.sh index 829d1d287..f75d3c686 100755 --- a/build.sh +++ b/build.sh @@ -13,10 +13,10 @@ for path in src/**/*.csproj; do dotnet build -f netstandard1.3 -c Release ${path} done -for path in test/Serilog.Tests/*.csproj; do +for path in test/*.Tests/*.csproj; do dotnet test -f netcoreapp1.0 -c Release ${path} done -# for path in test/Serilog.PerformanceTests/Serilog.PerformanceTests.csproj; do -# dotnet test -f netcoreapp1.0 -c Release ${path} -# done +for path in test/*.PerformanceTests/*.PerformanceTests.csproj; do + dotnet test -f netcoreapp1.1 -c Release ${path} +done diff --git a/test/Serilog.PerformanceTests/Serilog.PerformanceTests.csproj b/test/Serilog.PerformanceTests/Serilog.PerformanceTests.csproj index 4aff922fa..9b54fe0d9 100644 --- a/test/Serilog.PerformanceTests/Serilog.PerformanceTests.csproj +++ b/test/Serilog.PerformanceTests/Serilog.PerformanceTests.csproj @@ -1,13 +1,15 @@  - netcoreapp1.0;net452 + netcoreapp1.1;net452 Serilog.PerformanceTests ../../assets/Serilog.snk true true Serilog.PerformanceTests true - $(PackageTargetFallback);dnxcore50;portable-net45+win8 + + $(PackageTargetFallback);dnxcore50;portable-net45+win8 + @@ -16,7 +18,7 @@ - + From 7b2c70f7383c2768a6f1242b4952627852d59b61 Mon Sep 17 00:00:00 2001 From: Adam Chester Date: Sun, 5 Mar 2017 11:43:25 +1000 Subject: [PATCH 14/58] Prevent appveyor from auto-running tests --- appveyor.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/appveyor.yml b/appveyor.yml index af782b38a..47092aa4a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -8,6 +8,7 @@ install: - ps: $env:DOTNET_INSTALL_DIR = "$pwd\.dotnetcli" - ps: '& .\build\installcli.ps1 -InstallDir "$env:DOTNET_INSTALL_DIR" -NoPath -Version 1.0.0-rc4-004771' - ps: $env:Path = "$env:DOTNET_INSTALL_DIR;$env:Path" +test: off build_script: - ps: ./Build.ps1 artifacts: From a825eff70dd9654d2ded6045567a4f5ddd176ac7 Mon Sep 17 00:00:00 2001 From: Adam Chester Date: Sun, 5 Mar 2017 11:52:32 +1000 Subject: [PATCH 15/58] Only build perf tests on OSX/Linux (not run) --- build.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build.sh b/build.sh index f75d3c686..f48816514 100755 --- a/build.sh +++ b/build.sh @@ -18,5 +18,6 @@ for path in test/*.Tests/*.csproj; do done for path in test/*.PerformanceTests/*.PerformanceTests.csproj; do - dotnet test -f netcoreapp1.1 -c Release ${path} + dotnet build -f netcoreapp1.1 -c Release ${path} + # dotnet test -f netcoreapp1.1 -c Release ${path} done From 5ee4695d11d12338c0f0b936d16d24194c5761b3 Mon Sep 17 00:00:00 2001 From: Adam Chester Date: Sun, 5 Mar 2017 12:07:14 +1000 Subject: [PATCH 16/58] Increase ulimit --- build.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build.sh b/build.sh index f48816514..faa23c867 100755 --- a/build.sh +++ b/build.sh @@ -5,6 +5,9 @@ install_script_url=https://raw.githubusercontent.com/dotnet/cli/rel/1.0.0/script curl -sSL $install_script_url | bash /dev/stdin --version "$DotnetCliVersion" --install-dir "$DOTNET_INSTALL_DIR" export PATH="$DOTNET_INSTALL_DIR:$PATH" +# See issue https://github.com/NuGet/Home/issues/2163 +ulimit -n 2048 + dotnet --info dotnet restore From 64d1fe01eb93a1f920d2a62cf688dd9b04f06641 Mon Sep 17 00:00:00 2001 From: Adam Chester Date: Wed, 8 Mar 2017 11:10:35 +1000 Subject: [PATCH 17/58] Update CLI to 1.0.0 --- .travis.yml | 4 ++-- Serilog.sln | 66 ++++++++++++++++++++++++++-------------------------- appveyor.yml | 2 +- build.sh | 2 +- global.json | 2 +- 5 files changed, 38 insertions(+), 38 deletions(-) diff --git a/.travis.yml b/.travis.yml index 15fad5c21..b153fb9e6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,11 +6,11 @@ matrix: dist: trusty sudo: required dotnet: 1.0.0-preview2-003121 - CLI_VERSION: 1.0.0-rc4-004771 + CLI_VERSION: 1.0.0 - os: osx # OSX 10.11 osx_image: xcode7.3 dotnet: 1.0.0-preview2-003121 - CLI_VERSION: 1.0.0-rc4-004771 + CLI_VERSION: 1.0.0 script: - ./build.sh \ No newline at end of file diff --git a/Serilog.sln b/Serilog.sln index 086baa1a7..1e8496923 100644 --- a/Serilog.sln +++ b/Serilog.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26206.0 +VisualStudioVersion = 15.0.26228.4 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "assets", "assets", "{E9D1B5E1-DEB9-4A04-8BAB-24EC7240ADAF}" ProjectSection(SolutionItems) = preProject @@ -42,52 +42,52 @@ Global GlobalSection(ProjectConfigurationPlatforms) = postSolution {AB00B377-9F1E-4D4B-B6B0-B95F53BCAEF1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AB00B377-9F1E-4D4B-B6B0-B95F53BCAEF1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AB00B377-9F1E-4D4B-B6B0-B95F53BCAEF1}.Debug|x64.ActiveCfg = Debug|x64 - {AB00B377-9F1E-4D4B-B6B0-B95F53BCAEF1}.Debug|x64.Build.0 = Debug|x64 - {AB00B377-9F1E-4D4B-B6B0-B95F53BCAEF1}.Debug|x86.ActiveCfg = Debug|x86 - {AB00B377-9F1E-4D4B-B6B0-B95F53BCAEF1}.Debug|x86.Build.0 = Debug|x86 + {AB00B377-9F1E-4D4B-B6B0-B95F53BCAEF1}.Debug|x64.ActiveCfg = Debug|Any CPU + {AB00B377-9F1E-4D4B-B6B0-B95F53BCAEF1}.Debug|x64.Build.0 = Debug|Any CPU + {AB00B377-9F1E-4D4B-B6B0-B95F53BCAEF1}.Debug|x86.ActiveCfg = Debug|Any CPU + {AB00B377-9F1E-4D4B-B6B0-B95F53BCAEF1}.Debug|x86.Build.0 = Debug|Any CPU {AB00B377-9F1E-4D4B-B6B0-B95F53BCAEF1}.Release|Any CPU.ActiveCfg = Release|Any CPU {AB00B377-9F1E-4D4B-B6B0-B95F53BCAEF1}.Release|Any CPU.Build.0 = Release|Any CPU - {AB00B377-9F1E-4D4B-B6B0-B95F53BCAEF1}.Release|x64.ActiveCfg = Release|x64 - {AB00B377-9F1E-4D4B-B6B0-B95F53BCAEF1}.Release|x64.Build.0 = Release|x64 - {AB00B377-9F1E-4D4B-B6B0-B95F53BCAEF1}.Release|x86.ActiveCfg = Release|x86 - {AB00B377-9F1E-4D4B-B6B0-B95F53BCAEF1}.Release|x86.Build.0 = Release|x86 + {AB00B377-9F1E-4D4B-B6B0-B95F53BCAEF1}.Release|x64.ActiveCfg = Release|Any CPU + {AB00B377-9F1E-4D4B-B6B0-B95F53BCAEF1}.Release|x64.Build.0 = Release|Any CPU + {AB00B377-9F1E-4D4B-B6B0-B95F53BCAEF1}.Release|x86.ActiveCfg = Release|Any CPU + {AB00B377-9F1E-4D4B-B6B0-B95F53BCAEF1}.Release|x86.Build.0 = Release|Any CPU {37EF0B5E-0363-4A47-AF3E-51FA6E79E3CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {37EF0B5E-0363-4A47-AF3E-51FA6E79E3CF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {37EF0B5E-0363-4A47-AF3E-51FA6E79E3CF}.Debug|x64.ActiveCfg = Debug|x64 - {37EF0B5E-0363-4A47-AF3E-51FA6E79E3CF}.Debug|x64.Build.0 = Debug|x64 - {37EF0B5E-0363-4A47-AF3E-51FA6E79E3CF}.Debug|x86.ActiveCfg = Debug|x86 - {37EF0B5E-0363-4A47-AF3E-51FA6E79E3CF}.Debug|x86.Build.0 = Debug|x86 + {37EF0B5E-0363-4A47-AF3E-51FA6E79E3CF}.Debug|x64.ActiveCfg = Debug|Any CPU + {37EF0B5E-0363-4A47-AF3E-51FA6E79E3CF}.Debug|x64.Build.0 = Debug|Any CPU + {37EF0B5E-0363-4A47-AF3E-51FA6E79E3CF}.Debug|x86.ActiveCfg = Debug|Any CPU + {37EF0B5E-0363-4A47-AF3E-51FA6E79E3CF}.Debug|x86.Build.0 = Debug|Any CPU {37EF0B5E-0363-4A47-AF3E-51FA6E79E3CF}.Release|Any CPU.ActiveCfg = Release|Any CPU {37EF0B5E-0363-4A47-AF3E-51FA6E79E3CF}.Release|Any CPU.Build.0 = Release|Any CPU - {37EF0B5E-0363-4A47-AF3E-51FA6E79E3CF}.Release|x64.ActiveCfg = Release|x64 - {37EF0B5E-0363-4A47-AF3E-51FA6E79E3CF}.Release|x64.Build.0 = Release|x64 - {37EF0B5E-0363-4A47-AF3E-51FA6E79E3CF}.Release|x86.ActiveCfg = Release|x86 - {37EF0B5E-0363-4A47-AF3E-51FA6E79E3CF}.Release|x86.Build.0 = Release|x86 + {37EF0B5E-0363-4A47-AF3E-51FA6E79E3CF}.Release|x64.ActiveCfg = Release|Any CPU + {37EF0B5E-0363-4A47-AF3E-51FA6E79E3CF}.Release|x64.Build.0 = Release|Any CPU + {37EF0B5E-0363-4A47-AF3E-51FA6E79E3CF}.Release|x86.ActiveCfg = Release|Any CPU + {37EF0B5E-0363-4A47-AF3E-51FA6E79E3CF}.Release|x86.Build.0 = Release|Any CPU {B11B911D-977A-42CE-900A-596CF59F6FFA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B11B911D-977A-42CE-900A-596CF59F6FFA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B11B911D-977A-42CE-900A-596CF59F6FFA}.Debug|x64.ActiveCfg = Debug|x64 - {B11B911D-977A-42CE-900A-596CF59F6FFA}.Debug|x64.Build.0 = Debug|x64 - {B11B911D-977A-42CE-900A-596CF59F6FFA}.Debug|x86.ActiveCfg = Debug|x86 - {B11B911D-977A-42CE-900A-596CF59F6FFA}.Debug|x86.Build.0 = Debug|x86 + {B11B911D-977A-42CE-900A-596CF59F6FFA}.Debug|x64.ActiveCfg = Debug|Any CPU + {B11B911D-977A-42CE-900A-596CF59F6FFA}.Debug|x64.Build.0 = Debug|Any CPU + {B11B911D-977A-42CE-900A-596CF59F6FFA}.Debug|x86.ActiveCfg = Debug|Any CPU + {B11B911D-977A-42CE-900A-596CF59F6FFA}.Debug|x86.Build.0 = Debug|Any CPU {B11B911D-977A-42CE-900A-596CF59F6FFA}.Release|Any CPU.ActiveCfg = Release|Any CPU {B11B911D-977A-42CE-900A-596CF59F6FFA}.Release|Any CPU.Build.0 = Release|Any CPU - {B11B911D-977A-42CE-900A-596CF59F6FFA}.Release|x64.ActiveCfg = Release|x64 - {B11B911D-977A-42CE-900A-596CF59F6FFA}.Release|x64.Build.0 = Release|x64 - {B11B911D-977A-42CE-900A-596CF59F6FFA}.Release|x86.ActiveCfg = Release|x86 - {B11B911D-977A-42CE-900A-596CF59F6FFA}.Release|x86.Build.0 = Release|x86 + {B11B911D-977A-42CE-900A-596CF59F6FFA}.Release|x64.ActiveCfg = Release|Any CPU + {B11B911D-977A-42CE-900A-596CF59F6FFA}.Release|x64.Build.0 = Release|Any CPU + {B11B911D-977A-42CE-900A-596CF59F6FFA}.Release|x86.ActiveCfg = Release|Any CPU + {B11B911D-977A-42CE-900A-596CF59F6FFA}.Release|x86.Build.0 = Release|Any CPU {B4AC7ED9-517B-47E9-BB49-15F8A8478E62}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B4AC7ED9-517B-47E9-BB49-15F8A8478E62}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B4AC7ED9-517B-47E9-BB49-15F8A8478E62}.Debug|x64.ActiveCfg = Debug|x64 - {B4AC7ED9-517B-47E9-BB49-15F8A8478E62}.Debug|x64.Build.0 = Debug|x64 - {B4AC7ED9-517B-47E9-BB49-15F8A8478E62}.Debug|x86.ActiveCfg = Debug|x86 - {B4AC7ED9-517B-47E9-BB49-15F8A8478E62}.Debug|x86.Build.0 = Debug|x86 + {B4AC7ED9-517B-47E9-BB49-15F8A8478E62}.Debug|x64.ActiveCfg = Debug|Any CPU + {B4AC7ED9-517B-47E9-BB49-15F8A8478E62}.Debug|x64.Build.0 = Debug|Any CPU + {B4AC7ED9-517B-47E9-BB49-15F8A8478E62}.Debug|x86.ActiveCfg = Debug|Any CPU + {B4AC7ED9-517B-47E9-BB49-15F8A8478E62}.Debug|x86.Build.0 = Debug|Any CPU {B4AC7ED9-517B-47E9-BB49-15F8A8478E62}.Release|Any CPU.ActiveCfg = Release|Any CPU {B4AC7ED9-517B-47E9-BB49-15F8A8478E62}.Release|Any CPU.Build.0 = Release|Any CPU - {B4AC7ED9-517B-47E9-BB49-15F8A8478E62}.Release|x64.ActiveCfg = Release|x64 - {B4AC7ED9-517B-47E9-BB49-15F8A8478E62}.Release|x64.Build.0 = Release|x64 - {B4AC7ED9-517B-47E9-BB49-15F8A8478E62}.Release|x86.ActiveCfg = Release|x86 - {B4AC7ED9-517B-47E9-BB49-15F8A8478E62}.Release|x86.Build.0 = Release|x86 + {B4AC7ED9-517B-47E9-BB49-15F8A8478E62}.Release|x64.ActiveCfg = Release|Any CPU + {B4AC7ED9-517B-47E9-BB49-15F8A8478E62}.Release|x64.Build.0 = Release|Any CPU + {B4AC7ED9-517B-47E9-BB49-15F8A8478E62}.Release|x86.ActiveCfg = Release|Any CPU + {B4AC7ED9-517B-47E9-BB49-15F8A8478E62}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/appveyor.yml b/appveyor.yml index 47092aa4a..6c3d55e65 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -6,7 +6,7 @@ install: - ps: mkdir -Force ".\build\" | Out-Null - ps: Invoke-WebRequest "https://raw.githubusercontent.com/dotnet/cli/rel/1.0.0/scripts/obtain/dotnet-install.ps1" -OutFile ".\build\installcli.ps1" - ps: $env:DOTNET_INSTALL_DIR = "$pwd\.dotnetcli" - - ps: '& .\build\installcli.ps1 -InstallDir "$env:DOTNET_INSTALL_DIR" -NoPath -Version 1.0.0-rc4-004771' + - ps: '& .\build\installcli.ps1 -InstallDir "$env:DOTNET_INSTALL_DIR" -NoPath -Version 1.0.0' - ps: $env:Path = "$env:DOTNET_INSTALL_DIR;$env:Path" test: off build_script: diff --git a/build.sh b/build.sh index faa23c867..100633557 100755 --- a/build.sh +++ b/build.sh @@ -1,6 +1,6 @@ #!/bin/bash export DOTNET_INSTALL_DIR="$PWD/.dotnetcli" -DotnetCliVersion=${CLI_VERSION:="1.0.0-rc4-004771"} +DotnetCliVersion=${CLI_VERSION:="1.0.0"} install_script_url=https://raw.githubusercontent.com/dotnet/cli/rel/1.0.0/scripts/obtain/dotnet-install.sh curl -sSL $install_script_url | bash /dev/stdin --version "$DotnetCliVersion" --install-dir "$DOTNET_INSTALL_DIR" export PATH="$DOTNET_INSTALL_DIR:$PATH" diff --git a/global.json b/global.json index 490585a9d..6cedd685d 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "projects": [ "src", "test" ], "sdk": { - "version": "1.0.0-rc4-004771" + "version": "1.0.0" } } From e67472698d97ac703739b1780070cf08e66ef5cf Mon Sep 17 00:00:00 2001 From: Adam Chester Date: Wed, 8 Mar 2017 11:35:30 +1000 Subject: [PATCH 18/58] DisableImplicitFrameworkReferences --- src/Serilog/Serilog.csproj | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/Serilog/Serilog.csproj b/src/Serilog/Serilog.csproj index 8315519dc..772e0ecef 100644 --- a/src/Serilog/Serilog.csproj +++ b/src/Serilog/Serilog.csproj @@ -16,8 +16,10 @@ http://serilog.net http://www.apache.org/licenses/LICENSE-2.0 false + + true - + @@ -29,6 +31,17 @@ + + + + + + + + + + + @@ -40,11 +53,22 @@ - $(DefineConstants);ASYNCLOCAL;HASHTABLE + $(DefineConstants);ASYNCLOCAL;HASHTABLE + + + + + + + + + + + From 3a46862a8cdc03176db95fb0b0257205bf41ddb4 Mon Sep 17 00:00:00 2001 From: Adam Chester Date: Wed, 8 Mar 2017 16:27:31 +1000 Subject: [PATCH 19/58] Fix `run_perf_tests.sh` --- run_perf_tests.sh | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/run_perf_tests.sh b/run_perf_tests.sh index 18403fd8e..c332aa20d 100755 --- a/run_perf_tests.sh +++ b/run_perf_tests.sh @@ -1,10 +1,6 @@ #!/bin/bash dotnet restore -for path in src/*/project.json; do - dirname="$(dirname "${path}")" - dotnet build ${dirname} -c Release -done -for path in test/Serilog.PerformanceTests/project.json; do - dirname="$(dirname "${path}")" - dotnet test ${dirname} -f netcoreapp1.0 -c Release -done \ No newline at end of file + +for path in test/*.PerformanceTests/*.csproj; do + dotnet test -f netcoreapp1.1 -c Release ${path} +done From 9ae6dfcf5b4fd8fcb63e88554c36f93b5657233c Mon Sep 17 00:00:00 2001 From: Adam Chester Date: Thu, 9 Mar 2017 06:03:13 +1000 Subject: [PATCH 20/58] Use magic sln project guids, so that VS features like live csproj file editing work correctly. --- Serilog.sln | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Serilog.sln b/Serilog.sln index 1e8496923..be7104f64 100644 --- a/Serilog.sln +++ b/Serilog.sln @@ -20,13 +20,13 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "assets", "assets", "{E9D1B5 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{791D4267-0D6F-4FDF-80F2-11F4E793B0F2}" EndProject -Project("{13B669BE-BB05-4DDF-9536-439F39A36129}") = "Serilog", "src\Serilog\Serilog.csproj", "{AB00B377-9F1E-4D4B-B6B0-B95F53BCAEF1}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Serilog", "src\Serilog\Serilog.csproj", "{AB00B377-9F1E-4D4B-B6B0-B95F53BCAEF1}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{290A2775-7CA0-4F81-9DDC-32E28C3A7565}" EndProject -Project("{13B669BE-BB05-4DDF-9536-439F39A36129}") = "TestDummies", "test\TestDummies\TestDummies.csproj", "{37EF0B5E-0363-4A47-AF3E-51FA6E79E3CF}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestDummies", "test\TestDummies\TestDummies.csproj", "{37EF0B5E-0363-4A47-AF3E-51FA6E79E3CF}" EndProject -Project("{13B669BE-BB05-4DDF-9536-439F39A36129}") = "Serilog.Tests", "test\Serilog.Tests\Serilog.Tests.csproj", "{B11B911D-977A-42CE-900A-596CF59F6FFA}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Serilog.Tests", "test\Serilog.Tests\Serilog.Tests.csproj", "{B11B911D-977A-42CE-900A-596CF59F6FFA}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Serilog.PerformanceTests", "test\Serilog.PerformanceTests\Serilog.PerformanceTests.csproj", "{B4AC7ED9-517B-47E9-BB49-15F8A8478E62}" EndProject From 3b9f10ca05a559518972e67583eda98d33aa55c1 Mon Sep 17 00:00:00 2001 From: Adam Chester Date: Thu, 9 Mar 2017 10:18:13 +1000 Subject: [PATCH 21/58] Disable travis OSX builds --- .travis.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index b153fb9e6..e10883035 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,10 +7,11 @@ matrix: sudo: required dotnet: 1.0.0-preview2-003121 CLI_VERSION: 1.0.0 - - os: osx # OSX 10.11 - osx_image: xcode7.3 - dotnet: 1.0.0-preview2-003121 - CLI_VERSION: 1.0.0 + # Disabled temporarily due to Travis OSX issues + # - os: osx # OSX 10.11 + # osx_image: xcode7.3 + # dotnet: 1.0.0-preview2-003121 + # CLI_VERSION: 1.0.0 script: - ./build.sh \ No newline at end of file From 568cfa9b7ef94e9a2c6b1dadc6faa89e53391136 Mon Sep 17 00:00:00 2001 From: Adam Chester Date: Fri, 10 Mar 2017 06:40:24 +1000 Subject: [PATCH 22/58] Use dotnet core sdk 1.0.1 --- .travis.yml | 6 ++---- appveyor.yml | 2 +- build.sh | 2 +- global.json | 2 +- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index e10883035..813887d99 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,13 +5,11 @@ matrix: - os: linux # Ubuntu 14.04 dist: trusty sudo: required - dotnet: 1.0.0-preview2-003121 - CLI_VERSION: 1.0.0 + dotnet: 1.0.1 # Disabled temporarily due to Travis OSX issues # - os: osx # OSX 10.11 # osx_image: xcode7.3 - # dotnet: 1.0.0-preview2-003121 - # CLI_VERSION: 1.0.0 + # dotnet: 1.0.1 script: - ./build.sh \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml index 6c3d55e65..576ff6ee9 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -6,7 +6,7 @@ install: - ps: mkdir -Force ".\build\" | Out-Null - ps: Invoke-WebRequest "https://raw.githubusercontent.com/dotnet/cli/rel/1.0.0/scripts/obtain/dotnet-install.ps1" -OutFile ".\build\installcli.ps1" - ps: $env:DOTNET_INSTALL_DIR = "$pwd\.dotnetcli" - - ps: '& .\build\installcli.ps1 -InstallDir "$env:DOTNET_INSTALL_DIR" -NoPath -Version 1.0.0' + - ps: '& .\build\installcli.ps1 -InstallDir "$env:DOTNET_INSTALL_DIR" -NoPath -Version 1.0.1' - ps: $env:Path = "$env:DOTNET_INSTALL_DIR;$env:Path" test: off build_script: diff --git a/build.sh b/build.sh index 100633557..461b5510b 100755 --- a/build.sh +++ b/build.sh @@ -1,6 +1,6 @@ #!/bin/bash export DOTNET_INSTALL_DIR="$PWD/.dotnetcli" -DotnetCliVersion=${CLI_VERSION:="1.0.0"} +DotnetCliVersion=${CLI_VERSION:="1.0.1"} install_script_url=https://raw.githubusercontent.com/dotnet/cli/rel/1.0.0/scripts/obtain/dotnet-install.sh curl -sSL $install_script_url | bash /dev/stdin --version "$DotnetCliVersion" --install-dir "$DOTNET_INSTALL_DIR" export PATH="$DOTNET_INSTALL_DIR:$PATH" diff --git a/global.json b/global.json index 6cedd685d..a88380bf8 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "projects": [ "src", "test" ], "sdk": { - "version": "1.0.0" + "version": "1.0.1" } } From 5a9114f8b5e0a5d6d4466fe5b8f616de226fa428 Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Fri, 10 Mar 2017 15:06:58 +1000 Subject: [PATCH 23/58] Cache the {NewLine} literal property to avoid an allocation on each render --- src/Serilog/Formatting/Display/OutputProperties.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Serilog/Formatting/Display/OutputProperties.cs b/src/Serilog/Formatting/Display/OutputProperties.cs index 33a1e1317..125701801 100644 --- a/src/Serilog/Formatting/Display/OutputProperties.cs +++ b/src/Serilog/Formatting/Display/OutputProperties.cs @@ -25,6 +25,8 @@ namespace Serilog.Formatting.Display /// public static class OutputProperties { + static readonly LiteralStringValue LiteralNewLine = new LiteralStringValue(Environment.NewLine); + /// /// The message rendered from the log event. /// @@ -66,7 +68,7 @@ public static IReadOnlyDictionary GetOutputProper result[MessagePropertyName] = new LogEventPropertyMessageValue(logEvent.MessageTemplate, logEvent.Properties); result[TimestampPropertyName] = new ScalarValue(logEvent.Timestamp); result[LevelPropertyName] = new LogEventLevelValue(logEvent.Level); - result[NewLinePropertyName] = new LiteralStringValue(Environment.NewLine); + result[NewLinePropertyName] = LiteralNewLine; var exception = logEvent.Exception == null ? "" : (logEvent.Exception + Environment.NewLine); result[ExceptionPropertyName] = new LiteralStringValue(exception); From b37f1583217f2e21601ba480ea294ffbaad4c856 Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Sun, 19 Mar 2017 11:49:54 +1000 Subject: [PATCH 24/58] It's 2017 [Skip CI] --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8db74f24a..350ad1a59 100644 --- a/README.md +++ b/README.md @@ -107,4 +107,4 @@ Branch | AppVeyor | Travis dev | [![Build status](https://ci.appveyor.com/api/projects/status/b9rm3l7kduryjgcj/branch/dev?svg=true)](https://ci.appveyor.com/project/serilog/serilog/branch/dev) | [![Build Status](https://travis-ci.org/serilog/serilog.svg?branch=dev)](https://travis-ci.org/serilog/serilog) master | [![Build status](https://ci.appveyor.com/api/projects/status/b9rm3l7kduryjgcj/branch/master?svg=true)](https://ci.appveyor.com/project/serilog/serilog/branch/master) | [![Build Status](https://travis-ci.org/serilog/serilog.svg?branch=master)](https://travis-ci.org/serilog/serilog) -_Serilog is copyright © 2013-2016 Serilog Contributors - Provided under the [Apache License, Version 2.0](http://apache.org/licenses/LICENSE-2.0.html). Needle and thread logo a derivative of work by [Kenneth Appiah](http://www.kensets.com/)._ +_Serilog is copyright © 2013-2017 Serilog Contributors - Provided under the [Apache License, Version 2.0](http://apache.org/licenses/LICENSE-2.0.html). Needle and thread logo a derivative of work by [Kenneth Appiah](http://www.kensets.com/)._ From a6b3cd0cffb768b9adba29c91d3a4bf0e8dc70c4 Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Sun, 19 Mar 2017 11:50:57 +1000 Subject: [PATCH 25/58] Fix the H1 markdown [Skip CI] --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 350ad1a59..71d8a07d1 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -#Serilog [![Build status](https://ci.appveyor.com/api/projects/status/b9rm3l7kduryjgcj/branch/master?svg=true)](https://ci.appveyor.com/project/serilog/serilog/branch/master) [![NuGet Version](http://img.shields.io/nuget/v/Serilog.svg?style=flat)](https://www.nuget.org/packages/Serilog/) [![Rager Releases](http://rager.io/badge.svg?url=https%3A%2F%2Fwww.nuget.org%2Fpackages%2FSerilog%2F)](http://rager.io/projects/search?badge=1&query=nuget.org/packages/Serilog/) [![Join the chat at https://gitter.im/serilog/serilog](https://img.shields.io/gitter/room/serilog/serilog.svg)](https://gitter.im/serilog/serilog) [![Stack Overflow](https://img.shields.io/badge/stack%20overflow-serilog-orange.svg)](http://stackoverflow.com/questions/tagged/serilog) +# Serilog [![Build status](https://ci.appveyor.com/api/projects/status/b9rm3l7kduryjgcj/branch/master?svg=true)](https://ci.appveyor.com/project/serilog/serilog/branch/master) [![NuGet Version](http://img.shields.io/nuget/v/Serilog.svg?style=flat)](https://www.nuget.org/packages/Serilog/) [![Rager Releases](http://rager.io/badge.svg?url=https%3A%2F%2Fwww.nuget.org%2Fpackages%2FSerilog%2F)](http://rager.io/projects/search?badge=1&query=nuget.org/packages/Serilog/) [![Join the chat at https://gitter.im/serilog/serilog](https://img.shields.io/gitter/room/serilog/serilog.svg)](https://gitter.im/serilog/serilog) [![Stack Overflow](https://img.shields.io/badge/stack%20overflow-serilog-orange.svg)](http://stackoverflow.com/questions/tagged/serilog) Serilog is a diagnostic logging library for .NET applications. It is easy to set up, has a clean API, and runs on all recent .NET platforms. While it's useful even in the simplest applications, Serilog's support for structured logging shines when instrumenting complex, distributed, and asynchronous applications and systems. From 0d7ad428fc8011803dab2ab283b93843186d9933 Mon Sep 17 00:00:00 2001 From: Matthew Erbs Date: Wed, 22 Mar 2017 14:37:31 +1000 Subject: [PATCH 26/58] Missing list for 2.4 for changes.md --- CHANGES.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 26b75dfd7..896534e27 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,14 @@ +2.4.0 +* #866 and #877- additional event payload limiting controls +* #833 - improve performance of message template cache lookup +* #885 - fix JSON formatting of `NaN` and infinity values +* #888 - allow minimum level overrides to be specified by configuration providers like _Serilog.Settings.AppSettings_ +* #903 - add further `Log` static methods to match `ILogger` methods +* #907 - properly dispose audit sinks +* #913 - include commit hash in `AssemblyInformationalVersion` +* #925 - allow configuration providers to specify `filter` directives +* Build and test coverage work in #821, #824, #896. + 2.3.0 * #870 - fix dispose for level-restricted sinks * #852 - fix dictionary capturing when key/value are anonymous types From f566978c56047b1488265b138f53d8549d70a9b3 Mon Sep 17 00:00:00 2001 From: John Du Hart Date: Sun, 2 Apr 2017 04:26:16 -0400 Subject: [PATCH 27/58] Sink wrapping (#955) `LoggerSinkConfiguration.Wrap()`: Improve configuration story for wrapper sinks like Serilog.Sinks.Async --- .../Configuration/LoggerSinkConfiguration.cs | 43 ++++++++++++++++++- .../Serilog.Tests/LoggerConfigurationTests.cs | 30 +++++++++++++ .../DummyLoggerConfigurationExtensions.cs | 11 ++++- test/TestDummies/DummyWrappingSink.cs | 26 +++++++++++ 4 files changed, 108 insertions(+), 2 deletions(-) create mode 100644 test/TestDummies/DummyWrappingSink.cs diff --git a/src/Serilog/Configuration/LoggerSinkConfiguration.cs b/src/Serilog/Configuration/LoggerSinkConfiguration.cs index 0552387cd..47d024e1a 100644 --- a/src/Serilog/Configuration/LoggerSinkConfiguration.cs +++ b/src/Serilog/Configuration/LoggerSinkConfiguration.cs @@ -150,6 +150,47 @@ public LoggerConfiguration Logger( { if (logger == null) throw new ArgumentNullException(nameof(logger)); return Sink(new SecondaryLoggerSink(logger, attemptDispose: false), restrictedToMinimumLevel); - } + } + + /// + /// Helper method for wrapping sinks. + /// + /// The parent sink configuration. + /// A function that allows for wrapping s + /// added in . + /// An action that configures sinks to be wrapped in . + /// Configuration object allowing method chaining. + public static LoggerConfiguration Wrap( + LoggerSinkConfiguration loggerSinkConfiguration, + Func wrapSink, + Action configureWrappedSink) + { + if (loggerSinkConfiguration == null) throw new ArgumentNullException(nameof(loggerSinkConfiguration)); + if (wrapSink == null) throw new ArgumentNullException(nameof(wrapSink)); + if (configureWrappedSink == null) throw new ArgumentNullException(nameof(configureWrappedSink)); + + void WrapAndAddSink(ILogEventSink sink) + { + bool sinkIsDisposable = sink is IDisposable; + + ILogEventSink wrappedSink = wrapSink(sink); + + if (sinkIsDisposable && !(wrappedSink is IDisposable)) + { + SelfLog.WriteLine("Wrapping sink {0} does not implement IDisposable, but wrapped sink {1} does.", wrappedSink, sink); + } + + loggerSinkConfiguration.Sink(wrappedSink); + } + + var capturingLoggerSinkConfiguration = new LoggerSinkConfiguration( + loggerSinkConfiguration._loggerConfiguration, + WrapAndAddSink, + loggerSinkConfiguration._applyInheritedConfiguration); + + configureWrappedSink(capturingLoggerSinkConfiguration); + + return loggerSinkConfiguration._loggerConfiguration; + } } } diff --git a/test/Serilog.Tests/LoggerConfigurationTests.cs b/test/Serilog.Tests/LoggerConfigurationTests.cs index f7bc7c94f..c757a2dfd 100644 --- a/test/Serilog.Tests/LoggerConfigurationTests.cs +++ b/test/Serilog.Tests/LoggerConfigurationTests.cs @@ -8,8 +8,10 @@ using Serilog.Configuration; using Serilog.Core; using Serilog.Core.Filters; +using Serilog.Debugging; using Serilog.Events; using Serilog.Tests.Support; +using TestDummies; namespace Serilog.Tests { @@ -577,5 +579,33 @@ public string Property get { throw new Exception("Boom!"); } } } + + [Fact] + public void WrappingDecoratesTheConfiguredSink() + { + var sink = new CollectingSink(); + var logger = new LoggerConfiguration() + .WriteTo.Dummy(w => w.Sink(sink)) + .CreateLogger(); + + logger.Write(Some.InformationEvent()); + + Assert.NotEmpty(DummyWrappingSink.Emitted); + Assert.NotEmpty(sink.Events); + } + + [Fact] + public void WrappingWarnsAboutNonDisposableWrapper() + { + var messages = new List(); + SelfLog.Enable(s => messages.Add(s)); + + new LoggerConfiguration() + .WriteTo.Dummy(w => w.Sink()) + .CreateLogger(); + + SelfLog.Disable(); + Assert.NotEmpty(messages); + } } } diff --git a/test/TestDummies/DummyLoggerConfigurationExtensions.cs b/test/TestDummies/DummyLoggerConfigurationExtensions.cs index d49e736c3..a8af6a77d 100644 --- a/test/TestDummies/DummyLoggerConfigurationExtensions.cs +++ b/test/TestDummies/DummyLoggerConfigurationExtensions.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using Serilog; using Serilog.Events; using Serilog.Formatting; @@ -42,5 +41,15 @@ public static LoggerConfiguration DummyRollingFile( { return loggerSinkConfiguration.Sink(new DummyRollingFileAuditSink(), restrictedToMinimumLevel); } + + public static LoggerConfiguration Dummy( + this LoggerSinkConfiguration loggerSinkConfiguration, + Action wrappedSinkAction) + { + return LoggerSinkConfiguration.Wrap( + loggerSinkConfiguration, + s => new DummyWrappingSink(s), + wrappedSinkAction); + } } } \ No newline at end of file diff --git a/test/TestDummies/DummyWrappingSink.cs b/test/TestDummies/DummyWrappingSink.cs new file mode 100644 index 000000000..9d7f96681 --- /dev/null +++ b/test/TestDummies/DummyWrappingSink.cs @@ -0,0 +1,26 @@ +using System; +using Serilog.Core; +using Serilog.Events; +using System.Collections.Generic; + +namespace TestDummies +{ + public class DummyWrappingSink : ILogEventSink + { + [ThreadStatic] + public static List Emitted = new List(); + + private readonly ILogEventSink _sink; + + public DummyWrappingSink(ILogEventSink sink) + { + _sink = sink; + } + + public void Emit(LogEvent logEvent) + { + Emitted.Add(logEvent); + _sink.Emit(logEvent); + } + } +} \ No newline at end of file From 32e748e78e0e203b36d856ed23b2df2a96a53bc9 Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Sun, 2 Apr 2017 18:27:08 +1000 Subject: [PATCH 28/58] Bump minor version - `LoggerSinkConfiguration.Wrap()` added API --- src/Serilog/Serilog.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Serilog/Serilog.csproj b/src/Serilog/Serilog.csproj index 772e0ecef..698c466f6 100644 --- a/src/Serilog/Serilog.csproj +++ b/src/Serilog/Serilog.csproj @@ -2,7 +2,7 @@ Simple .NET logging with fully-structured events - 2.4.1 + 2.5.0 Serilog Contributors net45;net46;netstandard1.0;netstandard1.3 true From 643dfa4f380ea6babf63586cd9737bcac85bdac4 Mon Sep 17 00:00:00 2001 From: Yury Pliner Date: Thu, 6 Apr 2017 03:17:46 +0500 Subject: [PATCH 29/58] Support {Properties} in output templates (#944) Fixes #825 - output template support for `Properties` --- src/Serilog/Events/MessageTemplate.cs | 5 ++ .../Display/LogEventPropertiesValue.cs | 81 +++++++++++++++++++ .../Display/MessageTemplateTextFormatter.cs | 4 +- .../Formatting/Display/OutputProperties.cs | 22 ++++- .../MessageTemplateTextFormatterTests.cs | 20 +++++ 5 files changed, 128 insertions(+), 4 deletions(-) create mode 100644 src/Serilog/Formatting/Display/LogEventPropertiesValue.cs diff --git a/src/Serilog/Events/MessageTemplate.cs b/src/Serilog/Events/MessageTemplate.cs index fa545d266..bb75f7234 100644 --- a/src/Serilog/Events/MessageTemplate.cs +++ b/src/Serilog/Events/MessageTemplate.cs @@ -28,6 +28,11 @@ namespace Serilog.Events /// public class MessageTemplate { + /// + /// Represents the empty message template. + /// + public static MessageTemplate Empty { get; } = new MessageTemplate(Enumerable.Empty()); + readonly MessageTemplateToken[] _tokens; // Optimisation for when the template is bound to diff --git a/src/Serilog/Formatting/Display/LogEventPropertiesValue.cs b/src/Serilog/Formatting/Display/LogEventPropertiesValue.cs new file mode 100644 index 000000000..1e47f0ee7 --- /dev/null +++ b/src/Serilog/Formatting/Display/LogEventPropertiesValue.cs @@ -0,0 +1,81 @@ +// 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 +{ + 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) + { + output.Write('{'); + + var delim = ""; + foreach (var kvp in _properties) + { + if (TemplateContainsPropertyName(_template, kvp.Key)) + { + continue; + } + + if (TemplateContainsPropertyName(_outputTemplate, kvp.Key)) + { + continue; + } + + output.Write(delim); + delim = ", "; + output.Write(kvp.Key); + output.Write(": "); + kvp.Value.Render(output, null, formatProvider); + } + + output.Write('}'); + } + + static bool TemplateContainsPropertyName(MessageTemplate template, string propertyName) + { + if (template.NamedProperties == null) + { + return false; + } + + for (var i = 0; i < template.NamedProperties.Length; i++) + { + var namedProperty = template.NamedProperties[i]; + if (namedProperty.PropertyName == propertyName) + { + return true; + } + } + + return false; + } + } +} \ No newline at end of file diff --git a/src/Serilog/Formatting/Display/MessageTemplateTextFormatter.cs b/src/Serilog/Formatting/Display/MessageTemplateTextFormatter.cs index 54f9a1fe7..0c1ae7f8d 100644 --- a/src/Serilog/Formatting/Display/MessageTemplateTextFormatter.cs +++ b/src/Serilog/Formatting/Display/MessageTemplateTextFormatter.cs @@ -61,8 +61,8 @@ public void Format(LogEvent logEvent, TextWriter 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); - + var outputProperties = OutputProperties.GetOutputProperties(logEvent, _outputTemplate); + foreach (var token in _outputTemplate.Tokens) { var pt = token as PropertyToken; diff --git a/src/Serilog/Formatting/Display/OutputProperties.cs b/src/Serilog/Formatting/Display/OutputProperties.cs index 125701801..14065c4db 100644 --- a/src/Serilog/Formatting/Display/OutputProperties.cs +++ b/src/Serilog/Formatting/Display/OutputProperties.cs @@ -52,12 +52,29 @@ public static class OutputProperties /// public const string ExceptionPropertyName = "Exception"; + /// + /// The properties of the log event. + /// + public const string PropertiesPropertyName = "Properties"; + /// /// Create properties from the provided log event. /// /// The log event. /// A dictionary with properties representing the log event. + [Obsolete("Pass the full output template using the other overload.")] public static IReadOnlyDictionary GetOutputProperties(LogEvent logEvent) + { + return GetOutputProperties(logEvent, MessageTemplate.Empty); + } + + /// + /// Create properties from the provided log event. + /// + /// The log event. + /// The output template. + /// A dictionary with properties representing the log event. + public static IReadOnlyDictionary GetOutputProperties(LogEvent logEvent, MessageTemplate outputTemplate) { var result = logEvent.Properties.ToDictionary(kvp => kvp.Key, kvp => kvp.Value); @@ -69,11 +86,12 @@ public static IReadOnlyDictionary GetOutputProper result[TimestampPropertyName] = new ScalarValue(logEvent.Timestamp); result[LevelPropertyName] = new LogEventLevelValue(logEvent.Level); result[NewLinePropertyName] = LiteralNewLine; + result[PropertiesPropertyName] = new LogEventPropertiesValue(logEvent.MessageTemplate, logEvent.Properties, outputTemplate); - var exception = logEvent.Exception == null ? "" : (logEvent.Exception + Environment.NewLine); + var exception = logEvent.Exception == null ? "" : logEvent.Exception + Environment.NewLine; result[ExceptionPropertyName] = new LiteralStringValue(exception); return result; } } -} +} \ No newline at end of file diff --git a/test/Serilog.Tests/Formatting/Display/MessageTemplateTextFormatterTests.cs b/test/Serilog.Tests/Formatting/Display/MessageTemplateTextFormatterTests.cs index b5a24855b..052ee267c 100644 --- a/test/Serilog.Tests/Formatting/Display/MessageTemplateTextFormatterTests.cs +++ b/test/Serilog.Tests/Formatting/Display/MessageTemplateTextFormatterTests.cs @@ -198,5 +198,25 @@ public void AppliesCustomFormatterToEnums() formatter.Format(evt, sw); Assert.Equal("Size Huge", sw.ToString()); } + + [Fact] + public void NonMessagePropertiesAreRendered() + { + var formatter = new MessageTemplateTextFormatter("{Properties}", CultureInfo.InvariantCulture); + var evt = DelegatingSink.GetLogEvent(l => l.ForContext("Foo", 42).Information("Hello from {Bar}!", "bar")); + var sw = new StringWriter(); + formatter.Format(evt, sw); + Assert.Equal("{Foo: 42}", sw.ToString()); + } + + [Fact] + public void DoNotDuplicatePropertiesAlreadyRenderedInOutputTemplate() + { + var formatter = new MessageTemplateTextFormatter("{Foo} {Properties}", CultureInfo.InvariantCulture); + var evt = DelegatingSink.GetLogEvent(l => l.ForContext("Foo", 42).ForContext("Bar", 42).Information("Hello from bar!")); + var sw = new StringWriter(); + formatter.Format(evt, sw); + Assert.Equal("42 {Bar: 42}", sw.ToString()); + } } } From f299b58e20c9b84e77ff050146e0dcb23be09218 Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Sat, 8 Apr 2017 08:01:11 +1000 Subject: [PATCH 30/58] Output template formatting harness --- test/Serilog.PerformanceTests/Harness.cs | 6 ++++ .../OutputTemplateRenderingBenchmark.cs | 35 +++++++++++++++++++ test/Serilog.PerformanceTests/Support/Some.cs | 14 ++++---- 3 files changed, 47 insertions(+), 8 deletions(-) create mode 100644 test/Serilog.PerformanceTests/OutputTemplateRenderingBenchmark.cs diff --git a/test/Serilog.PerformanceTests/Harness.cs b/test/Serilog.PerformanceTests/Harness.cs index 6b9a0dd1e..44b8d1ed9 100644 --- a/test/Serilog.PerformanceTests/Harness.cs +++ b/test/Serilog.PerformanceTests/Harness.cs @@ -62,5 +62,11 @@ public void Pipeline() { BenchmarkRunner.Run(); } + + [Fact] + public void OutputTemplateRendering() + { + BenchmarkRunner.Run(); + } } } \ No newline at end of file diff --git a/test/Serilog.PerformanceTests/OutputTemplateRenderingBenchmark.cs b/test/Serilog.PerformanceTests/OutputTemplateRenderingBenchmark.cs new file mode 100644 index 000000000..cae6a892d --- /dev/null +++ b/test/Serilog.PerformanceTests/OutputTemplateRenderingBenchmark.cs @@ -0,0 +1,35 @@ +using BenchmarkDotNet.Attributes; +using System.Globalization; +using System.IO; +using Serilog.Events; +using Serilog.Formatting.Display; +using Serilog.PerformanceTests.Support; + +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. + /// + 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. + } + + [Benchmark] + public void FormatToOutput() + { + Formatter.Format(HelloWorldEvent, _output); + } + } +} diff --git a/test/Serilog.PerformanceTests/Support/Some.cs b/test/Serilog.PerformanceTests/Support/Some.cs index 07fbf5aab..e1284b02c 100644 --- a/test/Serilog.PerformanceTests/Support/Some.cs +++ b/test/Serilog.PerformanceTests/Support/Some.cs @@ -1,19 +1,17 @@ using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading; using Serilog.Events; -using Serilog.Parsing; namespace Serilog.PerformanceTests.Support { static class Some { - public static LogEvent InformationEvent() + public static LogEvent InformationEvent(string messageTemplate = "Hello, world!", params object[] propertyValues) { - return new LogEvent(DateTime.Now, LogEventLevel.Information, - null, new MessageTemplate(Enumerable.Empty()), Enumerable.Empty()); + var logger = new LoggerConfiguration().CreateLogger(); +#pragma warning disable Serilog004 // Constant MessageTemplate verifier + logger.BindMessageTemplate(messageTemplate, propertyValues, out var parsedTemplate, out var boundProperties); +#pragma warning restore Serilog004 // Constant MessageTemplate verifier + return new LogEvent(DateTime.Now, LogEventLevel.Information, null, parsedTemplate, boundProperties); } } From 5944e29b1bb04aa9fcb6376112cd2089d2a494fe Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Sat, 8 Apr 2017 08:15:29 +1000 Subject: [PATCH 31/58] Fixes #959 - exception when parsing longer property tokens with zero-length names --- src/Serilog/Parsing/MessageTemplateParser.cs | 4 ++-- test/Serilog.Tests/Parsing/MessageTemplateParserTests.cs | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Serilog/Parsing/MessageTemplateParser.cs b/src/Serilog/Parsing/MessageTemplateParser.cs index 64721a147..7a9e1003c 100644 --- a/src/Serilog/Parsing/MessageTemplateParser.cs +++ b/src/Serilog/Parsing/MessageTemplateParser.cs @@ -95,8 +95,8 @@ static MessageTemplateToken ParsePropertyToken(int startAt, string messageTempla return new TextToken(rawText, first); var propertyName = propertyNameAndDestructuring; - Destructuring destructuring; - if (TryGetDestructuringHint(propertyName[0], out destructuring)) + var destructuring = Destructuring.Default; + if (propertyName.Length != 0 && TryGetDestructuringHint(propertyName[0], out destructuring)) propertyName = propertyName.Substring(1); if (propertyName.Length == 0) diff --git a/test/Serilog.Tests/Parsing/MessageTemplateParserTests.cs b/test/Serilog.Tests/Parsing/MessageTemplateParserTests.cs index 611e45ad7..fdbe8de05 100644 --- a/test/Serilog.Tests/Parsing/MessageTemplateParserTests.cs +++ b/test/Serilog.Tests/Parsing/MessageTemplateParserTests.cs @@ -164,5 +164,11 @@ public void UnderscoresAreValidInPropertyNames() AssertParsedAs("{_123_Hello}", new PropertyToken("_123_Hello", "{_123_Hello}")); } + [Fact] + public void IndexOutOfRangeExceptionBugHasNotRegressed() + { + var parser = new MessageTemplateParser(); + parser.Parse("{,,}"); + } } } From c12f5742d6a6e3338ed322f79fffb12be02f7acf Mon Sep 17 00:00:00 2001 From: Matthew Erbs Date: Sun, 21 May 2017 08:37:09 +1000 Subject: [PATCH 32/58] VS2017 Appveyor image and 1.0.4 SDK for Travis --- .travis.yml | 2 +- appveyor.yml | 8 +------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index 813887d99..3f7297646 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ matrix: - os: linux # Ubuntu 14.04 dist: trusty sudo: required - dotnet: 1.0.1 + dotnet: 1.0.4 # Disabled temporarily due to Travis OSX issues # - os: osx # OSX 10.11 # osx_image: xcode7.3 diff --git a/appveyor.yml b/appveyor.yml index 576ff6ee9..7df8c2fe4 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,13 +1,7 @@ version: '{build}' skip_tags: true -image: Visual Studio 2015 +image: Visual Studio 2017 configuration: Release -install: - - ps: mkdir -Force ".\build\" | Out-Null - - ps: Invoke-WebRequest "https://raw.githubusercontent.com/dotnet/cli/rel/1.0.0/scripts/obtain/dotnet-install.ps1" -OutFile ".\build\installcli.ps1" - - ps: $env:DOTNET_INSTALL_DIR = "$pwd\.dotnetcli" - - ps: '& .\build\installcli.ps1 -InstallDir "$env:DOTNET_INSTALL_DIR" -NoPath -Version 1.0.1' - - ps: $env:Path = "$env:DOTNET_INSTALL_DIR;$env:Path" test: off build_script: - ps: ./Build.ps1 From 36f8429022beb651205cd93356bb4e7e451fb9d4 Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Sun, 28 May 2017 08:29:40 +1000 Subject: [PATCH 33/58] Rename `LogContext.PushProperties()` to `LogContext.Push()`; add a non-params overload to reduce allocs. Partially covers 773. --- src/Serilog/Context/LogContext.cs | 51 +++++++++++++++---- .../Core/Enrichers/FixedPropertyEnricher.cs | 3 +- test/Serilog.Tests/Context/LogContextTests.cs | 26 +++++++++- test/Serilog.Tests/Serilog.Tests.csproj | 2 +- 4 files changed, 68 insertions(+), 14 deletions(-) diff --git a/src/Serilog/Context/LogContext.cs b/src/Serilog/Context/LogContext.cs index 701c5252a..0b9723ad9 100644 --- a/src/Serilog/Context/LogContext.cs +++ b/src/Serilog/Context/LogContext.cs @@ -14,6 +14,7 @@ using System; +using System.ComponentModel; using Serilog.Core; using Serilog.Core.Enrichers; using Serilog.Events; @@ -62,7 +63,7 @@ public static class LogContext /// /// Push a property onto the context, returning an - /// that can later be used to remove the property, along with any others that + /// that must later be used to remove the property, along with any others that /// may have been pushed on top of it and not yet popped. The property must /// be popped from the same thread/logical call context. /// @@ -75,37 +76,69 @@ public static class LogContext /// A token that must be disposed, in order, to pop properties back off the stack. public static IDisposable PushProperty(string name, object value, bool destructureObjects = false) { + return Push(new PropertyEnricher(name, value, destructureObjects)); + } + + /// + /// Push an enricher onto context, returning an + /// that must later be used to remove the property, along with any others that + /// may have been pushed on top of it and not yet popped. The property must + /// be popped from the same thread/logical call context. + /// + /// Log Properties to push onto the log context + /// A token that must be disposed, in order, to pop properties back off the stack. + /// + public static IDisposable Push(ILogEventEnricher enricher) + { + if (enricher == null) throw new ArgumentNullException(nameof(enricher)); + var stack = GetOrCreateEnricherStack(); var bookmark = new ContextStackBookmark(stack); - Enrichers = stack.Push(new PropertyEnricher(name, value, destructureObjects)); + Enrichers = stack.Push(enricher); return bookmark; } /// - /// Push multiple properties onto the context, returning an - /// that can later be used to remove the properties. The properties must + /// Push multiple enrichers onto the context, returning an + /// that must later be used to remove the property, along with any others that + /// may have been pushed on top of it and not yet popped. The property must /// be popped from the same thread/logical call context. /// - /// Log Properties to push onto the log context + /// . + /// Log Properties to push onto the log context /// A token that must be disposed, in order, to pop properties back off the stack. /// - public static IDisposable PushProperties(params ILogEventEnricher[] properties) + public static IDisposable Push(params ILogEventEnricher[] enrichers) { - if (properties == null) throw new ArgumentNullException(nameof(properties)); + if (enrichers == null) throw new ArgumentNullException(nameof(enrichers)); var stack = GetOrCreateEnricherStack(); var bookmark = new ContextStackBookmark(stack); - foreach (var prop in properties) - stack = stack.Push(prop); + for (var i = 0; i < enrichers.Length; ++i) + stack = stack.Push(enrichers[i]); Enrichers = stack; return bookmark; } + /// + /// Push enrichers onto the log context. This method is obsolete, please + /// use instead. + /// + /// Log Properties to push onto the log context + /// A token that must be disposed, in order, to pop properties back off the stack. + /// + [Obsolete("Please use `LogContext.Push(properties)` instead.")] + [EditorBrowsable(EditorBrowsableState.Never)] + public static IDisposable PushProperties(params ILogEventEnricher[] properties) + { + return Push(properties); + } + static ImmutableStack GetOrCreateEnricherStack() { var enrichers = Enrichers; diff --git a/src/Serilog/Core/Enrichers/FixedPropertyEnricher.cs b/src/Serilog/Core/Enrichers/FixedPropertyEnricher.cs index 840af394b..16df1c427 100644 --- a/src/Serilog/Core/Enrichers/FixedPropertyEnricher.cs +++ b/src/Serilog/Core/Enrichers/FixedPropertyEnricher.cs @@ -23,8 +23,7 @@ class FixedPropertyEnricher : ILogEventEnricher public FixedPropertyEnricher(LogEventProperty logEventProperty) { - if (logEventProperty == null) throw new ArgumentNullException(nameof(logEventProperty)); - _logEventProperty = logEventProperty; + _logEventProperty = logEventProperty ?? throw new ArgumentNullException(nameof(logEventProperty)); } public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) diff --git a/test/Serilog.Tests/Context/LogContextTests.cs b/test/Serilog.Tests/Context/LogContextTests.cs index 17987f2ad..f2c184e29 100644 --- a/test/Serilog.Tests/Context/LogContextTests.cs +++ b/test/Serilog.Tests/Context/LogContextTests.cs @@ -24,6 +24,28 @@ public LogContextTests() #endif } + [Fact] + public void PushedPropertiesAreAvailableToLoggers() + { + LogEvent lastEvent = null; + + var log = new LoggerConfiguration() + .Enrich.FromLogContext() + .WriteTo.Sink(new DelegatingSink(e => lastEvent = e)) + .CreateLogger(); + + using (LogContext.PushProperty("A", 1)) + using (LogContext.Push(new PropertyEnricher("B", 2))) + using (LogContext.Push(new PropertyEnricher("C", 3), new PropertyEnricher("D", 4))) // Different overload + { + log.Write(Some.InformationEvent()); + Assert.Equal(1, lastEvent.Properties["A"].LiteralValue()); + Assert.Equal(2, lastEvent.Properties["B"].LiteralValue()); + Assert.Equal(3, lastEvent.Properties["C"].LiteralValue()); + Assert.Equal(4, lastEvent.Properties["D"].LiteralValue()); + } + } + [Fact] public void MoreNestedPropertiesOverrideLessNestedOnes() { @@ -63,13 +85,13 @@ public void MultipleNestedPropertiesOverrideLessNestedOnes() .WriteTo.Sink(new DelegatingSink(e => lastEvent = e)) .CreateLogger(); - using (LogContext.PushProperties(new PropertyEnricher("A1", 1), new PropertyEnricher("A2", 2))) + using (LogContext.Push(new PropertyEnricher("A1", 1), new PropertyEnricher("A2", 2))) { log.Write(Some.InformationEvent()); Assert.Equal(1, lastEvent.Properties["A1"].LiteralValue()); Assert.Equal(2, lastEvent.Properties["A2"].LiteralValue()); - using (LogContext.PushProperties(new PropertyEnricher("A1", 10), new PropertyEnricher("A2", 20))) + using (LogContext.Push(new PropertyEnricher("A1", 10), new PropertyEnricher("A2", 20))) { log.Write(Some.InformationEvent()); Assert.Equal(10, lastEvent.Properties["A1"].LiteralValue()); diff --git a/test/Serilog.Tests/Serilog.Tests.csproj b/test/Serilog.Tests/Serilog.Tests.csproj index dfa074061..c0fded0b0 100644 --- a/test/Serilog.Tests/Serilog.Tests.csproj +++ b/test/Serilog.Tests/Serilog.Tests.csproj @@ -29,7 +29,7 @@ $(DefineConstants);APPDOMAIN;REMOTING;GETCURRENTMETHOD - $(DefineConstants);ASYNCLOCAL + $(DefineConstants);ASYNCLOCAL;GETCURRENTMETHOD From 6190ca819f3f3a63faa282170f48e23ebf82d37c Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Sun, 28 May 2017 08:36:01 +1000 Subject: [PATCH 34/58] #773 - clone and re-import LogContext. --- src/Serilog/Context/LogContext.cs | 31 +++++++++---------- test/Serilog.Tests/Context/LogContextTests.cs | 24 ++++++++++++++ 2 files changed, 39 insertions(+), 16 deletions(-) diff --git a/src/Serilog/Context/LogContext.cs b/src/Serilog/Context/LogContext.cs index 0b9723ad9..accfe9da0 100644 --- a/src/Serilog/Context/LogContext.cs +++ b/src/Serilog/Context/LogContext.cs @@ -139,6 +139,17 @@ public static IDisposable PushProperties(params ILogEventEnricher[] properties) return Push(properties); } + /// + /// Obtain an enricher that represents the current contents of the . This + /// can be pushed back onto the context in a different location/thread when required. + /// + /// An enricher that represents the current contents of the . + public static ILogEventEnricher Clone() + { + var stack = GetOrCreateEnricherStack(); + return new SafeAggregateEnricher(stack); + } + static ImmutableStack GetOrCreateEnricherStack() { var enrichers = Enrichers; @@ -181,14 +192,8 @@ public void Dispose() static ImmutableStack Enrichers { - get - { - return Data.Value; - } - set - { - Data.Value = value; - } + get => Data.Value; + set => Data.Value = value; } #elif REMOTING @@ -211,14 +216,8 @@ static ImmutableStack Enrichers static ImmutableStack Enrichers { - get - { - return Data; - } - set - { - Data = value; - } + get => Data; + set => Data = value; } #endif } diff --git a/test/Serilog.Tests/Context/LogContextTests.cs b/test/Serilog.Tests/Context/LogContextTests.cs index f2c184e29..a6bf641ac 100644 --- a/test/Serilog.Tests/Context/LogContextTests.cs +++ b/test/Serilog.Tests/Context/LogContextTests.cs @@ -12,6 +12,7 @@ #endif using System.Threading; using System.Threading.Tasks; +using Serilog.Core; namespace Serilog.Tests.Context { @@ -46,6 +47,29 @@ public void PushedPropertiesAreAvailableToLoggers() } } + [Fact] + public void LogContextCanBeCloned() + { + LogEvent lastEvent = null; + + var log = new LoggerConfiguration() + .Enrich.FromLogContext() + .WriteTo.Sink(new DelegatingSink(e => lastEvent = e)) + .CreateLogger(); + + ILogEventEnricher clonedContext; + using (LogContext.PushProperty("A", 1)) + { + clonedContext = LogContext.Clone(); + } + + using (LogContext.Push(clonedContext)) + { + log.Write(Some.InformationEvent()); + Assert.Equal(1, lastEvent.Properties["A"].LiteralValue()); + } + } + [Fact] public void MoreNestedPropertiesOverrideLessNestedOnes() { From 60b71b4ee6bae6d8607e0fafa8a70096b92da69f Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Mon, 29 May 2017 07:22:45 +1000 Subject: [PATCH 35/58] Review feedback items --- src/Serilog/Context/LogContext.cs | 8 ++--- test/Serilog.Tests/Context/LogContextTests.cs | 30 +++++++++++++++++++ 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/Serilog/Context/LogContext.cs b/src/Serilog/Context/LogContext.cs index accfe9da0..b4ebd2e37 100644 --- a/src/Serilog/Context/LogContext.cs +++ b/src/Serilog/Context/LogContext.cs @@ -80,12 +80,12 @@ public static IDisposable PushProperty(string name, object value, bool destructu } /// - /// Push an enricher onto context, returning an + /// Push an enricher onto the context, returning an /// that must later be used to remove the property, along with any others that /// may have been pushed on top of it and not yet popped. The property must /// be popped from the same thread/logical call context. /// - /// Log Properties to push onto the log context + /// An enricher to push onto the log context /// A token that must be disposed, in order, to pop properties back off the stack. /// public static IDisposable Push(ILogEventEnricher enricher) @@ -107,7 +107,7 @@ public static IDisposable Push(ILogEventEnricher enricher) /// be popped from the same thread/logical call context. /// /// . - /// Log Properties to push onto the log context + /// Enrichers to push onto the log context /// A token that must be disposed, in order, to pop properties back off the stack. /// public static IDisposable Push(params ILogEventEnricher[] enrichers) @@ -129,7 +129,7 @@ public static IDisposable Push(params ILogEventEnricher[] enrichers) /// Push enrichers onto the log context. This method is obsolete, please /// use instead. /// - /// Log Properties to push onto the log context + /// Enrichers to push onto the log context /// A token that must be disposed, in order, to pop properties back off the stack. /// [Obsolete("Please use `LogContext.Push(properties)` instead.")] diff --git a/test/Serilog.Tests/Context/LogContextTests.cs b/test/Serilog.Tests/Context/LogContextTests.cs index a6bf641ac..4809f2bff 100644 --- a/test/Serilog.Tests/Context/LogContextTests.cs +++ b/test/Serilog.Tests/Context/LogContextTests.cs @@ -70,6 +70,36 @@ public void LogContextCanBeCloned() } } + [Fact] + public void ClonedLogContextCanSharedAcrossThreads() + { + LogEvent lastEvent = null; + + var log = new LoggerConfiguration() + .Enrich.FromLogContext() + .WriteTo.Sink(new DelegatingSink(e => lastEvent = e)) + .CreateLogger(); + + ILogEventEnricher clonedContext; + using (LogContext.PushProperty("A", 1)) + { + clonedContext = LogContext.Clone(); + } + + var t = new Thread(() => + { + using (LogContext.Push(clonedContext)) + { + log.Write(Some.InformationEvent()); + } + }); + + t.Start(); + t.Join(); + + Assert.Equal(1, lastEvent.Properties["A"].LiteralValue()); + } + [Fact] public void MoreNestedPropertiesOverrideLessNestedOnes() { From e3910e9f28f9302a6eb8f759a4fe365a5ed714e0 Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Wed, 31 May 2017 09:46:51 +1000 Subject: [PATCH 36/58] ValueTuple to sequence value conversion --- .../Parameters/PropertyValueConverter.cs | 29 +++++++++- src/Serilog/Serilog.csproj | 56 ++++++++++--------- .../Parameters/PropertyValueConverterTests.cs | 24 +++++++- 3 files changed, 79 insertions(+), 30 deletions(-) diff --git a/src/Serilog/Parameters/PropertyValueConverter.cs b/src/Serilog/Parameters/PropertyValueConverter.cs index 712af6f18..3c9333332 100755 --- a/src/Serilog/Parameters/PropertyValueConverter.cs +++ b/src/Serilog/Parameters/PropertyValueConverter.cs @@ -74,7 +74,7 @@ public PropertyValueConverter( new SimpleScalarConversionPolicy(BuiltInScalarTypes.Concat(additionalScalarTypes)), new NullableScalarConversionPolicy(), new EnumScalarConversionPolicy(), - new ByteArrayScalarConversionPolicy(), + new ByteArrayScalarConversionPolicy() }; _destructuringPolicies = additionalDestructuringPolicies @@ -190,6 +190,33 @@ LogEventPropertyValue CreatePropertyValue(object value, Destructuring destructur enumerable.Cast().Take(_maximumCollectionCount).Select(o => limiter.CreatePropertyValue(o, destructuring))); } + if (value is IStructuralEquatable) + { + var type = value.GetType(); + if (type.IsConstructedGenericType) + { + var definition = type.GetGenericTypeDefinition(); + if (definition == typeof(ValueTuple<>) || definition == typeof(ValueTuple<,>) || + definition == typeof(ValueTuple<,,>) || definition == typeof(ValueTuple<,,,>) || + definition == typeof(ValueTuple<,,,,>) || definition == typeof(ValueTuple<,,,,,>) || + definition == typeof(ValueTuple<,,,,,,>)) // Ignore the 8+ value case for now. + { + var elements = new List(); + foreach (var field in type.GetTypeInfo().DeclaredFields) + { + if (field.IsPublic && !field.IsStatic) + { + var fieldValue = field.GetValue(value); + var propertyValue = limiter.CreatePropertyValue(fieldValue, destructuring); + elements.Add(propertyValue); + } + } + + return new SequenceValue(elements); + } + } + } + if (destructuring == Destructuring.Destructure) { var type = value.GetType(); diff --git a/src/Serilog/Serilog.csproj b/src/Serilog/Serilog.csproj index 698c466f6..2362223d5 100644 --- a/src/Serilog/Serilog.csproj +++ b/src/Serilog/Serilog.csproj @@ -23,25 +23,44 @@ + + - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -56,19 +75,4 @@ $(DefineConstants);ASYNCLOCAL;HASHTABLE - - - - - - - - - - - - - - - diff --git a/test/Serilog.Tests/Parameters/PropertyValueConverterTests.cs b/test/Serilog.Tests/Parameters/PropertyValueConverterTests.cs index 025f1e979..63d5a1a71 100644 --- a/test/Serilog.Tests/Parameters/PropertyValueConverterTests.cs +++ b/test/Serilog.Tests/Parameters/PropertyValueConverterTests.cs @@ -8,6 +8,8 @@ using Serilog.Parsing; using Serilog.Tests.Support; +// ReSharper disable UnusedAutoPropertyAccessor.Global, UnusedParameter.Local + namespace Serilog.Tests.Parameters { public class PropertyValueConverterTests @@ -188,7 +190,7 @@ public class BaseWithProps public class DerivedWithOverrides : BaseWithProps { - new public string PropA { get; set; } + public new string PropA { get; set; } public override string PropB { get; set; } public string PropD { get; set; } } @@ -216,7 +218,7 @@ public void NewAndInheritedPropertiesAppearOnlyOnce() class HasIndexer { - public string this[int index] { get { return "Indexer"; } } + public string this[int index] => "Indexer"; } [Fact] @@ -231,7 +233,7 @@ public void IndexerPropertiesAreIgnoredWhenDestructuring() // (reducing garbage). class HasItem { - public string Item { get { return "Item"; } } + public string Item => "Item"; } [Fact] @@ -253,6 +255,22 @@ public void CSharpAnonymousTypesAreRecognizedWhenDestructuring() var structuredValue = (StructureValue)result; Assert.Equal(null, structuredValue.TypeTag); } + + [Fact] + public void ValueTuplesAreRecognizedWhenDestructuring() + { + var o = (1, "A", new[] { "B" }); + var result = _converter.CreatePropertyValue(o); + + var sequenceValue = Assert.IsType(result); + + Assert.Equal(3, sequenceValue.Elements.Count); + Assert.Equal(new ScalarValue(1), sequenceValue.Elements[0]); + Assert.Equal(new ScalarValue("A"), sequenceValue.Elements[1]); + var nested = Assert.IsType(sequenceValue.Elements[2]); + Assert.Equal(1, nested.Elements.Count); + Assert.Equal(new ScalarValue("B"), nested.Elements[0]); + } } } From ce9b893c76785929d44632c6fb03c9c6d8321a85 Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Wed, 31 May 2017 10:26:29 +1000 Subject: [PATCH 37/58] A quick extract-method refactoring --- .../Parameters/PropertyValueConverter.cs | 100 +++++++++++------- 1 file changed, 63 insertions(+), 37 deletions(-) diff --git a/src/Serilog/Parameters/PropertyValueConverter.cs b/src/Serilog/Parameters/PropertyValueConverter.cs index 3c9333332..12ae58195 100755 --- a/src/Serilog/Parameters/PropertyValueConverter.cs +++ b/src/Serilog/Parameters/PropertyValueConverter.cs @@ -162,6 +162,29 @@ LogEventPropertyValue CreatePropertyValue(object value, Destructuring destructur } } + if (TryConvertEnumerable(value, destructuring, valueType, limiter, out var enumerableResult)) + return enumerableResult; + + if (TryConvertValueTuple(value, destructuring, valueType, limiter, 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); + } + + return new ScalarValue(value.ToString()); + } + + bool TryConvertEnumerable(object value, Destructuring destructuring, Type valueType, DepthLimiter limiter, out LogEventPropertyValue result) + { var enumerable = value as IEnumerable; if (enumerable != null) { @@ -179,57 +202,60 @@ LogEventPropertyValue CreatePropertyValue(object value, Destructuring destructur var keyProperty = typeInfo.GetDeclaredProperty("Key"); var valueProperty = typeInfo.GetDeclaredProperty("Value"); - return new DictionaryValue(enumerable.Cast().Take(_maximumCollectionCount) - .Select(kvp => new KeyValuePair( - (ScalarValue)limiter.CreatePropertyValue(keyProperty.GetValue(kvp), destructuring), - limiter.CreatePropertyValue(valueProperty.GetValue(kvp), destructuring))) - .Where(kvp => kvp.Key.Value != null)); + { + result = new DictionaryValue(enumerable.Cast().Take(_maximumCollectionCount) + .Select(kvp => new KeyValuePair( + (ScalarValue) limiter.CreatePropertyValue(keyProperty.GetValue(kvp), destructuring), + limiter.CreatePropertyValue(valueProperty.GetValue(kvp), destructuring))) + .Where(kvp => kvp.Key.Value != null)); + return true; + } } - return new SequenceValue( - enumerable.Cast().Take(_maximumCollectionCount).Select(o => limiter.CreatePropertyValue(o, destructuring))); + { + result = new SequenceValue( + enumerable.Cast().Take(_maximumCollectionCount).Select(o => limiter.CreatePropertyValue(o, destructuring))); + return true; + } + } + + result = null; + return false; + } + + static bool TryConvertValueTuple(object value, Destructuring destructuring, Type valueType, DepthLimiter limiter, out LogEventPropertyValue result) + { + if (!(value is IStructuralEquatable && valueType.IsConstructedGenericType)) + { + result = null; + return false; } - if (value is IStructuralEquatable) + var definition = valueType.GetGenericTypeDefinition(); + if (definition == typeof(ValueTuple<>) || definition == typeof(ValueTuple<,>) || + definition == typeof(ValueTuple<,,>) || definition == typeof(ValueTuple<,,,>) || + definition == typeof(ValueTuple<,,,,>) || definition == typeof(ValueTuple<,,,,,>) || + definition == typeof(ValueTuple<,,,,,,>)) // Ignore the 8+ value case for now. { - var type = value.GetType(); - if (type.IsConstructedGenericType) + var elements = new List(); + foreach (var field in valueType.GetTypeInfo().DeclaredFields) { - var definition = type.GetGenericTypeDefinition(); - if (definition == typeof(ValueTuple<>) || definition == typeof(ValueTuple<,>) || - definition == typeof(ValueTuple<,,>) || definition == typeof(ValueTuple<,,,>) || - definition == typeof(ValueTuple<,,,,>) || definition == typeof(ValueTuple<,,,,,>) || - definition == typeof(ValueTuple<,,,,,,>)) // Ignore the 8+ value case for now. + if (field.IsPublic && !field.IsStatic) { - var elements = new List(); - foreach (var field in type.GetTypeInfo().DeclaredFields) - { - if (field.IsPublic && !field.IsStatic) - { - var fieldValue = field.GetValue(value); - var propertyValue = limiter.CreatePropertyValue(fieldValue, destructuring); - elements.Add(propertyValue); - } - } - - return new SequenceValue(elements); + var fieldValue = field.GetValue(value); + var propertyValue = limiter.CreatePropertyValue(fieldValue, destructuring); + elements.Add(propertyValue); } } - } - if (destructuring == Destructuring.Destructure) - { - var type = value.GetType(); - var typeTag = type.Name; - if (typeTag.Length <= 0 || IsCompilerGeneratedType(type)) { - typeTag = null; + result = new SequenceValue(elements); + return true; } - - return new StructureValue(GetProperties(value, limiter), typeTag); } - return new ScalarValue(value.ToString()); + result = null; + return false; } LogEventPropertyValue Stringify(object value) From 3d80e9ee01e8f952f45daff378549b518f650940 Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Wed, 31 May 2017 10:29:36 +1000 Subject: [PATCH 38/58] Remove redundant blocks --- .../Parameters/PropertyValueConverter.cs | 33 +++++++++---------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/src/Serilog/Parameters/PropertyValueConverter.cs b/src/Serilog/Parameters/PropertyValueConverter.cs index 12ae58195..1e627ab40 100755 --- a/src/Serilog/Parameters/PropertyValueConverter.cs +++ b/src/Serilog/Parameters/PropertyValueConverter.cs @@ -202,21 +202,22 @@ bool TryConvertEnumerable(object value, Destructuring destructuring, Type valueT var keyProperty = typeInfo.GetDeclaredProperty("Key"); var valueProperty = typeInfo.GetDeclaredProperty("Value"); - { - result = new DictionaryValue(enumerable.Cast().Take(_maximumCollectionCount) - .Select(kvp => new KeyValuePair( - (ScalarValue) limiter.CreatePropertyValue(keyProperty.GetValue(kvp), destructuring), - limiter.CreatePropertyValue(valueProperty.GetValue(kvp), destructuring))) - .Where(kvp => kvp.Key.Value != null)); - return true; - } - } - - { - result = new SequenceValue( - enumerable.Cast().Take(_maximumCollectionCount).Select(o => limiter.CreatePropertyValue(o, destructuring))); + result = new DictionaryValue(enumerable + .Cast() + .Take(_maximumCollectionCount) + .Select(kvp => new KeyValuePair( + (ScalarValue) limiter.CreatePropertyValue(keyProperty.GetValue(kvp), destructuring), + limiter.CreatePropertyValue(valueProperty.GetValue(kvp), destructuring))) + .Where(kvp => kvp.Key.Value != null)); return true; } + + result = new SequenceValue(enumerable + .Cast() + .Take(_maximumCollectionCount) + .Select(o => limiter.CreatePropertyValue(o, destructuring))); + + return true; } result = null; @@ -248,10 +249,8 @@ static bool TryConvertValueTuple(object value, Destructuring destructuring, Type } } - { - result = new SequenceValue(elements); - return true; - } + result = new SequenceValue(elements); + return true; } result = null; From f3d2edd4a3efcd8cf2e6c1559e0ee2a18d912550 Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Wed, 31 May 2017 10:37:53 +1000 Subject: [PATCH 39/58] Minimal test cases --- .../Parameters/PropertyValueConverterTests.cs | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/test/Serilog.Tests/Parameters/PropertyValueConverterTests.cs b/test/Serilog.Tests/Parameters/PropertyValueConverterTests.cs index 63d5a1a71..bb73ef177 100644 --- a/test/Serilog.Tests/Parameters/PropertyValueConverterTests.cs +++ b/test/Serilog.Tests/Parameters/PropertyValueConverterTests.cs @@ -271,6 +271,39 @@ public void ValueTuplesAreRecognizedWhenDestructuring() Assert.Equal(1, nested.Elements.Count); Assert.Equal(new ScalarValue("B"), nested.Elements[0]); } + + [Fact] + public void AllTupleLengthsUpToSevenAreSupported() + { + var tuples = new object[] + { + ValueTuple.Create(1), + (1, 2), + (1, 2, 3), + (1, 2, 3, 4), + (1, 2, 3, 4, 5), + (1, 2, 3, 4, 5, 6), + (1, 2, 3, 4, 5, 6, 7) + }; + + foreach (var t in tuples) + Assert.IsType(_converter.CreatePropertyValue(t)); + } + + [Fact] + public void EightPlusValueTupleElementsAreIgnored() + { + var scalar = _converter.CreatePropertyValue((1, 2, 3, 4, 5, 6, 7, 8)); + Assert.IsType(scalar); + } + + [Fact] + public void DestructuringIsTransitivelyApplied() + { + var tuple = _converter.CreatePropertyValue(ValueTuple.Create(new {A = 1}), true); + var sequence = Assert.IsType(tuple); + Assert.IsType(sequence.Elements[0]); + } } } From b4888cebe7fb27fcf2b78b2965c9785bbd8d11ec Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Wed, 31 May 2017 12:12:53 +1000 Subject: [PATCH 40/58] Added message template rendering benchmark --- test/Serilog.PerformanceTests/Harness.cs | 6 +++ .../MessageTemplateRenderingBenchmark.cs | 41 +++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 test/Serilog.PerformanceTests/MessageTemplateRenderingBenchmark.cs diff --git a/test/Serilog.PerformanceTests/Harness.cs b/test/Serilog.PerformanceTests/Harness.cs index 44b8d1ed9..72d32eef4 100644 --- a/test/Serilog.PerformanceTests/Harness.cs +++ b/test/Serilog.PerformanceTests/Harness.cs @@ -68,5 +68,11 @@ public void OutputTemplateRendering() { BenchmarkRunner.Run(); } + + [Fact] + public void MessageTemplateRenderingBenchmark() + { + BenchmarkRunner.Run(); + } } } \ No newline at end of file diff --git a/test/Serilog.PerformanceTests/MessageTemplateRenderingBenchmark.cs b/test/Serilog.PerformanceTests/MessageTemplateRenderingBenchmark.cs new file mode 100644 index 000000000..76023f421 --- /dev/null +++ b/test/Serilog.PerformanceTests/MessageTemplateRenderingBenchmark.cs @@ -0,0 +1,41 @@ +using BenchmarkDotNet.Attributes; +using System.IO; +using Serilog.Events; +using Serilog.PerformanceTests.Support; + +namespace Serilog.PerformanceTests +{ + /// + /// Determines the cost of rendering a message template. + /// + public class MessageTemplateRenderingBenchmark + { + static readonly LogEvent NoProperties = + Some.InformationEvent("This template has no properties"); + + static readonly LogEvent VariedProperties = + 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. + } + + [Benchmark] + public void TemplateWithNoProperties() + { + NoProperties.MessageTemplate.Render(NoProperties.Properties, _output); + } + + [Benchmark] + public void TemplateWithVariedProperties() + { + VariedProperties.MessageTemplate.Render(VariedProperties.Properties, _output); + } + } +} From d2dd76d2f62a8c4eb35c333077bf25e00b625d40 Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Wed, 31 May 2017 14:09:54 +1000 Subject: [PATCH 41/58] Initial work for #958 - stop allocating output properties during rendering --- src/Serilog/Events/ScalarValue.cs | 15 ++- .../Formatting/Display/LiteralStringValue.cs | 4 +- .../Formatting/Display/LogEventLevelValue.cs | 72 +++++++------- .../Display/LogEventPropertiesValue.cs | 12 ++- .../Display/LogEventPropertyMessageValue.cs | 1 + .../Display/MessageTemplateTextFormatter.cs | 98 ++++++++++++++----- .../Formatting/Display/OutputProperties.cs | 6 +- src/Serilog/Formatting/Display/Padding.cs | 21 ++-- src/Serilog/Parsing/PropertyToken.cs | 6 +- src/Serilog/Parsing/TextToken.cs | 3 +- src/Serilog/Serilog.csproj | 2 + 11 files changed, 157 insertions(+), 83 deletions(-) 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/LiteralStringValue.cs b/src/Serilog/Formatting/Display/LiteralStringValue.cs index 82f172536..a056baca2 100644 --- a/src/Serilog/Formatting/Display/LiteralStringValue.cs +++ b/src/Serilog/Formatting/Display/LiteralStringValue.cs @@ -20,14 +20,14 @@ namespace Serilog.Formatting.Display { // 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/LogEventLevelValue.cs b/src/Serilog/Formatting/Display/LogEventLevelValue.cs index d850722c3..055c25cf8 100644 --- a/src/Serilog/Formatting/Display/LogEventLevelValue.cs +++ b/src/Serilog/Formatting/Display/LogEventLevelValue.cs @@ -54,6 +54,7 @@ class LogEventLevelValue : LogEventPropertyValue new []{ "F", "FA", "FTL", "FATL" } }; + [Obsolete("Not used by the current output formatting implementation.")] public LogEventLevelValue(LogEventLevel value) { _value = value; @@ -64,48 +65,49 @@ public LogEventLevelValue(LogEventLevel value) /// public override void Render(TextWriter output, string format = null, IFormatProvider formatProvider = null) { - if (format != null && (format.Length == 2 || format.Length == 3)) + output.Write(GetLevelMoniker(_value, format)); + } + + 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) { - // 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'; - } + width *= 10; + width += format[2] - '0'; + } - if (width < 1) - return; + if (width < 1) + return string.Empty; - if (width > 4) - { - var value = _value.ToString(); - if (value.Length > width) - value = value.Substring(0, width); - output.Write(Casing.Format(value)); - return; - } + 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) + var index = (int)value; + if (index >= 0 && index <= (int) LogEventLevel.Fatal) + { + switch (format[0]) { - 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; - } + case 'w': + return _lowercaseLevelMap[index][width - 1]; + case 'u': + return _uppercaseLevelMap[index][width - 1]; + case 't': + return _titleCaseLevelMap[index][width - 1]; } } - output.Write(Casing.Format(_value.ToString(), format)); + return Casing.Format(value.ToString(), format); } } -} \ No newline at end of file +} diff --git a/src/Serilog/Formatting/Display/LogEventPropertiesValue.cs b/src/Serilog/Formatting/Display/LogEventPropertiesValue.cs index 1e47f0ee7..c58ac9384 100644 --- a/src/Serilog/Formatting/Display/LogEventPropertiesValue.cs +++ b/src/Serilog/Formatting/Display/LogEventPropertiesValue.cs @@ -25,6 +25,7 @@ class LogEventPropertiesValue : LogEventPropertyValue readonly IReadOnlyDictionary _properties; readonly MessageTemplate _outputTemplate; + [Obsolete("Not used by the current output formatting implementation.")] public LogEventPropertiesValue(MessageTemplate template, IReadOnlyDictionary properties, MessageTemplate outputTemplate) { _template = template; @@ -33,18 +34,23 @@ public LogEventPropertiesValue(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/Display/LogEventPropertyMessageValue.cs b/src/Serilog/Formatting/Display/LogEventPropertyMessageValue.cs index f021962cd..d897ca914 100644 --- a/src/Serilog/Formatting/Display/LogEventPropertyMessageValue.cs +++ b/src/Serilog/Formatting/Display/LogEventPropertyMessageValue.cs @@ -19,6 +19,7 @@ namespace Serilog.Formatting.Display { + [Obsolete("Not used by the current output formatting implementation.")] class LogEventPropertyMessageValue : LogEventPropertyValue { readonly MessageTemplate _template; diff --git a/src/Serilog/Formatting/Display/MessageTemplateTextFormatter.cs b/src/Serilog/Formatting/Display/MessageTemplateTextFormatter.cs index 0c1ae7f8d..fe4ddb6e9 100644 --- a/src/Serilog/Formatting/Display/MessageTemplateTextFormatter.cs +++ b/src/Serilog/Formatting/Display/MessageTemplateTextFormatter.cs @@ -35,6 +35,8 @@ public class MessageTemplateTextFormatter : ITextFormatter readonly IFormatProvider _formatProvider; readonly MessageTemplate _outputTemplate; + static readonly IReadOnlyDictionary NoProperties = new Dictionary(); + /// /// Construct a . /// @@ -58,42 +60,90 @@ 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); + tt.Render(NoProperties, output, _formatProvider); 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; + var pt = (PropertyToken)token; - // 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) + if (pt.PropertyName == OutputProperties.MessagePropertyName) { - var overridden = new Dictionary + if (pt.Alignment.HasValue) { - { pt.PropertyName, new LiteralStringValue((string) sv.Value) } - }; - - token.Render(overridden, output, _formatProvider); + var sw = new StringWriter(); + logEvent.MessageTemplate.Render(logEvent.Properties, sw, _formatProvider); + Padding.Apply(output, sw.ToString(), pt.Alignment); + } + else + { + logEvent.MessageTemplate.Render(logEvent.Properties, output, _formatProvider); + } + } + else if (pt.PropertyName == OutputProperties.TimestampPropertyName) + { + if (pt.Alignment.HasValue) + { + var sw = new StringWriter(); + ScalarValue.Render(logEvent.Timestamp, sw, pt.Format, _formatProvider); + Padding.Apply(output, sw.ToString(), pt.Alignment); + } + else + { + ScalarValue.Render(logEvent.Timestamp, output, pt.Format, _formatProvider); + } + } + else if (pt.PropertyName == OutputProperties.LevelPropertyName) + { + var moniker = LogEventLevelValue.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 if (pt.PropertyName == OutputProperties.PropertiesPropertyName) + { + if (pt.Alignment.HasValue) + { + var sw = new StringWriter(); + LogEventPropertiesValue.Render(logEvent.MessageTemplate, logEvent.Properties, _outputTemplate, sw, _formatProvider); + Padding.Apply(output, sw.ToString(), pt.Alignment); + } + else + { + LogEventPropertiesValue.Render(logEvent.MessageTemplate, logEvent.Properties, _outputTemplate, output, _formatProvider); + } } else { - token.Render(outputProperties, output, _formatProvider); + // First variation from normal rendering - 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; + + // 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?.Value is string literalString) + { + var cased = Casing.Format(literalString, pt.Format); + Padding.Apply(output, cased, pt.Alignment); + } + else + { + token.Render(logEvent.Properties, output, _formatProvider); + } } } } diff --git a/src/Serilog/Formatting/Display/OutputProperties.cs b/src/Serilog/Formatting/Display/OutputProperties.cs index 14065c4db..022b64467 100644 --- a/src/Serilog/Formatting/Display/OutputProperties.cs +++ b/src/Serilog/Formatting/Display/OutputProperties.cs @@ -17,6 +17,8 @@ using System.Linq; using Serilog.Events; +#pragma warning disable 618 + namespace Serilog.Formatting.Display { /// @@ -62,7 +64,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 +76,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); diff --git a/src/Serilog/Formatting/Display/Padding.cs b/src/Serilog/Formatting/Display/Padding.cs index de6744f34..6fcf7e0c2 100644 --- a/src/Serilog/Formatting/Display/Padding.cs +++ b/src/Serilog/Formatting/Display/Padding.cs @@ -6,12 +6,14 @@ namespace Serilog.Formatting.Display { 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) + if (!alignment.HasValue || value.Length <= alignment.Value.Width) { output.Write(value); return; @@ -19,13 +21,20 @@ public static void Apply(TextWriter output, string value, Alignment? alignment) 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(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/Parsing/PropertyToken.cs b/src/Serilog/Parsing/PropertyToken.cs index ef4db7c3a..73d879926 100644 --- a/src/Serilog/Parsing/PropertyToken.cs +++ b/src/Serilog/Parsing/PropertyToken.cs @@ -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; diff --git a/src/Serilog/Parsing/TextToken.cs b/src/Serilog/Parsing/TextToken.cs index 9035d57d1..daf1531ca 100644 --- a/src/Serilog/Parsing/TextToken.cs +++ b/src/Serilog/Parsing/TextToken.cs @@ -32,8 +32,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)); } /// diff --git a/src/Serilog/Serilog.csproj b/src/Serilog/Serilog.csproj index 698c466f6..fed10897a 100644 --- a/src/Serilog/Serilog.csproj +++ b/src/Serilog/Serilog.csproj @@ -18,6 +18,8 @@ false true + True + From 391882a3dd3e1c86f0ea116b7ad71f3f9ed3b761 Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Wed, 31 May 2017 14:19:57 +1000 Subject: [PATCH 42/58] Fix tests --- src/Serilog/Formatting/Display/Padding.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Serilog/Formatting/Display/Padding.cs b/src/Serilog/Formatting/Display/Padding.cs index 6fcf7e0c2..7872d680f 100644 --- a/src/Serilog/Formatting/Display/Padding.cs +++ b/src/Serilog/Formatting/Display/Padding.cs @@ -13,7 +13,7 @@ static class Padding /// public static void Apply(TextWriter output, string value, Alignment? alignment) { - if (!alignment.HasValue || value.Length <= alignment.Value.Width) + if (!alignment.HasValue || value.Length >= alignment.Value.Width) { output.Write(value); return; From b02acd281df277d8d0d6282e6377344f309a4afc Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Wed, 31 May 2017 15:12:18 +1000 Subject: [PATCH 43/58] Separate current and obsolete formatting code --- src/Serilog/Formatting/Display/Casing.cs | 16 +++++++- ...ventLevelValue.cs => LevelOutputFormat.cs} | 35 ++++------------ .../Display/MessageTemplateTextFormatter.cs | 8 ++-- .../{ => Obsolete}/LiteralStringValue.cs | 2 +- .../Display/Obsolete/LogEventLevelValue.cs | 40 ++++++++++++++++++ .../Obsolete/LogEventPropertiesValue.cs | 41 +++++++++++++++++++ .../LogEventPropertyMessageValue.cs | 2 +- .../Formatting/Display/OutputProperties.cs | 5 ++- src/Serilog/Formatting/Display/Padding.cs | 16 +++++++- ...tiesValue.cs => PropertiesOutputFormat.cs} | 21 +--------- 10 files changed, 131 insertions(+), 55 deletions(-) rename src/Serilog/Formatting/Display/{LogEventLevelValue.cs => LevelOutputFormat.cs} (76%) rename src/Serilog/Formatting/Display/{ => Obsolete}/LiteralStringValue.cs (97%) create mode 100644 src/Serilog/Formatting/Display/Obsolete/LogEventLevelValue.cs create mode 100644 src/Serilog/Formatting/Display/Obsolete/LogEventPropertiesValue.cs rename src/Serilog/Formatting/Display/{ => Obsolete}/LogEventPropertyMessageValue.cs (96%) rename src/Serilog/Formatting/Display/{LogEventPropertiesValue.cs => PropertiesOutputFormat.cs} (70%) diff --git a/src/Serilog/Formatting/Display/Casing.cs b/src/Serilog/Formatting/Display/Casing.cs index b024e8b87..a4e717278 100644 --- a/src/Serilog/Formatting/Display/Casing.cs +++ b/src/Serilog/Formatting/Display/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.Formatting.Display { static class Casing { diff --git a/src/Serilog/Formatting/Display/LogEventLevelValue.cs b/src/Serilog/Formatting/Display/LevelOutputFormat.cs similarity index 76% rename from src/Serilog/Formatting/Display/LogEventLevelValue.cs rename to src/Serilog/Formatting/Display/LevelOutputFormat.cs index 055c25cf8..8e3977c70 100644 --- a/src/Serilog/Formatting/Display/LogEventLevelValue.cs +++ b/src/Serilog/Formatting/Display/LevelOutputFormat.cs @@ -1,4 +1,4 @@ -// Copyright 2013-2015 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. @@ -12,21 +12,18 @@ // 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 + /// + /// 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 { - readonly LogEventLevel _value; - static readonly string[][] _titleCaseLevelMap = { new []{ "V", "Vb", "Vrb", "Verb" }, new []{ "D", "De", "Dbg", "Dbug" }, @@ -54,20 +51,6 @@ class LogEventLevelValue : LogEventPropertyValue new []{ "F", "FA", "FTL", "FATL" } }; - [Obsolete("Not used by the current output formatting implementation.")] - 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(GetLevelMoniker(_value, format)); - } - public static string GetLevelMoniker(LogEventLevel value, string format = null) { if (format == null || format.Length != 2 && format.Length != 3) @@ -110,4 +93,4 @@ public static string GetLevelMoniker(LogEventLevel value, string format = null) return 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 fe4ddb6e9..ee247f249 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. @@ -98,7 +98,7 @@ public void Format(LogEvent logEvent, TextWriter output) } else if (pt.PropertyName == OutputProperties.LevelPropertyName) { - var moniker = LogEventLevelValue.GetLevelMoniker(logEvent.Level, pt.Format); + var moniker = LevelOutputFormat.GetLevelMoniker(logEvent.Level, pt.Format); Padding.Apply(output, moniker, pt.Alignment); } else if (pt.PropertyName == OutputProperties.NewLinePropertyName) @@ -115,12 +115,12 @@ public void Format(LogEvent logEvent, TextWriter output) if (pt.Alignment.HasValue) { var sw = new StringWriter(); - LogEventPropertiesValue.Render(logEvent.MessageTemplate, logEvent.Properties, _outputTemplate, sw, _formatProvider); + PropertiesOutputFormat.Render(logEvent.MessageTemplate, logEvent.Properties, _outputTemplate, sw, _formatProvider); Padding.Apply(output, sw.ToString(), pt.Alignment); } else { - LogEventPropertiesValue.Render(logEvent.MessageTemplate, logEvent.Properties, _outputTemplate, output, _formatProvider); + PropertiesOutputFormat.Render(logEvent.MessageTemplate, logEvent.Properties, _outputTemplate, output, _formatProvider); } } else diff --git a/src/Serilog/Formatting/Display/LiteralStringValue.cs b/src/Serilog/Formatting/Display/Obsolete/LiteralStringValue.cs similarity index 97% rename from src/Serilog/Formatting/Display/LiteralStringValue.cs rename to src/Serilog/Formatting/Display/Obsolete/LiteralStringValue.cs index a056baca2..f537c5e24 100644 --- a/src/Serilog/Formatting/Display/LiteralStringValue.cs +++ b/src/Serilog/Formatting/Display/Obsolete/LiteralStringValue.cs @@ -16,7 +16,7 @@ using System.IO; using Serilog.Events; -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. 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 96% rename from src/Serilog/Formatting/Display/LogEventPropertyMessageValue.cs rename to src/Serilog/Formatting/Display/Obsolete/LogEventPropertyMessageValue.cs index d897ca914..9507a7fb2 100644 --- a/src/Serilog/Formatting/Display/LogEventPropertyMessageValue.cs +++ b/src/Serilog/Formatting/Display/Obsolete/LogEventPropertyMessageValue.cs @@ -17,7 +17,7 @@ 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 diff --git a/src/Serilog/Formatting/Display/OutputProperties.cs b/src/Serilog/Formatting/Display/OutputProperties.cs index 022b64467..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,7 @@ using System.Collections.Generic; using System.Linq; using Serilog.Events; +using Serilog.Formatting.Display.Obsolete; #pragma warning disable 618 @@ -96,4 +97,4 @@ internal static IReadOnlyDictionary GetOutputProp return result; } } -} \ No newline at end of file +} diff --git a/src/Serilog/Formatting/Display/Padding.cs b/src/Serilog/Formatting/Display/Padding.cs index 7872d680f..bd0e059fc 100644 --- a/src/Serilog/Formatting/Display/Padding.cs +++ b/src/Serilog/Formatting/Display/Padding.cs @@ -1,4 +1,18 @@ -using System.IO; +// 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; diff --git a/src/Serilog/Formatting/Display/LogEventPropertiesValue.cs b/src/Serilog/Formatting/Display/PropertiesOutputFormat.cs similarity index 70% rename from src/Serilog/Formatting/Display/LogEventPropertiesValue.cs rename to src/Serilog/Formatting/Display/PropertiesOutputFormat.cs index c58ac9384..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,25 +19,8 @@ namespace Serilog.Formatting.Display { - class LogEventPropertiesValue : LogEventPropertyValue + static class PropertiesOutputFormat { - readonly MessageTemplate _template; - readonly IReadOnlyDictionary _properties; - readonly MessageTemplate _outputTemplate; - - [Obsolete("Not used by the current output formatting implementation.")] - 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) - { - Render(_template, _properties, _outputTemplate, output, formatProvider); - } - public static void Render(MessageTemplate template, IReadOnlyDictionary properties, MessageTemplate outputTemplate, TextWriter output, IFormatProvider formatProvider = null) { output.Write('{'); From ffee0dba4d4182f913cc71e2b4284a7f72b33832 Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Wed, 31 May 2017 22:22:45 +1000 Subject: [PATCH 44/58] Separate rendering of message templates from their representation --- .../Data/LogEventPropertyValueVisitor.cs | 4 +- src/Serilog/Events/MessageTemplate.cs | 15 ++- .../Display/MessageTemplateRenderer.cs | 100 ++++++++++++++++++ .../Display/MessageTemplateTextFormatter.cs | 4 +- src/Serilog/Formatting/Json/JsonFormatter.cs | 3 +- src/Serilog/Parsing/PropertyToken.cs | 27 +---- 6 files changed, 116 insertions(+), 37 deletions(-) create mode 100644 src/Serilog/Formatting/Display/MessageTemplateRenderer.cs 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..55daeb35d 100644 --- a/src/Serilog/Events/MessageTemplate.cs +++ b/src/Serilog/Events/MessageTemplate.cs @@ -17,6 +17,7 @@ using System.IO; using System.Linq; using Serilog.Debugging; +using Serilog.Formatting.Display; using Serilog.Parsing; 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,7 @@ 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); - } + MessageTemplateRenderer.Render(this, properties, output, null, formatProvider); } } } diff --git a/src/Serilog/Formatting/Display/MessageTemplateRenderer.cs b/src/Serilog/Formatting/Display/MessageTemplateRenderer.cs new file mode 100644 index 000000000..34fa4b305 --- /dev/null +++ b/src/Serilog/Formatting/Display/MessageTemplateRenderer.cs @@ -0,0 +1,100 @@ +// 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.Collections.Generic; +using System.IO; +using Serilog.Events; +using Serilog.Formatting.Json; +using Serilog.Parsing; + +namespace Serilog.Formatting.Display +{ + static class MessageTemplateRenderer + { + static JsonValueFormatter JsonValueFormatter = new JsonValueFormatter("$type"); + + public static void Render(MessageTemplate messageTemplate, IReadOnlyDictionary properties, TextWriter output, string format = null, IFormatProvider formatProvider = null) + { + if (messageTemplate == null) throw new ArgumentNullException(nameof(messageTemplate)); + if (properties == null) throw new ArgumentNullException(nameof(properties)); + if (output == null) throw new ArgumentNullException(nameof(output)); + + bool isLiteral = false, isJson = false; + + if (format != null && (format.Length == 1 || format.Length == 2)) + { + isLiteral = format[0] == 'l' || format[1] == 'l'; + isJson = format[0] == 'j' || format[1] == 'j'; + } + + foreach (var token in messageTemplate.TokenArray) + { + if (token is TextToken tt) + { + output.Write(tt.Text); + } + else + { + var pt = (PropertyToken) token; + RenderPropertyToken(pt, properties, output, formatProvider, isLiteral, isJson); + } + } + } + + 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/Formatting/Display/MessageTemplateTextFormatter.cs b/src/Serilog/Formatting/Display/MessageTemplateTextFormatter.cs index ee247f249..1013b8f14 100644 --- a/src/Serilog/Formatting/Display/MessageTemplateTextFormatter.cs +++ b/src/Serilog/Formatting/Display/MessageTemplateTextFormatter.cs @@ -75,12 +75,12 @@ public void Format(LogEvent logEvent, TextWriter output) if (pt.Alignment.HasValue) { var sw = new StringWriter(); - logEvent.MessageTemplate.Render(logEvent.Properties, sw, _formatProvider); + MessageTemplateRenderer.Render(logEvent.MessageTemplate, logEvent.Properties, sw, pt.Format, _formatProvider); Padding.Apply(output, sw.ToString(), pt.Alignment); } else { - logEvent.MessageTemplate.Render(logEvent.Properties, output, _formatProvider); + MessageTemplateRenderer.Render(logEvent.MessageTemplate, logEvent.Properties, output, pt.Format, _formatProvider); } } else if (pt.PropertyName == OutputProperties.TimestampPropertyName) diff --git a/src/Serilog/Formatting/Json/JsonFormatter.cs b/src/Serilog/Formatting/Json/JsonFormatter.cs index aded1eb29..ee97bcc61 100644 --- a/src/Serilog/Formatting/Json/JsonFormatter.cs +++ b/src/Serilog/Formatting/Json/JsonFormatter.cs @@ -20,6 +20,7 @@ using System.IO; using System.Linq; using Serilog.Events; +using Serilog.Formatting.Display; using Serilog.Parsing; 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/Parsing/PropertyToken.cs b/src/Serilog/Parsing/PropertyToken.cs index 73d879926..403ce5e3d 100644 --- a/src/Serilog/Parsing/PropertyToken.cs +++ b/src/Serilog/Parsing/PropertyToken.cs @@ -87,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); } /// @@ -138,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. /// From 888a49866d65256bb75ed1f59c019f725c1cbac8 Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Thu, 1 Jun 2017 19:47:15 +1000 Subject: [PATCH 45/58] Review feedback - avoid package dependency on platforms without native ValueTuple --- .../Parameters/PropertyValueConverter.cs | 12 ++++- src/Serilog/Serilog.csproj | 50 +++++++++---------- test/Serilog.Tests/Serilog.Tests.csproj | 1 + 3 files changed, 35 insertions(+), 28 deletions(-) diff --git a/src/Serilog/Parameters/PropertyValueConverter.cs b/src/Serilog/Parameters/PropertyValueConverter.cs index 1e627ab40..657836dba 100755 --- a/src/Serilog/Parameters/PropertyValueConverter.cs +++ b/src/Serilog/Parameters/PropertyValueConverter.cs @@ -233,10 +233,20 @@ static bool TryConvertValueTuple(object value, Destructuring destructuring, Type } var definition = valueType.GetGenericTypeDefinition(); + + // Ignore the 8+ value case for now. +#if VALUETUPLE if (definition == typeof(ValueTuple<>) || definition == typeof(ValueTuple<,>) || definition == typeof(ValueTuple<,,>) || definition == typeof(ValueTuple<,,,>) || definition == typeof(ValueTuple<,,,,>) || definition == typeof(ValueTuple<,,,,,>) || - definition == typeof(ValueTuple<,,,,,,>)) // Ignore the 8+ value case for now. + definition == typeof(ValueTuple<,,,,,,>)) +#else + var defn = definition.FullName; + if (defn == "System.ValueTuple`1" || defn == "System.ValueTuple`2" || + defn == "System.ValueTuple`3" || defn == "System.ValueTuple`4" || + defn == "System.ValueTuple`5" || defn == "System.ValueTuple`6" || + defn == "System.ValueTuple`7") +#endif { var elements = new List(); foreach (var field in valueType.GetTypeInfo().DeclaredFields) diff --git a/src/Serilog/Serilog.csproj b/src/Serilog/Serilog.csproj index 2362223d5..ad479c83b 100644 --- a/src/Serilog/Serilog.csproj +++ b/src/Serilog/Serilog.csproj @@ -23,44 +23,40 @@ - - - - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/test/Serilog.Tests/Serilog.Tests.csproj b/test/Serilog.Tests/Serilog.Tests.csproj index dfa074061..389b2f5f4 100644 --- a/test/Serilog.Tests/Serilog.Tests.csproj +++ b/test/Serilog.Tests/Serilog.Tests.csproj @@ -18,6 +18,7 @@ + From a74938cda85d00257e28e661649a277a0e21aacc Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Thu, 1 Jun 2017 20:14:03 +1000 Subject: [PATCH 46/58] Namespace layout and RESHARPER GREEN! --- Serilog.sln.DotSettings | 13 ++- .../{Parameters => Capturing}/DepthLimiter.cs | 2 +- .../GetablePropertyFinder.cs | 2 +- .../MessageTemplateProcessor.cs | 4 +- .../PropertyBinder.cs | 2 +- .../PropertyValueConverter.cs | 4 +- src/Serilog/Context/LogContext.cs | 1 - src/Serilog/Core/Logger.cs | 2 +- .../Core/Pipeline/MessageTemplateCache.cs | 6 +- src/Serilog/Events/MessageTemplate.cs | 2 +- .../Display/MessageTemplateTextFormatter.cs | 1 + src/Serilog/Formatting/Json/JsonFormatter.cs | 2 +- src/Serilog/LoggerConfiguration.cs | 2 +- src/Serilog/Parsing/PropertyToken.cs | 2 +- .../MessageTemplateRenderer.cs | 3 +- .../LevelControlBenchmark.cs | 4 - .../LogContextEnrichmentBenchmark.cs | 4 - .../MessageTemplateParsingBenchmark.cs | 8 -- .../NestedLoggerLatencyBenchmark.cs | 4 - .../PipelineBenchmark.cs | 8 -- test/Serilog.PerformanceTests/Support/Some.cs | 3 - .../Core/LogEventPropertyCapturingTests.cs | 2 +- .../Core/MessageTemplateTests.cs | 2 +- .../Core/SecondaryLoggerSinkTests.cs | 13 +-- .../Events/LogEventPropertyValueTests.cs | 2 +- .../Json/JsonValueFormatterTests.cs | 3 - .../Serilog.Tests/LoggerConfigurationTests.cs | 13 ++- .../MethodOverloadConventionTests.cs | 83 ++++++++++--------- .../Parameters/PropertyValueConverterTests.cs | 2 +- .../Settings/KeyValuePairSettingsTests.cs | 5 +- .../Settings/SettingValueConversionsTests.cs | 2 +- .../Serilog.Tests/Support/DisposableLogger.cs | 2 +- ...EventPropertyStructuralEqualityComparer.cs | 3 +- .../Support/LogEventPropertyValueComparer.cs | 2 +- test/Serilog.Tests/Support/StringSink.cs | 3 +- test/TestDummies/DummyThreadIdEnricher.cs | 6 +- test/TestDummies/Properties/AssemblyInfo.cs | 1 - 37 files changed, 97 insertions(+), 126 deletions(-) rename src/Serilog/{Parameters => Capturing}/DepthLimiter.cs (98%) rename src/Serilog/{Parameters => Capturing}/GetablePropertyFinder.cs (98%) rename src/Serilog/{Parameters => Capturing}/MessageTemplateProcessor.cs (92%) rename src/Serilog/{Parameters => Capturing}/PropertyBinder.cs (99%) rename src/Serilog/{Parameters => Capturing}/PropertyValueConverter.cs (99%) mode change 100755 => 100644 rename src/Serilog/{Formatting/Display => Rendering}/MessageTemplateRenderer.cs (98%) 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 e51b23794..1b5150536 100644 --- a/src/Serilog/Parameters/DepthLimiter.cs +++ b/src/Serilog/Capturing/DepthLimiter.cs @@ -17,7 +17,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 old mode 100755 new mode 100644 similarity index 99% rename from src/Serilog/Parameters/PropertyValueConverter.cs rename to src/Serilog/Capturing/PropertyValueConverter.cs index 712af6f18..6b3cc53b8 --- 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 @@ -258,7 +258,7 @@ IEnumerable GetProperties(object value, ILogEventPropertyValue 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, recursive.CreatePropertyValue(propValue, true)); } 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/Events/MessageTemplate.cs b/src/Serilog/Events/MessageTemplate.cs index 55daeb35d..240cee9ed 100644 --- a/src/Serilog/Events/MessageTemplate.cs +++ b/src/Serilog/Events/MessageTemplate.cs @@ -17,8 +17,8 @@ using System.IO; using System.Linq; using Serilog.Debugging; -using Serilog.Formatting.Display; using Serilog.Parsing; +using Serilog.Rendering; namespace Serilog.Events { diff --git a/src/Serilog/Formatting/Display/MessageTemplateTextFormatter.cs b/src/Serilog/Formatting/Display/MessageTemplateTextFormatter.cs index 1013b8f14..5295d7af1 100644 --- a/src/Serilog/Formatting/Display/MessageTemplateTextFormatter.cs +++ b/src/Serilog/Formatting/Display/MessageTemplateTextFormatter.cs @@ -17,6 +17,7 @@ using System.IO; using Serilog.Events; using Serilog.Parsing; +using Serilog.Rendering; namespace Serilog.Formatting.Display { diff --git a/src/Serilog/Formatting/Json/JsonFormatter.cs b/src/Serilog/Formatting/Json/JsonFormatter.cs index ee97bcc61..5e762ad7c 100644 --- a/src/Serilog/Formatting/Json/JsonFormatter.cs +++ b/src/Serilog/Formatting/Json/JsonFormatter.cs @@ -20,8 +20,8 @@ using System.IO; using System.Linq; using Serilog.Events; -using Serilog.Formatting.Display; using Serilog.Parsing; +using Serilog.Rendering; namespace Serilog.Formatting.Json { 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/PropertyToken.cs b/src/Serilog/Parsing/PropertyToken.cs index 403ce5e3d..282f9b1e2 100644 --- a/src/Serilog/Parsing/PropertyToken.cs +++ b/src/Serilog/Parsing/PropertyToken.cs @@ -18,7 +18,7 @@ using System.Globalization; using System.IO; using Serilog.Events; -using Serilog.Formatting.Display; +using Serilog.Rendering; namespace Serilog.Parsing { diff --git a/src/Serilog/Formatting/Display/MessageTemplateRenderer.cs b/src/Serilog/Rendering/MessageTemplateRenderer.cs similarity index 98% rename from src/Serilog/Formatting/Display/MessageTemplateRenderer.cs rename to src/Serilog/Rendering/MessageTemplateRenderer.cs index 34fa4b305..446e52556 100644 --- a/src/Serilog/Formatting/Display/MessageTemplateRenderer.cs +++ b/src/Serilog/Rendering/MessageTemplateRenderer.cs @@ -16,10 +16,11 @@ using System.Collections.Generic; using System.IO; using Serilog.Events; +using Serilog.Formatting.Display; using Serilog.Formatting.Json; using Serilog.Parsing; -namespace Serilog.Formatting.Display +namespace Serilog.Rendering { static class MessageTemplateRenderer { 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..a8320447a 100644 --- a/test/Serilog.PerformanceTests/MessageTemplateParsingBenchmark.cs +++ b/test/Serilog.PerformanceTests/MessageTemplateParsingBenchmark.cs @@ -1,13 +1,5 @@ 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 { 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/PipelineBenchmark.cs b/test/Serilog.PerformanceTests/PipelineBenchmark.cs index 6812f2345..dc5440604 100644 --- a/test/Serilog.PerformanceTests/PipelineBenchmark.cs +++ b/test/Serilog.PerformanceTests/PipelineBenchmark.cs @@ -14,16 +14,8 @@ // 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 { diff --git a/test/Serilog.PerformanceTests/Support/Some.cs b/test/Serilog.PerformanceTests/Support/Some.cs index 07fbf5aab..5c0287224 100644 --- a/test/Serilog.PerformanceTests/Support/Some.cs +++ b/test/Serilog.PerformanceTests/Support/Some.cs @@ -1,8 +1,5 @@ using System; -using System.Collections.Generic; -using System.IO; using System.Linq; -using System.Threading; using Serilog.Events; using Serilog.Parsing; 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/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 c757a2dfd..55f05d105 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/Parameters/PropertyValueConverterTests.cs b/test/Serilog.Tests/Parameters/PropertyValueConverterTests.cs index 025f1e979..6d3a47357 100644 --- a/test/Serilog.Tests/Parameters/PropertyValueConverterTests.cs +++ b/test/Serilog.Tests/Parameters/PropertyValueConverterTests.cs @@ -1,10 +1,10 @@ using System; using System.Collections.Generic; 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/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 From 2ce90e416bb3483e8d64e8b9bf5e844d7df921e1 Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Thu, 1 Jun 2017 20:39:30 +1000 Subject: [PATCH 47/58] Improve flow of MessageTemplateRenderer --- .../Formatting/Display/LevelOutputFormat.cs | 1 + .../Display/MessageTemplateTextFormatter.cs | 84 +++++++------------ .../Display/Obsolete/LiteralStringValue.cs | 1 + src/Serilog/Parsing/TextToken.cs | 3 +- .../Display => Rendering}/Casing.cs | 2 +- .../Rendering/MessageTemplateRenderer.cs | 10 ++- .../Display => Rendering}/Padding.cs | 3 +- 7 files changed, 45 insertions(+), 59 deletions(-) rename src/Serilog/{Formatting/Display => Rendering}/Casing.cs (97%) rename src/Serilog/{Formatting/Display => Rendering}/Padding.cs (97%) diff --git a/src/Serilog/Formatting/Display/LevelOutputFormat.cs b/src/Serilog/Formatting/Display/LevelOutputFormat.cs index 8e3977c70..76f9b3d5e 100644 --- a/src/Serilog/Formatting/Display/LevelOutputFormat.cs +++ b/src/Serilog/Formatting/Display/LevelOutputFormat.cs @@ -13,6 +13,7 @@ // limitations under the License. using Serilog.Events; +using Serilog.Rendering; namespace Serilog.Formatting.Display { diff --git a/src/Serilog/Formatting/Display/MessageTemplateTextFormatter.cs b/src/Serilog/Formatting/Display/MessageTemplateTextFormatter.cs index 5295d7af1..3ce7c27f9 100644 --- a/src/Serilog/Formatting/Display/MessageTemplateTextFormatter.cs +++ b/src/Serilog/Formatting/Display/MessageTemplateTextFormatter.cs @@ -70,34 +70,7 @@ public void Format(LogEvent logEvent, TextWriter output) } var pt = (PropertyToken)token; - - if (pt.PropertyName == OutputProperties.MessagePropertyName) - { - if (pt.Alignment.HasValue) - { - var sw = new StringWriter(); - MessageTemplateRenderer.Render(logEvent.MessageTemplate, logEvent.Properties, sw, pt.Format, _formatProvider); - Padding.Apply(output, sw.ToString(), pt.Alignment); - } - else - { - MessageTemplateRenderer.Render(logEvent.MessageTemplate, logEvent.Properties, output, pt.Format, _formatProvider); - } - } - else if (pt.PropertyName == OutputProperties.TimestampPropertyName) - { - if (pt.Alignment.HasValue) - { - var sw = new StringWriter(); - ScalarValue.Render(logEvent.Timestamp, sw, pt.Format, _formatProvider); - Padding.Apply(output, sw.ToString(), pt.Alignment); - } - else - { - ScalarValue.Render(logEvent.Timestamp, output, pt.Format, _formatProvider); - } - } - else if (pt.PropertyName == OutputProperties.LevelPropertyName) + if (pt.PropertyName == OutputProperties.LevelPropertyName) { var moniker = LevelOutputFormat.GetLevelMoniker(logEvent.Level, pt.Format); Padding.Apply(output, moniker, pt.Alignment); @@ -111,40 +84,47 @@ public void Format(LogEvent logEvent, TextWriter output) var exception = logEvent.Exception == null ? "" : logEvent.Exception + Environment.NewLine; Padding.Apply(output, exception, pt.Alignment); } - else if (pt.PropertyName == OutputProperties.PropertiesPropertyName) + else { - if (pt.Alignment.HasValue) + // 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) { - var sw = new StringWriter(); - PropertiesOutputFormat.Render(logEvent.MessageTemplate, logEvent.Properties, _outputTemplate, sw, _formatProvider); - Padding.Apply(output, sw.ToString(), pt.Alignment); + MessageTemplateRenderer.Render(logEvent.MessageTemplate, logEvent.Properties, writer, pt.Format, _formatProvider); } - else + else if (pt.PropertyName == OutputProperties.TimestampPropertyName) { - PropertiesOutputFormat.Render(logEvent.MessageTemplate, logEvent.Properties, _outputTemplate, output, _formatProvider); + ScalarValue.Render(logEvent.Timestamp, writer, pt.Format, _formatProvider); } - } - else - { - // First variation from normal rendering - 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; - - // 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?.Value is string literalString) + else if (pt.PropertyName == OutputProperties.PropertiesPropertyName) { - var cased = Casing.Format(literalString, pt.Format); - Padding.Apply(output, cased, pt.Alignment); + PropertiesOutputFormat.Render(logEvent.MessageTemplate, logEvent.Properties, _outputTemplate, writer, _formatProvider); } else { - token.Render(logEvent.Properties, output, _formatProvider); + // 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/Obsolete/LiteralStringValue.cs b/src/Serilog/Formatting/Display/Obsolete/LiteralStringValue.cs index f537c5e24..e7bc44023 100644 --- a/src/Serilog/Formatting/Display/Obsolete/LiteralStringValue.cs +++ b/src/Serilog/Formatting/Display/Obsolete/LiteralStringValue.cs @@ -15,6 +15,7 @@ using System; using System.IO; using Serilog.Events; +using Serilog.Rendering; namespace Serilog.Formatting.Display.Obsolete { diff --git a/src/Serilog/Parsing/TextToken.cs b/src/Serilog/Parsing/TextToken.cs index daf1531ca..974e5f530 100644 --- a/src/Serilog/Parsing/TextToken.cs +++ b/src/Serilog/Parsing/TextToken.cs @@ -16,6 +16,7 @@ using System.Collections.Generic; using System.IO; using Serilog.Events; +using Serilog.Rendering; namespace Serilog.Parsing { @@ -49,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 97% rename from src/Serilog/Formatting/Display/Casing.cs rename to src/Serilog/Rendering/Casing.cs index a4e717278..62aa022f5 100644 --- a/src/Serilog/Formatting/Display/Casing.cs +++ b/src/Serilog/Rendering/Casing.cs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -namespace Serilog.Formatting.Display +namespace Serilog.Rendering { static class Casing { diff --git a/src/Serilog/Rendering/MessageTemplateRenderer.cs b/src/Serilog/Rendering/MessageTemplateRenderer.cs index 446e52556..e4584b924 100644 --- a/src/Serilog/Rendering/MessageTemplateRenderer.cs +++ b/src/Serilog/Rendering/MessageTemplateRenderer.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,7 +16,6 @@ using System.Collections.Generic; using System.IO; using Serilog.Events; -using Serilog.Formatting.Display; using Serilog.Formatting.Json; using Serilog.Parsing; @@ -44,7 +43,7 @@ public static void Render(MessageTemplate messageTemplate, IReadOnlyDictionary properties, TextWriter output, IFormatProvider formatProvider, bool isLiteral, bool isJson) { LogEventPropertyValue propertyValue; diff --git a/src/Serilog/Formatting/Display/Padding.cs b/src/Serilog/Rendering/Padding.cs similarity index 97% rename from src/Serilog/Formatting/Display/Padding.cs rename to src/Serilog/Rendering/Padding.cs index bd0e059fc..23ea8206e 100644 --- a/src/Serilog/Formatting/Display/Padding.cs +++ b/src/Serilog/Rendering/Padding.cs @@ -13,10 +13,9 @@ // limitations under the License. using System.IO; - using Serilog.Parsing; -namespace Serilog.Formatting.Display +namespace Serilog.Rendering { static class Padding { From 3ba9d2a1669133b7535fa34b90282b3408bb5d51 Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Thu, 1 Jun 2017 21:17:02 +1000 Subject: [PATCH 48/58] Tests for {Message:l} and {Message:j} formatting --- src/Serilog/Formatting/Raw/RawFormatter.cs | 2 ++ src/Serilog/Parsing/MessageTemplateToken.cs | 1 + .../Rendering/MessageTemplateRenderer.cs | 14 ++++++--- .../PropertyValueConverterTests.cs | 4 +-- .../MessageTemplateTextFormatterTests.cs | 29 +++++++++++++++++++ 5 files changed, 44 insertions(+), 6 deletions(-) rename test/Serilog.Tests/{Parameters => Capturing}/PropertyValueConverterTests.cs (99%) 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/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/Rendering/MessageTemplateRenderer.cs b/src/Serilog/Rendering/MessageTemplateRenderer.cs index e4584b924..7da313f09 100644 --- a/src/Serilog/Rendering/MessageTemplateRenderer.cs +++ b/src/Serilog/Rendering/MessageTemplateRenderer.cs @@ -33,14 +33,20 @@ public static void Render(MessageTemplate messageTemplate, IReadOnlyDictionary 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()); + } } } From 5f5770d298c6fc4872b2d2eed0250eda8c342b41 Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Fri, 2 Jun 2017 08:43:48 +1000 Subject: [PATCH 49/58] Render text token through the external method --- .../Formatting/Display/MessageTemplateTextFormatter.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Serilog/Formatting/Display/MessageTemplateTextFormatter.cs b/src/Serilog/Formatting/Display/MessageTemplateTextFormatter.cs index 3ce7c27f9..ac45223db 100644 --- a/src/Serilog/Formatting/Display/MessageTemplateTextFormatter.cs +++ b/src/Serilog/Formatting/Display/MessageTemplateTextFormatter.cs @@ -13,7 +13,6 @@ // limitations under the License. using System; -using System.Collections.Generic; using System.IO; using Serilog.Events; using Serilog.Parsing; @@ -36,8 +35,6 @@ public class MessageTemplateTextFormatter : ITextFormatter readonly IFormatProvider _formatProvider; readonly MessageTemplate _outputTemplate; - static readonly IReadOnlyDictionary NoProperties = new Dictionary(); - /// /// Construct a . /// @@ -65,7 +62,7 @@ public void Format(LogEvent logEvent, TextWriter output) { if (token is TextToken tt) { - tt.Render(NoProperties, output, _formatProvider); + MessageTemplateRenderer.RenderTextToken(tt, output); continue; } From 0596b33eea8fa00ab8dafcd03c08952c7b29dfc7 Mon Sep 17 00:00:00 2001 From: Matthew Erbs Date: Sat, 3 Jun 2017 08:59:18 +1000 Subject: [PATCH 50/58] Independent Build for Perf Tests. --- appveyor-perftest.yml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 appveyor-perftest.yml diff --git a/appveyor-perftest.yml b/appveyor-perftest.yml new file mode 100644 index 000000000..cb30b3e60 --- /dev/null +++ b/appveyor-perftest.yml @@ -0,0 +1,7 @@ +version: '{build}' +skip_tags: true +image: Visual Studio 2017 +configuration: Release +test: off +build_script: +- ps: ./RunPerfTests.ps1 \ No newline at end of file From 8c33f2357fcffb3f89fbac19b057316a56bd6754 Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Sat, 3 Jun 2017 11:13:40 +1000 Subject: [PATCH 51/58] Review feedback/test case names. --- .../Serilog.Tests/Parameters/PropertyValueConverterTests.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/Serilog.Tests/Parameters/PropertyValueConverterTests.cs b/test/Serilog.Tests/Parameters/PropertyValueConverterTests.cs index bb73ef177..3728fb0a2 100644 --- a/test/Serilog.Tests/Parameters/PropertyValueConverterTests.cs +++ b/test/Serilog.Tests/Parameters/PropertyValueConverterTests.cs @@ -273,7 +273,7 @@ public void ValueTuplesAreRecognizedWhenDestructuring() } [Fact] - public void AllTupleLengthsUpToSevenAreSupported() + public void AllTupleLengthsUpToSevenAreSupportedForCapturing() { var tuples = new object[] { @@ -291,14 +291,14 @@ public void AllTupleLengthsUpToSevenAreSupported() } [Fact] - public void EightPlusValueTupleElementsAreIgnored() + public void EightPlusValueTupleElementsAreIgnoredByCapturing() { var scalar = _converter.CreatePropertyValue((1, 2, 3, 4, 5, 6, 7, 8)); Assert.IsType(scalar); } [Fact] - public void DestructuringIsTransitivelyApplied() + public void ValueTupleDestructuringIsTransitivelyApplied() { var tuple = _converter.CreatePropertyValue(ValueTuple.Create(new {A = 1}), true); var sequence = Assert.IsType(tuple); From 639427613a990666115644b801ac6602e9cf5516 Mon Sep 17 00:00:00 2001 From: Matthew Erbs Date: Sat, 3 Jun 2017 14:52:47 +1000 Subject: [PATCH 52/58] Removed install from build script and rely on Travis yml --- build.sh | 9 --------- 1 file changed, 9 deletions(-) diff --git a/build.sh b/build.sh index 461b5510b..9d02afdfc 100755 --- a/build.sh +++ b/build.sh @@ -1,13 +1,4 @@ #!/bin/bash -export DOTNET_INSTALL_DIR="$PWD/.dotnetcli" -DotnetCliVersion=${CLI_VERSION:="1.0.1"} -install_script_url=https://raw.githubusercontent.com/dotnet/cli/rel/1.0.0/scripts/obtain/dotnet-install.sh -curl -sSL $install_script_url | bash /dev/stdin --version "$DotnetCliVersion" --install-dir "$DOTNET_INSTALL_DIR" -export PATH="$DOTNET_INSTALL_DIR:$PATH" - -# See issue https://github.com/NuGet/Home/issues/2163 -ulimit -n 2048 - dotnet --info dotnet restore From 0308bc702686d886b4a00738dc6acacc0cf86064 Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Mon, 5 Jun 2017 08:37:46 +1000 Subject: [PATCH 53/58] Update BenchmarkDotNet to 0.10.6 --- .../Serilog.PerformanceTests.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/Serilog.PerformanceTests/Serilog.PerformanceTests.csproj b/test/Serilog.PerformanceTests/Serilog.PerformanceTests.csproj index 9b54fe0d9..7853b5859 100644 --- a/test/Serilog.PerformanceTests/Serilog.PerformanceTests.csproj +++ b/test/Serilog.PerformanceTests/Serilog.PerformanceTests.csproj @@ -1,6 +1,6 @@  - netcoreapp1.1;net452 + netcoreapp1.1;net46 Serilog.PerformanceTests ../../assets/Serilog.snk true @@ -18,11 +18,11 @@ - + - + From 4b0e2bef32c482f3d2ee5fc4f36ac707298772e4 Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Mon, 5 Jun 2017 08:50:45 +1000 Subject: [PATCH 54/58] Fix some dodgy string formatting benchmarks --- .../MessageTemplateRenderingBenchmark.cs | 9 +- .../OutputTemplateRenderingBenchmark.cs | 9 +- .../Support/NullTextWriter.cs | 160 ++++++++++++++++++ 3 files changed, 162 insertions(+), 16 deletions(-) create mode 100644 test/Serilog.PerformanceTests/Support/NullTextWriter.cs diff --git a/test/Serilog.PerformanceTests/MessageTemplateRenderingBenchmark.cs b/test/Serilog.PerformanceTests/MessageTemplateRenderingBenchmark.cs index 76023f421..125e2a512 100644 --- a/test/Serilog.PerformanceTests/MessageTemplateRenderingBenchmark.cs +++ b/test/Serilog.PerformanceTests/MessageTemplateRenderingBenchmark.cs @@ -17,14 +17,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/OutputTemplateRenderingBenchmark.cs b/test/Serilog.PerformanceTests/OutputTemplateRenderingBenchmark.cs index cae6a892d..17df8db72 100644 --- a/test/Serilog.PerformanceTests/OutputTemplateRenderingBenchmark.cs +++ b/test/Serilog.PerformanceTests/OutputTemplateRenderingBenchmark.cs @@ -17,14 +17,7 @@ public class OutputTemplateRenderingBenchmark 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/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) + { + } + } +} From c17ea150ec9587dd9ab78b65845502d603b30dbf Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Tue, 6 Jun 2017 07:46:56 +1000 Subject: [PATCH 55/58] Prevent xunit from shadow-copying test assemblies --- test/Serilog.PerformanceTests/xunit.runner.json | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 test/Serilog.PerformanceTests/xunit.runner.json diff --git a/test/Serilog.PerformanceTests/xunit.runner.json b/test/Serilog.PerformanceTests/xunit.runner.json new file mode 100644 index 000000000..42db7ef95 --- /dev/null +++ b/test/Serilog.PerformanceTests/xunit.runner.json @@ -0,0 +1,3 @@ +{ + "shadowCopy": false +} From e23e2bb7249631ee27580b3bd3cc00c5c9029141 Mon Sep 17 00:00:00 2001 From: Sergey Komisarchik Date: Thu, 6 Apr 2017 23:12:45 +0300 Subject: [PATCH 56/58] less allocations --- .../AllocationsBenchmark-report-github.md | 18 +++ .../AllocationsBenchmark-report-github.md | 19 +++ src/Serilog/Core/IScalarConversionPolicy.cs | 3 +- src/Serilog/Parameters/DepthLimiter.cs | 42 ++++-- .../Parameters/PropertyValueConverter.cs | 141 +++++++++++------- .../ByteArrayScalarConversionPolicy.cs | 4 +- .../Policies/EnumScalarConversionPolicy.cs | 4 +- .../NullableScalarConversionPolicy.cs | 39 ----- .../Policies/SimpleScalarConversionPolicy.cs | 4 +- .../AllocationsBenchmark.cs | 107 +++++++++++++ test/Serilog.PerformanceTests/Harness.cs | 9 +- .../Serilog.PerformanceTests.csproj | 22 ++- .../xunit.runner.json | 3 + test/Serilog.Tests/Context/LogContextTests.cs | 23 +-- .../Serilog.Tests/LoggerConfigurationTests.cs | 4 +- .../Parameters/PropertyValueConverterTests.cs | 57 +++++++ test/Serilog.Tests/Serilog.Tests.csproj | 2 +- 17 files changed, 350 insertions(+), 151 deletions(-) create mode 100644 results/net46/AllocationsBenchmark-report-github.md create mode 100644 results/netcoreapp1.1/AllocationsBenchmark-report-github.md mode change 100755 => 100644 src/Serilog/Parameters/PropertyValueConverter.cs delete mode 100644 src/Serilog/Policies/NullableScalarConversionPolicy.cs create mode 100644 test/Serilog.PerformanceTests/AllocationsBenchmark.cs create mode 100644 test/Serilog.PerformanceTests/xunit.runner.json 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() - .Take(_maximumCollectionCount) - .Select(kvp => new KeyValuePair( - (ScalarValue) limiter.CreatePropertyValue(keyProperty.GetValue(kvp), destructuring), - limiter.CreatePropertyValue(valueProperty.GetValue(kvp), destructuring))) - .Where(kvp => kvp.Key.Value != null)); + result = new DictionaryValue(MapToDictionaryElements(dictionary, destructuring)); return true; - } - result = new SequenceValue(enumerable - .Cast() - .Take(_maximumCollectionCount) - .Select(o => limiter.CreatePropertyValue(o, destructuring))); + IEnumerable> MapToDictionaryElements(IDictionary dictionaryEntries, Destructuring destructure) + { + var count = 0; + foreach (DictionaryEntry entry in dictionaryEntries) + { + if (++count > _maximumCollectionCount) + { + yield break; + } + + var pair = new KeyValuePair( + (ScalarValue)_depthLimiter.CreatePropertyValue(entry.Key, destructure), + _depthLimiter.CreatePropertyValue(entry.Value, destructure)); + + if (pair.Key.Value != null) + yield return pair; + } + } + } + result = new SequenceValue(MapToSequenceElements(enumerable, destructuring)); return true; + + IEnumerable MapToSequenceElements(IEnumerable sequence, Destructuring destructure) + { + var count = 0; + foreach (var element in sequence) + { + if (++count > _maximumCollectionCount) + { + yield break; + } + + yield return _depthLimiter.CreatePropertyValue(element, destructure); + } + } } result = null; return false; } - static bool TryConvertValueTuple(object value, Destructuring destructuring, Type valueType, DepthLimiter limiter, out LogEventPropertyValue result) + bool TryConvertValueTuple(object value, Destructuring destructuring, Type valueType, out LogEventPropertyValue result) { if (!(value is IStructuralEquatable && valueType.IsConstructedGenericType)) { @@ -254,7 +260,7 @@ static bool TryConvertValueTuple(object value, Destructuring destructuring, Type if (field.IsPublic && !field.IsStatic) { var fieldValue = field.GetValue(value); - var propertyValue = limiter.CreatePropertyValue(fieldValue, destructuring); + var propertyValue = _depthLimiter.CreatePropertyValue(fieldValue, destructuring); elements.Add(propertyValue); } } @@ -267,6 +273,24 @@ static bool TryConvertValueTuple(object value, Destructuring destructuring, Type return false; } + bool TryConvertCompilerGeneratedType(object value, Destructuring destructuring, Type valueType, out LogEventPropertyValue result) + { + if (destructuring == Destructuring.Destructure) + { + var typeTag = valueType.Name; + if (typeTag.Length <= 0 || IsCompilerGeneratedType(valueType)) + { + typeTag = null; + } + + result = new StructureValue(GetProperties(value), typeTag); + return true; + } + + result = null; + return false; + } + LogEventPropertyValue Stringify(object value) { var stringified = value.ToString(); @@ -284,11 +308,18 @@ string TruncateIfNecessary(string text) return text; } - bool IsValueTypeDictionary(Type valueType) + bool TryGetDictionary(object value, Type valueType, out IDictionary dictionary) { - return valueType.IsConstructedGenericType && - valueType.GetGenericTypeDefinition() == typeof (Dictionary<,>) && - IsValidDictionaryKeyType(valueType.GenericTypeArguments[0]); + if (valueType.IsConstructedGenericType && + valueType.GetGenericTypeDefinition() == typeof(Dictionary<,>) && + IsValidDictionaryKeyType(valueType.GenericTypeArguments[0])) + { + dictionary = (IDictionary)value; + return true; + } + + dictionary = null; + return false; } bool IsValidDictionaryKeyType(Type valueType) @@ -297,7 +328,7 @@ bool IsValidDictionaryKeyType(Type valueType) valueType.GetTypeInfo().IsEnum; } - IEnumerable GetProperties(object value, ILogEventPropertyValueFactory recursive) + IEnumerable GetProperties(object value) { foreach (var prop in value.GetType().GetPropertiesRecursive()) { @@ -322,7 +353,7 @@ IEnumerable GetProperties(object value, ILogEventPropertyValue propValue = "The property accessor threw an exception: " + ex.InnerException.GetType().Name; } - yield return new LogEventProperty(prop.Name, recursive.CreatePropertyValue(propValue, true)); + yield return new LogEventProperty(prop.Name, _depthLimiter.CreatePropertyValue(propValue, Destructuring.Destructure)); } } diff --git a/src/Serilog/Policies/ByteArrayScalarConversionPolicy.cs b/src/Serilog/Policies/ByteArrayScalarConversionPolicy.cs index d0180eaf8..38504f9cc 100644 --- a/src/Serilog/Policies/ByteArrayScalarConversionPolicy.cs +++ b/src/Serilog/Policies/ByteArrayScalarConversionPolicy.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. @@ -25,7 +25,7 @@ class ByteArrayScalarConversionPolicy : IScalarConversionPolicy { const int MaximumByteArrayLength = 1024; - public bool TryConvertToScalar(object value, ILogEventPropertyValueFactory propertyValueFactory, out ScalarValue result) + public bool TryConvertToScalar(object value, out ScalarValue result) { var bytes = value as byte[]; if (bytes == null) diff --git a/src/Serilog/Policies/EnumScalarConversionPolicy.cs b/src/Serilog/Policies/EnumScalarConversionPolicy.cs index 2a215cba4..ebb59a7de 100644 --- a/src/Serilog/Policies/EnumScalarConversionPolicy.cs +++ b/src/Serilog/Policies/EnumScalarConversionPolicy.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. @@ -20,7 +20,7 @@ namespace Serilog.Policies { class EnumScalarConversionPolicy : IScalarConversionPolicy { - public bool TryConvertToScalar(object value, ILogEventPropertyValueFactory propertyValueFactory, out ScalarValue result) + public bool TryConvertToScalar(object value, out ScalarValue result) { if (value.GetType().GetTypeInfo().IsEnum) { diff --git a/src/Serilog/Policies/NullableScalarConversionPolicy.cs b/src/Serilog/Policies/NullableScalarConversionPolicy.cs deleted file mode 100644 index e4a19f138..000000000 --- a/src/Serilog/Policies/NullableScalarConversionPolicy.cs +++ /dev/null @@ -1,39 +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 Serilog.Core; -using Serilog.Events; - -namespace Serilog.Policies -{ - class NullableScalarConversionPolicy : IScalarConversionPolicy - { - public bool TryConvertToScalar(object value, ILogEventPropertyValueFactory propertyValueFactory, out ScalarValue result) - { - var type = value.GetType(); - if (!type.IsConstructedGenericType || type.GetGenericTypeDefinition() != typeof(Nullable<>)) - { - result = null; - return false; - } - - var targetType = type.GenericTypeArguments[0]; - - var innerValue = Convert.ChangeType(value, targetType); - result = propertyValueFactory.CreatePropertyValue(innerValue) as ScalarValue; - return result != null; - } - } -} diff --git a/src/Serilog/Policies/SimpleScalarConversionPolicy.cs b/src/Serilog/Policies/SimpleScalarConversionPolicy.cs index 4a87b6d4f..56c599848 100644 --- a/src/Serilog/Policies/SimpleScalarConversionPolicy.cs +++ b/src/Serilog/Policies/SimpleScalarConversionPolicy.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. @@ -28,7 +28,7 @@ public SimpleScalarConversionPolicy(IEnumerable scalarTypes) _scalarTypes = new HashSet(scalarTypes); } - public bool TryConvertToScalar(object value, ILogEventPropertyValueFactory propertyValueFactory, out ScalarValue result) + public bool TryConvertToScalar(object value, out ScalarValue result) { if (_scalarTypes.Contains(value.GetType())) { diff --git a/test/Serilog.PerformanceTests/AllocationsBenchmark.cs b/test/Serilog.PerformanceTests/AllocationsBenchmark.cs new file mode 100644 index 000000000..1805e01b4 --- /dev/null +++ b/test/Serilog.PerformanceTests/AllocationsBenchmark.cs @@ -0,0 +1,107 @@ +using Serilog.Events; +using Serilog.Parsing; +using Serilog.Core.Enrichers; + +using System; +using System.Linq; +using System.Collections.Generic; + +using BenchmarkDotNet.Attributes; + +namespace Serilog.PerformanceTests +{ + [MemoryDiagnoser] + public class AllocationsBenchmark + { + readonly ILogger _logger; + readonly ILogger _enrichedLogger; + readonly LogEvent _emptyEvent; + readonly object _dictionaryValue; + readonly object _anonymousObject; + readonly object _sequence; + + public AllocationsBenchmark() + { + _logger = new LoggerConfiguration().CreateLogger(); + + _enrichedLogger = _logger.ForContext(new PropertyEnricher("Prop", "Value")); + + _emptyEvent = new LogEvent( + DateTimeOffset.Now, + LogEventLevel.Information, + null, + new MessageTemplate(Enumerable.Empty()), + Enumerable.Empty()); + + _anonymousObject = new + { + Level11 = "Val1", + Level12 = new + { + Level21 = (int?)42, + Level22 = new + { + Level31 = System.Reflection.BindingFlags.FlattenHierarchy, + Level32 = new + { + X = 3, + Y = "4", + Z = (short?)5 + } + } + } + }; + + _dictionaryValue = new Dictionary { + { "Level11", "Val1" }, + { "Level12", new Dictionary() { + { "Level21", (int?)42 }, + { "Level22", new Dictionary() { + { "Level31", System.Reflection.BindingFlags.FlattenHierarchy }, + { "Level32", new { X = 3, Y = "4", Z = (short?)5 } } + } + } + } + } + }; + + _sequence = new List { "1", 2, (int?)3, "4", (short)5 }; + } + + [Benchmark(Baseline = true)] + public void LogEmpty() + { + _logger.Write(_emptyEvent); + } + + [Benchmark] + public void LogEmptyWithEnricher() + { + _enrichedLogger.Write(_emptyEvent); + } + + [Benchmark] + public void LogScalar() + { + _logger.Information("Template: {ScalarValue}", "42"); + } + + [Benchmark] + public void LogDictionary() + { + _logger.Information("Template: {DictionaryValue}", _dictionaryValue); + } + + [Benchmark] + public void LogSequence() + { + _logger.Information("Template: {SequenceValue}", _sequence); + } + + [Benchmark] + public void LogAnonymous() + { + _logger.Information("Template: {@AnonymousObject}.", _anonymousObject); + } + } +} diff --git a/test/Serilog.PerformanceTests/Harness.cs b/test/Serilog.PerformanceTests/Harness.cs index 72d32eef4..dd283c70f 100644 --- a/test/Serilog.PerformanceTests/Harness.cs +++ b/test/Serilog.PerformanceTests/Harness.cs @@ -1,5 +1,5 @@ -// Copyright 2013-2016 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. @@ -20,6 +20,13 @@ namespace Serilog.PerformanceTests { public class Harness { + // dotnet test -c Release -f net46 --filter "FullyQualifiedName=Serilog.PerformanceTests.Harness.AllocationsBenchmark" + [Fact] + public void AllocationsBenchmark() + { + BenchmarkRunner.Run(); + } + [Fact] public void MessageTemplateCacheBenchmark() { diff --git a/test/Serilog.PerformanceTests/Serilog.PerformanceTests.csproj b/test/Serilog.PerformanceTests/Serilog.PerformanceTests.csproj index 9b54fe0d9..dcb0d41ae 100644 --- a/test/Serilog.PerformanceTests/Serilog.PerformanceTests.csproj +++ b/test/Serilog.PerformanceTests/Serilog.PerformanceTests.csproj @@ -1,31 +1,27 @@  - netcoreapp1.1;net452 + netcoreapp1.1;net46 Serilog.PerformanceTests ../../assets/Serilog.snk true true - Serilog.PerformanceTests - true - - $(PackageTargetFallback);dnxcore50;portable-net45+win8 - + + + + + + - - - - - - - + + diff --git a/test/Serilog.PerformanceTests/xunit.runner.json b/test/Serilog.PerformanceTests/xunit.runner.json new file mode 100644 index 000000000..34b2fe2cd --- /dev/null +++ b/test/Serilog.PerformanceTests/xunit.runner.json @@ -0,0 +1,3 @@ +{ + "shadowCopy": false +} \ No newline at end of file diff --git a/test/Serilog.Tests/Context/LogContextTests.cs b/test/Serilog.Tests/Context/LogContextTests.cs index 4809f2bff..1020d439b 100644 --- a/test/Serilog.Tests/Context/LogContextTests.cs +++ b/test/Serilog.Tests/Context/LogContextTests.cs @@ -192,32 +192,13 @@ public async Task ContextPropertiesCrossAsyncCalls() #if APPDOMAIN // Must not actually try to pass context across domains, // since user property types may not be serializable. - [Fact(Skip = "Needs to be updated for dotnet runner.")] + [Fact] public void DoesNotPreventCrossDomainCalls() { - var projectRoot = Environment.CurrentDirectory; - while (!File.Exists(Path.Combine(projectRoot, "global.json"))) - { - projectRoot = Directory.GetParent(projectRoot).FullName; - } - AppDomain domain = null; try { - const string configuration = -#if DEBUG - "Debug"; -#else - "Release"; -#endif - - var domaininfo = new AppDomainSetup - { - ApplicationBase = projectRoot, - PrivateBinPath = @"test\Serilog.Tests\bin\Debug\net452\win7-x64".Replace("Debug", configuration) - }; - var evidence = AppDomain.CurrentDomain.Evidence; - domain = AppDomain.CreateDomain("LogContextTest", evidence, domaininfo); + domain = AppDomain.CreateDomain("LogContextTests", null, AppDomain.CurrentDomain.SetupInformation); var callable = (RemotelyCallable)domain.CreateInstanceAndUnwrap(typeof(RemotelyCallable).Assembly.FullName, typeof(RemotelyCallable).FullName); diff --git a/test/Serilog.Tests/LoggerConfigurationTests.cs b/test/Serilog.Tests/LoggerConfigurationTests.cs index c757a2dfd..61808a6aa 100644 --- a/test/Serilog.Tests/LoggerConfigurationTests.cs +++ b/test/Serilog.Tests/LoggerConfigurationTests.cs @@ -268,10 +268,10 @@ public void MaximumDestructuringDepthIsEffective() } }; - var xs = LogAndGetAsString(x, conf => conf.Destructure.ToMaximumStringLength(3), "@"); + var xs = LogAndGetAsString(x, conf => conf.Destructure.ToMaximumDepth(3), "@"); Assert.Contains("C", xs); - Assert.DoesNotContain(xs, "D"); + Assert.DoesNotContain("D", xs); } [Fact] diff --git a/test/Serilog.Tests/Parameters/PropertyValueConverterTests.cs b/test/Serilog.Tests/Parameters/PropertyValueConverterTests.cs index 3728fb0a2..732b737ad 100644 --- a/test/Serilog.Tests/Parameters/PropertyValueConverterTests.cs +++ b/test/Serilog.Tests/Parameters/PropertyValueConverterTests.cs @@ -1,7 +1,11 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; +using System.Threading; + using Xunit; + using Serilog.Core; using Serilog.Events; using Serilog.Parameters; @@ -17,6 +21,59 @@ public class PropertyValueConverterTests readonly PropertyValueConverter _converter = new PropertyValueConverter(10, 1000, 1000, Enumerable.Empty(), Enumerable.Empty(), false); + [Fact] + public async Task MaximumDepthIsEffectiveAndThreadSafe() + { + var _converter = new PropertyValueConverter(3, 1000, 1000, Enumerable.Empty(), Enumerable.Empty(), false); + + var barrier = new Barrier(participantCount: 3); + + var t1 = + Task.Run(() => DoThreadTest(new { Root = new { B = new { C = new { D = new { E = "F" } } } } }, + result => + { + Assert.Contains("B", result); + Assert.Contains("C", result); + Assert.DoesNotContain("D", result); + Assert.DoesNotContain("E", result); + })); + + var t2 = + Task.Run(() => DoThreadTest(new { Root = new { Y = new { Z = "5" } } }, + result => + { + Assert.Contains("Y", result); + Assert.Contains("Z", result); + })); + + var t3 = + Task.Run(() => DoThreadTest(new { Root = new { M = new { N = new { V = 8 } } } }, + result => + { + Assert.Contains("M", result); + Assert.Contains("N", result); + Assert.DoesNotContain("V", result); + })); + + await Task.WhenAll(t1, t2, t3); + + void DoThreadTest(object logObject, Action assertAction) + { + for (var i = 0; i < 100; ++i) + { + barrier.SignalAndWait(); + + var propValue = _converter.CreatePropertyValue(logObject, true); + + Assert.IsType(propValue); + + var result = ((StructureValue)propValue).Properties.SingleOrDefault(p => p.Name == "Root")?.Value?.ToString(); + + assertAction.Invoke(result); + } + } + } + [Fact] public void UnderDestructuringAByteArrayIsAScalarValue() { diff --git a/test/Serilog.Tests/Serilog.Tests.csproj b/test/Serilog.Tests/Serilog.Tests.csproj index c6ff91916..1c0981998 100644 --- a/test/Serilog.Tests/Serilog.Tests.csproj +++ b/test/Serilog.Tests/Serilog.Tests.csproj @@ -30,7 +30,7 @@ $(DefineConstants);APPDOMAIN;REMOTING;GETCURRENTMETHOD - $(DefineConstants);ASYNCLOCAL;GETCURRENTMETHOD + $(DefineConstants);APPDOMAIN;ASYNCLOCAL;GETCURRENTMETHOD From e205c078b9fd0704e7bd778e2a214049472535df Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Wed, 7 Jun 2017 20:10:35 +1000 Subject: [PATCH 57/58] Fewer arg checks; seal message template token classes; encourage inlining --- src/Serilog/Events/MessageTemplate.cs | 2 ++ src/Serilog/Parsing/PropertyToken.cs | 2 +- src/Serilog/Parsing/TextToken.cs | 2 +- src/Serilog/Rendering/MessageTemplateRenderer.cs | 6 ++---- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Serilog/Events/MessageTemplate.cs b/src/Serilog/Events/MessageTemplate.cs index 240cee9ed..b1664aeea 100644 --- a/src/Serilog/Events/MessageTemplate.cs +++ b/src/Serilog/Events/MessageTemplate.cs @@ -158,6 +158,8 @@ public string Render(IReadOnlyDictionary properti /// Supplies culture-specific formatting information, or null. public void Render(IReadOnlyDictionary properties, TextWriter output, IFormatProvider formatProvider = null) { + 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/Parsing/PropertyToken.cs b/src/Serilog/Parsing/PropertyToken.cs index 282f9b1e2..01dcc2109 100644 --- a/src/Serilog/Parsing/PropertyToken.cs +++ b/src/Serilog/Parsing/PropertyToken.cs @@ -25,7 +25,7 @@ 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; diff --git a/src/Serilog/Parsing/TextToken.cs b/src/Serilog/Parsing/TextToken.cs index 974e5f530..493a1b56d 100644 --- a/src/Serilog/Parsing/TextToken.cs +++ b/src/Serilog/Parsing/TextToken.cs @@ -23,7 +23,7 @@ namespace Serilog.Parsing /// /// A message template token representing literal text. /// - public class TextToken : MessageTemplateToken + public sealed class TextToken : MessageTemplateToken { /// /// Construct a . diff --git a/src/Serilog/Rendering/MessageTemplateRenderer.cs b/src/Serilog/Rendering/MessageTemplateRenderer.cs index 7da313f09..090e39e98 100644 --- a/src/Serilog/Rendering/MessageTemplateRenderer.cs +++ b/src/Serilog/Rendering/MessageTemplateRenderer.cs @@ -15,6 +15,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Runtime.CompilerServices; using Serilog.Events; using Serilog.Formatting.Json; using Serilog.Parsing; @@ -25,12 +26,9 @@ 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) { - if (messageTemplate == null) throw new ArgumentNullException(nameof(messageTemplate)); - if (properties == null) throw new ArgumentNullException(nameof(properties)); - if (output == null) throw new ArgumentNullException(nameof(output)); - bool isLiteral = false, isJson = false; if (format != null) From 62f26ffcd2200297df64e8715b9492317f87a778 Mon Sep 17 00:00:00 2001 From: Nicholas Blumhardt Date: Thu, 15 Jun 2017 08:47:27 +0200 Subject: [PATCH 58/58] Fix defined constants for net46 target --- src/Serilog/Serilog.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Serilog/Serilog.csproj b/src/Serilog/Serilog.csproj index 0e6af3504..8643248d6 100644 --- a/src/Serilog/Serilog.csproj +++ b/src/Serilog/Serilog.csproj @@ -66,7 +66,7 @@ - $(DefineConstants);ASYNCLOCAL + $(DefineConstants);ASYNCLOCAL;HASHTABLE