diff --git a/src/Honeycomb.Serilog.Sink/Honeycomb.Serilog.Sink.csproj b/src/Honeycomb.Serilog.Sink/Honeycomb.Serilog.Sink.csproj
index f9e90c2..ff1eafc 100644
--- a/src/Honeycomb.Serilog.Sink/Honeycomb.Serilog.Sink.csproj
+++ b/src/Honeycomb.Serilog.Sink/Honeycomb.Serilog.Sink.csproj
@@ -10,6 +10,7 @@
evilpilaf © $([System.DateTime]::Now.Year)
true
LICENSE.TXT
+ latest
@@ -49,7 +50,7 @@
-
+
diff --git a/src/Honeycomb.Serilog.Sink/HoneycombSerilogSink.cs b/src/Honeycomb.Serilog.Sink/HoneycombSerilogSink.cs
index 232aa3a..2566aeb 100644
--- a/src/Honeycomb.Serilog.Sink/HoneycombSerilogSink.cs
+++ b/src/Honeycomb.Serilog.Sink/HoneycombSerilogSink.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
@@ -13,73 +13,74 @@
namespace Honeycomb.Serilog.Sink
{
- internal class HoneycombSerilogSink : PeriodicBatchingSink
+ internal class HoneycombSerilogSink : IBatchedLogEventSink, IDisposable
{
#if NETCOREAPP
- private static readonly SocketsHttpHandler _socketsHttpHandler = new SocketsHttpHandler { PooledConnectionLifetime = TimeSpan.FromMinutes(30) };
+ private static SocketsHttpHandler _socketsHttpHandler;
+
+ private static SocketsHttpHandler SocketsHttpHandler
+ {
+ get
+ {
+ return _socketsHttpHandler ??= new SocketsHttpHandler { PooledConnectionLifetime = TimeSpan.FromMinutes(30) };
+ }
+ }
+
protected virtual HttpClient Client => BuildHttpClient();
#else
private static readonly Lazy _clientBuilder = new Lazy(BuildHttpClient);
protected virtual HttpClient Client => _clientBuilder.Value;
#endif
- private static readonly Uri _honeycombApiUrl = new Uri("https://api.honeycomb.io/");
-
private readonly string _apiKey;
-
private readonly string _teamId;
+ private static readonly Uri _honeycombApiUrl = new Uri(HoneycombBaseUri);
+
+ private const string JsonContentType = "application/json";
+ private const string HoneycombBaseUri = "https://api.honeycomb.io/";
+ private const string HoneycombBatchEndpointTemplate = "/1/batch/{0}";
+ private const string HoneycombTeamIdHeaderName = "X-Honeycomb-Team";
+
+ private const string SelfLogMessageText = "Failure sending event to Honeycomb, received {statusCode} response with content {content}";
/// The name of the team to submit the events to
/// The API key given in the Honeycomb ui
- /// The maximum number of events to include in a single batch.
- /// The time to wait between checking for event batches.
- public HoneycombSerilogSink(
- string teamId,
- string apiKey,
- int batchSizeLimit,
- TimeSpan period)
- : base(batchSizeLimit, period)
+ public HoneycombSerilogSink(string teamId, string apiKey)
{
_teamId = string.IsNullOrWhiteSpace(teamId) ? throw new ArgumentNullException(nameof(teamId)) : teamId;
_apiKey = string.IsNullOrWhiteSpace(apiKey) ? throw new ArgumentNullException(nameof(apiKey)) : apiKey;
}
- protected override async Task EmitBatchAsync(IEnumerable events)
+ public async Task EmitBatchAsync(IEnumerable events)
{
- using (TextWriter writer = new StringWriter())
- {
- BuildLogEvent(events, writer);
- await SendBatchedEvents(writer.ToString());
- }
+ using TextWriter writer = new StringWriter();
+ BuildLogEvent(events, writer);
+ await SendBatchedEvents(writer.ToString()).ConfigureAwait(false);
}
private async Task SendBatchedEvents(string events)
{
- var requestMessage = new HttpRequestMessage(HttpMethod.Post, $"/1/batch/{_teamId}")
+ using var requestMessage = new HttpRequestMessage(HttpMethod.Post, string.Format(HoneycombBatchEndpointTemplate, _teamId))
{
- Content = new StringContent(events, Encoding.UTF8, "application/json"),
+ Content = new StringContent(events, Encoding.UTF8, JsonContentType),
Version = new Version(2, 0)
};
- requestMessage.Headers.Add("X-Honeycomb-Team", _apiKey);
+ requestMessage.Headers.Add(HoneycombTeamIdHeaderName, _apiKey);
var response = await SendRequest(requestMessage).ConfigureAwait(false);
if (!response.IsSuccessStatusCode)
{
- using (Stream contentStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false))
- using (var reader = new StreamReader(contentStream))
- {
- var responseContent = await reader.ReadToEndAsync().ConfigureAwait(false);
- SelfLog.WriteLine("Failure sending event to Honeycomb, received {statusCode} response with content {content}", response.StatusCode, responseContent);
- }
+ using Stream contentStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
+ using var reader = new StreamReader(contentStream);
+ var responseContent = await reader.ReadToEndAsync().ConfigureAwait(false);
+ SelfLog.WriteLine(SelfLogMessageText, response.StatusCode, responseContent);
}
}
private async Task SendRequest(HttpRequestMessage request)
{
#if NETCOREAPP
- using (var client = Client)
- {
- return await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
- }
+ using var client = Client;
+ return await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
#else
return await Client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
#endif
@@ -102,7 +103,7 @@ private static HttpClient BuildHttpClient()
{
HttpClient client;
#if NETCOREAPP
- client = new HttpClient(_socketsHttpHandler, disposeHandler: false);
+ client = new HttpClient(SocketsHttpHandler, disposeHandler: false);
#else
client = new HttpClient();
#endif
@@ -110,5 +111,29 @@ private static HttpClient BuildHttpClient()
return client;
}
+
+ public Task OnEmptyBatchAsync()
+ {
+ return Task.CompletedTask;
+ }
+
+ private void ReleaseUnmanagedResources()
+ {
+#if NETCORE
+ _socketsHttpHandler?.Dispose();
+ _socketsHttpHandler = null;
+#endif
+ }
+
+ public void Dispose()
+ {
+ ReleaseUnmanagedResources();
+ GC.SuppressFinalize(this);
+ }
+
+ ~HoneycombSerilogSink()
+ {
+ ReleaseUnmanagedResources();
+ }
}
}
diff --git a/src/Honeycomb.Serilog.Sink/HoneycombSinkExtensions.cs b/src/Honeycomb.Serilog.Sink/HoneycombSinkExtensions.cs
index e6da33f..54a2cc9 100644
--- a/src/Honeycomb.Serilog.Sink/HoneycombSinkExtensions.cs
+++ b/src/Honeycomb.Serilog.Sink/HoneycombSinkExtensions.cs
@@ -1,12 +1,14 @@
-using System;
+using System;
using Serilog;
using Serilog.Configuration;
+using Serilog.Sinks.PeriodicBatching;
namespace Honeycomb.Serilog.Sink
{
public static class HoneycombSinkExtensions
{
+ ///
/// The name of the team to submit the events to
/// The API key given in the Honeycomb ui
/// The maximum number of events to include in a single batch.
@@ -17,7 +19,25 @@ public static LoggerConfiguration HoneycombSink(this LoggerSinkConfiguration log
int batchSizeLimit,
TimeSpan period)
{
- return loggerConfiguration.Sink(new HoneycombSerilogSink(teamId, apiKey, batchSizeLimit, period));
+ var batchingOptions = new PeriodicBatchingSinkOptions
+ {
+ BatchSizeLimit = batchSizeLimit,
+ Period = period
+ };
+
+ return loggerConfiguration.HoneycombSink(teamId, apiKey, batchingOptions);
+ }
+
+ public static LoggerConfiguration HoneycombSink(this LoggerSinkConfiguration loggerConfiguration,
+ string teamId,
+ string apiKey,
+ PeriodicBatchingSinkOptions batchingOptions = default)
+ {
+ var honeycombSink = new HoneycombSerilogSink(teamId, apiKey);
+
+ var batchingSink = new PeriodicBatchingSink(honeycombSink, batchingOptions ?? new PeriodicBatchingSinkOptions());
+
+ return loggerConfiguration.Sink(batchingSink);
}
}
}
diff --git a/test/Honeycomb.Serilog.Sink.Tests/HoneycombSerilogSinkStub.cs b/test/Honeycomb.Serilog.Sink.Tests/HoneycombSerilogSinkStub.cs
index f8e788e..fd5f4d8 100644
--- a/test/Honeycomb.Serilog.Sink.Tests/HoneycombSerilogSinkStub.cs
+++ b/test/Honeycomb.Serilog.Sink.Tests/HoneycombSerilogSinkStub.cs
@@ -1,6 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Net.Http;
+using System.Net.Http;
using System.Threading.Tasks;
using Serilog.Events;
@@ -11,8 +9,8 @@ internal class HoneycombSerilogSinkStub : HoneycombSerilogSink
{
private readonly HttpClient _client;
- public HoneycombSerilogSinkStub(HttpClient client, string teamId, string apiKey, int batchSizeLimit, TimeSpan period)
- : base(teamId, apiKey, batchSizeLimit, period)
+ public HoneycombSerilogSinkStub(HttpClient client, string teamId, string apiKey)
+ : base(teamId, apiKey)
{
_client = client;
}
diff --git a/test/Honeycomb.Serilog.Sink.Tests/HoneycombSerilogSinkTests.cs b/test/Honeycomb.Serilog.Sink.Tests/HoneycombSerilogSinkTests.cs
index 8cd03f1..caea00e 100644
--- a/test/Honeycomb.Serilog.Sink.Tests/HoneycombSerilogSinkTests.cs
+++ b/test/Honeycomb.Serilog.Sink.Tests/HoneycombSerilogSinkTests.cs
@@ -12,6 +12,7 @@
using Serilog.Events;
using Serilog.Parsing;
+using Serilog.Sinks.PeriodicBatching;
using Xunit;
@@ -187,7 +188,7 @@ public async Task Emit_GivenAMessageWithProperties_SendsThemAllAsync()
private HoneycombSerilogSinkStub CreateSut(string teamId, string apiKey, HttpClient client = null)
{
- return new HoneycombSerilogSinkStub(client, teamId, apiKey, 1, TimeSpan.FromMilliseconds(1));
+ return new HoneycombSerilogSinkStub(client, teamId, apiKey);
}
}
}