Skip to content

Commit 552d166

Browse files
authored
Merge pull request #56 from serilog/dev
2.4.0 Release
2 parents 76fc7d9 + 9de1140 commit 552d166

13 files changed

+509
-170
lines changed

Diff for: README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ The `WriteTo` and `Enrich` sections support the same syntax, for example the fol
4949
"WriteTo": ["LiterateConsole", "DiagnosticTrace"]
5050
```
5151

52-
Or alternatively, the long-form (`"Name":` ...) sytax from the first example can be used when arguments need to be supplied.
52+
Or alternatively, the long-form (`"Name":` ...) syntax from the first example can be used when arguments need to be supplied.
5353

5454
(This package implements a convention using `DependencyContext` to find any package with `Serilog` anywhere in the name and pulls configuration methods from it, so the `Using` example above is redundant.)
5555

Diff for: sample/Sample/Sample.csproj

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
</ItemGroup>
1515

1616
<ItemGroup>
17-
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="1.0.0" />
17+
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="1.1.1" />
18+
<PackageReference Include="Serilog.Sinks.Async" Version="1.0.1" />
1819
<PackageReference Include="Serilog.Sinks.Literate" Version="2.0.0" />
1920
<PackageReference Include="Serilog.Sinks.RollingFile" Version="3.0.0" />
2021
<PackageReference Include="Serilog.Enrichers.Environment" Version="2.0.0" />

Diff for: sample/Sample/appsettings.json

+29-14
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,36 @@
88
"MyApp.Something.Tricky": "Verbose"
99
}
1010
},
11-
"WriteTo": [
12-
{
13-
"Name": "LiterateConsole",
14-
"Args": {
15-
"outputTemplate": "[{Timestamp:HH:mm:ss} {SourceContext} [{Level}] {Message}{NewLine}{Exception}"
16-
}
17-
},
18-
{
19-
"Name": "File",
20-
"Args": {
21-
"path": "%TEMP%\\Logs\\serilog-configuration-sample.txt",
22-
"outputTemplate": "{Timestamp:o} [{Level:u3}] ({Application}/{MachineName}/{ThreadId}) {Message}{NewLine}{Exception}"
23-
}
11+
"WriteTo:Sublogger": {
12+
"Name": "Logger",
13+
"Args": {
14+
"configureLogger": {
15+
"WriteTo": [
16+
{
17+
"Name": "LiterateConsole",
18+
"Args": {
19+
"outputTemplate": "[{Timestamp:HH:mm:ss} {SourceContext} [{Level}] {Message}{NewLine}{Exception}"
20+
}
21+
}
22+
]
23+
},
24+
"restrictedToMinimumLevel": "Debug"
25+
}
26+
},
27+
"WriteTo:Async": {
28+
"Name": "Async",
29+
"Args": {
30+
"configure": [
31+
{
32+
"Name": "File",
33+
"Args": {
34+
"path": "%TEMP%\\Logs\\serilog-configuration-sample.txt",
35+
"outputTemplate": "{Timestamp:o} [{Level:u3}] ({Application}/{MachineName}/{ThreadId}) {Message}{NewLine}{Exception}"
36+
}
37+
}
38+
]
2439
}
25-
],
40+
},
2641
"Enrich": ["FromLogContext", "WithMachineName", "WithThreadId"],
2742
"Properties": {
2843
"Application": "Sample"

Diff for: src/Serilog.Settings.Configuration/Serilog.Settings.Configuration.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<PropertyGroup>
44
<Description>Microsoft.Extensions.Configuration (appsettings.json) support for Serilog.</Description>
5-
<VersionPrefix>2.3.1</VersionPrefix>
5+
<VersionPrefix>2.4.0</VersionPrefix>
66
<Authors>Serilog Contributors</Authors>
77
<TargetFrameworks>net451;netstandard1.6</TargetFrameworks>
88
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>

Diff for: src/Serilog.Settings.Configuration/Settings/Configuration/ConfigurationReader.cs

+113-142
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
using Serilog.Configuration;
2+
using System;
3+
using System.Reflection;
4+
5+
namespace Serilog.Settings.Configuration
6+
{
7+
class ConfigurationSectionArgumentValue : IConfigurationArgumentValue
8+
{
9+
readonly IConfigurationReader _configReader;
10+
11+
public ConfigurationSectionArgumentValue(IConfigurationReader configReader)
12+
{
13+
_configReader = configReader ?? throw new ArgumentNullException(nameof(configReader));
14+
}
15+
16+
public object ConvertTo(Type toType)
17+
{
18+
var typeInfo = toType.GetTypeInfo();
19+
if (!typeInfo.IsGenericType ||
20+
typeInfo.GetGenericTypeDefinition() is Type genericType && genericType != typeof(Action<>))
21+
{
22+
throw new InvalidOperationException("Argument value should be of type Action<>.");
23+
}
24+
25+
var configurationType = typeInfo.GenericTypeArguments[0];
26+
if (configurationType == typeof(LoggerSinkConfiguration))
27+
{
28+
return new Action<LoggerSinkConfiguration>(_configReader.ApplySinks);
29+
}
30+
31+
if (configurationType == typeof(LoggerConfiguration))
32+
{
33+
return new Action<LoggerConfiguration>(_configReader.Configure);
34+
}
35+
36+
throw new ArgumentException($"Handling {configurationType} is not implemented.");
37+
}
38+
}
39+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using System;
2+
3+
namespace Serilog.Settings.Configuration
4+
{
5+
interface IConfigurationArgumentValue
6+
{
7+
object ConvertTo(Type toType);
8+
}
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using Serilog.Configuration;
2+
3+
namespace Serilog.Settings.Configuration
4+
{
5+
interface IConfigurationReader : ILoggerSettings
6+
{
7+
void ApplySinks(LoggerSinkConfiguration loggerSinkConfiguration);
8+
}
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Reflection;
5+
6+
using Microsoft.Extensions.Primitives;
7+
8+
using Serilog.Core;
9+
using Serilog.Debugging;
10+
using Serilog.Events;
11+
12+
namespace Serilog.Settings.Configuration
13+
{
14+
class StringArgumentValue : IConfigurationArgumentValue
15+
{
16+
readonly Func<string> _valueProducer;
17+
readonly Func<IChangeToken> _changeTokenProducer;
18+
19+
public StringArgumentValue(Func<string> valueProducer, Func<IChangeToken> changeTokenProducer = null)
20+
{
21+
_valueProducer = valueProducer ?? throw new ArgumentNullException(nameof(valueProducer));
22+
_changeTokenProducer = changeTokenProducer;
23+
}
24+
25+
static readonly Dictionary<Type, Func<string, object>> ExtendedTypeConversions = new Dictionary<Type, Func<string, object>>
26+
{
27+
{ typeof(Uri), s => new Uri(s) },
28+
{ typeof(TimeSpan), s => TimeSpan.Parse(s) }
29+
};
30+
31+
public object ConvertTo(Type toType)
32+
{
33+
var argumentValue = Environment.ExpandEnvironmentVariables(_valueProducer());
34+
35+
var toTypeInfo = toType.GetTypeInfo();
36+
if (toTypeInfo.IsGenericType && toType.GetGenericTypeDefinition() == typeof(Nullable<>))
37+
{
38+
if (string.IsNullOrEmpty(argumentValue))
39+
return null;
40+
41+
// unwrap Nullable<> type since we're not handling null situations
42+
toType = toTypeInfo.GenericTypeArguments[0];
43+
toTypeInfo = toType.GetTypeInfo();
44+
}
45+
46+
if (toTypeInfo.IsEnum)
47+
return Enum.Parse(toType, argumentValue);
48+
49+
var convertor = ExtendedTypeConversions
50+
.Where(t => t.Key.GetTypeInfo().IsAssignableFrom(toTypeInfo))
51+
.Select(t => t.Value)
52+
.FirstOrDefault();
53+
54+
if (convertor != null)
55+
return convertor(argumentValue);
56+
57+
if (toTypeInfo.IsInterface && !string.IsNullOrWhiteSpace(argumentValue))
58+
{
59+
var type = Type.GetType(argumentValue.Trim(), throwOnError: false);
60+
if (type != null)
61+
{
62+
var ctor = type.GetTypeInfo().DeclaredConstructors.FirstOrDefault(ci =>
63+
{
64+
var parameters = ci.GetParameters();
65+
return parameters.Length == 0 || parameters.All(pi => pi.HasDefaultValue);
66+
});
67+
68+
if (ctor == null)
69+
throw new InvalidOperationException($"A default constructor was not found on {type.FullName}.");
70+
71+
var call = ctor.GetParameters().Select(pi => pi.DefaultValue).ToArray();
72+
return ctor.Invoke(call);
73+
}
74+
}
75+
76+
if (toType == typeof(LoggingLevelSwitch))
77+
{
78+
if (!Enum.TryParse(argumentValue, out LogEventLevel minimumLevel))
79+
throw new InvalidOperationException($"The value `{argumentValue}` is not a valid Serilog level.");
80+
81+
var levelSwitch = new LoggingLevelSwitch(minimumLevel);
82+
83+
if (_changeTokenProducer != null)
84+
{
85+
ChangeToken.OnChange(
86+
_changeTokenProducer,
87+
() =>
88+
{
89+
var newArgumentValue = _valueProducer();
90+
91+
if (Enum.TryParse(newArgumentValue, out minimumLevel))
92+
levelSwitch.MinimumLevel = minimumLevel;
93+
else
94+
SelfLog.WriteLine($"The value `{newArgumentValue}` is not a valid Serilog level.");
95+
});
96+
}
97+
98+
return levelSwitch;
99+
}
100+
101+
return Convert.ChangeType(argumentValue, toType);
102+
}
103+
}
104+
}

0 commit comments

Comments
 (0)