Skip to content

Commit

Permalink
Fixes #161 add subsecond decimal configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
EEParker committed Mar 16, 2024
1 parent dcacbbc commit 734392e
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 20 deletions.
Expand Up @@ -31,6 +31,7 @@ public class CompactSplunkJsonFormatter : ITextFormatter
private static readonly JsonValueFormatter ValueFormatter = new JsonValueFormatter(typeTagName: "$type");
private readonly string _suffix;
private readonly bool _renderTemplate;
private readonly int _subSecondDecimals;

/// <summary>
/// Construct a <see cref="CompactSplunkJsonFormatter"/>.
Expand All @@ -40,9 +41,13 @@ public class CompactSplunkJsonFormatter : ITextFormatter
/// <param name="host">The host of the event</param>
/// <param name="index">The Splunk index to log to</param>
/// <param name="renderTemplate">If true, the template used will be rendered and written to the output as a property named MessageTemplate</param>
public CompactSplunkJsonFormatter(bool renderTemplate = false, string source = null, string sourceType = null, string host = null, string index = null)
/// <param name="subSecondDecimals">Timestamp sub-second precision</param>

public CompactSplunkJsonFormatter(bool renderTemplate = false, string source = null, string sourceType = null, string host = null, string index = null, int subSecondDecimals = 3)
{
_renderTemplate = renderTemplate;
_subSecondDecimals = subSecondDecimals;

var suffixWriter = new StringWriter();
suffixWriter.Write("}"); // Terminates "event"

Expand Down Expand Up @@ -80,7 +85,7 @@ public void Format(LogEvent logEvent, TextWriter output)
if (output == null) throw new ArgumentNullException(nameof(output));

output.Write("{\"time\":\"");
output.Write(logEvent.Timestamp.ToEpoch().ToString(CultureInfo.InvariantCulture));
output.Write(logEvent.Timestamp.ToEpoch(_subSecondDecimals).ToString(CultureInfo.InvariantCulture));
output.Write("\",\"event\":{\"@l\":\"");
output.Write(logEvent.Level);
output.Write('"');
Expand Down
4 changes: 2 additions & 2 deletions src/Serilog.Sinks.Splunk/Sinks/Splunk/Epoch.cs
Expand Up @@ -20,15 +20,15 @@ internal static class EpochExtensions
{
private static DateTimeOffset Epoch = new DateTimeOffset(1970,1,1,0,0,0,TimeSpan.Zero);

public static double ToEpoch(this DateTimeOffset value)
public static double ToEpoch(this DateTimeOffset value, int subSecondDecimals = 3)
{
// From Splunk HTTP Collector Protocol
// The default time format is epoch time format, in the format <sec>.<ms>.
// For example, 1433188255.500 indicates 1433188255 seconds and 500 milliseconds after epoch,
// or Monday, June 1, 2015, at 7:50:55 PM GMT.
// See: http://dev.splunk.com/view/SP-CAAAE6P

return Math.Round((value - Epoch).TotalSeconds, 3, MidpointRounding.AwayFromZero);
return Math.Round((value - Epoch).TotalSeconds, subSecondDecimals, MidpointRounding.AwayFromZero);
}
}
}
20 changes: 13 additions & 7 deletions src/Serilog.Sinks.Splunk/Sinks/Splunk/EventCollectorSink.cs
Expand Up @@ -56,17 +56,20 @@ public class EventCollectorSink : IBatchedLogEventSink
/// <param name="eventCollectorToken">The token to use when authenticating with the event collector</param>
/// <param name="formatProvider">The format provider used when rendering the message</param>
/// <param name="renderTemplate">Whether to render the message template</param>
/// <param name="subSecondDecimals">Timestamp sub-second precision</param>
public EventCollectorSink(
string splunkHost,
string eventCollectorToken,
IFormatProvider formatProvider = null,
bool renderTemplate = true)
bool renderTemplate = true,
int subSecondDecimals = 3)
: this(
splunkHost,
eventCollectorToken,
null, null, null, null, null,
formatProvider,
renderTemplate)
renderTemplate,
subSecondDecimals: subSecondDecimals)
{
}

