diff --git a/seqcli.sln.DotSettings b/seqcli.sln.DotSettings
index 95d327ba..93bc904b 100644
--- a/seqcli.sln.DotSettings
+++ b/seqcli.sln.DotSettings
@@ -18,6 +18,7 @@
True
True
True
+ True
True
True
True
diff --git a/src/SeqCli/Connection/SeqConnectionFactory.cs b/src/SeqCli/Api/SeqConnectionFactory.cs
similarity index 97%
rename from src/SeqCli/Connection/SeqConnectionFactory.cs
rename to src/SeqCli/Api/SeqConnectionFactory.cs
index 89596982..76c4bf18 100644
--- a/src/SeqCli/Connection/SeqConnectionFactory.cs
+++ b/src/SeqCli/Api/SeqConnectionFactory.cs
@@ -16,9 +16,8 @@
using Seq.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Encryptor;
-namespace SeqCli.Connection;
+namespace SeqCli.Api;
static class SeqConnectionFactory
{
diff --git a/src/SeqCli/Cli/Commands/ApiKey/CreateCommand.cs b/src/SeqCli/Cli/Commands/ApiKey/CreateCommand.cs
index 514daa0c..437fe98a 100644
--- a/src/SeqCli/Cli/Commands/ApiKey/CreateCommand.cs
+++ b/src/SeqCli/Cli/Commands/ApiKey/CreateCommand.cs
@@ -19,9 +19,9 @@
using Seq.Api.Model.LogEvents;
using Seq.Api.Model.Security;
using Seq.Api.Model.Shared;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
using SeqCli.Levels;
using SeqCli.Util;
using Serilog;
diff --git a/src/SeqCli/Cli/Commands/ApiKey/ListCommand.cs b/src/SeqCli/Cli/Commands/ApiKey/ListCommand.cs
index 9a7d387a..3e2a9dbf 100644
--- a/src/SeqCli/Cli/Commands/ApiKey/ListCommand.cs
+++ b/src/SeqCli/Cli/Commands/ApiKey/ListCommand.cs
@@ -15,9 +15,9 @@
using System;
using System.Linq;
using System.Threading.Tasks;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
namespace SeqCli.Cli.Commands.ApiKey;
diff --git a/src/SeqCli/Cli/Commands/ApiKey/RemoveCommand.cs b/src/SeqCli/Cli/Commands/ApiKey/RemoveCommand.cs
index d809ec7e..b3789c91 100644
--- a/src/SeqCli/Cli/Commands/ApiKey/RemoveCommand.cs
+++ b/src/SeqCli/Cli/Commands/ApiKey/RemoveCommand.cs
@@ -15,9 +15,9 @@
using System;
using System.Linq;
using System.Threading.Tasks;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
using Serilog;
namespace SeqCli.Cli.Commands.ApiKey;
diff --git a/src/SeqCli/Cli/Commands/ApiKey/UpdateCommand.cs b/src/SeqCli/Cli/Commands/ApiKey/UpdateCommand.cs
index 46a77309..6c5d289e 100644
--- a/src/SeqCli/Cli/Commands/ApiKey/UpdateCommand.cs
+++ b/src/SeqCli/Cli/Commands/ApiKey/UpdateCommand.cs
@@ -13,7 +13,6 @@
// limitations under the License.
using Seq.Api;
-using SeqCli.Connection;
namespace SeqCli.Cli.Commands.ApiKey;
diff --git a/src/SeqCli/Cli/Commands/App/InstallCommand.cs b/src/SeqCli/Cli/Commands/App/InstallCommand.cs
index 4d284b29..b365a8d6 100644
--- a/src/SeqCli/Cli/Commands/App/InstallCommand.cs
+++ b/src/SeqCli/Cli/Commands/App/InstallCommand.cs
@@ -16,9 +16,9 @@
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
using SeqCli.Util;
using Serilog;
diff --git a/src/SeqCli/Cli/Commands/App/ListCommand.cs b/src/SeqCli/Cli/Commands/App/ListCommand.cs
index 166f3bc5..1add7dc5 100644
--- a/src/SeqCli/Cli/Commands/App/ListCommand.cs
+++ b/src/SeqCli/Cli/Commands/App/ListCommand.cs
@@ -1,9 +1,9 @@
using System;
using System.Linq;
using System.Threading.Tasks;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
namespace SeqCli.Cli.Commands.App;
diff --git a/src/SeqCli/Cli/Commands/App/UninstallCommand.cs b/src/SeqCli/Cli/Commands/App/UninstallCommand.cs
index 03f40b02..16e74b3f 100644
--- a/src/SeqCli/Cli/Commands/App/UninstallCommand.cs
+++ b/src/SeqCli/Cli/Commands/App/UninstallCommand.cs
@@ -1,9 +1,9 @@
using System;
using System.Linq;
using System.Threading.Tasks;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
using SeqCli.Util;
using Serilog;
diff --git a/src/SeqCli/Cli/Commands/App/UpdateCommand.cs b/src/SeqCli/Cli/Commands/App/UpdateCommand.cs
index 4c30d62b..7399f2f7 100644
--- a/src/SeqCli/Cli/Commands/App/UpdateCommand.cs
+++ b/src/SeqCli/Cli/Commands/App/UpdateCommand.cs
@@ -15,9 +15,9 @@
using System;
using System.Globalization;
using System.Threading.Tasks;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
using SeqCli.Util;
using Serilog;
diff --git a/src/SeqCli/Cli/Commands/AppInstance/CreateCommand.cs b/src/SeqCli/Cli/Commands/AppInstance/CreateCommand.cs
index af5aa731..4f9a024d 100644
--- a/src/SeqCli/Cli/Commands/AppInstance/CreateCommand.cs
+++ b/src/SeqCli/Cli/Commands/AppInstance/CreateCommand.cs
@@ -3,9 +3,9 @@
using System.Linq;
using System.Threading.Tasks;
using Seq.Api.Model.AppInstances;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
using SeqCli.Signals;
using SeqCli.Util;
using Serilog;
diff --git a/src/SeqCli/Cli/Commands/AppInstance/ListCommand.cs b/src/SeqCli/Cli/Commands/AppInstance/ListCommand.cs
index 2e9e2c45..f882b119 100644
--- a/src/SeqCli/Cli/Commands/AppInstance/ListCommand.cs
+++ b/src/SeqCli/Cli/Commands/AppInstance/ListCommand.cs
@@ -1,9 +1,9 @@
using System;
using System.Linq;
using System.Threading.Tasks;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
namespace SeqCli.Cli.Commands.AppInstance;
diff --git a/src/SeqCli/Cli/Commands/AppInstance/RemoveCommand.cs b/src/SeqCli/Cli/Commands/AppInstance/RemoveCommand.cs
index 33da86b2..d72ae404 100644
--- a/src/SeqCli/Cli/Commands/AppInstance/RemoveCommand.cs
+++ b/src/SeqCli/Cli/Commands/AppInstance/RemoveCommand.cs
@@ -1,9 +1,9 @@
using System;
using System.Linq;
using System.Threading.Tasks;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
using Serilog;
namespace SeqCli.Cli.Commands.AppInstance;
diff --git a/src/SeqCli/Cli/Commands/AppInstance/UpdateCommand.cs b/src/SeqCli/Cli/Commands/AppInstance/UpdateCommand.cs
index 22e44af1..ac0661dc 100644
--- a/src/SeqCli/Cli/Commands/AppInstance/UpdateCommand.cs
+++ b/src/SeqCli/Cli/Commands/AppInstance/UpdateCommand.cs
@@ -13,7 +13,6 @@
// limitations under the License.
using Seq.Api;
-using SeqCli.Connection;
namespace SeqCli.Cli.Commands.AppInstance;
diff --git a/src/SeqCli/Cli/Commands/Bench/BenchCommand.cs b/src/SeqCli/Cli/Commands/Bench/BenchCommand.cs
index 596bbbe4..c38e8b6c 100644
--- a/src/SeqCli/Cli/Commands/Bench/BenchCommand.cs
+++ b/src/SeqCli/Cli/Commands/Bench/BenchCommand.cs
@@ -22,9 +22,9 @@
using Seq.Api;
using Seq.Api.Model.Data;
using Seq.Api.Model.Signals;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
using SeqCli.Sample.Loader;
using SeqCli.Util;
using Serilog;
diff --git a/src/SeqCli/Cli/Commands/Cluster/HealthCommand.cs b/src/SeqCli/Cli/Commands/Cluster/HealthCommand.cs
index a868cb52..a239739e 100644
--- a/src/SeqCli/Cli/Commands/Cluster/HealthCommand.cs
+++ b/src/SeqCli/Cli/Commands/Cluster/HealthCommand.cs
@@ -18,9 +18,9 @@
using Seq.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
using SeqCli.Util;
using Seq.Api.Model.Cluster;
+using SeqCli.Api;
using Serilog;
namespace SeqCli.Cli.Commands.Cluster;
diff --git a/src/SeqCli/Cli/Commands/Dashboard/ListCommand.cs b/src/SeqCli/Cli/Commands/Dashboard/ListCommand.cs
index 087f9fc4..89dc94c1 100644
--- a/src/SeqCli/Cli/Commands/Dashboard/ListCommand.cs
+++ b/src/SeqCli/Cli/Commands/Dashboard/ListCommand.cs
@@ -15,9 +15,9 @@
using System;
using System.Linq;
using System.Threading.Tasks;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
namespace SeqCli.Cli.Commands.Dashboard;
diff --git a/src/SeqCli/Cli/Commands/Dashboard/RemoveCommand.cs b/src/SeqCli/Cli/Commands/Dashboard/RemoveCommand.cs
index 61022b26..c16dc0a9 100644
--- a/src/SeqCli/Cli/Commands/Dashboard/RemoveCommand.cs
+++ b/src/SeqCli/Cli/Commands/Dashboard/RemoveCommand.cs
@@ -15,9 +15,9 @@
using System;
using System.Linq;
using System.Threading.Tasks;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
using Serilog;
namespace SeqCli.Cli.Commands.Dashboard;
diff --git a/src/SeqCli/Cli/Commands/Dashboard/RenderCommand.cs b/src/SeqCli/Cli/Commands/Dashboard/RenderCommand.cs
index 652066a0..4d78f61b 100644
--- a/src/SeqCli/Cli/Commands/Dashboard/RenderCommand.cs
+++ b/src/SeqCli/Cli/Commands/Dashboard/RenderCommand.cs
@@ -18,9 +18,9 @@
using Newtonsoft.Json;
using Seq.Api.Model.Dashboarding;
using Seq.Api.Model.Signals;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
using SeqCli.Syntax;
using SeqCli.Util;
using Serilog;
diff --git a/src/SeqCli/Cli/Commands/Diagnostics/IngestionLogCommand.cs b/src/SeqCli/Cli/Commands/Diagnostics/IngestionLogCommand.cs
new file mode 100644
index 00000000..390a4189
--- /dev/null
+++ b/src/SeqCli/Cli/Commands/Diagnostics/IngestionLogCommand.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Threading.Tasks;
+using SeqCli.Api;
+using SeqCli.Cli.Features;
+using SeqCli.Config;
+
+namespace SeqCli.Cli.Commands.Diagnostics;
+
+[Command("diagnostics", "ingestionlog", "Retrieve the ingestion log",
+ Example = "seqcli diagnostics ingestionlog")]
+class IngestionLogCommand : Command
+{
+ readonly ConnectionFeature _connection;
+ readonly StoragePathFeature _storagePath;
+
+ public IngestionLogCommand()
+ {
+ _connection = Enable();
+ _storagePath = Enable();
+ }
+
+ protected override async Task Run()
+ {
+ var config = RuntimeConfigurationLoader.Load(_storagePath);
+ var connection = SeqConnectionFactory.Connect(_connection, config);
+
+ var ingestionLog = await connection.Diagnostics.GetIngestionLogAsync();
+ Console.WriteLine(ingestionLog);
+
+ return 0;
+ }
+}
diff --git a/src/SeqCli/Cli/Commands/ExpressionIndex/CreateCommand.cs b/src/SeqCli/Cli/Commands/ExpressionIndex/CreateCommand.cs
index d0760376..cd454a42 100644
--- a/src/SeqCli/Cli/Commands/ExpressionIndex/CreateCommand.cs
+++ b/src/SeqCli/Cli/Commands/ExpressionIndex/CreateCommand.cs
@@ -15,9 +15,9 @@
using System;
using System.Threading.Tasks;
using Seq.Api.Model.Signals;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
using SeqCli.Signals;
using SeqCli.Syntax;
using SeqCli.Util;
diff --git a/src/SeqCli/Cli/Commands/ExpressionIndex/ListCommand.cs b/src/SeqCli/Cli/Commands/ExpressionIndex/ListCommand.cs
index 16b00cb8..133c26bc 100644
--- a/src/SeqCli/Cli/Commands/ExpressionIndex/ListCommand.cs
+++ b/src/SeqCli/Cli/Commands/ExpressionIndex/ListCommand.cs
@@ -1,8 +1,8 @@
using System;
using System.Threading.Tasks;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
namespace SeqCli.Cli.Commands.ExpressionIndex;
diff --git a/src/SeqCli/Cli/Commands/ExpressionIndex/RemoveCommand.cs b/src/SeqCli/Cli/Commands/ExpressionIndex/RemoveCommand.cs
index b00e7a41..38784e73 100644
--- a/src/SeqCli/Cli/Commands/ExpressionIndex/RemoveCommand.cs
+++ b/src/SeqCli/Cli/Commands/ExpressionIndex/RemoveCommand.cs
@@ -13,9 +13,9 @@
// limitations under the License.
using System.Threading.Tasks;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
using Serilog;
namespace SeqCli.Cli.Commands.ExpressionIndex;
diff --git a/src/SeqCli/Cli/Commands/Feed/CreateCommand.cs b/src/SeqCli/Cli/Commands/Feed/CreateCommand.cs
index 9d4aea80..2a4543ff 100644
--- a/src/SeqCli/Cli/Commands/Feed/CreateCommand.cs
+++ b/src/SeqCli/Cli/Commands/Feed/CreateCommand.cs
@@ -14,9 +14,9 @@
using System;
using System.Threading.Tasks;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
using SeqCli.Util;
using Serilog;
diff --git a/src/SeqCli/Cli/Commands/Feed/ListCommand.cs b/src/SeqCli/Cli/Commands/Feed/ListCommand.cs
index a7d45220..d4b15670 100644
--- a/src/SeqCli/Cli/Commands/Feed/ListCommand.cs
+++ b/src/SeqCli/Cli/Commands/Feed/ListCommand.cs
@@ -15,9 +15,9 @@
using System;
using System.Linq;
using System.Threading.Tasks;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
namespace SeqCli.Cli.Commands.Feed;
diff --git a/src/SeqCli/Cli/Commands/Feed/RemoveCommand.cs b/src/SeqCli/Cli/Commands/Feed/RemoveCommand.cs
index 3180bfb5..4710d24f 100644
--- a/src/SeqCli/Cli/Commands/Feed/RemoveCommand.cs
+++ b/src/SeqCli/Cli/Commands/Feed/RemoveCommand.cs
@@ -15,9 +15,9 @@
using System;
using System.Linq;
using System.Threading.Tasks;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
using Serilog;
namespace SeqCli.Cli.Commands.Feed;
diff --git a/src/SeqCli/Cli/Commands/Feed/UpdateCommand.cs b/src/SeqCli/Cli/Commands/Feed/UpdateCommand.cs
index 59ed98b3..28525ff8 100644
--- a/src/SeqCli/Cli/Commands/Feed/UpdateCommand.cs
+++ b/src/SeqCli/Cli/Commands/Feed/UpdateCommand.cs
@@ -13,7 +13,6 @@
// limitations under the License.
using Seq.Api;
-using SeqCli.Connection;
namespace SeqCli.Cli.Commands.Feed;
diff --git a/src/SeqCli/Cli/Commands/Forwarder/RunCommand.cs b/src/SeqCli/Cli/Commands/Forwarder/RunCommand.cs
index d0ab573f..98a60764 100644
--- a/src/SeqCli/Cli/Commands/Forwarder/RunCommand.cs
+++ b/src/SeqCli/Cli/Commands/Forwarder/RunCommand.cs
@@ -17,15 +17,16 @@
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Net;
+using System.Threading;
using System.Threading.Tasks;
using Autofac;
using Autofac.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
using SeqCli.Forwarder;
using SeqCli.Forwarder.Util;
using SeqCli.Forwarder.Web.Api;
@@ -206,23 +207,45 @@ static async Task RunStandardIOAsync(ServerService service, TextWriter cout
{
service.Start();
- try
+ var waitForShutDownRequest = new TaskCompletionSource();
+ var done = new ManualResetEventSlim(false);
+
+ void ShutDown()
{
- Console.TreatControlCAsInput = true;
- var k = Console.ReadKey(true);
- while (k.Key != ConsoleKey.C || !k.Modifiers.HasFlag(ConsoleModifiers.Control))
- k = Console.ReadKey(true);
+ waitForShutDownRequest.TrySetResult();
+ done.Wait();
+ }
- cout.WriteLine("Ctrl+C pressed; stopping...");
+ try
+ {
Console.TreatControlCAsInput = false;
+ Console.CancelKeyPress += (_, _) =>
+ {
+ cout.WriteLine("Ctrl+C pressed; stopping...");
+ Log.Information("Interrupt signal received");
+ ShutDown();
+ };
}
- catch (Exception ex)
+ catch (IOException)
{
- Log.Debug(ex, "Console not attached, waiting for any input");
- Console.Read();
+ Log.Information("Disabling Ctrl+C handling; process is non-interactive");
}
- await service.StopAsync();
+ AppDomain.CurrentDomain.ProcessExit += (_, _) =>
+ {
+ Log.Information("Termination signal received");
+ ShutDown();
+ };
+
+ try
+ {
+ await waitForShutDownRequest.Task;
+ await service.StopAsync();
+ }
+ finally
+ {
+ done.Set();
+ }
return 0;
}
diff --git a/src/SeqCli/Cli/Commands/Index/ListCommand.cs b/src/SeqCli/Cli/Commands/Index/ListCommand.cs
index 78138f70..780e510b 100644
--- a/src/SeqCli/Cli/Commands/Index/ListCommand.cs
+++ b/src/SeqCli/Cli/Commands/Index/ListCommand.cs
@@ -17,9 +17,9 @@
using System.Linq;
using System.Threading.Tasks;
using Seq.Api.Model.Indexes;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
namespace SeqCli.Cli.Commands.Index;
diff --git a/src/SeqCli/Cli/Commands/Index/SuppressCommand.cs b/src/SeqCli/Cli/Commands/Index/SuppressCommand.cs
index bd330179..27517e29 100644
--- a/src/SeqCli/Cli/Commands/Index/SuppressCommand.cs
+++ b/src/SeqCli/Cli/Commands/Index/SuppressCommand.cs
@@ -15,9 +15,9 @@
using System;
using System.Threading.Tasks;
using Seq.Api.Model.Indexes;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
using Serilog;
namespace SeqCli.Cli.Commands.Index;
diff --git a/src/SeqCli/Cli/Commands/IngestCommand.cs b/src/SeqCli/Cli/Commands/IngestCommand.cs
index 1827ed59..8a548c06 100644
--- a/src/SeqCli/Cli/Commands/IngestCommand.cs
+++ b/src/SeqCli/Cli/Commands/IngestCommand.cs
@@ -15,9 +15,9 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
using SeqCli.Ingestion;
using SeqCli.Levels;
using SeqCli.PlainText;
diff --git a/src/SeqCli/Cli/Commands/License/ApplyCommand.cs b/src/SeqCli/Cli/Commands/License/ApplyCommand.cs
index 53b50da9..6972c6f9 100644
--- a/src/SeqCli/Cli/Commands/License/ApplyCommand.cs
+++ b/src/SeqCli/Cli/Commands/License/ApplyCommand.cs
@@ -2,9 +2,9 @@
using System.IO;
using System.Text;
using System.Threading.Tasks;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
using SeqCli.Util;
using Serilog;
diff --git a/src/SeqCli/Cli/Commands/License/ShowCommand.cs b/src/SeqCli/Cli/Commands/License/ShowCommand.cs
index 7f163efb..5f15a451 100644
--- a/src/SeqCli/Cli/Commands/License/ShowCommand.cs
+++ b/src/SeqCli/Cli/Commands/License/ShowCommand.cs
@@ -4,9 +4,9 @@
using System.Threading.Tasks;
using Seq.Api.Model;
using Seq.Api.Model.License;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
using SeqCli.Util;
using Serilog;
diff --git a/src/SeqCli/Cli/Commands/LogCommand.cs b/src/SeqCli/Cli/Commands/LogCommand.cs
index be3c5f8e..a360ba32 100644
--- a/src/SeqCli/Cli/Commands/LogCommand.cs
+++ b/src/SeqCli/Cli/Commands/LogCommand.cs
@@ -23,7 +23,6 @@
using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
using Serilog;
// ReSharper disable UseAwaitUsing, MethodHasAsyncOverload
diff --git a/src/SeqCli/Cli/Commands/Node/HealthCommand.cs b/src/SeqCli/Cli/Commands/Node/HealthCommand.cs
index 60a82b76..5a3fcc37 100644
--- a/src/SeqCli/Cli/Commands/Node/HealthCommand.cs
+++ b/src/SeqCli/Cli/Commands/Node/HealthCommand.cs
@@ -19,9 +19,9 @@
using System.Threading.Tasks;
using Newtonsoft.Json;
using Seq.Api;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
using Serilog;
namespace SeqCli.Cli.Commands.Node;
diff --git a/src/SeqCli/Cli/Commands/Node/ListCommand.cs b/src/SeqCli/Cli/Commands/Node/ListCommand.cs
index c374c6a0..a6f42b3e 100644
--- a/src/SeqCli/Cli/Commands/Node/ListCommand.cs
+++ b/src/SeqCli/Cli/Commands/Node/ListCommand.cs
@@ -15,9 +15,9 @@
using System;
using System.Linq;
using System.Threading.Tasks;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
namespace SeqCli.Cli.Commands.Node;
diff --git a/src/SeqCli/Cli/Commands/QueryCommand.cs b/src/SeqCli/Cli/Commands/QueryCommand.cs
index 1c54110f..95b63481 100644
--- a/src/SeqCli/Cli/Commands/QueryCommand.cs
+++ b/src/SeqCli/Cli/Commands/QueryCommand.cs
@@ -15,9 +15,9 @@
using System;
using System.Threading.Tasks;
using Newtonsoft.Json;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
using Serilog;
// ReSharper disable UnusedType.Global
diff --git a/src/SeqCli/Cli/Commands/RetentionPolicy/CreateCommand.cs b/src/SeqCli/Cli/Commands/RetentionPolicy/CreateCommand.cs
index aa5c6a07..5947752d 100644
--- a/src/SeqCli/Cli/Commands/RetentionPolicy/CreateCommand.cs
+++ b/src/SeqCli/Cli/Commands/RetentionPolicy/CreateCommand.cs
@@ -15,9 +15,9 @@
using System;
using System.Threading.Tasks;
using Seq.Api.Model.Signals;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
using SeqCli.Signals;
using SeqCli.Syntax;
using SeqCli.Util;
diff --git a/src/SeqCli/Cli/Commands/RetentionPolicy/ListCommand.cs b/src/SeqCli/Cli/Commands/RetentionPolicy/ListCommand.cs
index 391866ad..a8d410a7 100644
--- a/src/SeqCli/Cli/Commands/RetentionPolicy/ListCommand.cs
+++ b/src/SeqCli/Cli/Commands/RetentionPolicy/ListCommand.cs
@@ -14,9 +14,9 @@
using System;
using System.Threading.Tasks;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
namespace SeqCli.Cli.Commands.RetentionPolicy;
diff --git a/src/SeqCli/Cli/Commands/RetentionPolicy/RemoveCommand.cs b/src/SeqCli/Cli/Commands/RetentionPolicy/RemoveCommand.cs
index 3d9266e0..a6e6acf4 100644
--- a/src/SeqCli/Cli/Commands/RetentionPolicy/RemoveCommand.cs
+++ b/src/SeqCli/Cli/Commands/RetentionPolicy/RemoveCommand.cs
@@ -14,9 +14,9 @@
using System;
using System.Threading.Tasks;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
using Serilog;
namespace SeqCli.Cli.Commands.RetentionPolicy;
diff --git a/src/SeqCli/Cli/Commands/RetentionPolicy/UpdateCommand.cs b/src/SeqCli/Cli/Commands/RetentionPolicy/UpdateCommand.cs
index ca6503ce..7a1dc349 100644
--- a/src/SeqCli/Cli/Commands/RetentionPolicy/UpdateCommand.cs
+++ b/src/SeqCli/Cli/Commands/RetentionPolicy/UpdateCommand.cs
@@ -13,7 +13,6 @@
// limitations under the License.
using Seq.Api;
-using SeqCli.Connection;
namespace SeqCli.Cli.Commands.RetentionPolicy;
diff --git a/src/SeqCli/Cli/Commands/Sample/IngestCommand.cs b/src/SeqCli/Cli/Commands/Sample/IngestCommand.cs
index a5dd3790..4f4bf6da 100644
--- a/src/SeqCli/Cli/Commands/Sample/IngestCommand.cs
+++ b/src/SeqCli/Cli/Commands/Sample/IngestCommand.cs
@@ -15,9 +15,9 @@
using System;
using System.Linq;
using System.Threading.Tasks;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
using SeqCli.Sample.Loader;
namespace SeqCli.Cli.Commands.Sample;
diff --git a/src/SeqCli/Cli/Commands/Sample/SetupCommand.cs b/src/SeqCli/Cli/Commands/Sample/SetupCommand.cs
index fb0c0722..187ca169 100644
--- a/src/SeqCli/Cli/Commands/Sample/SetupCommand.cs
+++ b/src/SeqCli/Cli/Commands/Sample/SetupCommand.cs
@@ -18,11 +18,11 @@
using System.Linq;
using System.Threading.Tasks;
using SeqCli.Cli.Features;
-using SeqCli.Connection;
using SeqCli.Templates.Ast;
using SeqCli.Templates.Import;
using SeqCli.Util;
using Seq.Api;
+using SeqCli.Api;
using SeqCli.Config;
// ReSharper disable once UnusedType.Global
diff --git a/src/SeqCli/Cli/Commands/SearchCommand.cs b/src/SeqCli/Cli/Commands/SearchCommand.cs
index 151be6eb..adea7806 100644
--- a/src/SeqCli/Cli/Commands/SearchCommand.cs
+++ b/src/SeqCli/Cli/Commands/SearchCommand.cs
@@ -18,9 +18,9 @@
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
using Seq.Api.Model.Events;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
using SeqCli.Levels;
using SeqCli.Util;
using Serilog;
diff --git a/src/SeqCli/Cli/Commands/Settings/ClearCommand.cs b/src/SeqCli/Cli/Commands/Settings/ClearCommand.cs
index 7d527e43..760d9d2f 100644
--- a/src/SeqCli/Cli/Commands/Settings/ClearCommand.cs
+++ b/src/SeqCli/Cli/Commands/Settings/ClearCommand.cs
@@ -14,9 +14,9 @@
using System;
using System.Threading.Tasks;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
namespace SeqCli.Cli.Commands.Settings;
diff --git a/src/SeqCli/Cli/Commands/Settings/SetCommand.cs b/src/SeqCli/Cli/Commands/Settings/SetCommand.cs
index edc26154..f01a2f01 100644
--- a/src/SeqCli/Cli/Commands/Settings/SetCommand.cs
+++ b/src/SeqCli/Cli/Commands/Settings/SetCommand.cs
@@ -14,9 +14,9 @@
using System;
using System.Threading.Tasks;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
using Serilog;
namespace SeqCli.Cli.Commands.Settings;
diff --git a/src/SeqCli/Cli/Commands/Settings/ShowCommand.cs b/src/SeqCli/Cli/Commands/Settings/ShowCommand.cs
index f6f7ef5b..312da195 100644
--- a/src/SeqCli/Cli/Commands/Settings/ShowCommand.cs
+++ b/src/SeqCli/Cli/Commands/Settings/ShowCommand.cs
@@ -15,9 +15,9 @@
using System;
using System.Globalization;
using System.Threading.Tasks;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
namespace SeqCli.Cli.Commands.Settings;
diff --git a/src/SeqCli/Cli/Commands/Shared/UpdateCommand.cs b/src/SeqCli/Cli/Commands/Shared/UpdateCommand.cs
index de40eaa5..15238f8f 100644
--- a/src/SeqCli/Cli/Commands/Shared/UpdateCommand.cs
+++ b/src/SeqCli/Cli/Commands/Shared/UpdateCommand.cs
@@ -15,9 +15,9 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
using SeqCli.Templates.Ast;
using SeqCli.Templates.Import;
using SeqCli.Templates.Parser;
diff --git a/src/SeqCli/Cli/Commands/Signal/CreateCommand.cs b/src/SeqCli/Cli/Commands/Signal/CreateCommand.cs
index 16cb2f99..414d124a 100644
--- a/src/SeqCli/Cli/Commands/Signal/CreateCommand.cs
+++ b/src/SeqCli/Cli/Commands/Signal/CreateCommand.cs
@@ -18,9 +18,9 @@
using System.Threading.Tasks;
using Seq.Api.Model.Shared;
using Seq.Api.Model.Signals;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
using SeqCli.Util;
namespace SeqCli.Cli.Commands.Signal;
diff --git a/src/SeqCli/Cli/Commands/Signal/ImportCommand.cs b/src/SeqCli/Cli/Commands/Signal/ImportCommand.cs
index b9c79f78..d810c8b5 100644
--- a/src/SeqCli/Cli/Commands/Signal/ImportCommand.cs
+++ b/src/SeqCli/Cli/Commands/Signal/ImportCommand.cs
@@ -18,9 +18,9 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Seq.Api.Model.Signals;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
namespace SeqCli.Cli.Commands.Signal;
diff --git a/src/SeqCli/Cli/Commands/Signal/ListCommand.cs b/src/SeqCli/Cli/Commands/Signal/ListCommand.cs
index a035489c..24932b36 100644
--- a/src/SeqCli/Cli/Commands/Signal/ListCommand.cs
+++ b/src/SeqCli/Cli/Commands/Signal/ListCommand.cs
@@ -15,9 +15,9 @@
using System;
using System.Linq;
using System.Threading.Tasks;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
namespace SeqCli.Cli.Commands.Signal;
diff --git a/src/SeqCli/Cli/Commands/Signal/RemoveCommand.cs b/src/SeqCli/Cli/Commands/Signal/RemoveCommand.cs
index a989d7e5..75a5a397 100644
--- a/src/SeqCli/Cli/Commands/Signal/RemoveCommand.cs
+++ b/src/SeqCli/Cli/Commands/Signal/RemoveCommand.cs
@@ -15,9 +15,9 @@
using System;
using System.Linq;
using System.Threading.Tasks;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
using Serilog;
namespace SeqCli.Cli.Commands.Signal;
diff --git a/src/SeqCli/Cli/Commands/Signal/UpdateCommand.cs b/src/SeqCli/Cli/Commands/Signal/UpdateCommand.cs
index 29f93fd4..93e17bf0 100644
--- a/src/SeqCli/Cli/Commands/Signal/UpdateCommand.cs
+++ b/src/SeqCli/Cli/Commands/Signal/UpdateCommand.cs
@@ -13,7 +13,6 @@
// limitations under the License.
using Seq.Api;
-using SeqCli.Connection;
namespace SeqCli.Cli.Commands.Signal;
diff --git a/src/SeqCli/Cli/Commands/TailCommand.cs b/src/SeqCli/Cli/Commands/TailCommand.cs
index ae8c5907..26510b84 100644
--- a/src/SeqCli/Cli/Commands/TailCommand.cs
+++ b/src/SeqCli/Cli/Commands/TailCommand.cs
@@ -15,9 +15,9 @@
using System;
using System.Threading;
using System.Threading.Tasks;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
using SeqCli.Ingestion;
namespace SeqCli.Cli.Commands;
diff --git a/src/SeqCli/Cli/Commands/Template/ExportCommand.cs b/src/SeqCli/Cli/Commands/Template/ExportCommand.cs
index 71cefcf5..624db07b 100644
--- a/src/SeqCli/Cli/Commands/Template/ExportCommand.cs
+++ b/src/SeqCli/Cli/Commands/Template/ExportCommand.cs
@@ -2,9 +2,9 @@
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
using SeqCli.Templates.Export;
using SeqCli.Util;
using Serilog;
diff --git a/src/SeqCli/Cli/Commands/Template/ImportCommand.cs b/src/SeqCli/Cli/Commands/Template/ImportCommand.cs
index 2259b68d..338e5f6a 100644
--- a/src/SeqCli/Cli/Commands/Template/ImportCommand.cs
+++ b/src/SeqCli/Cli/Commands/Template/ImportCommand.cs
@@ -3,9 +3,9 @@
using System.IO;
using System.Linq;
using System.Threading.Tasks;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
using SeqCli.Templates.Ast;
using SeqCli.Templates.Export;
using SeqCli.Templates.Import;
diff --git a/src/SeqCli/Cli/Commands/User/CreateCommand.cs b/src/SeqCli/Cli/Commands/User/CreateCommand.cs
index 09a8064c..e670b9f7 100644
--- a/src/SeqCli/Cli/Commands/User/CreateCommand.cs
+++ b/src/SeqCli/Cli/Commands/User/CreateCommand.cs
@@ -16,9 +16,9 @@
using System.Linq;
using System.Threading.Tasks;
using Seq.Api.Model.Shared;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
using SeqCli.Util;
using Serilog;
diff --git a/src/SeqCli/Cli/Commands/User/ListCommand.cs b/src/SeqCli/Cli/Commands/User/ListCommand.cs
index d7de035d..52965047 100644
--- a/src/SeqCli/Cli/Commands/User/ListCommand.cs
+++ b/src/SeqCli/Cli/Commands/User/ListCommand.cs
@@ -15,9 +15,9 @@
using System;
using System.Linq;
using System.Threading.Tasks;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
namespace SeqCli.Cli.Commands.User;
diff --git a/src/SeqCli/Cli/Commands/User/RemoveCommand.cs b/src/SeqCli/Cli/Commands/User/RemoveCommand.cs
index 082ec8e7..8616fafa 100644
--- a/src/SeqCli/Cli/Commands/User/RemoveCommand.cs
+++ b/src/SeqCli/Cli/Commands/User/RemoveCommand.cs
@@ -15,9 +15,9 @@
using System;
using System.Linq;
using System.Threading.Tasks;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
using Serilog;
namespace SeqCli.Cli.Commands.User;
diff --git a/src/SeqCli/Cli/Commands/User/UpdateCommand.cs b/src/SeqCli/Cli/Commands/User/UpdateCommand.cs
index de30ec3f..c1024d3f 100644
--- a/src/SeqCli/Cli/Commands/User/UpdateCommand.cs
+++ b/src/SeqCli/Cli/Commands/User/UpdateCommand.cs
@@ -13,7 +13,6 @@
// limitations under the License.
using Seq.Api;
-using SeqCli.Connection;
namespace SeqCli.Cli.Commands.User;
diff --git a/src/SeqCli/Cli/Commands/Workspace/CreateCommand.cs b/src/SeqCli/Cli/Commands/Workspace/CreateCommand.cs
index 52103479..cf4999d1 100644
--- a/src/SeqCli/Cli/Commands/Workspace/CreateCommand.cs
+++ b/src/SeqCli/Cli/Commands/Workspace/CreateCommand.cs
@@ -2,9 +2,9 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
using SeqCli.Util;
// ReSharper disable once UnusedType.Global
diff --git a/src/SeqCli/Cli/Commands/Workspace/ListCommand.cs b/src/SeqCli/Cli/Commands/Workspace/ListCommand.cs
index 9212b5e6..8bf57afa 100644
--- a/src/SeqCli/Cli/Commands/Workspace/ListCommand.cs
+++ b/src/SeqCli/Cli/Commands/Workspace/ListCommand.cs
@@ -1,9 +1,9 @@
using System;
using System.Linq;
using System.Threading.Tasks;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
namespace SeqCli.Cli.Commands.Workspace;
diff --git a/src/SeqCli/Cli/Commands/Workspace/RemoveCommand.cs b/src/SeqCli/Cli/Commands/Workspace/RemoveCommand.cs
index 6208f068..c5efb71f 100644
--- a/src/SeqCli/Cli/Commands/Workspace/RemoveCommand.cs
+++ b/src/SeqCli/Cli/Commands/Workspace/RemoveCommand.cs
@@ -1,9 +1,9 @@
using System;
using System.Linq;
using System.Threading.Tasks;
+using SeqCli.Api;
using SeqCli.Cli.Features;
using SeqCli.Config;
-using SeqCli.Connection;
using Serilog;
namespace SeqCli.Cli.Commands.Workspace;
diff --git a/src/SeqCli/Cli/Commands/Workspace/UpdateCommand.cs b/src/SeqCli/Cli/Commands/Workspace/UpdateCommand.cs
index 121b7511..bc2d3498 100644
--- a/src/SeqCli/Cli/Commands/Workspace/UpdateCommand.cs
+++ b/src/SeqCli/Cli/Commands/Workspace/UpdateCommand.cs
@@ -13,7 +13,6 @@
// limitations under the License.
using Seq.Api;
-using SeqCli.Connection;
namespace SeqCli.Cli.Commands.Workspace;
diff --git a/src/SeqCli/Config/Forwarder/SeqCliForwarderDiagnosticConfig.cs b/src/SeqCli/Config/Forwarder/SeqCliForwarderDiagnosticConfig.cs
index 326257d9..eb761d90 100644
--- a/src/SeqCli/Config/Forwarder/SeqCliForwarderDiagnosticConfig.cs
+++ b/src/SeqCli/Config/Forwarder/SeqCliForwarderDiagnosticConfig.cs
@@ -4,11 +4,11 @@
namespace SeqCli.Config.Forwarder;
-public class SeqCliForwarderDiagnosticConfig
+class SeqCliForwarderDiagnosticConfig
{
public LogEventLevel InternalLoggingLevel { get; set; } = LogEventLevel.Information;
public string? InternalLogServerUri { get; set; }
public string? InternalLogServerApiKey { get; set; }
public bool ExposeIngestionLog { get; set; }
public bool IngestionLogShowDetail { get; set; }
-}
\ No newline at end of file
+}
diff --git a/src/SeqCli/Config/RuntimeConfigurationLoader.cs b/src/SeqCli/Config/RuntimeConfigurationLoader.cs
index 9dee4560..521c5a87 100644
--- a/src/SeqCli/Config/RuntimeConfigurationLoader.cs
+++ b/src/SeqCli/Config/RuntimeConfigurationLoader.cs
@@ -29,7 +29,7 @@ public static SeqCliConfig Load(StoragePathFeature storage)
var config = SeqCliConfig.ReadFromFile(storage.ConfigFilePath);
EnvironmentOverrides.Apply(DefaultEnvironmentVariablePrefix, config);
-
+
return config;
}
}
\ No newline at end of file
diff --git a/src/SeqCli/Config/SeqCliConnectionConfig.cs b/src/SeqCli/Config/SeqCliConnectionConfig.cs
index 0fd7bd6a..7c3cc2a1 100644
--- a/src/SeqCli/Config/SeqCliConnectionConfig.cs
+++ b/src/SeqCli/Config/SeqCliConnectionConfig.cs
@@ -58,4 +58,4 @@ public void EncodeApiKey(string? apiKey, IDataProtector dataProtector)
public uint? PooledConnectionLifetimeMilliseconds { get; set; } = null;
public ulong EventBodyLimitBytes { get; set; } = 256 * 1024;
public ulong PayloadLimitBytes { get; set; } = 10 * 1024 * 1024;
-}
\ No newline at end of file
+}
diff --git a/src/SeqCli/Forwarder/Diagnostics/IngestionLog.cs b/src/SeqCli/Forwarder/Diagnostics/IngestionLog.cs
index e3fbadf2..f3613026 100644
--- a/src/SeqCli/Forwarder/Diagnostics/IngestionLog.cs
+++ b/src/SeqCli/Forwarder/Diagnostics/IngestionLog.cs
@@ -47,7 +47,7 @@ public static ILogger ForClient(IPAddress? clientHostIP)
return Log.ForContext("ClientHostIP", clientHostIP);
}
- public static ILogger ForPayload(IPAddress clientHostIP, string payload)
+ public static ILogger ForPayload(IPAddress? clientHostIP, string payload)
{
var prefix = CapturePrefix(payload);
return ForClient(clientHostIP)
diff --git a/src/SeqCli/Forwarder/ForwarderModule.cs b/src/SeqCli/Forwarder/ForwarderModule.cs
index f06280c4..960c01d1 100644
--- a/src/SeqCli/Forwarder/ForwarderModule.cs
+++ b/src/SeqCli/Forwarder/ForwarderModule.cs
@@ -21,7 +21,10 @@
using SeqCli.Forwarder.Channel;
using SeqCli.Forwarder.Web.Api;
using SeqCli.Forwarder.Web.Host;
+using Serilog;
+using Serilog.Formatting;
using Serilog.Formatting.Display;
+using Serilog.Templates;
namespace SeqCli.Forwarder;
@@ -45,28 +48,35 @@ protected override void Load(ContainerBuilder builder)
builder.RegisterType().SingleInstance();
builder.Register(_ => new ForwardingChannelMap(_bufferPath, _connection, _apiKey)).SingleInstance();
- builder.RegisterType().As();
builder.RegisterType().As();
if (_config.Forwarder.Diagnostics.ExposeIngestionLog)
{
+ Log.Warning("Configured to expose ingestion log via HTTP API");
builder.RegisterType().As();
+
+ var ingestionLogTemplate = "[{@t:o} {@l:u3}] {@m}\n";
+ if (_config.Forwarder.Diagnostics.IngestionLogShowDetail)
+ {
+ Log.Warning("Including full client, payload, and error detail in the ingestion log");
+ ingestionLogTemplate +=
+ "{#if ClientHostIP is not null}Client IP address: {ClientHostIP}\n{#end}" +
+ "{#if DocumentStart is not null}First {StartToLog} characters of payload: {DocumentStart:l}\n{#end}" +
+ "{@x}";
+ }
+
+ builder.Register(_ => new ExpressionTemplate(ingestionLogTemplate)).As();
}
-
- builder.RegisterInstance(new MessageTemplateTextFormatter(
- "[{Timestamp:o} {Level:u3}] {Message}{NewLine}" + (_config.Forwarder.Diagnostics.IngestionLogShowDetail
- ? ""
- : "Client IP address: {ClientHostIP}{NewLine}First {StartToLog} characters of payload: {DocumentStart:l}{NewLine}{Exception}{NewLine}"))).SingleInstance();
builder.Register(c =>
{
var config = c.Resolve();
var baseUri = config.Connection.ServerUrl;
if (string.IsNullOrWhiteSpace(baseUri))
- throw new ArgumentException("The destination Seq server URL must be configured in SeqForwarder.json.");
+ throw new ArgumentException("The destination Seq server URL must be configured in `SeqCli.json`.");
- if (!baseUri.EndsWith("/"))
- baseUri += "/";
+ if (!baseUri.EndsWith('/'))
+ baseUri += '/';
// additional configuration options that require the use of SocketsHttpHandler should be added to
// this expression, using an "or" operator.
diff --git a/src/SeqCli/Forwarder/Web/Api/ApiRootEndpoints.cs b/src/SeqCli/Forwarder/Web/Api/ApiRootEndpoints.cs
deleted file mode 100644
index 60b418f6..00000000
--- a/src/SeqCli/Forwarder/Web/Api/ApiRootEndpoints.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright © Datalust Pty Ltd
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-using System.Text;
-using Microsoft.AspNetCore.Builder;
-using Microsoft.AspNetCore.Http;
-
-namespace SeqCli.Forwarder.Web.Api;
-
-class ApiRootEndpoints : IMapEndpoints
-{
- readonly Encoding _utf8 = new UTF8Encoding(false);
-
- public void MapEndpoints(WebApplication app)
- {
- app.MapGet("/api",
- () => Results.Content("{\"Links\":{\"Events\":\"/api/events/describe\"}}", "application/json", _utf8));
- }
-}
\ No newline at end of file
diff --git a/src/SeqCli/Forwarder/Web/Api/IngestionEndpoints.cs b/src/SeqCli/Forwarder/Web/Api/IngestionEndpoints.cs
index 00a44555..b1cb184f 100644
--- a/src/SeqCli/Forwarder/Web/Api/IngestionEndpoints.cs
+++ b/src/SeqCli/Forwarder/Web/Api/IngestionEndpoints.cs
@@ -14,6 +14,7 @@
using System;
using System.Buffers;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text;
using System.Text.Json;
@@ -21,7 +22,6 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
-using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.Net.Http.Headers;
using SeqCli.Api;
using SeqCli.Forwarder.Channel;
@@ -64,6 +64,100 @@ async Task IngestAsync(HttpContext context)
.Error("Client supplied a legacy raw-format (non-CLEF) payload");
return Results.BadRequest("Only newline-delimited JSON (CLEF) payloads are supported.");
}
+
+ async Task IngestCompactFormatAsync(HttpContext context)
+ {
+ try
+ {
+ var cts = CancellationTokenSource.CreateLinkedTokenSource(context.RequestAborted);
+ cts.CancelAfter(TimeSpan.FromSeconds(5));
+
+ var log = _forwardingChannels.Get(GetApiKey(context.Request));
+
+ var payload = ArrayPool.Shared.Rent(1024 * 1024 * 10);
+ var writeHead = 0;
+ var readHead = 0;
+
+ var done = false;
+ while (!done)
+ {
+ // Fill the memory buffer from as much of the incoming request payload as possible; buffering in memory increases the
+ // size of write batches.
+ while (!done)
+ {
+ var remaining = payload.Length - writeHead;
+ if (remaining == 0)
+ {
+ break;
+ }
+
+ var read = await context.Request.Body.ReadAsync(payload.AsMemory(writeHead, remaining), cts.Token);
+ if (read == 0)
+ {
+ done = true;
+ }
+
+ writeHead += read;
+ }
+
+ // Validate what we read, marking out a batch of one or more complete newline-delimited events.
+ var batchStart = readHead;
+ var batchEnd = readHead;
+ while (batchEnd < writeHead)
+ {
+ var eventStart = batchEnd;
+ var nlIndex = payload.AsSpan()[eventStart..].IndexOf((byte)'\n');
+
+ if (nlIndex == -1)
+ {
+ break;
+ }
+
+ var eventEnd = eventStart + nlIndex + 1;
+
+ batchEnd = eventEnd;
+ readHead = batchEnd;
+
+ if (!ValidateClef(payload.AsSpan()[eventStart..eventEnd], out var error))
+ {
+ var payloadText = Encoding.UTF8.GetString(payload.AsSpan()[eventStart..eventEnd]);
+ IngestionLog.ForPayload(context.Connection.RemoteIpAddress, payloadText)
+ .Error("Payload validation failed: {Error}", error);
+ return Results.BadRequest($"Payload validation failed: {error}.");
+ }
+ }
+
+ if (batchStart != batchEnd)
+ {
+ await Write(log, ArrayPool.Shared, payload, batchStart..batchEnd, cts.Token);
+ }
+
+ // Copy any unprocessed data into our buffer and continue
+ if (!done)
+ {
+ var retain = writeHead - readHead;
+ payload.AsSpan()[readHead..writeHead].CopyTo(payload.AsSpan()[..retain]);
+ readHead = 0;
+ writeHead = retain;
+ }
+ }
+
+ // Exception cases are handled by `Write`
+ ArrayPool.Shared.Return(payload);
+
+ return TypedResults.Content(
+ null,
+ "application/json",
+ Utf8,
+ StatusCodes.Status201Created);
+ }
+ catch (Exception ex)
+ {
+ IngestionLog.ForClient(context.Connection.RemoteIpAddress)
+ .Error(ex, "Ingestion failed");
+ return Results.InternalServerError();
+ }
+ }
static bool DefaultedBoolQuery(HttpRequest request, string queryParameterName)
{
@@ -90,115 +184,21 @@ static bool DefaultedBoolQuery(HttpRequest request, string queryParameterName)
if (apiKeyHeader.Count > 0) return apiKeyHeader.Last();
return request.Query.TryGetValue("apiKey", out var apiKey) ? apiKey.Last() : null;
}
-
- async Task IngestCompactFormatAsync(HttpContext context)
- {
- var cts = CancellationTokenSource.CreateLinkedTokenSource(context.RequestAborted);
- cts.CancelAfter(TimeSpan.FromSeconds(5));
-
- var log = _forwardingChannels.Get(GetApiKey(context.Request));
-
- var payload = ArrayPool.Shared.Rent(1024 * 1024 * 10);
- var writeHead = 0;
- var readHead = 0;
- var discarding = false;
-
- var done = false;
- while (!done)
- {
- // Fill our buffer
- while (!done)
- {
- var remaining = payload.Length - writeHead;
- if (remaining == 0)
- {
- break;
- }
-
- var read = await context.Request.Body.ReadAsync(payload.AsMemory(writeHead, remaining), context.RequestAborted);
- if (read == 0)
- {
- done = true;
- }
-
- writeHead += read;
- }
-
- // Process events
- var batchStart = readHead;
- var batchEnd = readHead;
- while (batchEnd < writeHead)
- {
- var eventStart = batchEnd;
- var nlIndex = payload.AsSpan()[eventStart..].IndexOf((byte)'\n');
-
- if (nlIndex == -1)
- {
- break;
- }
-
- var eventEnd = eventStart + nlIndex + 1;
-
- if (discarding)
- {
- batchStart = eventEnd;
- batchEnd = eventEnd;
- readHead = batchEnd;
-
- discarding = false;
- }
- else
- {
- batchEnd = eventEnd;
- readHead = batchEnd;
-
- if (!ValidateClef(payload.AsSpan()[eventStart..batchEnd]))
- {
- await Write(log, ArrayPool.Shared, payload, batchStart..eventStart, cts.Token);
- batchStart = batchEnd;
- }
- }
- }
-
- if (batchStart != batchEnd)
- {
- await Write(log, ArrayPool.Shared, payload, batchStart..batchEnd, cts.Token);
- }
- else if (batchStart == 0)
- {
- readHead = payload.Length;
- discarding = true;
- }
-
- // Copy any unprocessed data into our buffer and continue
- if (!done)
- {
- var retain = payload.Length - readHead;
- payload.AsSpan()[retain..].CopyTo(payload.AsSpan()[..retain]);
- readHead = retain;
- writeHead = retain;
- }
- }
-
- // Exception cases are handled by `Write`
- ArrayPool.Shared.Return(payload);
-
- return TypedResults.Content(
- null,
- "application/json",
- Utf8,
- StatusCodes.Status201Created);
- }
- static bool ValidateClef(Span evt)
+ static bool ValidateClef(Span evt, [NotNullWhen(false)] out string? errorFragment)
{
+ // Note that `errorFragment` does not include user-supplied values; we opt in to adding this to
+ // the ingestion log and include it using `ForPayload()`.
+
var reader = new Utf8JsonReader(evt);
+ var foundTimestamp = false;
try
{
reader.Read();
if (reader.TokenType != JsonTokenType.StartObject)
{
+ errorFragment = $"unexpected token type `{reader.TokenType}`";
return false;
}
@@ -210,9 +210,22 @@ static bool ValidateClef(Span evt)
{
var name = reader.GetString();
- if (name != null & name!.StartsWith($"@"))
+ if (name == "@t")
{
- // Validate @ property
+ if (!reader.Read())
+ {
+ errorFragment = "payload ended prematurely";
+ return false;
+ }
+ var value = reader.GetString();
+ if (!DateTimeOffset.TryParse(value, out _))
+ {
+ errorFragment = "unparseable `@t` timestamp value";
+ return false;
+ }
+
+ foundTimestamp = true;
+ break;
}
}
}
@@ -220,9 +233,17 @@ static bool ValidateClef(Span evt)
}
catch (JsonException)
{
+ errorFragment = "JSON parsing failure";
+ return false;
+ }
+
+ if (!foundTimestamp)
+ {
+ errorFragment = "missing `@t` timestamp property";
return false;
}
+ errorFragment = null;
return true;
}
diff --git a/src/SeqCli/Forwarder/Web/Api/IngestionLogEndpoints.cs b/src/SeqCli/Forwarder/Web/Api/IngestionLogEndpoints.cs
index 60a69038..cf30acfb 100644
--- a/src/SeqCli/Forwarder/Web/Api/IngestionLogEndpoints.cs
+++ b/src/SeqCli/Forwarder/Web/Api/IngestionLogEndpoints.cs
@@ -17,22 +17,28 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using SeqCli.Forwarder.Diagnostics;
-using Serilog.Formatting.Display;
+using Serilog.Formatting;
namespace SeqCli.Forwarder.Web.Api;
class IngestionLogEndpoints : IMapEndpoints
{
- readonly MessageTemplateTextFormatter _formatter;
+ readonly ITextFormatter _formatter;
readonly Encoding _utf8 = new UTF8Encoding(false);
- public IngestionLogEndpoints(MessageTemplateTextFormatter formatter)
+ public IngestionLogEndpoints(ITextFormatter formatter)
{
_formatter = formatter;
}
public void MapEndpoints(WebApplication app)
{
+ app.MapGet("/api",
+ () => Results.Content("{\"Links\":{\"DiagnosticsResources\":\"/api/diagnostics/resources\"}}", "application/json", _utf8));
+
+ app.MapGet("/api/diagnostics/resources",
+ () => Results.Content("{\"Links\":{\"Self\":\"api/diagnostics/resources\",\"IngestionLog\":\"api/diagnostics/ingestion\"}}", "application/json", _utf8));
+
app.MapGet("api/diagnostics/ingestion", () =>
{
var events = IngestionLog.Read();
@@ -45,4 +51,4 @@ public void MapEndpoints(WebApplication app)
return Results.Content(log.ToString(), "text/plain", _utf8);
});
}
-}
\ No newline at end of file
+}
diff --git a/src/SeqCli/Forwarder/Web/Host/ServerService.cs b/src/SeqCli/Forwarder/Web/Host/ServerService.cs
index ca6545e9..3732497c 100644
--- a/src/SeqCli/Forwarder/Web/Host/ServerService.cs
+++ b/src/SeqCli/Forwarder/Web/Host/ServerService.cs
@@ -42,8 +42,8 @@ public void Start()
_host.Start();
- Log.Information("SeqCli Forwarder listening on {ListenUri}", _listenUri);
- IngestionLog.Log.Debug("SeqCli Forwarder is accepting events");
+ Log.Information("SeqCli forwarder listening on {ListenUri}", _listenUri);
+ IngestionLog.Log.Debug("The SeqCli forwarder ingestion API is accepting requests");
}
catch (Exception ex)
{
diff --git a/src/SeqCli/Properties/launchSettings.json b/src/SeqCli/Properties/launchSettings.json
index 11a965f9..f9a7cad5 100644
--- a/src/SeqCli/Properties/launchSettings.json
+++ b/src/SeqCli/Properties/launchSettings.json
@@ -3,7 +3,7 @@
"profiles": {
"SeqCli": {
"commandName": "Project",
- "commandLineArgs": "help --pre"
+ "commandLineArgs": "forwarder run --pre"
}
}
}
diff --git a/test/SeqCli.EndToEnd/Args.cs b/test/SeqCli.EndToEnd/Args.cs
index 4e1701ea..322c408a 100644
--- a/test/SeqCli.EndToEnd/Args.cs
+++ b/test/SeqCli.EndToEnd/Args.cs
@@ -17,16 +17,18 @@ public Regex[] TestCases() => args
static Regex ToArgRegex(string arg) => new(arg.Replace(".", "\\.").Replace("*", ".*"));
public bool Multiuser() => args.Any(a => a == "--license-certificate-stdin");
-
- public bool UseDockerSeq([NotNullWhen(true)] out string? imageTag)
+
+ public bool UseDockerSeq([NotNullWhen(true)] out string? imageTag, [NotNullWhen(true)] out string? containerRuntime)
{
if (args.Any(a => a == "--docker-server"))
{
imageTag = args.Any(a => a == "--pre") ? "preview" : "latest";
+ containerRuntime = args.Any(a => a == "--podman") ? "podman" : "docker";
return true;
}
imageTag = null;
+ containerRuntime = null;
return false;
}
}
diff --git a/test/SeqCli.EndToEnd/Diagnostics/IngestionLogTestCase.cs b/test/SeqCli.EndToEnd/Diagnostics/IngestionLogTestCase.cs
new file mode 100644
index 00000000..4a515e85
--- /dev/null
+++ b/test/SeqCli.EndToEnd/Diagnostics/IngestionLogTestCase.cs
@@ -0,0 +1,20 @@
+using System.Threading.Tasks;
+using Seq.Api;
+using SeqCli.EndToEnd.Support;
+using Serilog;
+using Xunit;
+
+namespace SeqCli.EndToEnd.Diagnostics;
+
+public class IngestionLogTestCase: ICliTestCase
+{
+ public Task ExecuteAsync(SeqConnection connection, ILogger logger, CliCommandRunner runner)
+ {
+ var exit = runner.Exec("diagnostics ingestionlog");
+ Assert.Equal(0, exit);
+
+ Assert.StartsWith("[20", runner.LastRunProcess!.Output);
+
+ return Task.CompletedTask;
+ }
+}
diff --git a/test/SeqCli.EndToEnd/Forwarder/ForwarderIngestionLogTestCase.cs b/test/SeqCli.EndToEnd/Forwarder/ForwarderIngestionLogTestCase.cs
new file mode 100644
index 00000000..f5b70db8
--- /dev/null
+++ b/test/SeqCli.EndToEnd/Forwarder/ForwarderIngestionLogTestCase.cs
@@ -0,0 +1,32 @@
+using System.Threading.Tasks;
+using Seq.Api;
+using SeqCli.EndToEnd.Support;
+using Serilog;
+using Xunit;
+
+namespace SeqCli.EndToEnd.Forwarder;
+
+public class ForwarderIngestionLogTestCase: ICliTestCase
+{
+ public async Task ExecuteAsync(SeqConnection connection, ILogger logger, CliCommandRunner runner)
+ {
+ var (proc1, listenUri1) = await runner.SpawnForwarderAsync();
+ using (proc1)
+ {
+ var exit = runner.Exec($"diagnostics ingestionlog -s {listenUri1}", disconnected: true);
+ Assert.NotEqual(0, exit);
+ }
+
+ var (proc2, listenUri2) = await runner.SpawnForwarderAsync(environment: new()
+ {
+ ["SEQCLI_FORWARDER_DIAGNOSTICS_EXPOSEINGESTIONLOG"] = "True"
+ });
+ using (proc2)
+ {
+ var exit = runner.Exec($"diagnostics ingestionlog -s {listenUri2}", disconnected: true);
+ Assert.Equal(0, exit);
+
+ Assert.StartsWith("[20", runner.LastRunProcess!.Output);
+ }
+ }
+}
diff --git a/test/SeqCli.EndToEnd/Forwarder/ForwarderSimpleIngestionTestCase.cs b/test/SeqCli.EndToEnd/Forwarder/ForwarderSimpleIngestionTestCase.cs
new file mode 100644
index 00000000..bb199942
--- /dev/null
+++ b/test/SeqCli.EndToEnd/Forwarder/ForwarderSimpleIngestionTestCase.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Globalization;
+using System.Threading.Tasks;
+using Seq.Api;
+using SeqCli.EndToEnd.Support;
+using Serilog;
+using Xunit;
+
+namespace SeqCli.EndToEnd.Forwarder;
+
+public class ForwarderSimpleIngestionTestCase: ICliTestCase
+{
+ public async Task ExecuteAsync(SeqConnection connection, ILogger logger, CliCommandRunner runner)
+ {
+ var (forwarder, forwarderUri) = await runner.SpawnForwarderAsync();
+ using (forwarder)
+ {
+ var ingestionLogger = new LoggerConfiguration()
+ .WriteTo.Seq(forwarderUri)
+ .CreateLogger();
+
+ const int itemCount = 1032;
+ for (var i = 0; i < itemCount; ++i)
+ {
+ ingestionLogger.ForContext("Ballast", new string('a', 51))
+ .Information("At item {I}", i);
+ }
+
+ // In recent versions this should be sufficient to flush any queued events.
+ await ingestionLogger.DisposeAsync();
+
+ // Give forwarder enough time to move data...
+ await Task.Delay(TimeSpan.FromSeconds(5));
+
+ var result = await connection.Data.QueryAsync("select count(*) from stream");
+ var retrievedCount = (long)result.Rows[0][0];
+
+ Assert.Equal(itemCount, retrievedCount);
+ }
+ }
+}
diff --git a/test/SeqCli.EndToEnd/Program.cs b/test/SeqCli.EndToEnd/Program.cs
index f517e730..35a392c9 100644
--- a/test/SeqCli.EndToEnd/Program.cs
+++ b/test/SeqCli.EndToEnd/Program.cs
@@ -1,18 +1,31 @@
-using System.Threading.Tasks;
+using System;
using Autofac;
+using SeqCli.EndToEnd;
using SeqCli.EndToEnd.Support;
+using Serilog;
+using Serilog.Debugging;
-namespace SeqCli.EndToEnd;
+Log.Logger = new LoggerConfiguration()
+ .WriteTo.Console()
+ .CreateLogger();
-static class Program
+SelfLog.Enable(Console.Error);
+
+try
{
- static async Task Main(string[] rawArgs)
- {
- var args = new Args(rawArgs);
+ var testDriverArgs = new Args(args);
- var builder = new ContainerBuilder();
- builder.RegisterModule(new TestDriverModule(args));
- await using var container = builder.Build();
- return await container.Resolve().Run();
- }
-}
\ No newline at end of file
+ var builder = new ContainerBuilder();
+ builder.RegisterModule(new TestDriverModule(testDriverArgs));
+ await using var container = builder.Build();
+ return await container.Resolve().Run();
+}
+catch (Exception ex)
+{
+ Log.Fatal(ex, "Testing failed");
+ return 1;
+}
+finally
+{
+ await Log.CloseAndFlushAsync();
+}
diff --git a/test/SeqCli.EndToEnd/Properties/launchSettings.json b/test/SeqCli.EndToEnd/Properties/launchSettings.json
index 231d5959..0e1d1c7e 100644
--- a/test/SeqCli.EndToEnd/Properties/launchSettings.json
+++ b/test/SeqCli.EndToEnd/Properties/launchSettings.json
@@ -8,6 +8,10 @@
"commandName": "Project",
"commandLineArgs": "--docker-server"
},
+ "SeqCli.EndToEnd (datalust/seq:latest, podman)": {
+ "commandName": "Project",
+ "commandLineArgs": "--docker-server --podman"
+ },
"SeqCli.EndToEnd (datalust/seq:preview)": {
"commandName": "Project",
"commandLineArgs": "--docker-server --pre"
diff --git a/test/SeqCli.EndToEnd/Support/CaptiveProcess.cs b/test/SeqCli.EndToEnd/Support/CaptiveProcess.cs
index 5d9bd00f..e805cb49 100644
--- a/test/SeqCli.EndToEnd/Support/CaptiveProcess.cs
+++ b/test/SeqCli.EndToEnd/Support/CaptiveProcess.cs
@@ -15,7 +15,7 @@ public sealed class CaptiveProcess : ITestProcess, IDisposable
readonly ManualResetEvent _outputComplete = new(false);
readonly ManualResetEvent _errorComplete = new(false);
- readonly object _sync = new();
+ readonly Lock _sync = new();
readonly StringWriter _output = new();
public CaptiveProcess(
@@ -27,7 +27,7 @@ public CaptiveProcess(
string stopCommandFullExePath = null,
string stopCommandArgs = null)
{
- if (fullExePath == null) throw new ArgumentNullException(nameof(fullExePath));
+ ArgumentNullException.ThrowIfNull(fullExePath);
_captureOutput = captureOutput;
_stopCommandFullExePath = stopCommandFullExePath;
_stopCommandArgs = stopCommandArgs;
diff --git a/test/SeqCli.EndToEnd/Support/CliCommandRunner.cs b/test/SeqCli.EndToEnd/Support/CliCommandRunner.cs
index f7853d02..6061017e 100644
--- a/test/SeqCli.EndToEnd/Support/CliCommandRunner.cs
+++ b/test/SeqCli.EndToEnd/Support/CliCommandRunner.cs
@@ -1,19 +1,82 @@
using System;
+using System.Collections.Generic;
+using System.Net.Http;
+using System.Net.Http.Headers;
+using System.Threading;
+using System.Threading.Tasks;
+using Serilog;
+// ReSharper disable MemberCanBePrivate.Global
#nullable enable
namespace SeqCli.EndToEnd.Support;
-public class CliCommandRunner(TestConfiguration configuration)
+public class CliCommandRunner(TestConfiguration configuration, TestDataFolder testDataFolder)
{
public static readonly TimeSpan DefaultExecTimeout = TimeSpan.FromSeconds(10);
public ITestProcess? LastRunProcess { get; private set; }
- public int Exec(string command, string? args = null, bool disconnected = false, TimeSpan? timeout = null)
+ public int Exec(string command, string? args = null, bool disconnected = false, Dictionary? environment = null, TimeSpan? timeout = null)
{
- using var process = configuration.SpawnCliProcess(command, args, skipServerArg: disconnected);
- LastRunProcess = process;
+ using var process = Spawn(command, args, disconnected, environment);
return process.WaitForExit(timeout ?? DefaultExecTimeout);
}
-}
\ No newline at end of file
+
+ public CaptiveProcess Spawn(string command, string? args = null, bool disconnected = false, Dictionary? environment = null)
+ {
+ var process = configuration.SpawnCliProcess(command, args, environment, skipServerArg: disconnected);
+ LastRunProcess = process;
+ return process;
+ }
+
+ public async Task<(CaptiveProcess, string)> SpawnForwarderAsync(Dictionary? environment = null)
+ {
+ var forwarderApiListenUri = $"http://127.0.0.1:{configuration.AllocatePort()}";
+
+ var env = environment ?? new();
+ env.Add("SEQCLI_FORWARDER_API_LISTENURI", forwarderApiListenUri);
+
+ var forwarder = Spawn("forwarder run", $"--pre --storage=\"{testDataFolder.Path}\"", environment: env);
+
+ await WaitForForwarderConnectionAsync(forwarderApiListenUri);
+
+ return (forwarder, forwarderApiListenUri);
+ }
+
+
+ static async Task WaitForForwarderConnectionAsync(string forwarderApiListenUri)
+ {
+ using var httpClient = new HttpClient();
+ var ingestEndpoint = $"{forwarderApiListenUri}/ingest/clef";
+
+ using var cts = new CancellationTokenSource();
+ cts.CancelAfter(TimeSpan.FromSeconds(30));
+
+ while (true)
+ {
+ cts.Token.ThrowIfCancellationRequested();
+
+ var content = new StringContent("", new MediaTypeHeaderValue("application/vnd.serilog.clef", "utf-8"));
+
+ try
+ {
+ using var shortCts = CancellationTokenSource.CreateLinkedTokenSource(cts.Token);
+ shortCts.CancelAfter(TimeSpan.FromSeconds(1));
+
+ var ingestionResult = await httpClient.PostAsync(ingestEndpoint, content, shortCts.Token);
+ if (ingestionResult.IsSuccessStatusCode)
+ return;
+
+ Log.Information("Waiting for forwarder API to become available; last result {StatusCode}", ingestionResult.StatusCode);
+ }
+ catch (Exception ex)
+ {
+ // Back around the loop
+ Log.Information("Waiting for forwarder API to become available; the last request failed ({Message})", ex.Message);
+ }
+
+ await Task.Delay(1000, cts.Token);
+ }
+ }
+}
diff --git a/test/SeqCli.EndToEnd/Support/TestConfiguration.cs b/test/SeqCli.EndToEnd/Support/TestConfiguration.cs
index a95023d9..ddb37565 100644
--- a/test/SeqCli.EndToEnd/Support/TestConfiguration.cs
+++ b/test/SeqCli.EndToEnd/Support/TestConfiguration.cs
@@ -5,10 +5,20 @@
namespace SeqCli.EndToEnd.Support;
-public class TestConfiguration(Args args)
+public class TestConfiguration
{
static int _nextServerPort = 9989;
- readonly int _serverListenPort = Interlocked.Increment(ref _nextServerPort);
+
+ public int AllocatePort() => Interlocked.Increment(ref _nextServerPort);
+
+ readonly int _serverListenPort;
+ readonly Args _args;
+
+ public TestConfiguration(Args args)
+ {
+ _args = args;
+ _serverListenPort = AllocatePort();
+ }
#pragma warning disable CA1822
public string ServerListenUrl => $"http://localhost:{_serverListenPort}";
@@ -19,7 +29,7 @@ public class TestConfiguration(Args args)
public static string TestedBinary => Path.Combine(EquivalentBaseDirectory, "seqcli.dll");
- public bool IsMultiuser => args.Multiuser();
+ public bool IsMultiuser => _args.Multiuser();
public CaptiveProcess SpawnCliProcess(string command, string additionalArgs = null, Dictionary environment = null, bool skipServerArg = false, bool supplyInput = false)
{
@@ -37,10 +47,9 @@ public CaptiveProcess SpawnServerProcess(string storagePath)
if (storagePath == null) throw new ArgumentNullException(nameof(storagePath));
var commandWithArgs = $"run --listen=\"{ServerListenUrl}\" --storage=\"{storagePath}\"";
- if (args.UseDockerSeq(out var imageTag))
+ if (_args.UseDockerSeq(out var imageTag, out var containerRuntime))
{
var containerName = Guid.NewGuid().ToString("n");
- const string containerRuntime = "docker";
return new CaptiveProcess(containerRuntime, $"run --name {containerName} -d -e ACCEPT_EULA=Y -e SEQ_FIRSTRUN_NOAUTHENTICATION=True -p {_serverListenPort}:80 datalust/seq:{imageTag}", stopCommandFullExePath: containerRuntime, stopCommandArgs: $"rm -f {containerName}");
}
diff --git a/test/SeqCli.EndToEnd/Support/TestDataFolder.cs b/test/SeqCli.EndToEnd/Support/TestDataFolder.cs
index 262d1664..fd4e106e 100644
--- a/test/SeqCli.EndToEnd/Support/TestDataFolder.cs
+++ b/test/SeqCli.EndToEnd/Support/TestDataFolder.cs
@@ -1,7 +1,5 @@
using System;
using System.IO;
-using Serilog;
-using Serilog.Core;
namespace SeqCli.EndToEnd.Support;
diff --git a/test/SeqCli.EndToEnd/Support/TestDriver.cs b/test/SeqCli.EndToEnd/Support/TestDriver.cs
index 2d53b8b9..8f03a423 100644
--- a/test/SeqCli.EndToEnd/Support/TestDriver.cs
+++ b/test/SeqCli.EndToEnd/Support/TestDriver.cs
@@ -26,17 +26,18 @@ public async Task Run()
int count = 0, passedCount = 0, skippedCount = 0;
var failed = new List();
- foreach (var testCaseFactory in _cases.OrderBy(_ => Guid.NewGuid()))
+ await Parallel.ForEachAsync(_cases.OrderBy(_ => Guid.NewGuid()), async (testCaseFactory, _) =>
{
count++;
await using var testCase = testCaseFactory.Value();
-
+
Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine($"RUNNING {testCase.Value.Description,-50}");
Console.ResetColor();
- var isMultiuser = testCaseFactory.Metadata.TryGetValue("Multiuser", out var multiuser) && true.Equals(multiuser);
+ var isMultiuser = testCaseFactory.Metadata.TryGetValue("Multiuser", out var multiuser) &&
+ true.Equals(multiuser);
testCaseFactory.Metadata.TryGetValue("MinimumApiVersion", out var minSeqVersion);
if (isMultiuser != testCase.Value.Configuration.IsMultiuser || minSeqVersion != null &&
!await testCase.Value.IsSupportedApiVersion((string)minSeqVersion))
@@ -44,9 +45,9 @@ public async Task Run()
skippedCount++;
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("SKIP");
- continue;
+ return;
}
-
+
try
{
await testCase.Value.ExecuteTestCaseAsync();
@@ -66,7 +67,7 @@ public async Task Run()
Console.WriteLine(ex);
Console.ResetColor();
}
- }
+ });
var (color, failMsg) = failed.Count != 0 ? (ConsoleColor.Red, "Failures:") : (ConsoleColor.Green, "");
Console.ForegroundColor = color;
diff --git a/test/SeqCli.EndToEnd/User/UserListTestCase.cs b/test/SeqCli.EndToEnd/User/UserListTestCase.cs
index 948ab043..7444cac6 100644
--- a/test/SeqCli.EndToEnd/User/UserListTestCase.cs
+++ b/test/SeqCli.EndToEnd/User/UserListTestCase.cs
@@ -1,5 +1,4 @@
-using System;
-using System.Threading.Tasks;
+using System.Threading.Tasks;
using Seq.Api;
using SeqCli.EndToEnd.Support;
using Serilog;