diff --git a/src/Honeycomb.Serilog.Sink/Honeycomb.Serilog.Sink.csproj b/src/Honeycomb.Serilog.Sink/Honeycomb.Serilog.Sink.csproj
index 4d5e767..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
diff --git a/src/Honeycomb.Serilog.Sink/HoneycombSerilogSink.cs b/src/Honeycomb.Serilog.Sink/HoneycombSerilogSink.cs
index 6253d8e..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,10 +13,19 @@
namespace Honeycomb.Serilog.Sink
{
- internal class HoneycombSerilogSink : IBatchedLogEventSink
+ 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);
@@ -24,12 +33,17 @@ internal class HoneycombSerilogSink : IBatchedLogEventSink
#endif
private readonly string _apiKey;
private readonly string _teamId;
- private static readonly Uri _honeycombApiUrl = new Uri("https://api.honeycomb.io/");
+ 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)
{
_teamId = string.IsNullOrWhiteSpace(teamId) ? throw new ArgumentNullException(nameof(teamId)) : teamId;
@@ -38,41 +52,35 @@ public HoneycombSerilogSink(string teamId, string apiKey)
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
@@ -95,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
@@ -108,5 +116,24 @@ 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();
+ }
}
}