Skip to content
This repository has been archived by the owner on Nov 3, 2021. It is now read-only.

Commit

Permalink
Merge pull request #9 from tsimbalar/addappsettings
Browse files Browse the repository at this point in the history
Add support for builder.AddAppSettings
  • Loading branch information
nblumhardt authored Mar 4, 2018
2 parents 0d8483f + 2992f77 commit 03a2181
Show file tree
Hide file tree
Showing 35 changed files with 860 additions and 11 deletions.
9 changes: 8 additions & 1 deletion serilog-settings-combined.sln
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26730.12
VisualStudioVersion = 15.0.27130.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E3A3B400-AD76-448B-A44B-A5D7314FAC44}"
EndProject
Expand All @@ -25,6 +25,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "assets", "assets", "{C789B5
assets\Serilog.snk = assets\Serilog.snk
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestDummies", "test\TestDummies\TestDummies.csproj", "{CCCCC5CA-A2A1-444F-8FD3-19B2823228CB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -39,13 +41,18 @@ Global
{20DF8798-4764-4213-BCF9-F0B55FABFDE9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{20DF8798-4764-4213-BCF9-F0B55FABFDE9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{20DF8798-4764-4213-BCF9-F0B55FABFDE9}.Release|Any CPU.Build.0 = Release|Any CPU
{CCCCC5CA-A2A1-444F-8FD3-19B2823228CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CCCCC5CA-A2A1-444F-8FD3-19B2823228CB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CCCCC5CA-A2A1-444F-8FD3-19B2823228CB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CCCCC5CA-A2A1-444F-8FD3-19B2823228CB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{DA007207-F261-49ED-9ED1-24F709C53E77} = {E3A3B400-AD76-448B-A44B-A5D7314FAC44}
{20DF8798-4764-4213-BCF9-F0B55FABFDE9} = {D4CACEEA-2101-42BB-B3AC-16E685850988}
{CCCCC5CA-A2A1-444F-8FD3-19B2823228CB} = {D4CACEEA-2101-42BB-B3AC-16E685850988}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {5DBD5279-7498-481B-92C0-829124A6E543}
Expand Down
6 changes: 6 additions & 0 deletions serilog-settings-combined.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_IFELSE_BRACES_STYLE/@EntryValue">DO_NOT_CHANGE</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_USING_BRACES_STYLE/@EntryValue">DO_NOT_CHANGE</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_WHILE_BRACES_STYLE/@EntryValue">DO_NOT_CHANGE</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_ACCESSORHOLDER_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_BEFORE_FIXED_PARENTHESES/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_BEFORE_SIZEOF_PARENTHESES/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_BEFORE_TYPEOF_PARENTHESES/@EntryValue">False</s:Boolean>
Expand Down Expand Up @@ -537,9 +538,14 @@ II.2.12 &lt;HandlesEvent /&gt;&#xD;
<s:String x:Key="/Default/CodeStyle/Naming/VBNaming/PredefinedNamingRules/=StaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/VBNaming/PredefinedNamingRules/=TypeParameters/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="T" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/VBNaming/PredefinedNamingRules/=TypesAndNamespaces/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpAttributeForSingleLineMethodUpgrade/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpFileLayoutPatternsUpgrade/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpRenamePlacementToArrangementMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAddAccessorOwnerDeclarationBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAlwaysTreatStructAsNotReorderableMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002EJavaScript_002ECodeStyle_002ESettingsUpgrade_002EJsCodeFormatterSettingsUpgrader/@EntryIndexedValue">True</s:Boolean>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// 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.

#if APPSETTINGS
using System;
using Serilog.Settings.AppSettings;
using Serilog.Settings.Combined;

namespace Serilog
{
/// <summary>
/// Extensions to allow combination of settings originating from config file appSettings
/// </summary>
public static class AppSettingsSettingsBuilderExtensions
{
/// <summary>
/// Reads the &lt;appSettings&gt; element of App.config or Web.config, searching for keys
/// that look like: <code>serilog:*</code>, which are used to configure
/// the logger.
/// </summary>
/// <param name="builder">The combined settings builder</param>
/// <param name="settingPrefix">Prefix to use when reading keys in appSettings. If specified the value
/// will be prepended to the setting keys and followed by :, for example "myapp" will use "myapp:serilog:minumum-level. If null
/// no prefix is applied.</param>
/// <param name="filePath">Specify the path to an alternative .config file location. If the file does not exist it will be ignored.
/// By default, the current application's configuration file will be used.</param>
/// <returns>An object allowing configuration to continue.</returns>
public static ICombinedSettingsBuilder AddAppSettings(this ICombinedSettingsBuilder builder, string settingPrefix = null, string filePath = null)
{
if (builder == null) throw new ArgumentNullException(nameof(builder));
var appSettings = new AppSettingsSettings(settingPrefix, filePath);
builder.AddKeyValuePairs(appSettings.GetKeyValuePairs());
return builder;
}
}
}
#endif
Original file line number Diff line number Diff line change
@@ -1,4 +1,18 @@
using System;
// Copyright 2013-2017 Serilog Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System;
using Serilog.Configuration;
using Serilog.Settings.Combined;

Expand Down
14 changes: 13 additions & 1 deletion src/Serilog.Settings.Combined/Serilog.Settings.Combined.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,19 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Serilog" Version="2.6.0-dev-00923" />
<PackageReference Include="Serilog" Version="2.6.0" />
<PackageReference Include="System.ValueTuple" Version="4.3.1" />
</ItemGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
<Reference Include="System.Configuration" />
<Reference Include="System.Core" />
<Reference Include="System" />
<Reference Include="Microsoft.CSharp" />
</ItemGroup>

<PropertyGroup Condition=" '$(TargetFramework)' == 'net45' ">
<DefineConstants>$(DefineConstants);APPSETTINGS</DefineConstants>
</PropertyGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// 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.

#if APPSETTINGS
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using Serilog.Debugging;

namespace Serilog.Settings.AppSettings
{
class AppSettingsSettings
{
readonly string _filePath;
readonly string _settingPrefix;

public AppSettingsSettings(string settingPrefix = null, string filePath = null)
{
_filePath = filePath;
_settingPrefix = settingPrefix == null ? "serilog:" : $"{settingPrefix}:serilog:";
}

public IEnumerable<KeyValuePair<string, string>> GetKeyValuePairs()
{
IEnumerable<KeyValuePair<string, string>> settings;

if (!string.IsNullOrWhiteSpace(_filePath))
{
if (!File.Exists(_filePath))
{
SelfLog.WriteLine("The specified configuration file `{0}` does not exist and will be ignored.", _filePath);
return Enumerable.Empty<KeyValuePair<string, string>>();
}

var map = new ExeConfigurationFileMap { ExeConfigFilename = _filePath };
var config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
settings = config.AppSettings.Settings
.Cast<KeyValueConfigurationElement>()
.Select(k => new KeyValuePair<string, string>(k.Key, k.Value));
}
else
{
settings = ConfigurationManager.AppSettings.AllKeys
.Select(k => new KeyValuePair<string, string>(k, ConfigurationManager.AppSettings[k]));
}

var pairs = settings
.Where(k => k.Key.StartsWith(_settingPrefix))
.Select(k => new KeyValuePair<string, string>(
k.Key.Substring(_settingPrefix.Length),
Environment.ExpandEnvironmentVariables(k.Value)));

return pairs;
}
}
}
#endif
Original file line number Diff line number Diff line change
@@ -1,4 +1,18 @@
using System;
// Copyright 2013-2017 Serilog Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System;
using System.Collections.Generic;

namespace Serilog.Settings.Combined
Expand Down
69 changes: 69 additions & 0 deletions test/Serilog.Settings.Combined.Tests/CombinedAppSettingsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#if APPSETTINGS
using System.Linq;
using Serilog.Events;
using Serilog.Tests.Support;
using TestDummies;
using Xunit;

namespace Serilog.Settings.Combined.Tests
{
public class CombinedAppSettingsTests
{
public CombinedAppSettingsTests()
{
DummyRollingFileSink.Reset();
}

[Fact]
public void CombinedCanMergeSettingsFromMultipleConfigFiles()
{
LogEvent evt = null;
var log = new LoggerConfiguration()
.ReadFrom.Combined(builder => builder
.AddAppSettings(filePath: "Samples/Initial.config")
.AddAppSettings(filePath: "Samples/Second.config")
.AddAppSettings(filePath: "Samples/Third.config")
)
.WriteTo.Sink(new DelegatingSink(e => evt = e))
.CreateLogger();

log.Information("Has a test property");
Assert.True(DummyRollingFileSink.Emitted.Any(), "Events should be written to DummyRollingFile");
Assert.Equal("DefinedInThird", DummyRollingFileSink.PathFormat);
Assert.Equal("DefinedInSecond", DummyRollingFileSink.OutputTemplate);

Assert.NotNull(evt);
Assert.Equal("OverridenInThird", evt.Properties["AppName"].LiteralValue());
Assert.Equal("DeclaredInSecond", evt.Properties["ServerName"].LiteralValue());
}

[Fact]
public void CombinedCanMergeAppSettingsWithInMemoryKeyValuePairs()
{
LogEvent evt = null;
var log = new LoggerConfiguration()
.ReadFrom.Combined(builder => builder
.AddKeyValuePair("minimum-level", "Verbose")
.AddKeyValuePair("using:TestDummies", "TestDummies")
.AddKeyValuePair("write-to:DummyRollingFile.restrictedToMinimumLevel", "Debug")
.AddKeyValuePair("enrich:with-property:AppName", "DeclaredInKeyValuePairs")
.AddAppSettings(filePath: "Samples/Second.config")
.AddKeyValuePair("write-to:DummyRollingFile.pathFormat", "DefinedInKeyValuePairs")
.AddKeyValuePair("enrich:with-property:AppName", "OverridenInKeyValuePairs")
)
.WriteTo.Sink(new DelegatingSink(e => evt = e))
.CreateLogger();

log.Information("Has a test property");
Assert.True(DummyRollingFileSink.Emitted.Any(), "Events should be written to DummyRollingFile");
Assert.Equal("DefinedInKeyValuePairs", DummyRollingFileSink.PathFormat);
Assert.Equal("DefinedInSecond", DummyRollingFileSink.OutputTemplate);

Assert.NotNull(evt);
Assert.Equal("OverridenInKeyValuePairs", evt.Properties["AppName"].LiteralValue());
Assert.Equal("DeclaredInSecond", evt.Properties["ServerName"].LiteralValue());
}
}
}

#endif
41 changes: 41 additions & 0 deletions test/Serilog.Settings.Combined.Tests/CombinedSettingsMixTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#if APPSETTINGS
using System.Linq;
using Serilog.Events;
using Serilog.Tests.Support;
using TestDummies;
using Xunit;

namespace Serilog.Settings.Combined.Tests
{
public class CombinedSettingsMixTests
{
[Fact]
public void CombinedCanMixAndMatchMultipleSources()
{
LogEvent evt = null;
// typical scenario : doing most of the config in code / default value
// .... and override a few things from config files
var log = new LoggerConfiguration()
.ReadFrom.Combined(builder => builder
.AddKeyValuePair("minimum-level", "Verbose")
.AddKeyValuePair("enrich:with-property:AppName", "DeclaredInInitial")
.AddKeyValuePair("using:TestDummies" ,"TestDummies")
.AddKeyValuePair("write-to:DummyRollingFile.pathFormat", "DeclaredInInitial")
.AddAppSettings(filePath: "Samples/ConfigOverrides.config")
.AddKeyValuePair("enrich:with-property:ExtraProp", "AddedAtTheVeryEnd")
)
.WriteTo.Sink(new DelegatingSink(e => evt = e))
.CreateLogger();

log.Information("Has a test property");
Assert.True(DummyRollingFileSink.Emitted.Any(), "Events should be written to DummyRollingFile");
Assert.Equal("DefinedInConfigFile", DummyRollingFileSink.PathFormat);

Assert.NotNull(evt);
Assert.Equal("DeclaredInInitial", evt.Properties["AppName"].LiteralValue());
Assert.Equal("DeclaredInConfigFile", evt.Properties["ServerName"].LiteralValue());
Assert.Equal("AddedAtTheVeryEnd", evt.Properties["ExtraProp"].LiteralValue());
}
}
}
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="serilog:write-to:DummyRollingFile.pathFormat" value="DefinedInConfigFile" />
<add key="serilog:enrich:with-property:ServerName" value="DeclaredInConfigFile" />
</appSettings>
</configuration>
11 changes: 11 additions & 0 deletions test/Serilog.Settings.Combined.Tests/Samples/Initial.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="serilog:minimum-level" value="Verbose" />
<add key="serilog:using:TestDummies" value="TestDummies" />
<add key="serilog:write-to:DummyRollingFile.restrictedToMinimumLevel" value="Debug" />
<!-- DummyRollingFile.pathFormat intentionnaly left empty here, to be declared later-->
<!-- DummyRollingFile.outputTemplate intentionnaly left empty here, to be declared later-->
<add key="serilog:enrich:with-property:AppName" value="DeclaredInInitial" />
</appSettings>
</configuration>
7 changes: 7 additions & 0 deletions test/Serilog.Settings.Combined.Tests/Samples/Second.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="serilog:write-to:DummyRollingFile.outputTemplate" value="DefinedInSecond" />
<add key="serilog:enrich:with-property:ServerName" value="DeclaredInSecond" />
</appSettings>
</configuration>
7 changes: 7 additions & 0 deletions test/Serilog.Settings.Combined.Tests/Samples/Third.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="serilog:write-to:DummyRollingFile.pathFormat" value="DefinedInThird" />
<add key="serilog:enrich:with-property:AppName" value="OverridenInThird" />
</appSettings>
</configuration>
Loading

0 comments on commit 03a2181

Please sign in to comment.