Skip to content

Commit d4fa88d

Browse files
authored
Merge pull request #34 from evilpilaf/new-batching
Use new batching approach
2 parents f39d5bc + 6ee2f9a commit d4fa88d

File tree

5 files changed

+88
-43
lines changed

5 files changed

+88
-43
lines changed

src/Honeycomb.Serilog.Sink/Honeycomb.Serilog.Sink.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
<Copyright>evilpilaf © $([System.DateTime]::Now.Year)</Copyright>
1111
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
1212
<PackageLicenseFile>LICENSE.TXT</PackageLicenseFile>
13+
<LangVersion>latest</LangVersion>
1314
</PropertyGroup>
1415

1516
<!-- SourceLink -->
@@ -49,7 +50,7 @@
4950
</PackageReference>
5051
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
5152
<PackageReference Include="Serilog" Version="2.9.0" />
52-
<PackageReference Include="Serilog.Sinks.PeriodicBatching" Version="2.2.0" />
53+
<PackageReference Include="Serilog.Sinks.PeriodicBatching" Version="2.3.0" />
5354
</ItemGroup>
5455

5556
<ItemGroup Condition=" '$(TargetFramework)' == 'net461' OR '$(TargetFramework)' == 'net462' OR '$(TargetFramework)' == 'net47' OR '$(TargetFramework)' == 'net471' OR '$(TargetFramework)' == 'net472' OR '$(TargetFramework)' == 'net48' ">
Lines changed: 59 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22
using System.Collections.Generic;
33
using System.IO;
44
using System.Net.Http;
@@ -13,73 +13,74 @@
1313

1414
namespace Honeycomb.Serilog.Sink
1515
{
16-
internal class HoneycombSerilogSink : PeriodicBatchingSink
16+
internal class HoneycombSerilogSink : IBatchedLogEventSink, IDisposable
1717
{
1818
#if NETCOREAPP
19-
private static readonly SocketsHttpHandler _socketsHttpHandler = new SocketsHttpHandler { PooledConnectionLifetime = TimeSpan.FromMinutes(30) };
19+
private static SocketsHttpHandler _socketsHttpHandler;
20+
21+
private static SocketsHttpHandler SocketsHttpHandler
22+
{
23+
get
24+
{
25+
return _socketsHttpHandler ??= new SocketsHttpHandler { PooledConnectionLifetime = TimeSpan.FromMinutes(30) };
26+
}
27+
}
28+
2029
protected virtual HttpClient Client => BuildHttpClient();
2130
#else
2231
private static readonly Lazy<HttpClient> _clientBuilder = new Lazy<HttpClient>(BuildHttpClient);
2332
protected virtual HttpClient Client => _clientBuilder.Value;
2433
#endif
25-
private static readonly Uri _honeycombApiUrl = new Uri("https://api.honeycomb.io/");
26-
2734
private readonly string _apiKey;
28-
2935
private readonly string _teamId;
36+
private static readonly Uri _honeycombApiUrl = new Uri(HoneycombBaseUri);
37+
38+
private const string JsonContentType = "application/json";
39+
private const string HoneycombBaseUri = "https://api.honeycomb.io/";
40+
private const string HoneycombBatchEndpointTemplate = "/1/batch/{0}";
41+
private const string HoneycombTeamIdHeaderName = "X-Honeycomb-Team";
42+
43+
private const string SelfLogMessageText = "Failure sending event to Honeycomb, received {statusCode} response with content {content}";
3044

3145
/// <param name="teamId">The name of the team to submit the events to</param>
3246
/// <param name="apiKey">The API key given in the Honeycomb ui</param>
33-
/// <param name="batchSizeLimit">The maximum number of events to include in a single batch.</param>
34-
/// <param name="period">The time to wait between checking for event batches.</param>
35-
public HoneycombSerilogSink(
36-
string teamId,
37-
string apiKey,
38-
int batchSizeLimit,
39-
TimeSpan period)
40-
: base(batchSizeLimit, period)
47+
public HoneycombSerilogSink(string teamId, string apiKey)
4148
{
4249
_teamId = string.IsNullOrWhiteSpace(teamId) ? throw new ArgumentNullException(nameof(teamId)) : teamId;
4350
_apiKey = string.IsNullOrWhiteSpace(apiKey) ? throw new ArgumentNullException(nameof(apiKey)) : apiKey;
4451
}
4552

46-
protected override async Task EmitBatchAsync(IEnumerable<LogEvent> events)
53+
public async Task EmitBatchAsync(IEnumerable<LogEvent> events)
4754
{
48-
using (TextWriter writer = new StringWriter())
49-
{
50-
BuildLogEvent(events, writer);
51-
await SendBatchedEvents(writer.ToString());
52-
}
55+
using TextWriter writer = new StringWriter();
56+
BuildLogEvent(events, writer);
57+
await SendBatchedEvents(writer.ToString()).ConfigureAwait(false);
5358
}
5459

5560
private async Task SendBatchedEvents(string events)
5661
{
57-
var requestMessage = new HttpRequestMessage(HttpMethod.Post, $"/1/batch/{_teamId}")
62+
using var requestMessage = new HttpRequestMessage(HttpMethod.Post, string.Format(HoneycombBatchEndpointTemplate, _teamId))
5863
{
59-
Content = new StringContent(events, Encoding.UTF8, "application/json"),
64+
Content = new StringContent(events, Encoding.UTF8, JsonContentType),
6065
Version = new Version(2, 0)
6166
};
6267

63-
requestMessage.Headers.Add("X-Honeycomb-Team", _apiKey);
68+
requestMessage.Headers.Add(HoneycombTeamIdHeaderName, _apiKey);
6469
var response = await SendRequest(requestMessage).ConfigureAwait(false);
6570
if (!response.IsSuccessStatusCode)
6671
{
67-
using (Stream contentStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false))
68-
using (var reader = new StreamReader(contentStream))
69-
{
70-
var responseContent = await reader.ReadToEndAsync().ConfigureAwait(false);
71-
SelfLog.WriteLine("Failure sending event to Honeycomb, received {statusCode} response with content {content}", response.StatusCode, responseContent);
72-
}
72+
using Stream contentStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
73+
using var reader = new StreamReader(contentStream);
74+
var responseContent = await reader.ReadToEndAsync().ConfigureAwait(false);
75+
SelfLog.WriteLine(SelfLogMessageText, response.StatusCode, responseContent);
7376
}
7477
}
7578

7679
private async Task<HttpResponseMessage> SendRequest(HttpRequestMessage request)
7780
{
7881
#if NETCOREAPP
79-
using (var client = Client)
80-
{
81-
return await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
82-
}
82+
using var client = Client;
83+
return await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
8384
#else
8485
return await Client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
8586
#endif
@@ -102,13 +103,37 @@ private static HttpClient BuildHttpClient()
102103
{
103104
HttpClient client;
104105
#if NETCOREAPP
105-
client = new HttpClient(_socketsHttpHandler, disposeHandler: false);
106+
client = new HttpClient(SocketsHttpHandler, disposeHandler: false);
106107
#else
107108
client = new HttpClient();
108109
#endif
109110
client.BaseAddress = _honeycombApiUrl;
110111

111112
return client;
112113
}
114+
115+
public Task OnEmptyBatchAsync()
116+
{
117+
return Task.CompletedTask;
118+
}
119+
120+
private void ReleaseUnmanagedResources()
121+
{
122+
#if NETCORE
123+
_socketsHttpHandler?.Dispose();
124+
_socketsHttpHandler = null;
125+
#endif
126+
}
127+
128+
public void Dispose()
129+
{
130+
ReleaseUnmanagedResources();
131+
GC.SuppressFinalize(this);
132+
}
133+
134+
~HoneycombSerilogSink()
135+
{
136+
ReleaseUnmanagedResources();
137+
}
113138
}
114139
}

