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;