Skip to content

Commit

Permalink
Use C#8 language features and extract constant strings
Browse files Browse the repository at this point in the history
  • Loading branch information
evilpilaf committed Mar 9, 2020
1 parent e3d6bfc commit 6ee2f9a
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 25 deletions.
1 change: 1 addition & 0 deletions src/Honeycomb.Serilog.Sink/Honeycomb.Serilog.Sink.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<Copyright>evilpilaf © $([System.DateTime]::Now.Year)</Copyright>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<PackageLicenseFile>LICENSE.TXT</PackageLicenseFile>
<LangVersion>latest</LangVersion>
</PropertyGroup>

<!-- SourceLink -->
Expand Down
77 changes: 52 additions & 25 deletions src/Honeycomb.Serilog.Sink/HoneycombSerilogSink.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
Expand All @@ -13,23 +13,37 @@

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<HttpClient> _clientBuilder = new Lazy<HttpClient>(BuildHttpClient);
protected virtual HttpClient Client => _clientBuilder.Value;
#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}";

/// <param name="teamId">The name of the team to submit the events to</param>
/// <param name="apiKey">The API key given in the Honeycomb ui</param>
/// <param name="batchSizeLimit">The maximum number of events to include in a single batch.</param>
/// <param name="period">The time to wait between checking for event batches.</param>
public HoneycombSerilogSink(string teamId, string apiKey)
{
_teamId = string.IsNullOrWhiteSpace(teamId) ? throw new ArgumentNullException(nameof(teamId)) : teamId;
Expand All @@ -38,41 +52,35 @@ public HoneycombSerilogSink(string teamId, string apiKey)

public async Task EmitBatchAsync(IEnumerable<LogEvent> 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<HttpResponseMessage> 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
Expand All @@ -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
Expand All @@ -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();
}
}
}

0 comments on commit 6ee2f9a

Please sign in to comment.