src/Honeycomb.Serilog.Sink/HoneycombSinkExtensions.cs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1-
using System;
1+
using System;
22

33
using Serilog;
44
using Serilog.Configuration;
5+
using Serilog.Sinks.PeriodicBatching;
56

67
namespace Honeycomb.Serilog.Sink
78
{
89
public static class HoneycombSinkExtensions
910
{
11+
/// <param name="loggerConfiguration"></param>
1012
/// <param name="teamId">The name of the team to submit the events to</param>
1113
/// <param name="apiKey">The API key given in the Honeycomb ui</param>
1214
/// <param name="batchSizeLimit">The maximum number of events to include in a single batch.</param>
@@ -17,7 +19,25 @@ public static LoggerConfiguration HoneycombSink(this LoggerSinkConfiguration log
1719
int batchSizeLimit,
1820
TimeSpan period)
1921
{
20-
return loggerConfiguration.Sink(new HoneycombSerilogSink(teamId, apiKey, batchSizeLimit, period));
22+
var batchingOptions = new PeriodicBatchingSinkOptions
23+
{
24+
BatchSizeLimit = batchSizeLimit,
25+
Period = period
26+
};
27+
28+
return loggerConfiguration.HoneycombSink(teamId, apiKey, batchingOptions);
29+
}
30+
31+
public static LoggerConfiguration HoneycombSink(this LoggerSinkConfiguration loggerConfiguration,
32+
string teamId,
33+
string apiKey,
34+
PeriodicBatchingSinkOptions batchingOptions = default)
35+
{
36+
var honeycombSink = new HoneycombSerilogSink(teamId, apiKey);
37+
38+
var batchingSink = new PeriodicBatchingSink(honeycombSink, batchingOptions ?? new PeriodicBatchingSinkOptions());
39+
40+
return loggerConfiguration.Sink(batchingSink);
2141
}
2242
}
2343
}

test/Honeycomb.Serilog.Sink.Tests/HoneycombSerilogSinkStub.cs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
using System;
2-
using System.Collections.Generic;
3-
using System.Net.Http;
1+
using System.Net.Http;
42
using System.Threading.Tasks;
53

64
using Serilog.Events;
@@ -11,8 +9,8 @@ internal class HoneycombSerilogSinkStub : HoneycombSerilogSink
119
{
1210
private readonly HttpClient _client;
1311

14-
public HoneycombSerilogSinkStub(HttpClient client, string teamId, string apiKey, int batchSizeLimit, TimeSpan period)
15-
: base(teamId, apiKey, batchSizeLimit, period)
12+
public HoneycombSerilogSinkStub(HttpClient client, string teamId, string apiKey)
13+
: base(teamId, apiKey)
1614
{
1715
_client = client;
1816
}

test/Honeycomb.Serilog.Sink.Tests/HoneycombSerilogSinkTests.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
using Serilog.Events;
1414
using Serilog.Parsing;
15+
using Serilog.Sinks.PeriodicBatching;
1516

1617
using Xunit;
1718

@@ -187,7 +188,7 @@ public async Task Emit_GivenAMessageWithProperties_SendsThemAllAsync()
187188

188189
private HoneycombSerilogSinkStub CreateSut(string teamId, string apiKey, HttpClient client = null)
189190
{
190-
return new HoneycombSerilogSinkStub(client, teamId, apiKey, 1, TimeSpan.FromMilliseconds(1));
191+
return new HoneycombSerilogSinkStub(client, teamId, apiKey);
191192
}
192193
}
193194
}

0 commit comments

Comments
 (0)