diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a63d39f..a973ae35 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ This project adheres to [Semantic Versioning](http://semver.org/) and is followi ## Unreleased +### :zap: Added + +- [#49](https://github.com/FantasticFiasco/serilog-sinks-http/issues/49), [#123](https://github.com/FantasticFiasco/serilog-sinks-http/issues/123) [BREAKING CHANGE] Improve support for configuring HTTP client when using [Serilog.Settings.Configuration](https://github.com/serilog/serilog-settings-configuration). See [Custom HTTP client in wiki](https://github.com/FantasticFiasco/serilog-sinks-http/wiki/Custom-HTTP-client) for more information. (discovered by [@brunorsantos](https://github.com/brunorsantos)) + ## [6.0.0] - 2020-05-13 ### :zap: Added diff --git a/src/Serilog.Sinks.Http/Extensions/Microsoft/Extensions/Configuration/IConfiguration.cs b/src/Serilog.Sinks.Http/Extensions/Microsoft/Extensions/Configuration/IConfiguration.cs new file mode 100644 index 00000000..75484dda --- /dev/null +++ b/src/Serilog.Sinks.Http/Extensions/Microsoft/Extensions/Configuration/IConfiguration.cs @@ -0,0 +1,23 @@ +#if !NETSTANDARD_2_0 +// ReSharper disable once CheckNamespace +namespace Microsoft.Extensions.Configuration +{ + /// + /// Represents a set of key/value application configuration properties. + /// + /// + /// Polyfill for + /// + /// Microsoft.Extensions.Configuration.IConfiguration. + /// + public interface IConfiguration + { + /// + /// Gets or sets a configuration value. + /// + /// The configuration key. + /// The configuration value. + string this[string key] { get; set; } + } +} +#endif diff --git a/src/Serilog.Sinks.Http/LoggerSinkConfigurationExtensions.cs b/src/Serilog.Sinks.Http/LoggerSinkConfigurationExtensions.cs index d1bcad71..03b58375 100644 --- a/src/Serilog.Sinks.Http/LoggerSinkConfigurationExtensions.cs +++ b/src/Serilog.Sinks.Http/LoggerSinkConfigurationExtensions.cs @@ -15,6 +15,7 @@ using System; using System.ComponentModel; using System.Net.Http; +using Microsoft.Extensions.Configuration; using Serilog.Configuration; using Serilog.Events; using Serilog.Formatting; @@ -64,6 +65,12 @@ public static class LoggerSinkConfigurationExtensions /// A custom implementation. Default value is /// . /// + /// + /// Configuration passed to . Parameter is either manually + /// specified when configuring the sink in source code or automatically passed in when + /// configuring the sink using + /// Serilog.Settings.Configuration. + /// /// Logger configuration, allowing configuration to continue. public static LoggerConfiguration Http( this LoggerSinkConfiguration sinkConfiguration, @@ -74,7 +81,8 @@ public static LoggerConfiguration Http( ITextFormatter textFormatter = null, IBatchFormatter batchFormatter = null, LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, - IHttpClient httpClient = null) + IHttpClient httpClient = null, + IConfiguration configuration = null) { if (sinkConfiguration == null) throw new ArgumentNullException(nameof(sinkConfiguration)); @@ -83,6 +91,7 @@ public static LoggerConfiguration Http( textFormatter = textFormatter ?? new NormalRenderedTextFormatter(); batchFormatter = batchFormatter ?? new DefaultBatchFormatter(); httpClient = httpClient ?? new DefaultHttpClient(); + httpClient.Configure(configuration); var sink = queueLimit != null ? new HttpSink(requestUri, batchPostingLimit, queueLimit.Value, period.Value, textFormatter, batchFormatter, httpClient) @@ -105,7 +114,8 @@ public static LoggerConfiguration DurableHttp( ITextFormatter textFormatter = null, IBatchFormatter batchFormatter = null, LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, - IHttpClient httpClient = null) + IHttpClient httpClient = null, + IConfiguration configuration = null) { return DurableHttpUsingTimeRolledBuffers( sinkConfiguration: sinkConfiguration, @@ -119,7 +129,8 @@ public static LoggerConfiguration DurableHttp( textFormatter: textFormatter, batchFormatter: batchFormatter, restrictedToMinimumLevel: restrictedToMinimumLevel, - httpClient: httpClient); + httpClient: httpClient, + configuration: configuration); } /// @@ -175,6 +186,12 @@ public static LoggerConfiguration DurableHttp( /// A custom implementation. Default value is /// . /// + /// + /// Configuration passed to . Parameter is either manually + /// specified when configuring the sink in source code or automatically passed in when + /// configuring the sink using + /// Serilog.Settings.Configuration. + /// /// Logger configuration, allowing configuration to continue. public static LoggerConfiguration DurableHttpUsingTimeRolledBuffers( this LoggerSinkConfiguration sinkConfiguration, @@ -188,7 +205,8 @@ public static LoggerConfiguration DurableHttpUsingTimeRolledBuffers( ITextFormatter textFormatter = null, IBatchFormatter batchFormatter = null, LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, - IHttpClient httpClient = null) + IHttpClient httpClient = null, + IConfiguration configuration = null) { if (sinkConfiguration == null) throw new ArgumentNullException(nameof(sinkConfiguration)); @@ -197,6 +215,7 @@ public static LoggerConfiguration DurableHttpUsingTimeRolledBuffers( textFormatter = textFormatter ?? new NormalRenderedTextFormatter(); batchFormatter = batchFormatter ?? new DefaultBatchFormatter(); httpClient = httpClient ?? new DefaultHttpClient(); + httpClient.Configure(configuration); var sink = new TimeRolledDurableHttpSink( requestUri: requestUri, @@ -268,6 +287,12 @@ public static LoggerConfiguration DurableHttpUsingTimeRolledBuffers( /// A custom implementation. Default value is /// . /// + /// + /// Configuration passed to . Parameter is either manually + /// specified when configuring the sink in source code or automatically passed in when + /// configuring the sink using + /// Serilog.Settings.Configuration. + /// /// Logger configuration, allowing configuration to continue. public static LoggerConfiguration DurableHttpUsingFileSizeRolledBuffers( this LoggerSinkConfiguration sinkConfiguration, @@ -281,7 +306,8 @@ public static LoggerConfiguration DurableHttpUsingFileSizeRolledBuffers( ITextFormatter textFormatter = null, IBatchFormatter batchFormatter = null, LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, - IHttpClient httpClient = null) + IHttpClient httpClient = null, + IConfiguration configuration = null) { if (sinkConfiguration == null) throw new ArgumentNullException(nameof(sinkConfiguration)); @@ -290,6 +316,7 @@ public static LoggerConfiguration DurableHttpUsingFileSizeRolledBuffers( textFormatter = textFormatter ?? new NormalRenderedTextFormatter(); batchFormatter = batchFormatter ?? new DefaultBatchFormatter(); httpClient = httpClient ?? new DefaultHttpClient(); + httpClient.Configure(configuration); var sink = new FileSizeRolledDurableHttpSink( requestUri: requestUri, diff --git a/src/Serilog.Sinks.Http/Serilog.Sinks.Http.csproj b/src/Serilog.Sinks.Http/Serilog.Sinks.Http.csproj index 11d65153..cb504650 100644 --- a/src/Serilog.Sinks.Http/Serilog.Sinks.Http.csproj +++ b/src/Serilog.Sinks.Http/Serilog.Sinks.Http.csproj @@ -1,5 +1,7 @@  + + Serilog.Sinks.Http A Serilog sink sending log events over HTTP. @@ -30,9 +32,15 @@ - + + + + + + + @@ -43,8 +51,14 @@ $(DefineConstants);HRESULTS - - + + + + + + $(DefineConstants);NETSTANDARD_2_0 + + \ No newline at end of file diff --git a/src/Serilog.Sinks.Http/Sinks/Http/IHttpClient.cs b/src/Serilog.Sinks.Http/Sinks/Http/IHttpClient.cs index 28fa17bc..045fa442 100644 --- a/src/Serilog.Sinks.Http/Sinks/Http/IHttpClient.cs +++ b/src/Serilog.Sinks.Http/Sinks/Http/IHttpClient.cs @@ -15,6 +15,7 @@ using System; using System.Net.Http; using System.Threading.Tasks; +using Microsoft.Extensions.Configuration; namespace Serilog.Sinks.Http { @@ -23,6 +24,12 @@ namespace Serilog.Sinks.Http /// public interface IHttpClient : IDisposable { + /// + /// Configures the HTTP client. + /// + /// The application configuration properties. + void Configure(IConfiguration configuration); + /// /// Sends a POST request to the specified Uri as an asynchronous operation. /// diff --git a/src/Serilog.Sinks.Http/Sinks/Http/Private/Network/DefaultHttpClient.cs b/src/Serilog.Sinks.Http/Sinks/Http/Private/Network/DefaultHttpClient.cs index 1af0be9d..24912eaa 100644 --- a/src/Serilog.Sinks.Http/Sinks/Http/Private/Network/DefaultHttpClient.cs +++ b/src/Serilog.Sinks.Http/Sinks/Http/Private/Network/DefaultHttpClient.cs @@ -14,6 +14,7 @@ using System.Net.Http; using System.Threading.Tasks; +using Microsoft.Extensions.Configuration; namespace Serilog.Sinks.Http.Private.Network { @@ -24,6 +25,11 @@ public class DefaultHttpClient : IHttpClient public DefaultHttpClient() => httpClient = new HttpClient(); + public void Configure(IConfiguration configuration) + { + // The default HTTP client requires no configuration + } + public Task PostAsync(string requestUri, HttpContent content) => httpClient.PostAsync(requestUri, content); diff --git a/test/Serilog.Sinks.HttpTests/DurableHttpSinkGivenAppSettingsShould.cs b/test/Serilog.Sinks.HttpTests/DurableHttpSinkGivenAppSettingsShould.cs index d8981107..e8c50ab6 100644 --- a/test/Serilog.Sinks.HttpTests/DurableHttpSinkGivenAppSettingsShould.cs +++ b/test/Serilog.Sinks.HttpTests/DurableHttpSinkGivenAppSettingsShould.cs @@ -16,8 +16,12 @@ public DurableHttpSinkGivenAppSettingsShould() Logger = new LoggerConfiguration() .ReadFrom.Configuration(configuration) .CreateLogger(); + + Configuration = configuration; } protected override Logger Logger { get; } + + protected override IConfiguration Configuration { get; } } } diff --git a/test/Serilog.Sinks.HttpTests/DurableHttpSinkGivenCodeConfigurationShould.cs b/test/Serilog.Sinks.HttpTests/DurableHttpSinkGivenCodeConfigurationShould.cs index 97d4751d..3c3d2306 100644 --- a/test/Serilog.Sinks.HttpTests/DurableHttpSinkGivenCodeConfigurationShould.cs +++ b/test/Serilog.Sinks.HttpTests/DurableHttpSinkGivenCodeConfigurationShould.cs @@ -1,4 +1,5 @@ using System; +using Microsoft.Extensions.Configuration; using Serilog.Core; using Serilog.Sinks.Http.BatchFormatters; using Serilog.Sinks.Http.TextFormatters; @@ -11,6 +12,8 @@ public class DurableHttpSinkGivenCodeConfigurationShould : SinkFixture public DurableHttpSinkGivenCodeConfigurationShould() { DeleteBufferFiles(); + + var configuration = new ConfigurationBuilder().Build(); #pragma warning disable CS0618 // Type or member is obsolete @@ -23,12 +26,17 @@ public DurableHttpSinkGivenCodeConfigurationShould() period: TimeSpan.FromMilliseconds(1), textFormatter: new NormalRenderedTextFormatter(), batchFormatter: new DefaultBatchFormatter(), - httpClient: new HttpClientMock()) + httpClient: new HttpClientMock(), + configuration: configuration) .CreateLogger(); #pragma warning restore CS0618 // Type or member is obsolete + + Configuration = configuration; } protected override Logger Logger { get; } + + protected override IConfiguration Configuration { get; } } } diff --git a/test/Serilog.Sinks.HttpTests/DurableHttpSinkUsingFileSizeRolledBuffersGivenAppSettingsShould.cs b/test/Serilog.Sinks.HttpTests/DurableHttpSinkUsingFileSizeRolledBuffersGivenAppSettingsShould.cs index 657d96d4..777fdc65 100644 --- a/test/Serilog.Sinks.HttpTests/DurableHttpSinkUsingFileSizeRolledBuffersGivenAppSettingsShould.cs +++ b/test/Serilog.Sinks.HttpTests/DurableHttpSinkUsingFileSizeRolledBuffersGivenAppSettingsShould.cs @@ -16,8 +16,12 @@ public DurableHttpSinkUsingFileSizeRolledBuffersGivenAppSettingsShould() Logger = new LoggerConfiguration() .ReadFrom.Configuration(configuration) .CreateLogger(); + + Configuration = configuration; } protected override Logger Logger { get; } + + protected override IConfiguration Configuration { get; } } } diff --git a/test/Serilog.Sinks.HttpTests/DurableHttpSinkUsingFileSizeRolledBuffersGivenCodeConfigurationShould.cs b/test/Serilog.Sinks.HttpTests/DurableHttpSinkUsingFileSizeRolledBuffersGivenCodeConfigurationShould.cs index fb86353f..77c28553 100644 --- a/test/Serilog.Sinks.HttpTests/DurableHttpSinkUsingFileSizeRolledBuffersGivenCodeConfigurationShould.cs +++ b/test/Serilog.Sinks.HttpTests/DurableHttpSinkUsingFileSizeRolledBuffersGivenCodeConfigurationShould.cs @@ -1,4 +1,5 @@ using System; +using Microsoft.Extensions.Configuration; using Serilog.Core; using Serilog.Sinks.Http.BatchFormatters; using Serilog.Sinks.Http.TextFormatters; @@ -12,6 +13,8 @@ public DurableHttpSinkUsingFileSizeRolledBuffersGivenCodeConfigurationShould() { DeleteBufferFiles(); + var configuration = new ConfigurationBuilder().Build(); + Logger = new LoggerConfiguration() .MinimumLevel.Verbose() .WriteTo @@ -21,10 +24,15 @@ public DurableHttpSinkUsingFileSizeRolledBuffersGivenCodeConfigurationShould() period: TimeSpan.FromMilliseconds(1), textFormatter: new NormalRenderedTextFormatter(), batchFormatter: new DefaultBatchFormatter(), - httpClient: new HttpClientMock()) + httpClient: new HttpClientMock(), + configuration: configuration) .CreateLogger(); + + Configuration = configuration; } protected override Logger Logger { get; } + + protected override IConfiguration Configuration { get; } } } diff --git a/test/Serilog.Sinks.HttpTests/DurableHttpSinkUsingTimeRolledBuffersGivenAppSettingsShould.cs b/test/Serilog.Sinks.HttpTests/DurableHttpSinkUsingTimeRolledBuffersGivenAppSettingsShould.cs index 5b29b9c5..56c3dce7 100644 --- a/test/Serilog.Sinks.HttpTests/DurableHttpSinkUsingTimeRolledBuffersGivenAppSettingsShould.cs +++ b/test/Serilog.Sinks.HttpTests/DurableHttpSinkUsingTimeRolledBuffersGivenAppSettingsShould.cs @@ -16,8 +16,12 @@ public DurableHttpSinkUsingTimeRolledBuffersGivenAppSettingsShould() Logger = new LoggerConfiguration() .ReadFrom.Configuration(configuration) .CreateLogger(); + + Configuration = configuration; } protected override Logger Logger { get; } + + protected override IConfiguration Configuration { get; } } } diff --git a/test/Serilog.Sinks.HttpTests/DurableHttpSinkUsingTimeRolledBuffersGivenCodeConfigurationShould.cs b/test/Serilog.Sinks.HttpTests/DurableHttpSinkUsingTimeRolledBuffersGivenCodeConfigurationShould.cs index e266ae6d..610e763c 100644 --- a/test/Serilog.Sinks.HttpTests/DurableHttpSinkUsingTimeRolledBuffersGivenCodeConfigurationShould.cs +++ b/test/Serilog.Sinks.HttpTests/DurableHttpSinkUsingTimeRolledBuffersGivenCodeConfigurationShould.cs @@ -1,4 +1,5 @@ using System; +using Microsoft.Extensions.Configuration; using Serilog.Core; using Serilog.Sinks.Http.BatchFormatters; using Serilog.Sinks.Http.TextFormatters; @@ -12,6 +13,8 @@ public DurableHttpSinkUsingTimeRolledBuffersGivenCodeConfigurationShould() { DeleteBufferFiles(); + var configuration = new ConfigurationBuilder().Build(); + Logger = new LoggerConfiguration() .MinimumLevel.Verbose() .WriteTo @@ -21,10 +24,15 @@ public DurableHttpSinkUsingTimeRolledBuffersGivenCodeConfigurationShould() period: TimeSpan.FromMilliseconds(1), textFormatter: new NormalRenderedTextFormatter(), batchFormatter: new DefaultBatchFormatter(), - httpClient: new HttpClientMock()) + httpClient: new HttpClientMock(), + configuration: configuration) .CreateLogger(); + + Configuration = configuration; } protected override Logger Logger { get; } + + protected override IConfiguration Configuration { get; } } } diff --git a/test/Serilog.Sinks.HttpTests/HttpSinkGivenAppSettingsShould.cs b/test/Serilog.Sinks.HttpTests/HttpSinkGivenAppSettingsShould.cs index c770dd78..97500ab0 100644 --- a/test/Serilog.Sinks.HttpTests/HttpSinkGivenAppSettingsShould.cs +++ b/test/Serilog.Sinks.HttpTests/HttpSinkGivenAppSettingsShould.cs @@ -14,8 +14,12 @@ public HttpSinkGivenAppSettingsShould() Logger = new LoggerConfiguration() .ReadFrom.Configuration(configuration) .CreateLogger(); + + Configuration = configuration; } protected override Logger Logger { get; } + + protected override IConfiguration Configuration { get; } } } diff --git a/test/Serilog.Sinks.HttpTests/HttpSinkGivenCodeConfigurationShould.cs b/test/Serilog.Sinks.HttpTests/HttpSinkGivenCodeConfigurationShould.cs index 7f00c242..c1e483bd 100644 --- a/test/Serilog.Sinks.HttpTests/HttpSinkGivenCodeConfigurationShould.cs +++ b/test/Serilog.Sinks.HttpTests/HttpSinkGivenCodeConfigurationShould.cs @@ -1,4 +1,5 @@ using System; +using Microsoft.Extensions.Configuration; using Serilog.Core; using Serilog.Sinks.Http.BatchFormatters; using Serilog.Sinks.Http.TextFormatters; @@ -8,7 +9,10 @@ namespace Serilog { public class HttpSinkGivenCodeConfigurationShould : SinkFixture { - public HttpSinkGivenCodeConfigurationShould() => + public HttpSinkGivenCodeConfigurationShould() + { + var configuration = new ConfigurationBuilder().Build(); + Logger = new LoggerConfiguration() .MinimumLevel.Verbose() .WriteTo @@ -19,9 +23,15 @@ public HttpSinkGivenCodeConfigurationShould() => period: TimeSpan.FromMilliseconds(1), textFormatter: new NormalRenderedTextFormatter(), batchFormatter: new DefaultBatchFormatter(), - httpClient: new HttpClientMock()) + httpClient: new HttpClientMock(), + configuration: configuration) .CreateLogger(); + Configuration = configuration; + } + protected override Logger Logger { get; } + + protected override IConfiguration Configuration { get; } } } diff --git a/test/Serilog.Sinks.HttpTests/SinkFixture.cs b/test/Serilog.Sinks.HttpTests/SinkFixture.cs index 1455cbd9..7b6fbafe 100644 --- a/test/Serilog.Sinks.HttpTests/SinkFixture.cs +++ b/test/Serilog.Sinks.HttpTests/SinkFixture.cs @@ -2,6 +2,7 @@ using System.IO; using System.Linq; using System.Threading.Tasks; +using Microsoft.Extensions.Configuration; using Serilog.Core; using Serilog.Events; using Serilog.Support; @@ -13,6 +14,14 @@ namespace Serilog public abstract class SinkFixture : IDisposable { protected abstract Logger Logger { get; } + protected abstract IConfiguration Configuration { get; } + + [Fact] + public void ConfigureHttpClient() + { + // Assert + HttpClientMock.Instance.Configuration.ShouldBe(Configuration); + } [Theory] [InlineData(LogEventLevel.Verbose)] diff --git a/test/Serilog.Sinks.HttpTests/Support/HttpClientMock.cs b/test/Serilog.Sinks.HttpTests/Support/HttpClientMock.cs index 3404da3d..a3900db5 100644 --- a/test/Serilog.Sinks.HttpTests/Support/HttpClientMock.cs +++ b/test/Serilog.Sinks.HttpTests/Support/HttpClientMock.cs @@ -4,6 +4,7 @@ using System.Net; using System.Net.Http; using System.Threading.Tasks; +using Microsoft.Extensions.Configuration; using Newtonsoft.Json; using Serilog.Sinks.Http; using Serilog.Sinks.Http.BatchFormatters; @@ -37,6 +38,8 @@ public HttpClientMock() .Select(logEvent => logEvent.RenderedMessage) .ToArray(); + public IConfiguration Configuration { get; private set; } + public async Task WaitAsync(int expectedLogEventCount) { // 10 000 iterations, each waiting at least 1ms, means that a test has 10s to pass @@ -59,6 +62,9 @@ public async Task WaitAsync(int expectedLogEventCount) public void SimulateNetworkFailure() => simulateNetworkFailure = true; + + public void Configure(IConfiguration configuration) => Configuration = configuration; + public async Task PostAsync(string requestUri, HttpContent content) { if (simulateNetworkFailure)