From 032f366ecee7b4ae70610d37cd8520aa6fa751c2 Mon Sep 17 00:00:00 2001 From: Havagan Date: Fri, 15 Mar 2024 22:58:05 -0400 Subject: [PATCH] Splunk 9.1 + .NET 6 (#166) * Sample: Target net6.0. Added additional logging statements. * Docker: Splunk 9.1. * Tests: Target net6.0 and updated nuget packages. * Added constant for services/collector. Event request trims / from uri. Updated collector URL for Splunk 9.1 --- README.md | 3 +- sample/Sample/Program.cs | 115 ++++++++++++------ sample/Sample/Sample.csproj | 12 +- sample/Sample/appsettings.json | 38 +++--- sample/splunk/Dockerfile | 2 +- .../ConfigurationDefaults.cs | 18 +++ .../Serilog.Sinks.Splunk.csproj | 1 + .../Sinks/Splunk/EventCollectorClient.cs | 6 +- .../Sinks/Splunk/EventCollectorRequest.cs | 16 +-- .../SplunkLoggingConfigurationExtensions.cs | 27 ++-- .../Serilog.Sinks.Splunk.Tests.csproj | 10 +- 11 files changed, 153 insertions(+), 95 deletions(-) create mode 100644 src/Serilog.Sinks.Splunk/ConfigurationDefaults.cs diff --git a/README.md b/README.md index fbafc83..df769a4 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ To start using the Splunk Event Collector (Splunk 6.3 and above), logging can be ```csharp var log = new LoggerConfiguration() - .WriteTo.EventCollector("https://mysplunk:8088/services/collector", "myeventcollectortoken") + .WriteTo.EventCollector("https://mysplunk:8088/services/collector/event", "myeventcollectortoken") .CreateLogger(); ``` @@ -50,6 +50,7 @@ If using `appsettings.json` for configuration the following example illustrates "Name": "EventCollector", "Args": { "splunkHost": "http://splunk:8088", + "uriPath": "services/collector/event", "eventCollectorToken": "00112233-4455-6677-8899-AABBCCDDEEFF" } } diff --git a/sample/Sample/Program.cs b/sample/Sample/Program.cs index dc9d556..a77ee35 100644 --- a/sample/Sample/Program.cs +++ b/sample/Sample/Program.cs @@ -4,58 +4,97 @@ using Serilog; using Serilog.Sinks.Splunk; using Microsoft.Extensions.Configuration; +using System; + namespace Sample { public class Program { - const string SPLUNK_FULL_ENDPOINT = "http://splunk:8088/services/collector"; // Full splunk url - const string SPLUNK_ENDPOINT = "http://splunk:8088"; // Your splunk url + const string SPLUNK_FULL_ENDPOINT = "http://splunk:8088/services/collector/event"; // Full splunk url + const string SPLUNK_ENDPOINT = "http://splunk:8088"; // Your splunk url const string SPLUNK_HEC_TOKEN = "00112233-4455-6677-8899-AABBCCDDEEFF"; // Your HEC token. See http://docs.splunk.com/Documentation/Splunk/latest/Data/UsetheHTTPEventCollector - public static string EventCollectorToken = SPLUNK_HEC_TOKEN; + public static string EventCollectorToken = SPLUNK_HEC_TOKEN; public static void Main(string[] args) { - var eventsToCreate = 100; - var runSSL = false; - var millisecsToWait = 60000; - - if (args.Length > 0) - eventsToCreate = int.Parse(args[0]); - - if (args.Length == 2) - runSSL = bool.Parse(args[1]); - - if (args.Length == 3) - millisecsToWait = int.Parse(args[2]); - - Serilog.Debugging.SelfLog.Enable(System.Console.Out); - Log.Information("Sample app starting up..."); - Log.Information("Waiting {} millisecs...", millisecsToWait); - System.Threading.Thread.Sleep(millisecsToWait); - - UsingAppSettingsJson(eventsToCreate); - UsingHostOnly(eventsToCreate); - UsingHostOnly(eventsToCreate); - UsingFullUri(eventsToCreate); - OverridingSource(eventsToCreate); - OverridingSourceType(eventsToCreate); - OverridingHost(eventsToCreate); - WithNoTemplate(eventsToCreate); - WithCompactSplunkFormatter(eventsToCreate); - - if (runSSL) + // Bootstrap a simple logger. + var logger = new LoggerConfiguration() + .WriteTo.Console() + .CreateLogger(); + + try { - UsingSSL(eventsToCreate); - } - AddCustomFields(eventsToCreate); + logger.Information("Sample app starting up..."); + logger.Information("Startup arguments \"{Arguments}\".", args); + + var eventsToCreate = 100; + var runSSL = false; + var millisecsToWait = 60000; + + if (args.Length > 0) + eventsToCreate = int.Parse(args[0]); + + if (args.Length == 2) + runSSL = bool.Parse(args[1]); + + if (args.Length == 3) + millisecsToWait = int.Parse(args[2]); + + Serilog.Debugging.SelfLog.Enable(msg => + { + Console.WriteLine(msg); + throw new Exception("Failed to write to Serilog.", new Exception(msg)); + }); + + logger.Information("Waiting {MillisecondsToWait} millisecs...", millisecsToWait); + System.Threading.Thread.Sleep(millisecsToWait); + + logger.Information("Creating logger {MethodName}.", nameof(UsingAppSettingsJson)); + UsingAppSettingsJson(eventsToCreate); + + logger.Information("Creating logger {MethodName}.", nameof(UsingHostOnly)); + UsingHostOnly(eventsToCreate); + + logger.Information("Creating logger {MethodName}.", nameof(UsingFullUri)); + UsingFullUri(eventsToCreate); - Log.Information("Done...."); + logger.Information("Creating logger {MethodName}.", nameof(OverridingSource)); + OverridingSource(eventsToCreate); + + logger.Information("Creating logger {MethodName}.", nameof(OverridingSourceType)); + OverridingSourceType(eventsToCreate); + + logger.Information("Creating logger {MethodName}.", nameof(OverridingHost)); + OverridingHost(eventsToCreate); + + logger.Information("Creating logger {MethodName}.", nameof(WithNoTemplate)); + WithNoTemplate(eventsToCreate); + + logger.Information("Creating logger {MethodName}.", nameof(WithCompactSplunkFormatter)); + WithCompactSplunkFormatter(eventsToCreate); + + if (runSSL) + { + logger.Information("Creating logger {MethodName}.", nameof(UsingSSL)); + UsingSSL(eventsToCreate); + } + + logger.Information("Creating logger {MethodName}.", nameof(AddCustomFields)); + AddCustomFields(eventsToCreate); + } + finally + { + logger.Information("Done..."); + Log.CloseAndFlush(); + } } + public static void UsingAppSettingsJson(int eventsToCreate) { var configuration = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json") + .AddUserSecrets() .Build(); Log.Logger = new LoggerConfiguration() @@ -263,7 +302,7 @@ public static void AddCustomFields(int eventsToCreate) , host: System.Environment.MachineName , source: "BackPackTestServerChannel" , sourceType: "_json" - ,fields: metaData) + , fields: metaData) .Enrich.WithProperty("Serilog.Sinks.Splunk.Sample", "ViaEventCollector") .Enrich.WithProperty("Serilog.Sinks.Splunk.Sample.TestType", "AddCustomFields") .CreateLogger(); @@ -277,5 +316,5 @@ public static void AddCustomFields(int eventsToCreate) } } - + } diff --git a/sample/Sample/Sample.csproj b/sample/Sample/Sample.csproj index d4e39be..3402781 100644 --- a/sample/Sample/Sample.csproj +++ b/sample/Sample/Sample.csproj @@ -2,14 +2,16 @@ Exe - net5.0 + net6.0 + 7e06bf41-4a1d-4a41-bcf3-cacd41388d5f - - - - + + + + + diff --git a/sample/Sample/appsettings.json b/sample/Sample/appsettings.json index 9a485cf..70ed38e 100644 --- a/sample/Sample/appsettings.json +++ b/sample/Sample/appsettings.json @@ -1,22 +1,24 @@ { - "Serilog": { - "Using": ["Serilog.Sinks.Console", "Serilog.Sinks.Splunk"], - "MinimumLevel": "Information", - "WriteTo": [{ - "Name": "Console" - }, - { - "Name": "EventCollector", - "Args": { - "splunkHost": "http://splunk:8088", - "eventCollectorToken": "00112233-4455-6677-8899-AABBCCDDEEFF" - } - } - ], - "Properties": { - "Application": "Serilog Splunk Console Sample", - "Serilog.Sinks.Splunk.Sample": "ViaEventCollector", - "Serilog.Sinks.Splunk.Sample.TestType": "AppSettings.json" + "Serilog": { + "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.Splunk" ], + "MinimumLevel": "Information", + "WriteTo": [ + { + "Name": "Console" + }, + { + "Name": "EventCollector", + "Args": { + "splunkHost": "http://splunk:8088/", + "uriPath": "services/collector/event", + "eventCollectorToken": "00112233-4455-6677-8899-AABBCCDDEEFF" } + } + ], + "Properties": { + "Application": "Serilog Splunk Console Sample", + "Serilog.Sinks.Splunk.Sample": "ViaEventCollector", + "Serilog.Sinks.Splunk.Sample.TestType": "AppSettings.json" } + } } \ No newline at end of file diff --git a/sample/splunk/Dockerfile b/sample/splunk/Dockerfile index 8c006a2..868c0df 100644 --- a/sample/splunk/Dockerfile +++ b/sample/splunk/Dockerfile @@ -1,2 +1,2 @@ -FROM splunk/splunk:7.2 +FROM splunk/splunk:9.1 ADD etc ${SPLUNK_HOME}/etc \ No newline at end of file diff --git a/src/Serilog.Sinks.Splunk/ConfigurationDefaults.cs b/src/Serilog.Sinks.Splunk/ConfigurationDefaults.cs new file mode 100644 index 0000000..7a4c402 --- /dev/null +++ b/src/Serilog.Sinks.Splunk/ConfigurationDefaults.cs @@ -0,0 +1,18 @@ +namespace Serilog +{ + internal static class ConfigurationDefaults + { + internal const string DefaultSource = ""; + internal const string DefaultSourceType = ""; + internal const string DefaultHost = ""; + internal const string DefaultIndex = ""; + + /// + /// The default HTTP Event Collector path when not set via configuration. + /// + /// + /// https://docs.splunk.com/Documentation/Splunk/9.1.0/Data/UsetheHTTPEventCollector#Send_data_to_HTTP_Event_Collector_on_Splunk_Enterprise + /// + internal const string DefaultEventCollectorPath = "services/collector/event"; + } +} diff --git a/src/Serilog.Sinks.Splunk/Serilog.Sinks.Splunk.csproj b/src/Serilog.Sinks.Splunk/Serilog.Sinks.Splunk.csproj index 7d69174..de5c091 100644 --- a/src/Serilog.Sinks.Splunk/Serilog.Sinks.Splunk.csproj +++ b/src/Serilog.Sinks.Splunk/Serilog.Sinks.Splunk.csproj @@ -18,6 +18,7 @@ true true true + latest diff --git a/src/Serilog.Sinks.Splunk/Sinks/Splunk/EventCollectorClient.cs b/src/Serilog.Sinks.Splunk/Sinks/Splunk/EventCollectorClient.cs index 98f4be4..77c1e3b 100644 --- a/src/Serilog.Sinks.Splunk/Sinks/Splunk/EventCollectorClient.cs +++ b/src/Serilog.Sinks.Splunk/Sinks/Splunk/EventCollectorClient.cs @@ -36,7 +36,11 @@ public EventCollectorClient(string eventCollectorToken, HttpMessageHandler messa private void SetHeaders(string eventCollectorToken) { - DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(AUTH_SCHEME, eventCollectorToken); + // Reminder: If the event collector url is redirected, all authentication headers will be removed. + // See: https://github.com/dotnet/runtime/blob/ccfe21882e4a2206ce49cd5b32d3eb3cab3e530f/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/RedirectHandler.cs#L53 + + DefaultRequestHeaders.Authorization ??= new AuthenticationHeaderValue(AUTH_SCHEME, eventCollectorToken); + if (!this.DefaultRequestHeaders.Contains(SPLUNK_REQUEST_CHANNEL)) { this.DefaultRequestHeaders.Add(SPLUNK_REQUEST_CHANNEL, Guid.NewGuid().ToString()); diff --git a/src/Serilog.Sinks.Splunk/Sinks/Splunk/EventCollectorRequest.cs b/src/Serilog.Sinks.Splunk/Sinks/Splunk/EventCollectorRequest.cs index 6b9dfd8..82a0772 100644 --- a/src/Serilog.Sinks.Splunk/Sinks/Splunk/EventCollectorRequest.cs +++ b/src/Serilog.Sinks.Splunk/Sinks/Splunk/EventCollectorRequest.cs @@ -21,18 +21,14 @@ namespace Serilog.Sinks.Splunk { internal class EventCollectorRequest : HttpRequestMessage { - internal EventCollectorRequest(string splunkHost, string jsonPayLoad, string uri ="services/collector") + internal EventCollectorRequest(string splunkHost, string jsonPayLoad, string uri = ConfigurationDefaults.DefaultEventCollectorPath) { - var hostUrl = $@"{splunkHost}/{uri}"; - - if(splunkHost.Contains("services/collector")) - { - hostUrl = $@"{splunkHost}"; - } - - var stringContent = new StringContent(jsonPayLoad, Encoding.UTF8, "application/json"); + var hostUrl = splunkHost.Contains(ConfigurationDefaults.DefaultEventCollectorPath) + ? splunkHost + : $"{splunkHost.TrimEnd('/')}/{uri.TrimStart('/').TrimEnd('/')}"; + RequestUri = new Uri(hostUrl); - Content = stringContent; + Content = new StringContent(jsonPayLoad, Encoding.UTF8, "application/json"); Method = HttpMethod.Post; } } diff --git a/src/Serilog.Sinks.Splunk/SplunkLoggingConfigurationExtensions.cs b/src/Serilog.Sinks.Splunk/SplunkLoggingConfigurationExtensions.cs index 1e4d3fd..f986358 100644 --- a/src/Serilog.Sinks.Splunk/SplunkLoggingConfigurationExtensions.cs +++ b/src/Serilog.Sinks.Splunk/SplunkLoggingConfigurationExtensions.cs @@ -28,11 +28,6 @@ namespace Serilog /// public static class SplunkLoggingConfigurationExtensions { - internal const string DefaultSource = ""; - internal const string DefaultSourceType = ""; - internal const string DefaultHost = ""; - internal const string DefaultIndex = ""; - /// /// Adds a sink that writes log events as to a Splunk instance via the HTTP Event Collector. /// @@ -57,11 +52,11 @@ public static LoggerConfiguration EventCollector( this LoggerSinkConfiguration configuration, string splunkHost, string eventCollectorToken, - string uriPath = "services/collector", - string source = DefaultSource, - string sourceType = DefaultSourceType, - string host = DefaultHost, - string index = DefaultIndex, + string uriPath = ConfigurationDefaults.DefaultEventCollectorPath, + string source = ConfigurationDefaults.DefaultSource, + string sourceType = ConfigurationDefaults.DefaultSourceType, + string host = ConfigurationDefaults.DefaultHost, + string index = ConfigurationDefaults.DefaultIndex, LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, IFormatProvider formatProvider = null, bool renderTemplate = true, @@ -112,7 +107,7 @@ public static LoggerConfiguration EventCollector( string splunkHost, string eventCollectorToken, ITextFormatter jsonFormatter, - string uriPath = "services/collector", + string uriPath = ConfigurationDefaults.DefaultEventCollectorPath, LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, int batchIntervalInSeconds = 2, int batchSizeLimit = 100, @@ -163,11 +158,11 @@ public static LoggerConfiguration EventCollector( string splunkHost, string eventCollectorToken, CustomFields fields, - string uriPath = "services/collector", - string source = DefaultSource, - string sourceType = DefaultSourceType, - string host = DefaultHost, - string index = DefaultIndex, + string uriPath = ConfigurationDefaults.DefaultEventCollectorPath, + string source = ConfigurationDefaults.DefaultSource, + string sourceType = ConfigurationDefaults.DefaultSourceType, + string host = ConfigurationDefaults.DefaultHost, + string index = ConfigurationDefaults.DefaultIndex, LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, IFormatProvider formatProvider = null, bool renderTemplate = true, diff --git a/test/Serilog.Sinks.Splunk.Tests/Serilog.Sinks.Splunk.Tests.csproj b/test/Serilog.Sinks.Splunk.Tests/Serilog.Sinks.Splunk.Tests.csproj index 0f38bad..d8f0579 100644 --- a/test/Serilog.Sinks.Splunk.Tests/Serilog.Sinks.Splunk.Tests.csproj +++ b/test/Serilog.Sinks.Splunk.Tests/Serilog.Sinks.Splunk.Tests.csproj @@ -1,7 +1,7 @@  - net5.0 + net6.0 Serilog.Sinks.Splunk.Tests Serilog.Sinks.Splunk.Tests true @@ -15,11 +15,11 @@ - - - + + + - + all runtime; build; native; contentfiles; analyzers; buildtransitive