1
- using System ;
1
+ using System ;
2
2
using System . Collections . Generic ;
3
3
using System . IO ;
4
4
using System . Net . Http ;
13
13
14
14
namespace Honeycomb . Serilog . Sink
15
15
{
16
- internal class HoneycombSerilogSink : PeriodicBatchingSink
16
+ internal class HoneycombSerilogSink : IBatchedLogEventSink , IDisposable
17
17
{
18
18
#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
+
20
29
protected virtual HttpClient Client => BuildHttpClient ( ) ;
21
30
#else
22
31
private static readonly Lazy < HttpClient > _clientBuilder = new Lazy < HttpClient > ( BuildHttpClient ) ;
23
32
protected virtual HttpClient Client => _clientBuilder . Value ;
24
33
#endif
25
- private static readonly Uri _honeycombApiUrl = new Uri ( "https://api.honeycomb.io/" ) ;
26
-
27
34
private readonly string _apiKey ;
28
-
29
35
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}" ;
30
44
31
45
/// <param name="teamId">The name of the team to submit the events to</param>
32
46
/// <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 )
41
48
{
42
49
_teamId = string . IsNullOrWhiteSpace ( teamId ) ? throw new ArgumentNullException ( nameof ( teamId ) ) : teamId ;
43
50
_apiKey = string . IsNullOrWhiteSpace ( apiKey ) ? throw new ArgumentNullException ( nameof ( apiKey ) ) : apiKey ;
44
51
}
45
52
46
- protected override async Task EmitBatchAsync ( IEnumerable < LogEvent > events )
53
+ public async Task EmitBatchAsync ( IEnumerable < LogEvent > events )
47
54
{
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 ) ;
53
58
}
54
59
55
60
private async Task SendBatchedEvents ( string events )
56
61
{
57
- var requestMessage = new HttpRequestMessage ( HttpMethod . Post , $ "/1/batch/ { _teamId } " )
62
+ using var requestMessage = new HttpRequestMessage ( HttpMethod . Post , string . Format ( HoneycombBatchEndpointTemplate , _teamId ) )
58
63
{
59
- Content = new StringContent ( events , Encoding . UTF8 , "application/json" ) ,
64
+ Content = new StringContent ( events , Encoding . UTF8 , JsonContentType ) ,
60
65
Version = new Version ( 2 , 0 )
61
66
} ;
62
67
63
- requestMessage . Headers . Add ( "X-Honeycomb-Team" , _apiKey ) ;
68
+ requestMessage . Headers . Add ( HoneycombTeamIdHeaderName , _apiKey ) ;
64
69
var response = await SendRequest ( requestMessage ) . ConfigureAwait ( false ) ;
65
70
if ( ! response . IsSuccessStatusCode )
66
71
{
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 ) ;
73
76
}
74
77
}
75
78
76
79
private async Task < HttpResponseMessage > SendRequest ( HttpRequestMessage request )
77
80
{
78
81
#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 ) ;
83
84
#else
84
85
return await Client . SendAsync ( request , HttpCompletionOption . ResponseHeadersRead ) ;
85
86
#endif
@@ -102,13 +103,37 @@ private static HttpClient BuildHttpClient()
102
103
{
103
104
HttpClient client ;
104
105
#if NETCOREAPP
105
- client = new HttpClient ( _socketsHttpHandler , disposeHandler : false ) ;
106
+ client = new HttpClient ( SocketsHttpHandler , disposeHandler : false ) ;
106
107
#else
107
108
client = new HttpClient ( ) ;
108
109
#endif
109
110
client . BaseAddress = _honeycombApiUrl ;
110
111
111
112
return client ;
112
113
}
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
+ }
113
138
}
114
139
}
0 commit comments