Skip to content

Commit

Permalink
feat: add support for durability
Browse files Browse the repository at this point in the history
Added support for the sink to be created as durable. A durable sink will persist log events on disk before sending them over the network, thus protecting against data loss after a system or process restart.

Fixes #3
  • Loading branch information
FantasticFiasco authored Mar 4, 2017
1 parent 8c0918c commit 9be3be9
Show file tree
Hide file tree
Showing 50 changed files with 2,119 additions and 439 deletions.
2 changes: 1 addition & 1 deletion Build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ foreach ($src in ls src/*) {
Pop-Location
}

foreach ($test in ls test/*.Tests) {
foreach ($test in ls test/*Tests) {
Push-Location $test

echo "build: Testing project in $test"
Expand Down
13 changes: 11 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,24 @@

All notable changes to this project will be documented in this file.

This project adheres to [Semantic Versioning](http://semver.org/) and is following the [change log format](https://github.com/olivierlacan/keep-a-changelog).
This project adheres to [Semantic Versioning](http://semver.org/) and is following the [change log format](http://keepachangelog.com/).

## Unreleased

### Added

- A sink is durable when created using `Http(string, DurableOptions)`. A durable sink will persist log events on disk before sending them over the network, thus protecting against data loss after a system or process restart.

### Changed

- [BREAKING CHANGE] The syntax for creating a non-durable sink has been changed from `Http(string)` to `Http(string, Options)` to accommodate for the syntax to create a durable sink. A non-durable sink will loose data after a system or process restart.
- Improve compatibility by supporting .NET Standard 1.3

## 2.0.0 2016-11-23

### Changed

- Custom implementation of `IHttpClient` can be passed to sink when creating it (contribution by [@lhaussknecht](https://github.com/lhaussknecht))
- [BREAKING CHANGE] Custom implementation of `IHttpClient` can be passed to sink when creating it (contribution by [@lhaussknecht](https://github.com/lhaussknecht))

## 1.0.0 2016-11-03

Expand Down
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,20 @@
A [Serilog](http://serilog.net/) sink that sends HTTP POST requests over the network.

**Package** - [Serilog.Sinks.Http](https://www.nuget.org/packages/serilog.sinks.http)
| **Platforms** - .NET 4.5, .NETStandard 1.5
| **Platforms** - .NET 4.5, .NETStandard 1.3

### Getting started

In the example shown, the sink will send a HTTP POST request to URI `www.mylogs.com`.
In the following example, the sink will send a HTTP POST request to `www.mylogs.com`.

```csharp
Serilog.ILogger log = new LoggerConfiguration()
.MinimumLevel.Verbose()
.WriteTo.Http("www.mylogs.com")
.WriteTo.Http("www.mylogs.com", new Options())
.CreateLogger();
```

The sink is batching multiple events into a single request, and the following hypothetical payload is sent as JSON.
The sink is batching multiple log events into a single request, and the following hypothetical payload is sent as JSON.

```json
{
Expand Down Expand Up @@ -53,6 +53,10 @@ The sink is batching multiple events into a single request, and the following hy
}
```

### Durability

A sink can be created as durable by calling `Http(string, DurableOptions)` instead of `Http(string, Options)`. A durable sink will persist log events on disk before sending them over the network, thus protecting against data loss after a system or process restart.

### Typical use case

Producing log events is only half the story. Unless you are consuming them in a matter that benefits you in development or operations, there is really no need to produce them in the first place.
Expand Down
29 changes: 22 additions & 7 deletions serilog-sinks-http.sln
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,19 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "documentation", "documentation", "{A726A97C-1A7C-4898-BD7E-DC399921DA66}"
ProjectSection(SolutionItems) = preProject
CHANGELOG.md = CHANGELOG.md
CONTRIBUTING.md = CONTRIBUTING.md
.github\CONTRIBUTING.md = .github\CONTRIBUTING.md
.github\ISSUE_TEMPLATE.md = .github\ISSUE_TEMPLATE.md
LICENSE = LICENSE
README.md = README.md
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{9C45525E-C6CE-43B4-95A6-11198A27F4BE}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Serilog.Sinks.Http.Tests", "test\Serilog.Sinks.Http.Tests\Serilog.Sinks.Http.Tests.xproj", "{F6BD0EB1-9960-4105-B5EF-8BF027D69AAD}"
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Serilog.Sinks.Http.IntegrationTests", "test\Serilog.Sinks.Http.IntegrationTests\Serilog.Sinks.Http.IntegrationTests.xproj", "{236CF8CC-3C6B-4138-BBEC-7FEC46E76726}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Serilog.Sinks.Http.IntegrationTests.Server", "test\Serilog.Sinks.Http.IntegrationTests.Server\Serilog.Sinks.Http.IntegrationTests.Server.xproj", "{D40B4248-AE0A-4027-9A4F-142F27FC97BE}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Serilog.Sinks.Http.Tests", "test\Serilog.Sinks.Http.Tests\Serilog.Sinks.Http.Tests.xproj", "{B49EC523-5353-445E-A056-77EDDF6EF9C1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand All @@ -35,16 +40,26 @@ Global
{33E1DD8E-E72D-43A9-AB5B-31356F6E794D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{33E1DD8E-E72D-43A9-AB5B-31356F6E794D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{33E1DD8E-E72D-43A9-AB5B-31356F6E794D}.Release|Any CPU.Build.0 = Release|Any CPU
{F6BD0EB1-9960-4105-B5EF-8BF027D69AAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F6BD0EB1-9960-4105-B5EF-8BF027D69AAD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F6BD0EB1-9960-4105-B5EF-8BF027D69AAD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F6BD0EB1-9960-4105-B5EF-8BF027D69AAD}.Release|Any CPU.Build.0 = Release|Any CPU
{236CF8CC-3C6B-4138-BBEC-7FEC46E76726}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{236CF8CC-3C6B-4138-BBEC-7FEC46E76726}.Debug|Any CPU.Build.0 = Debug|Any CPU
{236CF8CC-3C6B-4138-BBEC-7FEC46E76726}.Release|Any CPU.ActiveCfg = Release|Any CPU
{236CF8CC-3C6B-4138-BBEC-7FEC46E76726}.Release|Any CPU.Build.0 = Release|Any CPU
{D40B4248-AE0A-4027-9A4F-142F27FC97BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D40B4248-AE0A-4027-9A4F-142F27FC97BE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D40B4248-AE0A-4027-9A4F-142F27FC97BE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D40B4248-AE0A-4027-9A4F-142F27FC97BE}.Release|Any CPU.Build.0 = Release|Any CPU
{B49EC523-5353-445E-A056-77EDDF6EF9C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B49EC523-5353-445E-A056-77EDDF6EF9C1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B49EC523-5353-445E-A056-77EDDF6EF9C1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B49EC523-5353-445E-A056-77EDDF6EF9C1}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{33E1DD8E-E72D-43A9-AB5B-31356F6E794D} = {DB19D3CD-BF05-45EA-97D8-FC9F64BF0B7B}
{F6BD0EB1-9960-4105-B5EF-8BF027D69AAD} = {9C45525E-C6CE-43B4-95A6-11198A27F4BE}
{236CF8CC-3C6B-4138-BBEC-7FEC46E76726} = {9C45525E-C6CE-43B4-95A6-11198A27F4BE}
{D40B4248-AE0A-4027-9A4F-142F27FC97BE} = {9C45525E-C6CE-43B4-95A6-11198A27F4BE}
{B49EC523-5353-445E-A056-77EDDF6EF9C1} = {9C45525E-C6CE-43B4-95A6-11198A27F4BE}
EndGlobalSection
EndGlobal
122 changes: 74 additions & 48 deletions src/Serilog.Sinks.Http/LoggerSinkConfigurationExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,61 +13,87 @@
// limitations under the License.

using System;
using System.Net.Http;
using Serilog.Configuration;
using Serilog.Events;
using Serilog.Sinks.Http;
using Serilog.Sinks.Http.Private;

namespace Serilog
{
/// <summary>
/// Adds the WriteTo.Http() extension method to <see cref="LoggerConfiguration"/>.
/// </summary>
public static class LoggerSinkConfigurationExtensions
{
/// <summary>
/// Adds a sink that sends log events using HTTP POST over the network.
/// </summary>
/// <param name="sinkConfiguration">The logger configuration.</param>
/// <param name="requestUri">The URI the request is sent to.</param>
/// <param name="batchPostingLimit">
/// The maximum number of events to post in a single batch. The default is
/// <see cref="HttpSink.DefaultBatchPostingLimit"/>.
/// </param>
/// <param name="period">
/// The time to wait between checking for event batches. The default is
/// <see cref="HttpSink.DefaultPeriod"/>.
/// </param>
/// <param name="formatProvider">Supplies culture-specific formatting information, or null.</param>
/// <param name="restrictedToMinimumLevel">
/// The minimum level for events passed through the sink. The default is
/// <see cref="LevelAlias.Minimum"/>.
/// </param>
/// <param name="httpClient">
/// A custom <see cref="IHttpClient"/> implementation.
/// </param>
/// <returns>Logger configuration, allowing configuration to continue.</returns>
public static LoggerConfiguration Http(
this LoggerSinkConfiguration sinkConfiguration,
string requestUri,
int? batchPostingLimit = null,
TimeSpan? period = null,
IFormatProvider formatProvider = null,
LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum,
IHttpClient httpClient = null)
{
if (sinkConfiguration == null)
throw new ArgumentNullException(nameof(sinkConfiguration));
/// <summary>
/// Adds the WriteTo.Http() and WriteTo.DurableHttp() extension method to
/// <see cref="LoggerConfiguration"/>.
/// </summary>
public static class LoggerSinkConfigurationExtensions
{
/// <summary>
/// Adds a non durable sink that sends log events using HTTP POST over the network. A
/// non-durable sink will loose data after a system or process restart.
/// </summary>
/// <param name="sinkConfiguration">The logger configuration.</param>
/// <param name="requestUri">The URI the request is sent to.</param>
/// <param name="options">The sink options.</param>
/// <param name="restrictedToMinimumLevel">
/// The minimum level for events passed through the sink. Default value is
/// <see cref="LevelAlias.Minimum"/>.
/// </param>
/// <param name="httpClient">
/// A custom <see cref="IHttpClient"/> implementation. Default value is
/// <see cref="HttpClient"/>.
/// </param>
/// <returns>Logger configuration, allowing configuration to continue.</returns>
public static LoggerConfiguration Http(
this LoggerSinkConfiguration sinkConfiguration,
string requestUri,
Options options,
LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum,
IHttpClient httpClient = null)
{
if (sinkConfiguration == null)
throw new ArgumentNullException(nameof(sinkConfiguration));

var client = httpClient ?? new HttpClientWrapper();
var sink = new HttpSink(
httpClient ?? new HttpClientWrapper(),
requestUri,
options);

var sink = new HttpSink(
client,
requestUri,
batchPostingLimit ?? HttpSink.DefaultBatchPostingLimit,
period ?? HttpSink.DefaultPeriod,
formatProvider);
return sinkConfiguration.Sink(sink, restrictedToMinimumLevel);
}

return sinkConfiguration.Sink(sink, restrictedToMinimumLevel);
}
}
/// <summary>
/// Adds a durable sink that sends log events using HTTP POST over the network. A durable
/// sink will persist log events on disk before sending them over the network, thus
/// protecting against data loss after a system or process restart.
/// </summary>
/// <param name="sinkConfiguration">The logger configuration.</param>
/// <param name="requestUri">The URI the request is sent to.</param>
/// <param name="options">The sink options.</param>
/// <param name="restrictedToMinimumLevel">
/// The minimum level for events passed through the sink. Default value is
/// <see cref="LevelAlias.Minimum"/>.
/// </param>
/// <param name="httpClient">
/// A custom <see cref="IHttpClient"/> implementation. Default value is
/// <see cref="HttpClient"/>.
/// </param>
/// <returns>Logger configuration, allowing configuration to continue.</returns>
public static LoggerConfiguration DurableHttp(
this LoggerSinkConfiguration sinkConfiguration,
string requestUri,
DurableOptions options,
LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum,
IHttpClient httpClient = null)
{
if (sinkConfiguration == null)
throw new ArgumentNullException(nameof(sinkConfiguration));

var sink = new DurableHttpSink(
httpClient ?? new HttpClientWrapper(),
requestUri,
options);

return sinkConfiguration.Sink(sink, restrictedToMinimumLevel);
}
}
}
10 changes: 9 additions & 1 deletion src/Serilog.Sinks.Http/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
using System;
using System.Reflection;
using System.Runtime.CompilerServices;

[assembly: AssemblyVersion("1.0.0.0")]

[assembly: CLSCompliant(true)]
[assembly: CLSCompliant(true)]

[assembly: InternalsVisibleTo("Serilog.Sinks.Http.Tests, PublicKey=" +
"0024000004800000940000000602000000240000525341310004000001000100fb8d13fd344a1c" +
"6fe0fe83ef33c1080bf30690765bc6eb0df26ebfdf8f21670c64265b30db09f73a0dea5b3db4c9" +
"d18dbf6d5a25af5ce9016f281014d79dc3b4201ac646c451830fc7e61a2dfd633d34c39f87b818" +
"94191652df5ac63cc40c77f3542f702bda692e6e8a9158353df189007a49da0f3cfd55eb250066" +
"b19485ec")]
36 changes: 36 additions & 0 deletions src/Serilog.Sinks.Http/Sinks/Http/DurableOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright 2015-2016 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.

namespace Serilog.Sinks.Http
{
/// <summary>
/// Class describing the options for a durable HTTP sink.
/// </summary>
public class DurableOptions : Options
{
/// <summary>
/// Gets or sets the path for a set of files that will be used to buffer events until they
/// can be successfully transmitted across the network. Individual files will be created
/// using the pattern <see cref="BufferBaseFilename"/>-{Date}.json. Default value is
/// 'Buffer'.
/// </summary>
public string BufferBaseFilename { get; set; } = "Buffer";

/// <summary>
/// Gets or sets the maximum size, in bytes, to which the buffer log file for a specific date
/// will be allowed to grow. By default no limit will be applied.
/// </summary>
public long? BufferFileSizeLimitBytes { get; set; }
}
}
25 changes: 0 additions & 25 deletions src/Serilog.Sinks.Http/Sinks/Http/HttpClientWrapper.cs

This file was deleted.

Loading

0 comments on commit 9be3be9

Please sign in to comment.