Expand All @@ -83,6 +86,7 @@ public class EventCollectorSink : IBatchedLogEventSink
/// <param name="sourceType">The source type of the event</param>
/// <param name="host">The host of the event</param>
/// <param name="messageHandler">The handler used to send HTTP requests</param>
/// <param name="subSecondDecimals">Timestamp sub-second precision</param>
public EventCollectorSink(
string splunkHost,
string eventCollectorToken,
Expand All @@ -93,13 +97,13 @@ public class EventCollectorSink : IBatchedLogEventSink
string index,
IFormatProvider formatProvider = null,
bool renderTemplate = true,
HttpMessageHandler messageHandler = null)
HttpMessageHandler messageHandler = null,
int subSecondDecimals = 3)
: this(
splunkHost,
eventCollectorToken,
uriPath,

new SplunkJsonFormatter(renderTemplate, formatProvider, source, sourceType, host, index),
new SplunkJsonFormatter(renderTemplate, formatProvider, source, sourceType, host, index, subSecondDecimals: subSecondDecimals),
messageHandler)
{
}
Expand All @@ -118,6 +122,7 @@ public class EventCollectorSink : IBatchedLogEventSink
/// <param name="sourceType">The source type of the event</param>
/// <param name="host">The host of the event</param>
/// <param name="messageHandler">The handler used to send HTTP requests</param>
/// <param name="subSecondDecimals">Timestamp sub-second precision</param>
public EventCollectorSink(
string splunkHost,
string eventCollectorToken,
Expand All @@ -129,13 +134,14 @@ public class EventCollectorSink : IBatchedLogEventSink
CustomFields fields,
IFormatProvider formatProvider = null,
bool renderTemplate = true,
HttpMessageHandler messageHandler = null)
HttpMessageHandler messageHandler = null,
int subSecondDecimals = 3)
// TODO here is the jsonformatter creation. We must make way to test output of jsonformatter.
: this(
splunkHost,
eventCollectorToken,
uriPath,
new SplunkJsonFormatter(renderTemplate, formatProvider, source, sourceType, host, index, fields),
new SplunkJsonFormatter(renderTemplate, formatProvider, source, sourceType, host, index, fields, subSecondDecimals: subSecondDecimals),
messageHandler)
{
}
Expand Down
14 changes: 10 additions & 4 deletions src/Serilog.Sinks.Splunk/Sinks/Splunk/SplunkJsonFormatter.cs
Expand Up @@ -32,6 +32,7 @@ public class SplunkJsonFormatter : ITextFormatter

private readonly bool _renderTemplate;
private readonly IFormatProvider _formatProvider;
private readonly int _subSecondDecimals;
private readonly string _suffix;

/// <inheritdoc />
Expand All @@ -56,14 +57,16 @@ public class SplunkJsonFormatter : ITextFormatter
/// <param name="source">The source of the event</param>
/// <param name="sourceType">The source type of the event</param>
/// <param name="host">The host of the event</param>
/// <param name="subSecondDecimals">Timestamp sub-second precision</param>
public SplunkJsonFormatter(
bool renderTemplate,
IFormatProvider formatProvider,
string source,
string sourceType,
string host,
string index)
: this(renderTemplate, formatProvider, source, sourceType, host, index, null)
string index,
int subSecondDecimals = 3)
: this(renderTemplate, formatProvider, source, sourceType, host, index, null, subSecondDecimals)
{
}

