Skip to content

Commit b5b8fe2

Browse files
committed
Move all JSON formatting into SplunkJsonFormatter; fixes #29 also
1 parent cbb5360 commit b5b8fe2

File tree

6 files changed

+91
-113
lines changed

6 files changed

+91
-113
lines changed

src/Serilog.Sinks.Splunk/Sinks/Splunk/EventCollectorRequest.cs

Lines changed: 0 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -14,55 +14,11 @@
1414

1515

1616
using System;
17-
using System.Globalization;
1817
using System.Net.Http;
1918
using System.Text;
2019

2120
namespace Serilog.Sinks.Splunk
2221
{
23-
internal class SplunkEvent
24-
{
25-
private string _payload;
26-
27-
internal SplunkEvent(string logEvent, string source, string sourceType, string host, string index, double time)
28-
{
29-
_payload = string.Empty;
30-
31-
var jsonPayLoad = @"{""event"":" + logEvent
32-
.Replace("\r\n", string.Empty);
33-
34-
if (!string.IsNullOrWhiteSpace(source))
35-
{
36-
jsonPayLoad = jsonPayLoad + @",""source"":""" + source + @"""";
37-
}
38-
if (!string.IsNullOrWhiteSpace(sourceType))
39-
{
40-
jsonPayLoad = jsonPayLoad + @",""sourceType"":""" + sourceType + @"""";
41-
}
42-
if (!string.IsNullOrWhiteSpace(host))
43-
{
44-
jsonPayLoad = jsonPayLoad + @",""host"":""" + host + @"""";
45-
}
46-
if (!string.IsNullOrWhiteSpace(index))
47-
{
48-
jsonPayLoad = jsonPayLoad + @",""index"":""" + index + @"""";
49-
}
50-
51-
if (time > 0)
52-
{
53-
jsonPayLoad = jsonPayLoad + @",""time"":" + time.ToString(CultureInfo.InvariantCulture);
54-
}
55-
56-
jsonPayLoad = jsonPayLoad + "}";
57-
_payload = jsonPayLoad;
58-
}
59-
60-
public string Payload
61-
{
62-
get { return _payload; }
63-
}
64-
}
65-
6622
internal class EventCollectorRequest : HttpRequestMessage
6723
{
6824
internal EventCollectorRequest(string splunkHost, string jsonPayLoad, string uri ="services/collector")

src/Serilog.Sinks.Splunk/Sinks/Splunk/EventCollectorSink.cs

Lines changed: 28 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
using System.IO;
1919
using System.Linq;
2020
using System.Net;
21-
using System.Net.Http;
2221
using System.Threading;
2322
using System.Threading.Tasks;
2423
using Serilog.Core;
@@ -33,20 +32,11 @@ namespace Serilog.Sinks.Splunk
3332
public class EventCollectorSink : ILogEventSink, IDisposable
3433
{
3534
private readonly string _splunkHost;
36-
private readonly string _eventCollectorToken;
37-
private readonly string _source;
38-
private readonly string _sourceType;
39-
private readonly string _host;
40-
private readonly string _index;
4135
private readonly string _uriPath;
4236
private readonly int _batchSizeLimitLimit;
4337
private readonly SplunkJsonFormatter _jsonFormatter;
4438
private readonly ConcurrentQueue<LogEvent> _queue;
4539
private readonly EventCollectorClient _httpClient;
46-
private const string DefaultSource = "";
47-
private const string DefaultSourceType = "";
48-
private const string DefaultHost = "";
49-
private const string DefaultIndex = "";
5040

5141
/// <summary>
5242
/// Taken from Splunk.Logging.Common
@@ -56,7 +46,7 @@ public class EventCollectorSink : ILogEventSink, IDisposable
5646
HttpStatusCode.Forbidden,
5747
HttpStatusCode.MethodNotAllowed,
5848
HttpStatusCode.BadRequest
59-
};
49+
};
6050

6151
/// <summary>
6252
/// Creates a new instance of the sink
@@ -73,24 +63,16 @@ public EventCollectorSink(
7363
int batchIntervalInSeconds = 5,
7464
int batchSizeLimit = 100,
7565
IFormatProvider formatProvider = null,
76-
bool renderTemplate = true
77-
)
66+
bool renderTemplate = true)
67+
: this(
68+
splunkHost,
69+
eventCollectorToken,
70+
null, null, null, null, null,
71+
batchIntervalInSeconds,
72+
batchSizeLimit,
73+
formatProvider,
74+
renderTemplate)
7875
{
79-
_splunkHost = splunkHost;
80-
_eventCollectorToken = eventCollectorToken;
81-
_queue = new ConcurrentQueue<LogEvent>();
82-
_jsonFormatter = new SplunkJsonFormatter(renderMessage: true, formatProvider: formatProvider, renderTemplate: renderTemplate);
83-
_batchSizeLimitLimit = batchSizeLimit;
84-
85-
var batchInterval = TimeSpan.FromSeconds(batchIntervalInSeconds);
86-
_httpClient = new EventCollectorClient(_eventCollectorToken);
87-
88-
var cancellationToken = new CancellationToken();
89-
90-
RepeatAction.OnInterval(
91-
batchInterval,
92-
async () => await ProcessQueue(),
93-
cancellationToken);
9476
}
9577

9678
/// <summary>
@@ -118,19 +100,23 @@ public EventCollectorSink(
118100
int batchIntervalInSeconds,
119101
int batchSizeLimit,
120102
IFormatProvider formatProvider = null,
121-
bool renderTemplate = true
122-
) : this(splunkHost,
123-
eventCollectorToken,
124-
batchIntervalInSeconds,
125-
batchSizeLimit,
126-
formatProvider,
127-
renderTemplate)
103+
bool renderTemplate = true)
128104
{
129-
_source = source;
130-
_sourceType = sourceType;
131-
_host = host;
132-
_index = index;
133105
_uriPath = uriPath;
106+
_splunkHost = splunkHost;
107+
_queue = new ConcurrentQueue<LogEvent>();
108+
_jsonFormatter = new SplunkJsonFormatter(renderTemplate, formatProvider, source, sourceType, host, index);
109+
_batchSizeLimitLimit = batchSizeLimit;
110+
111+
var batchInterval = TimeSpan.FromSeconds(batchIntervalInSeconds);
112+
_httpClient = new EventCollectorClient(eventCollectorToken);
113+
114+
var cancellationToken = new CancellationToken();
115+
116+
RepeatAction.OnInterval(
117+
batchInterval,
118+
async () => await ProcessQueue(),
119+
cancellationToken);
134120
}
135121

136122
/// <summary>
@@ -175,21 +161,14 @@ private async Task ProcessQueue()
175161

176162
private async Task Send(IEnumerable<LogEvent> events)
177163
{
178-
string allEvents = string.Empty;
164+
var allEvents = new StringWriter();
179165

180166
foreach (var logEvent in events)
181167
{
182-
var sw = new StringWriter();
183-
_jsonFormatter.Format(logEvent, sw);
184-
185-
var serialisedEvent = sw.ToString();
186-
187-
var splunkEvent = new SplunkEvent(serialisedEvent, _source, _sourceType, _host, _index, logEvent.Timestamp.ToEpoch());
188-
189-
allEvents = $"{allEvents}{splunkEvent.Payload}";
168+
_jsonFormatter.Format(logEvent, allEvents);
190169
}
191170

192-
var request = new EventCollectorRequest(_splunkHost, allEvents, _uriPath);
171+
var request = new EventCollectorRequest(_splunkHost, allEvents.ToString(), _uriPath);
193172
var response = await _httpClient.SendAsync(request);
194173

195174
if (response.IsSuccessStatusCode)

src/Serilog.Sinks.Splunk/Sinks/Splunk/SplunkJsonFormatter.cs

Lines changed: 60 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
using System;
1616
using System.Collections.Generic;
17+
using System.Globalization;
1718
using System.IO;
1819
using Serilog.Events;
1920
using Serilog.Formatting;
@@ -29,24 +30,69 @@ public class SplunkJsonFormatter : ITextFormatter
2930
static readonly JsonValueFormatter ValueFormatter = new JsonValueFormatter();
3031

3132
readonly bool _renderTemplate;
32-
readonly bool _renderMessage;
3333
readonly IFormatProvider _formatProvider;
34+
readonly string _suffix;
3435

3536
/// <summary>
3637
/// Construct a <see cref="SplunkJsonFormatter"/>.
3738
/// </summary>
38-
/// <param name="renderMessage">If true, the message will be rendered and written to the output as a
39-
/// property named RenderedMessage.</param>
4039
/// <param name="formatProvider">Supplies culture-specific formatting information, or null.</param>
4140
/// <param name="renderTemplate">If true, the template used will be rendered and written to the output as a property named MessageTemplate</param>
4241
public SplunkJsonFormatter(
43-
bool renderTemplate = true,
44-
bool renderMessage = false,
45-
IFormatProvider formatProvider = null)
42+
bool renderTemplate,
43+
IFormatProvider formatProvider)
44+
: this(renderTemplate, formatProvider, null, null, null, null)
45+
{
46+
}
47+
48+
/// <summary>
49+
/// Construct a <see cref="SplunkJsonFormatter"/>.
50+
/// </summary>
51+
/// <param name="formatProvider">Supplies culture-specific formatting information, or null.</param>
52+
/// <param name="renderTemplate">If true, the template used will be rendered and written to the output as a property named MessageTemplate</param>
53+
/// <param name="index">The Splunk index to log to</param>
54+
/// <param name="source">The source of the event</param>
55+
/// <param name="sourceType">The source type of the event</param>
56+
/// <param name="host">The host of the event</param>
57+
public SplunkJsonFormatter(
58+
bool renderTemplate,
59+
IFormatProvider formatProvider,
60+
string source,
61+
string sourceType,
62+
string host,
63+
string index)
4664
{
4765
_renderTemplate = renderTemplate;
48-
_renderMessage = renderMessage;
4966
_formatProvider = formatProvider;
67+
68+
var suffixWriter = new StringWriter();
69+
suffixWriter.Write("}"); // Terminates "event"
70+
71+
if (!string.IsNullOrWhiteSpace(source))
72+
{
73+
suffixWriter.Write(",\"source\":");
74+
JsonValueFormatter.WriteQuotedJsonString(source, suffixWriter);
75+
}
76+
77+
if (!string.IsNullOrWhiteSpace(sourceType))
78+
{
79+
suffixWriter.Write(",\"sourceType\":");
80+
JsonValueFormatter.WriteQuotedJsonString(sourceType, suffixWriter);
81+
}
82+
83+
if (!string.IsNullOrWhiteSpace(host))
84+
{
85+
suffixWriter.Write(",\"host\":");
86+
JsonValueFormatter.WriteQuotedJsonString(host, suffixWriter);
87+
}
88+
89+
if (!string.IsNullOrWhiteSpace(index))
90+
{
91+
suffixWriter.Write(",\"index\":");
92+
JsonValueFormatter.WriteQuotedJsonString(index, suffixWriter);
93+
}
94+
suffixWriter.Write('}'); // Terminates the payload
95+
_suffix = suffixWriter.ToString();
5096
}
5197

5298
/// <inheritdoc/>
@@ -55,22 +101,20 @@ public void Format(LogEvent logEvent, TextWriter output)
55101
if (logEvent == null) throw new ArgumentNullException(nameof(logEvent));
56102
if (output == null) throw new ArgumentNullException(nameof(output));
57103

58-
output.Write("{\"Timestamp\":\"");
59-
output.Write(logEvent.Timestamp.ToString("o"));
60-
output.Write("\",\"Level\":\"");
104+
output.Write("{\"time\":\"");
105+
output.Write(logEvent.Timestamp.ToEpoch().ToString(CultureInfo.InvariantCulture));
106+
output.Write("\",\"event\":{\"Level\":\"");
61107
output.Write(logEvent.Level);
108+
output.Write('"');
62109

63110
if (_renderTemplate)
64111
{
65112
output.Write("\",\"MessageTemplate\":");
66113
JsonValueFormatter.WriteQuotedJsonString(logEvent.MessageTemplate.Text, output);
67114
}
68115

69-
if (_renderMessage)
70-
{
71-
output.Write(",\"RenderedMessage\":");
72-
JsonValueFormatter.WriteQuotedJsonString(logEvent.RenderMessage(_formatProvider), output);
73-
}
116+
output.Write(",\"RenderedMessage\":");
117+
JsonValueFormatter.WriteQuotedJsonString(logEvent.RenderMessage(_formatProvider), output);
74118

75119
if (logEvent.Exception != null)
76120
{
@@ -81,8 +125,7 @@ public void Format(LogEvent logEvent, TextWriter output)
81125
if (logEvent.Properties.Count != 0)
82126
WriteProperties(logEvent.Properties, output);
83127

84-
output.Write('}');
85-
output.WriteLine();
128+
output.WriteLine(_suffix);
86129
}
87130

88131
static void WriteProperties(IReadOnlyDictionary<string, LogEventPropertyValue> properties, TextWriter output)

src/Serilog.Sinks.Splunk/Sinks/Splunk/TcpSink.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ private static TcpSocketWriter CreateSocketWriter(SplunkTcpSinkConnectionInfo co
102102

103103
private static SplunkJsonFormatter CreateDefaultFormatter(IFormatProvider formatProvider, bool renderTemplate)
104104
{
105-
return new SplunkJsonFormatter(renderMessage: true, formatProvider: formatProvider, renderTemplate: renderTemplate);
105+
return new SplunkJsonFormatter(renderTemplate, formatProvider);
106106
}
107107

108108
/// <inheritdoc/>

src/Serilog.Sinks.Splunk/Sinks/Splunk/UdpSink.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ public UdpSink(IPAddress hostAddress, int port, IFormatProvider formatProvider =
9696

9797
private static SplunkJsonFormatter CreateDefaultFormatter(IFormatProvider formatProvider, bool renderTemplate)
9898
{
99-
return new SplunkJsonFormatter(renderMessage: true, formatProvider: formatProvider, renderTemplate: renderTemplate);
99+
return new SplunkJsonFormatter(renderTemplate, formatProvider);
100100
}
101101

102102
/// <inheritdoc/>

test/Serilog.Sinks.Splunk.Tests/SplunkJsonFormatterTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public class SplunkJsonFormatterTests
1111
void AssertValidJson(Action<ILogger> act)
1212
{
1313
var output = new StringWriter();
14-
var formatter = new SplunkJsonFormatter();
14+
var formatter = new SplunkJsonFormatter(false, null);
1515
var log = new LoggerConfiguration()
1616
.WriteTo.Sink(new TextWriterSink(output, formatter))
1717
.CreateLogger();

0 commit comments

Comments
 (0)