public static async Task Main(string[] args)
        {
            if (args.Length == 0)
            {
                args = new[] { "./.env" };
            }

            if (args.Length == 1)
            {
                args = ArgumentFileReader.Read(args[0])?.ToArray() ?? Array.Empty <string>();
            }

            var runArgs      = ParseAndPromptForArguments(args);
            var runDuration  = DefaultRunDuration;
            var errorLogPath = DefaultErrorLogPath;

            // If not provided or malformed, use the default.

            if ((!string.IsNullOrEmpty(runArgs.RunDurationHours)) && (int.TryParse(runArgs.RunDurationHours, out var hours)))
            {
                runDuration = TimeSpan.FromHours(hours);
            }

            if (!string.IsNullOrEmpty(runArgs.LogPath))
            {
                errorLogPath = runArgs.LogPath;
            }

            using var cancellationSource = new CancellationTokenSource();
            using var errorWriter        = new StreamWriter(File.Open(errorLogPath, FileMode.Create, FileAccess.Write, FileShare.Read));
            using var metricsWriter      = Console.Out;
            using var azureEventListener = ListenForEventSourceErrors(errorWriter);

            try
            {
                var message = $"{ Environment.NewLine }{ Environment.NewLine }=============================={ Environment.NewLine }  Run Starting{ Environment.NewLine }=============================={ Environment.NewLine }";
                metricsWriter.WriteLine(message);
                errorWriter.WriteLine(message);

                cancellationSource.CancelAfter(runDuration);

                var configuration = new TestConfiguration
                {
                    EventHubsConnectionString = runArgs.EventHubsConnectionString,
                    EventHub = runArgs.EventHub
                };

                var testRun     = new TestRun(configuration);
                var testRunTask = testRun.Start(cancellationSource.Token);

                // Make an initial metrics report now that the run is taking place.

                await(Task.Delay(TimeSpan.FromSeconds(1)));
                await ReportMetricsAsync(metricsWriter, testRun.Metrics, runDuration, configuration);

                // Allow the run to take place, periodically reporting.

                while (!cancellationSource.IsCancellationRequested)
                {
                    try
                    {
                        await Task.Delay(DefaultProcessReportInterval, cancellationSource.Token);
                    }
                    catch (TaskCanceledException)
                    {
                        message = $"{ Environment.NewLine }{ Environment.NewLine }--------------------------------------------------------------------------{ Environment.NewLine }  The run is ending.  Waiting for clean-up and final reporting...{ Environment.NewLine }--------------------------------------------------------------------------{ Environment.NewLine }";
                        metricsWriter.WriteLine(message);
                        errorWriter.WriteLine(message);
                    }

                    await Task.WhenAll
                    (
                        ReportMetricsAsync(metricsWriter, testRun.Metrics, runDuration, configuration),
                        ReportErrorsAsync(errorWriter, testRun.ErrorsObserved)
                    );
                }

                // Allow the run to complete and then perform a final pas on reporting
                // to ensure that any straggling operations are captures.

                await testRunTask;
                Interlocked.Exchange(ref testRun.Metrics.RunDurationMilliseconds, runDuration.TotalMilliseconds);

                await Task.WhenAll
                (
                    ReportMetricsAsync(metricsWriter, testRun.Metrics, runDuration, configuration),
                    ReportErrorsAsync(errorWriter, testRun.ErrorsObserved)
                );

                message = $"{ Environment.NewLine }{ Environment.NewLine }=============================={ Environment.NewLine }  Run Complete{ Environment.NewLine }==============================";
                metricsWriter.WriteLine(message);
                errorWriter.WriteLine(message);
            }
            catch (Exception ex) when
                (ex is OutOfMemoryException ||
                ex is StackOverflowException ||
                ex is ThreadAbortException)
            {
                Environment.FailFast(ex.Message);
            }
            catch (Exception ex)
            {
                var message = $"{ Environment.NewLine }{ Environment.NewLine }=============================={ Environment.NewLine }  Error in the main loop.  Run aborting.  Message: [{ ex.Message }]{ Environment.NewLine }==============================";
                metricsWriter.WriteLine(message);
                errorWriter.WriteLine(message);
            }
            finally
            {
                errorWriter.Close();
            }
        }
        private static Task ReportMetricsAsync(TextWriter writer,
                                               Metrics metrics,
                                               TimeSpan runDuration,
                                               TestConfiguration configuration)
        {
            long metric;

            var message = new StringBuilder();

            // Run time

            var runDurationMilliseconds = Interlocked.CompareExchange(ref metrics.RunDurationMilliseconds, 0.0, 0.0);
            var currentDuration         = TimeSpan.FromMilliseconds(runDurationMilliseconds > 0.0 ? runDurationMilliseconds : 1);
            var averageMemory           = metrics.TotalMemoryUsed / metrics.MemorySamples;

            message.AppendLine("Run Metrics");
            message.AppendLine("=========================");
            message.AppendLine($"\tRun Duration:\t\t\t{ runDuration.ToString(@"dd\.hh\:mm\:ss") }");
            message.AppendLine($"\tElapsed:\t\t\t{ currentDuration.ToString(@"dd\.hh\:mm\:ss") } ({ (currentDuration / runDuration).ToString("P", CultureInfo.InvariantCulture) })");
            message.AppendLine($"\tTotal Processor Time:\t\t{ metrics.TotalProcessorTime.ToString(@"dd\.hh\:mm\:ss") }");
            message.AppendLine($"\tAverage Memory Use:\t\t{ FormatBytes(averageMemory) }");
            message.AppendLine($"\tCurrent Memory Use:\t\t{ FormatBytes(metrics.MemoryUsed) }");
            message.AppendLine($"\tPeak Memory Use:\t\t{ FormatBytes(metrics.PeakPhysicalMemory) }");
            message.AppendLine($"\tGC Gen 0 Collections:\t\t{ metrics.GenerationZeroCollections.ToString("n0") }");
            message.AppendLine($"\tGC Gen 1 Collections:\t\t{ metrics.GenerationOneCollections.ToString("n0") }");
            message.AppendLine($"\tGC Gen 2 Collections:\t\t{ metrics.GenerationTwoCollections.ToString("n0") }");
            message.AppendLine($"\tNumber of Publishers:\t\t{ configuration.ProducerCount.ToString("n0") }");
            message.AppendLine($"\tConcurrent Sends per Publisher:\t{ configuration.ConcurrentSends.ToString("n0") }");
            message.AppendLine($"\tTarget Batch Size:\t\t{ configuration.PublishBatchSize.ToString("n0") } (events)");
            message.AppendLine($"\tMinimum Message Size:\t\t{ configuration.PublishingBodyMinBytes.ToString("n0") } (bytes)");
            message.AppendLine($"\tLarge Message Factor:\t\t{ configuration.LargeMessageRandomFactorPercent.ToString("P", CultureInfo.InvariantCulture) }");
            message.AppendLine();

            // Publish and read pairing

            message.AppendLine("Publishing");
            message.AppendLine("=========================");

            var publishAttempts = (double)Interlocked.Read(ref metrics.PublishAttempts);

            message.AppendLine($"\tSend Attempts:\t\t\t{ publishAttempts.ToString("n0") }");
            publishAttempts = (publishAttempts > 0) ? publishAttempts : 0.001;

            var batches = (double)Interlocked.Read(ref metrics.BatchesPublished);

            message.AppendLine($"\tBatches Published:\t\t{ batches.ToString("n0") } ({ (batches / publishAttempts).ToString("P", CultureInfo.InvariantCulture) })");
            batches = (batches > 0) ? batches : 0.001;

            metric = Interlocked.Read(ref metrics.EventsPublished);
            message.AppendLine($"\tEvents Published:\t\t{ metric.ToString("n0") }");
            message.AppendLine($"\tAverage Events per Batch:\t{ ( metric / batches).ToString("n0") }");

            metric = Interlocked.Read(ref metrics.TotalPublshedSizeBytes);
            message.AppendLine($"\tAverage Batch Size:\t\t{ FormatBytes((long)(metric / batches)) }");

            message.AppendLine();

            // Client health

            message.AppendLine("Client Health");
            message.AppendLine("=========================");

            metric = Interlocked.Read(ref metrics.ProducerRestarted);
            message.AppendLine($"\tProducer Restarts:\t\t{ metric }");

            var cancelledSends = Interlocked.Read(ref metrics.CanceledSendExceptions);

            message.AppendLine($"\tAborted Sends:\t\t\t{ cancelledSends }");

            message.AppendLine();

            // Exceptions

            message.AppendLine("Exception Breakdown");
            message.AppendLine("=========================");

            var totalExceptions = (double)Interlocked.Read(ref metrics.TotalExceptions);

            message.AppendLine($"\tExceptions for All Operations:\t{ totalExceptions.ToString("n0") } ({ (totalExceptions / publishAttempts).ToString("P", CultureInfo.InvariantCulture) })");
            totalExceptions = (totalExceptions > 0) ? totalExceptions : 0.001;

            metric = Interlocked.Read(ref metrics.SendExceptions);
            message.AppendLine($"\tException During Send:\t\t{ metric.ToString("n0") } ({ (metric / totalExceptions).ToString("P", CultureInfo.InvariantCulture) })");

            metric = Interlocked.Read(ref metrics.GeneralExceptions);
            message.AppendLine($"\tGeneral Exceptions:\t\t{ metric.ToString("n0") } ({ (metric / totalExceptions).ToString("P", CultureInfo.InvariantCulture) })");

            metric = Interlocked.Read(ref metrics.TimeoutExceptions);
            message.AppendLine($"\tTimeout Exceptions:\t\t{ metric.ToString("n0") } ({ (metric / totalExceptions).ToString("P", CultureInfo.InvariantCulture) })");

            message.AppendLine($"\tOperation Canceled Exceptions:\t{ cancelledSends.ToString("n0") } ({ (cancelledSends / totalExceptions).ToString("P", CultureInfo.InvariantCulture) })");

            metric = Interlocked.Read(ref metrics.CommunicationExceptions);
            message.AppendLine($"\tCommunication Exceptions:\t{ metric.ToString("n0") } ({ (metric / totalExceptions).ToString("P", CultureInfo.InvariantCulture) })");

            metric = Interlocked.Read(ref metrics.ServiceBusyExceptions);
            message.AppendLine($"\tService Busy Exceptions:\t{ metric.ToString("n0") } ({ (metric / totalExceptions).ToString("P", CultureInfo.InvariantCulture) })");

            // Spacing

            message.AppendLine();
            message.AppendLine();
            message.AppendLine();
            message.AppendLine();

            return(writer.WriteLineAsync(message.ToString()));
        }