Skip to content

Commit

Permalink
Merge pull request #56 from serilog/dev
Browse files Browse the repository at this point in the history
2.4.0 Release
  • Loading branch information
nblumhardt authored May 18, 2017
2 parents 76fc7d9 + 9de1140 commit 552d166
Show file tree
Hide file tree
Showing 13 changed files with 509 additions and 170 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ The `WriteTo` and `Enrich` sections support the same syntax, for example the fol
"WriteTo": ["LiterateConsole", "DiagnosticTrace"]
```

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

(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.)

Expand Down
3 changes: 2 additions & 1 deletion sample/Sample/Sample.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="1.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="1.1.1" />
<PackageReference Include="Serilog.Sinks.Async" Version="1.0.1" />
<PackageReference Include="Serilog.Sinks.Literate" Version="2.0.0" />
<PackageReference Include="Serilog.Sinks.RollingFile" Version="3.0.0" />
<PackageReference Include="Serilog.Enrichers.Environment" Version="2.0.0" />
Expand Down
43 changes: 29 additions & 14 deletions sample/Sample/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,36 @@
"MyApp.Something.Tricky": "Verbose"
}
},
"WriteTo": [
{
"Name": "LiterateConsole",
"Args": {
"outputTemplate": "[{Timestamp:HH:mm:ss} {SourceContext} [{Level}] {Message}{NewLine}{Exception}"
}
},
{
"Name": "File",
"Args": {
"path": "%TEMP%\\Logs\\serilog-configuration-sample.txt",
"outputTemplate": "{Timestamp:o} [{Level:u3}] ({Application}/{MachineName}/{ThreadId}) {Message}{NewLine}{Exception}"
}
"WriteTo:Sublogger": {
"Name": "Logger",
"Args": {
"configureLogger": {
"WriteTo": [
{
"Name": "LiterateConsole",
"Args": {
"outputTemplate": "[{Timestamp:HH:mm:ss} {SourceContext} [{Level}] {Message}{NewLine}{Exception}"
}
}
]
},
"restrictedToMinimumLevel": "Debug"
}
},
"WriteTo:Async": {
"Name": "Async",
"Args": {
"configure": [
{
"Name": "File",
"Args": {
"path": "%TEMP%\\Logs\\serilog-configuration-sample.txt",
"outputTemplate": "{Timestamp:o} [{Level:u3}] ({Application}/{MachineName}/{ThreadId}) {Message}{NewLine}{Exception}"
}
}
]
}
],
},
"Enrich": ["FromLogContext", "WithMachineName", "WithThreadId"],
"Properties": {
"Application": "Sample"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<Description>Microsoft.Extensions.Configuration (appsettings.json) support for Serilog.</Description>
<VersionPrefix>2.3.1</VersionPrefix>
<VersionPrefix>2.4.0</VersionPrefix>
<Authors>Serilog Contributors</Authors>
<TargetFrameworks>net451;netstandard1.6</TargetFrameworks>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using Serilog.Configuration;
using System;
using System.Reflection;

namespace Serilog.Settings.Configuration
{
class ConfigurationSectionArgumentValue : IConfigurationArgumentValue
{
readonly IConfigurationReader _configReader;

public ConfigurationSectionArgumentValue(IConfigurationReader configReader)
{
_configReader = configReader ?? throw new ArgumentNullException(nameof(configReader));
}

public object ConvertTo(Type toType)
{
var typeInfo = toType.GetTypeInfo();
if (!typeInfo.IsGenericType ||
typeInfo.GetGenericTypeDefinition() is Type genericType && genericType != typeof(Action<>))
{
throw new InvalidOperationException("Argument value should be of type Action<>.");
}

var configurationType = typeInfo.GenericTypeArguments[0];
if (configurationType == typeof(LoggerSinkConfiguration))
{
return new Action<LoggerSinkConfiguration>(_configReader.ApplySinks);
}

if (configurationType == typeof(LoggerConfiguration))
{
return new Action<LoggerConfiguration>(_configReader.Configure);
}

throw new ArgumentException($"Handling {configurationType} is not implemented.");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System;

namespace Serilog.Settings.Configuration
{
interface IConfigurationArgumentValue
{
object ConvertTo(Type toType);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Serilog.Configuration;

namespace Serilog.Settings.Configuration
{
interface IConfigurationReader : ILoggerSettings
{
void ApplySinks(LoggerSinkConfiguration loggerSinkConfiguration);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

using Microsoft.Extensions.Primitives;

using Serilog.Core;
using Serilog.Debugging;
using Serilog.Events;

namespace Serilog.Settings.Configuration
{
class StringArgumentValue : IConfigurationArgumentValue
{
readonly Func<string> _valueProducer;
readonly Func<IChangeToken> _changeTokenProducer;

public StringArgumentValue(Func<string> valueProducer, Func<IChangeToken> changeTokenProducer = null)
{
_valueProducer = valueProducer ?? throw new ArgumentNullException(nameof(valueProducer));
_changeTokenProducer = changeTokenProducer;
}

static readonly Dictionary<Type, Func<string, object>> ExtendedTypeConversions = new Dictionary<Type, Func<string, object>>
{
{ typeof(Uri), s => new Uri(s) },
{ typeof(TimeSpan), s => TimeSpan.Parse(s) }
};

public object ConvertTo(Type toType)
{
var argumentValue = Environment.ExpandEnvironmentVariables(_valueProducer());

var toTypeInfo = toType.GetTypeInfo();
if (toTypeInfo.IsGenericType && toType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
if (string.IsNullOrEmpty(argumentValue))
return null;

// unwrap Nullable<> type since we're not handling null situations
toType = toTypeInfo.GenericTypeArguments[0];
toTypeInfo = toType.GetTypeInfo();
}

if (toTypeInfo.IsEnum)
return Enum.Parse(toType, argumentValue);

var convertor = ExtendedTypeConversions
.Where(t => t.Key.GetTypeInfo().IsAssignableFrom(toTypeInfo))
.Select(t => t.Value)
.FirstOrDefault();

if (convertor != null)
return convertor(argumentValue);

if (toTypeInfo.IsInterface && !string.IsNullOrWhiteSpace(argumentValue))
{
var type = Type.GetType(argumentValue.Trim(), throwOnError: false);
if (type != null)
{
var ctor = type.GetTypeInfo().DeclaredConstructors.FirstOrDefault(ci =>
{
var parameters = ci.GetParameters();
return parameters.Length == 0 || parameters.All(pi => pi.HasDefaultValue);
});

if (ctor == null)
throw new InvalidOperationException($"A default constructor was not found on {type.FullName}.");

var call = ctor.GetParameters().Select(pi => pi.DefaultValue).ToArray();
return ctor.Invoke(call);
}
}

if (toType == typeof(LoggingLevelSwitch))
{
if (!Enum.TryParse(argumentValue, out LogEventLevel minimumLevel))
throw new InvalidOperationException($"The value `{argumentValue}` is not a valid Serilog level.");

var levelSwitch = new LoggingLevelSwitch(minimumLevel);

if (_changeTokenProducer != null)
{
ChangeToken.OnChange(
_changeTokenProducer,
() =>
{
var newArgumentValue = _valueProducer();

if (Enum.TryParse(newArgumentValue, out minimumLevel))
levelSwitch.MinimumLevel = minimumLevel;
else
SelfLog.WriteLine($"The value `{newArgumentValue}` is not a valid Serilog level.");
});
}

return levelSwitch;
}

return Convert.ChangeType(argumentValue, toType);
}
}
}
Loading

0 comments on commit 552d166

Please sign in to comment.