Expand All @@ -77,17 +80,20 @@ public class SplunkJsonFormatter : ITextFormatter
/// <param name="sourceType">The source type of the event</param>
/// <param name="host">The host of the event</param>
/// <param name="customFields">Object that describes extra splunk fields that should be indexed with event see: http://dev.splunk.com/view/event-collector/SP-CAAAFB6 </param>
/// <param name="subSecondDecimals">Timestamp sub-second precision</param>
public SplunkJsonFormatter(
bool renderTemplate,
IFormatProvider formatProvider,
string source,
string sourceType,
string host,
string index,
CustomFields customFields)
CustomFields customFields,
int subSecondDecimals = 3)
{
_renderTemplate = renderTemplate;
_formatProvider = formatProvider;
_subSecondDecimals = subSecondDecimals;

using (var suffixWriter = new StringWriter())
{
Expand Down Expand Up @@ -157,7 +163,7 @@ public void Format(LogEvent logEvent, TextWriter output)
if (output == null) throw new ArgumentNullException(nameof(output));

output.Write("{\"time\":\"");
output.Write(logEvent.Timestamp.ToEpoch().ToString(CultureInfo.InvariantCulture));
output.Write(logEvent.Timestamp.ToEpoch(_subSecondDecimals).ToString(CultureInfo.InvariantCulture));
output.Write("\",\"event\":{\"Level\":\"");
output.Write(logEvent.Level);
output.Write('"');
Expand Down
18 changes: 13 additions & 5 deletions src/Serilog.Sinks.Splunk/SplunkLoggingConfigurationExtensions.cs
Expand Up @@ -17,7 +17,6 @@
using Serilog.Core;
using Serilog.Events;
using Serilog.Formatting;
using Serilog.Formatting.Json;
using Serilog.Sinks.PeriodicBatching;
using Serilog.Sinks.Splunk;
using System;
Expand Down Expand Up @@ -49,6 +48,7 @@ public static class SplunkLoggingConfigurationExtensions
/// <param name="queueLimit">Maximum number of events in the queue</param>
/// <param name="messageHandler">The handler used to send HTTP requests</param>
/// <param name="levelSwitch">A switch allowing the pass-through minimum level to be changed at runtime.</param>
/// <param name="subSecondDecimals">Timestamp sub-second precision</param>
/// <returns></returns>
public static LoggerConfiguration EventCollector(
this LoggerSinkConfiguration configuration,
Expand All @@ -66,7 +66,8 @@ public static class SplunkLoggingConfigurationExtensions
int batchSizeLimit = 100,
int? queueLimit = null,
HttpMessageHandler messageHandler = null,
LoggingLevelSwitch levelSwitch = null)
LoggingLevelSwitch levelSwitch = null,
int subSecondDecimals = 3)
{
if (configuration == null) throw new ArgumentNullException(nameof(configuration));

Expand All @@ -88,7 +89,9 @@ public static class SplunkLoggingConfigurationExtensions
index,
formatProvider,
renderTemplate,
messageHandler);
messageHandler,
subSecondDecimals: subSecondDecimals);

var batchingSink = new PeriodicBatchingSink(eventCollectorSink, batchingOptions);

return configuration.Sink(batchingSink, restrictedToMinimumLevel, levelSwitch);
Expand Down Expand Up @@ -168,6 +171,7 @@ public static class SplunkLoggingConfigurationExtensions
/// <param name="messageHandler">The handler used to send HTTP requests</param>
/// <param name="levelSwitch">A switch allowing the pass-through minimum level to be changed at runtime.</param>
/// <param name="fields">Customfields that will be indexed in splunk with this event</param>
/// <param name="subSecondDecimals">Timestamp sub-second precision</param>
/// <returns></returns>
public static LoggerConfiguration EventCollector(
this LoggerSinkConfiguration configuration,
Expand All @@ -186,7 +190,8 @@ public static class SplunkLoggingConfigurationExtensions
int batchSizeLimit = 100,
int? queueLimit = null,
HttpMessageHandler messageHandler = null,
LoggingLevelSwitch levelSwitch = null)
LoggingLevelSwitch levelSwitch = null,
int subSecondDecimals = 3)
{
if (configuration == null) throw new ArgumentNullException(nameof(configuration));

Expand All @@ -209,7 +214,10 @@ public static class SplunkLoggingConfigurationExtensions
fields,
formatProvider,
renderTemplate,
messageHandler);
messageHandler,
subSecondDecimals: subSecondDecimals
);


var batchingSink = new PeriodicBatchingSink(eventCollectorSink, batchingOptions);

Expand Down

0 comments on commit 734392e

Please sign in to comment.