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

Add support for builder.AddAppSettings #9

Merged
merged 3 commits into from
Mar 4, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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