From 734392e42597749aa8dee550f3ea53e4afa82451 Mon Sep 17 00:00:00 2001 From: EEParker Date: Fri, 15 Mar 2024 23:06:32 -0500 Subject: [PATCH] Fixes #161 add subsecond decimal configuration --- .../Splunk/CompactSplunkJsonFormatter.cs | 9 +++++++-- .../Sinks/Splunk/Epoch.cs | 4 ++-- .../Sinks/Splunk/EventCollectorSink.cs | 20 ++++++++++++------- .../Sinks/Splunk/SplunkJsonFormatter.cs | 14 +++++++++---- .../SplunkLoggingConfigurationExtensions.cs | 18 ++++++++++++----- 5 files changed, 45 insertions(+), 20 deletions(-) diff --git a/src/Serilog.Sinks.Splunk/Sinks/Splunk/CompactSplunkJsonFormatter.cs b/src/Serilog.Sinks.Splunk/Sinks/Splunk/CompactSplunkJsonFormatter.cs index 79132fa..f0472e3 100644 --- a/src/Serilog.Sinks.Splunk/Sinks/Splunk/CompactSplunkJsonFormatter.cs +++ b/src/Serilog.Sinks.Splunk/Sinks/Splunk/CompactSplunkJsonFormatter.cs @@ -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; /// /// Construct a . @@ -40,9 +41,13 @@ public class CompactSplunkJsonFormatter : ITextFormatter /// The host of the event /// The Splunk index to log to /// If true, the template used will be rendered and written to the output as a property named MessageTemplate - public CompactSplunkJsonFormatter(bool renderTemplate = false, string source = null, string sourceType = null, string host = null, string index = null) + /// Timestamp sub-second precision + + 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" @@ -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('"'); diff --git a/src/Serilog.Sinks.Splunk/Sinks/Splunk/Epoch.cs b/src/Serilog.Sinks.Splunk/Sinks/Splunk/Epoch.cs index 0f4c39b..fe662af 100644 --- a/src/Serilog.Sinks.Splunk/Sinks/Splunk/Epoch.cs +++ b/src/Serilog.Sinks.Splunk/Sinks/Splunk/Epoch.cs @@ -20,7 +20,7 @@ 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 .. @@ -28,7 +28,7 @@ public static double ToEpoch(this DateTimeOffset value) // 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); } } } diff --git a/src/Serilog.Sinks.Splunk/Sinks/Splunk/EventCollectorSink.cs b/src/Serilog.Sinks.Splunk/Sinks/Splunk/EventCollectorSink.cs index 1754dd2..a7fb4fc 100644 --- a/src/Serilog.Sinks.Splunk/Sinks/Splunk/EventCollectorSink.cs +++ b/src/Serilog.Sinks.Splunk/Sinks/Splunk/EventCollectorSink.cs @@ -56,17 +56,20 @@ public class EventCollectorSink : IBatchedLogEventSink /// The token to use when authenticating with the event collector /// The format provider used when rendering the message /// Whether to render the message template + /// Timestamp sub-second precision 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) { } @@ -83,6 +86,7 @@ public EventCollectorSink( /// The source type of the event /// The host of the event /// The handler used to send HTTP requests + /// Timestamp sub-second precision public EventCollectorSink( string splunkHost, string eventCollectorToken, @@ -93,13 +97,13 @@ public EventCollectorSink( 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) { } @@ -118,6 +122,7 @@ public EventCollectorSink( /// The source type of the event /// The host of the event /// The handler used to send HTTP requests + /// Timestamp sub-second precision public EventCollectorSink( string splunkHost, string eventCollectorToken, @@ -129,13 +134,14 @@ public EventCollectorSink( 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) { } diff --git a/src/Serilog.Sinks.Splunk/Sinks/Splunk/SplunkJsonFormatter.cs b/src/Serilog.Sinks.Splunk/Sinks/Splunk/SplunkJsonFormatter.cs index 17ee054..06191e8 100644 --- a/src/Serilog.Sinks.Splunk/Sinks/Splunk/SplunkJsonFormatter.cs +++ b/src/Serilog.Sinks.Splunk/Sinks/Splunk/SplunkJsonFormatter.cs @@ -32,6 +32,7 @@ public class SplunkJsonFormatter : ITextFormatter private readonly bool _renderTemplate; private readonly IFormatProvider _formatProvider; + private readonly int _subSecondDecimals; private readonly string _suffix; /// @@ -56,14 +57,16 @@ public SplunkJsonFormatter( /// The source of the event /// The source type of the event /// The host of the event + /// Timestamp sub-second precision 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) { } @@ -77,6 +80,7 @@ public SplunkJsonFormatter( /// The source type of the event /// The host of the event /// Object that describes extra splunk fields that should be indexed with event see: http://dev.splunk.com/view/event-collector/SP-CAAAFB6 + /// Timestamp sub-second precision public SplunkJsonFormatter( bool renderTemplate, IFormatProvider formatProvider, @@ -84,10 +88,12 @@ public SplunkJsonFormatter( string sourceType, string host, string index, - CustomFields customFields) + CustomFields customFields, + int subSecondDecimals = 3) { _renderTemplate = renderTemplate; _formatProvider = formatProvider; + _subSecondDecimals = subSecondDecimals; using (var suffixWriter = new StringWriter()) { @@ -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('"'); diff --git a/src/Serilog.Sinks.Splunk/SplunkLoggingConfigurationExtensions.cs b/src/Serilog.Sinks.Splunk/SplunkLoggingConfigurationExtensions.cs index 05165f6..5face81 100644 --- a/src/Serilog.Sinks.Splunk/SplunkLoggingConfigurationExtensions.cs +++ b/src/Serilog.Sinks.Splunk/SplunkLoggingConfigurationExtensions.cs @@ -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; @@ -49,6 +48,7 @@ public static class SplunkLoggingConfigurationExtensions /// Maximum number of events in the queue /// The handler used to send HTTP requests /// A switch allowing the pass-through minimum level to be changed at runtime. + /// Timestamp sub-second precision /// public static LoggerConfiguration EventCollector( this LoggerSinkConfiguration configuration, @@ -66,7 +66,8 @@ public static LoggerConfiguration EventCollector( 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)); @@ -88,7 +89,9 @@ public static LoggerConfiguration EventCollector( index, formatProvider, renderTemplate, - messageHandler); + messageHandler, + subSecondDecimals: subSecondDecimals); + var batchingSink = new PeriodicBatchingSink(eventCollectorSink, batchingOptions); return configuration.Sink(batchingSink, restrictedToMinimumLevel, levelSwitch); @@ -168,6 +171,7 @@ public static LoggerConfiguration EventCollector( /// The handler used to send HTTP requests /// A switch allowing the pass-through minimum level to be changed at runtime. /// Customfields that will be indexed in splunk with this event + /// Timestamp sub-second precision /// public static LoggerConfiguration EventCollector( this LoggerSinkConfiguration configuration, @@ -186,7 +190,8 @@ public static LoggerConfiguration EventCollector( 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)); @@ -209,7 +214,10 @@ public static LoggerConfiguration EventCollector( fields, formatProvider, renderTemplate, - messageHandler); + messageHandler, + subSecondDecimals: subSecondDecimals + ); + var batchingSink = new PeriodicBatchingSink(eventCollectorSink, batchingOptions);