From a47d8ec882b80ea0e74b49f1187bdc745ac1b32f Mon Sep 17 00:00:00 2001 From: Phil Bastian Date: Mon, 9 Jun 2025 14:53:17 +0800 Subject: [PATCH 01/56] convert audit loggers to ILogger --- src/Directory.Packages.props | 3 +- .../ServiceControlComponentRunner.cs | 2 +- .../Infrastructure/When_instance_is_setup.cs | 3 +- src/ServiceControl.Audit/App.config | 7 +-- .../Auditing/AuditIngestion.cs | 38 +++++++-------- .../Auditing/AuditIngestionFaultPolicy.cs | 22 +++++---- .../Auditing/AuditIngestor.cs | 14 +++--- .../Auditing/AuditPersister.cs | 47 +++++-------------- .../Auditing/FailedAuditImportCustomCheck.cs | 9 ++-- .../Auditing/ImportFailedAudits.cs | 21 ++++----- .../HostApplicationBuilderExtensions.cs | 15 +++--- .../Commands/ImportFailedAuditsCommand.cs | 8 ++-- .../Hosting/Commands/SetupCommand.cs | 8 ++-- .../Infrastructure/Settings/Settings.cs | 11 +++-- src/ServiceControl.Audit/Program.cs | 9 ++-- .../ServiceControl.Audit.csproj | 1 + .../WatchdogTests.cs | 4 +- .../LoggerUtil.cs | 29 ++++++++++++ .../ServiceControl.Infrastructure.csproj | 1 + src/ServiceControl.Infrastructure/Watchdog.cs | 20 ++++---- src/ServiceControl.Monitoring/App.config | 8 ++-- .../Recoverability/EditMessageTests.cs | 2 +- src/ServiceControl/App.config | 10 ++-- .../Operations/ErrorIngestion.cs | 32 ++++++------- src/ServiceControl/ServiceControl.csproj | 1 + .../UnattendServiceControlInstaller.cs | 1 + 26 files changed, 171 insertions(+), 155 deletions(-) create mode 100644 src/ServiceControl.Infrastructure/LoggerUtil.cs diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index f804f33b79..a8c9c56842 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -63,6 +63,7 @@ + @@ -91,4 +92,4 @@ - + \ No newline at end of file diff --git a/src/ServiceControl.Audit.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs b/src/ServiceControl.Audit.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs index 0866b504db..eb3bbaaf32 100644 --- a/src/ServiceControl.Audit.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs +++ b/src/ServiceControl.Audit.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs @@ -98,7 +98,7 @@ async Task InitializeServiceControl(ScenarioContext context) using (new DiagnosticTimer($"Creating infrastructure for {instanceName}")) { - var setupCommand = new SetupCommand(); + var setupCommand = new SetupCommand(LoggerUtil.CreateStaticLogger()); await setupCommand.Execute(new HostArguments([]), settings); } diff --git a/src/ServiceControl.Audit.UnitTests/Infrastructure/When_instance_is_setup.cs b/src/ServiceControl.Audit.UnitTests/Infrastructure/When_instance_is_setup.cs index f01c4595ea..1828bc21d5 100644 --- a/src/ServiceControl.Audit.UnitTests/Infrastructure/When_instance_is_setup.cs +++ b/src/ServiceControl.Audit.UnitTests/Infrastructure/When_instance_is_setup.cs @@ -12,6 +12,7 @@ using NServiceBus; using NServiceBus.Transport; using NUnit.Framework; + using ServiceControl.Infrastructure; using Transports; class When_instance_is_setup @@ -41,7 +42,7 @@ public async Task Should_provision_queues() AssemblyLoadContextResolver = static _ => AssemblyLoadContext.Default }; - var setupCommand = new SetupCommand(); + var setupCommand = new SetupCommand(LoggerUtil.CreateStaticLogger()); await setupCommand.Execute(new HostArguments([]), settings); Assert.That(FakeTransport.QueuesCreated, Is.EquivalentTo(new[] diff --git a/src/ServiceControl.Audit/App.config b/src/ServiceControl.Audit/App.config index 00a70ad0a2..a2c5ced58d 100644 --- a/src/ServiceControl.Audit/App.config +++ b/src/ServiceControl.Audit/App.config @@ -9,13 +9,13 @@ These settings are only here so that we can debug ServiceControl while developin - + - + @@ -27,7 +27,7 @@ These settings are only here so that we can debug ServiceControl while developin - + @@ -46,6 +46,7 @@ These settings are only here so that we can debug ServiceControl while developin + diff --git a/src/ServiceControl.Audit/Auditing/AuditIngestion.cs b/src/ServiceControl.Audit/Auditing/AuditIngestion.cs index e36f2036cb..182d7a4771 100644 --- a/src/ServiceControl.Audit/Auditing/AuditIngestion.cs +++ b/src/ServiceControl.Audit/Auditing/AuditIngestion.cs @@ -8,8 +8,8 @@ using Infrastructure.Settings; using Metrics; using Microsoft.Extensions.Hosting; + using Microsoft.Extensions.Logging; using NServiceBus; - using NServiceBus.Logging; using NServiceBus.Transport; using Persistence; using Persistence.UnitOfWork; @@ -27,7 +27,8 @@ public AuditIngestion( AuditIngestor auditIngestor, IAuditIngestionUnitOfWorkFactory unitOfWorkFactory, IHostApplicationLifetime applicationLifetime, - IngestionMetrics metrics + IngestionMetrics metrics, + ILogger logger ) { inputEndpoint = settings.AuditQueue; @@ -38,7 +39,7 @@ IngestionMetrics metrics this.settings = settings; this.applicationLifetime = applicationLifetime; this.metrics = metrics; - + this.logger = logger; if (!transportSettings.MaxConcurrency.HasValue) { throw new ArgumentException("MaxConcurrency is not set in TransportSettings"); @@ -54,7 +55,7 @@ IngestionMetrics metrics FullMode = BoundedChannelFullMode.Wait }); - errorHandlingPolicy = new AuditIngestionFaultPolicy(failedImportsStorage, settings.LoggingSettings, OnCriticalError, metrics); + errorHandlingPolicy = new AuditIngestionFaultPolicy(failedImportsStorage, settings.LoggingSettings, OnCriticalError, metrics, logger); watchdog = new Watchdog( "audit message ingestion", @@ -69,7 +70,7 @@ IngestionMetrics metrics Task OnCriticalError(string failure, Exception exception) { - logger.Fatal($"OnCriticalError. '{failure}'", exception); + logger.LogCritical(exception, "OnCriticalError. '{failure}'", failure); return watchdog.OnFailure(failure); } @@ -81,7 +82,7 @@ async Task EnsureStarted(CancellationToken cancellationToken) var canIngest = unitOfWorkFactory.CanIngestMore(); - logger.DebugFormat("Ensure started {0}", canIngest); + logger.LogDebug("Ensure started {canIngest}", canIngest); if (canIngest) { @@ -115,13 +116,13 @@ async Task SetUpAndStartInfrastructure(CancellationToken cancellationToken) { if (messageReceiver != null) { - logger.Debug("Infrastructure already Started"); + logger.LogDebug("Infrastructure already Started"); return; } try { - logger.Info("Starting infrastructure"); + logger.LogInformation("Starting infrastructure"); transportInfrastructure = await transportCustomization.CreateTransportInfrastructure( inputEndpoint, transportSettings, @@ -136,11 +137,11 @@ async Task SetUpAndStartInfrastructure(CancellationToken cancellationToken) await auditIngestor.VerifyCanReachForwardingAddress(cancellationToken); await messageReceiver.StartReceive(cancellationToken); - logger.Info(LogMessages.StartedInfrastructure); + logger.LogInformation(LogMessages.StartedInfrastructure); } catch (Exception e) { - logger.Error("Failed to start infrastructure", e); + logger.LogError(e, "Failed to start infrastructure"); throw; } } @@ -149,13 +150,13 @@ async Task StopAndTeardownInfrastructure(CancellationToken cancellationToken) { if (transportInfrastructure == null) { - logger.Debug("Infrastructure already Stopped"); + logger.LogDebug("Infrastructure already Stopped"); return; } try { - logger.Info("Stopping infrastructure"); + logger.LogInformation("Stopping infrastructure"); try { if (messageReceiver != null) @@ -171,11 +172,11 @@ async Task StopAndTeardownInfrastructure(CancellationToken cancellationToken) messageReceiver = null; transportInfrastructure = null; - logger.Info(LogMessages.StoppedInfrastructure); + logger.LogInformation(LogMessages.StoppedInfrastructure); } catch (Exception e) { - logger.Error("Failed to stop infrastructure", e); + logger.LogError(e, "Failed to stop infrastructure"); throw; } } @@ -254,11 +255,11 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) if (e is OperationCanceledException && stoppingToken.IsCancellationRequested) { - logger.Info("Batch cancelled", e); + logger.LogInformation(e, "Batch cancelled"); break; } - logger.Info("Ingesting messages failed", e); + logger.LogInformation(e, "Ingesting messages failed"); } finally { @@ -291,7 +292,7 @@ public override async Task StopAsync(CancellationToken cancellationToken) } catch (OperationCanceledException e) when (cancellationToken.IsCancellationRequested) { - logger.Info("Shutdown cancelled", e); + logger.LogInformation(e, "Shutdown cancelled"); } } } @@ -313,8 +314,7 @@ public override async Task StopAsync(CancellationToken cancellationToken) readonly Watchdog watchdog; readonly IHostApplicationLifetime applicationLifetime; readonly IngestionMetrics metrics; - - static readonly ILog logger = LogManager.GetLogger(); + readonly ILogger logger; internal static class LogMessages { diff --git a/src/ServiceControl.Audit/Auditing/AuditIngestionFaultPolicy.cs b/src/ServiceControl.Audit/Auditing/AuditIngestionFaultPolicy.cs index 6ccfbedcce..02c55db1a9 100644 --- a/src/ServiceControl.Audit/Auditing/AuditIngestionFaultPolicy.cs +++ b/src/ServiceControl.Audit/Auditing/AuditIngestionFaultPolicy.cs @@ -7,21 +7,27 @@ using System.Runtime.Versioning; using System.Threading; using System.Threading.Tasks; +using Configuration; using Infrastructure; -using NServiceBus.Logging; +using Metrics; +using Microsoft.Extensions.Logging; using NServiceBus.Transport; using Persistence; -using Configuration; -using Metrics; using ServiceControl.Infrastructure; class AuditIngestionFaultPolicy { - public AuditIngestionFaultPolicy(IFailedAuditStorage failedAuditStorage, LoggingSettings settings, Func onCriticalError, IngestionMetrics metrics) + public AuditIngestionFaultPolicy( + IFailedAuditStorage failedAuditStorage, + LoggingSettings settings, + Func onCriticalError, + IngestionMetrics metrics, + ILogger logger) { failureCircuitBreaker = new ImportFailureCircuitBreaker(onCriticalError); this.failedAuditStorage = failedAuditStorage; this.metrics = metrics; + this.logger = logger; if (!AppEnvironment.RunningInContainer) { @@ -75,7 +81,7 @@ async Task StoreFailedMessageDocument(ErrorContext errorContext, CancellationTok async Task DoLogging(Exception exception, FailedAuditImport failure, CancellationToken cancellationToken) { - log.Error("Failed importing error message", exception); + logger.LogError(exception, "Failed importing error message"); // Write to storage await failedAuditStorage.SaveFailedAuditImport(failure); @@ -83,12 +89,12 @@ async Task DoLogging(Exception exception, FailedAuditImport failure, Cancellatio if (!AppEnvironment.RunningInContainer) { // Write to Log Path - var filePath = Path.Combine(logPath, failure.Id + ".txt"); + var filePath = Path.Combine(logPath, $"{failure.Id}.txt"); await File.WriteAllTextAsync(filePath, failure.ExceptionInfo, cancellationToken); if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - WriteToEventLog("A message import has failed. A log file has been written to " + filePath); + WriteToEventLog($"A message import has failed. A log file has been written to {filePath}"); } } } @@ -107,5 +113,5 @@ void WriteToEventLog(string message) readonly string logPath; readonly ImportFailureCircuitBreaker failureCircuitBreaker; - static readonly ILog log = LogManager.GetLogger(); + readonly ILogger logger; } \ No newline at end of file diff --git a/src/ServiceControl.Audit/Auditing/AuditIngestor.cs b/src/ServiceControl.Audit/Auditing/AuditIngestor.cs index bf48d23e96..af5bbdac58 100644 --- a/src/ServiceControl.Audit/Auditing/AuditIngestor.cs +++ b/src/ServiceControl.Audit/Auditing/AuditIngestor.cs @@ -6,9 +6,9 @@ using System.Threading; using System.Threading.Tasks; using Infrastructure.Settings; + using Microsoft.Extensions.Logging; using Monitoring; using NServiceBus; - using NServiceBus.Logging; using NServiceBus.Routing; using NServiceBus.Transport; using Persistence.UnitOfWork; @@ -25,12 +25,13 @@ public AuditIngestor( IEnumerable auditEnrichers, // allows extending message enrichers with custom enrichers registered in the DI container IMessageSession messageSession, Lazy messageDispatcher, - ITransportCustomization transportCustomization + ITransportCustomization transportCustomization, + ILogger logger ) { this.settings = settings; this.messageDispatcher = messageDispatcher; - + this.logger = logger; var enrichers = new IEnrichImportedAuditMessages[] { new MessageTypeEnricher(), new EnrichWithTrackingIds(), new ProcessingStatisticsEnricher(), new DetectNewEndpointsFromAuditImportsEnricher(endpointInstanceMonitoring), new DetectSuccessfulRetriesEnricher(), new SagaRelationshipsEnricher() }.Concat(auditEnrichers).ToArray(); logQueueAddress = transportCustomization.ToTransportQualifiedQueueName(settings.AuditLogQueue); @@ -39,7 +40,8 @@ ITransportCustomization transportCustomization unitOfWorkFactory, enrichers, messageSession, - messageDispatcher + messageDispatcher, + logger ); } @@ -61,7 +63,7 @@ public async Task Ingest(List contexts, CancellationToken cancel } catch (Exception e) { - Log.Warn("Forwarding messages failed", e); + logger.LogWarning(e, "Forwarding messages failed"); // making sure to rethrow so that all messages get marked as failed throw; @@ -129,6 +131,6 @@ public async Task VerifyCanReachForwardingAddress(CancellationToken cancellation readonly Lazy messageDispatcher; readonly string logQueueAddress; - static readonly ILog Log = LogManager.GetLogger(); + readonly ILogger logger; } } \ No newline at end of file diff --git a/src/ServiceControl.Audit/Auditing/AuditPersister.cs b/src/ServiceControl.Audit/Auditing/AuditPersister.cs index e50f18b086..3677f2e7b4 100644 --- a/src/ServiceControl.Audit/Auditing/AuditPersister.cs +++ b/src/ServiceControl.Audit/Auditing/AuditPersister.cs @@ -6,9 +6,9 @@ using System.Threading; using System.Threading.Tasks; using Infrastructure; + using Microsoft.Extensions.Logging; using Monitoring; using NServiceBus; - using NServiceBus.Logging; using NServiceBus.Transport; using Persistence.UnitOfWork; using ServiceControl.Audit.Persistence.Infrastructure; @@ -20,7 +20,8 @@ class AuditPersister(IAuditIngestionUnitOfWorkFactory unitOfWorkFactory, IEnrichImportedAuditMessages[] enrichers, IMessageSession messageSession, - Lazy messageDispatcher) + Lazy messageDispatcher, + ILogger logger) { public async Task> Persist(IReadOnlyList contexts, CancellationToken cancellationToken) { @@ -72,20 +73,14 @@ public async Task> Persist(IReadOnlyList> Persist(IReadOnlyList> Persist(IReadOnlyList(metadata)); - if (Logger.IsDebugEnabled) - { - Logger.Debug($"Emitting {commandsToEmit.Count} commands and {messagesToEmit.Count} control messages."); - } + logger.LogDebug("Emitting {commandsToEmitCount} commands and {messagesToEmitCount} control messages.", commandsToEmit.Count, messagesToEmit.Count); foreach (var commandToEmit in commandsToEmit) { @@ -215,10 +198,7 @@ async Task ProcessAuditMessage(MessageContext context) await messageDispatcher.Value.Dispatch(new TransportOperations(messagesToEmit.ToArray()), new TransportTransaction()); //Do not hook into the incoming transaction - if (Logger.IsDebugEnabled) - { - Logger.Debug($"{commandsToEmit.Count} commands and {messagesToEmit.Count} control messages emitted."); - } + logger.LogDebug("{commandsToEmitCount} commands and {messagesToEmitCount} control messages emitted.", commandsToEmit.Count, messagesToEmit.Count); if (metadata.TryGetValue("SendingEndpoint", out var sendingEndpoint)) { @@ -235,16 +215,11 @@ await messageDispatcher.Value.Dispatch(new TransportOperations(messagesToEmit.To } catch (Exception e) { - if (Logger.IsWarnEnabled) - { - Logger.Warn($"Processing of message '{messageId}' failed.", e); - } + logger.LogWarning(e, "Processing of message '{messageId}' failed.", messageId); // releasing the failed message context early so that they can be retried outside the current batch context.GetTaskCompletionSource().TrySetException(e); } } - - static readonly ILog Logger = LogManager.GetLogger(); } } \ No newline at end of file diff --git a/src/ServiceControl.Audit/Auditing/FailedAuditImportCustomCheck.cs b/src/ServiceControl.Audit/Auditing/FailedAuditImportCustomCheck.cs index 8a914d9cd0..9f0190a051 100644 --- a/src/ServiceControl.Audit/Auditing/FailedAuditImportCustomCheck.cs +++ b/src/ServiceControl.Audit/Auditing/FailedAuditImportCustomCheck.cs @@ -3,16 +3,17 @@ namespace ServiceControl.Audit.Auditing using System; using System.Threading; using System.Threading.Tasks; + using Microsoft.Extensions.Logging; using NServiceBus.CustomChecks; - using NServiceBus.Logging; using ServiceControl.Audit.Persistence; class FailedAuditImportCustomCheck : CustomCheck { - public FailedAuditImportCustomCheck(IFailedAuditStorage store) + public FailedAuditImportCustomCheck(IFailedAuditStorage store, ILogger logger) : base("Audit Message Ingestion", "ServiceControl.Audit Health", TimeSpan.FromHours(1)) { this.store = store; + this.logger = logger; } public override async Task PerformCheck(CancellationToken cancellationToken = default) @@ -20,7 +21,7 @@ public override async Task PerformCheck(CancellationToken cancellat var count = await store.GetFailedAuditsCount(); if (count > 0) { - Logger.Warn(message); + logger.LogWarning(message); return CheckResult.Failed(message); } @@ -32,6 +33,6 @@ public override async Task PerformCheck(CancellationToken cancellat const string message = @"One or more audit messages have failed to import properly into ServiceControl.Audit and have been stored in the ServiceControl.Audit database. The import of these messages could have failed for a number of reasons and ServiceControl.Audit is not able to automatically reimport them. For guidance on how to resolve this see https://docs.particular.net/servicecontrol/import-failed-messages"; - static readonly ILog Logger = LogManager.GetLogger(typeof(FailedAuditImportCustomCheck)); + readonly ILogger logger; } } \ No newline at end of file diff --git a/src/ServiceControl.Audit/Auditing/ImportFailedAudits.cs b/src/ServiceControl.Audit/Auditing/ImportFailedAudits.cs index ee0f0dd6ef..070bdee325 100644 --- a/src/ServiceControl.Audit/Auditing/ImportFailedAudits.cs +++ b/src/ServiceControl.Audit/Auditing/ImportFailedAudits.cs @@ -4,8 +4,8 @@ namespace ServiceControl.Audit.Auditing using System.Threading; using System.Threading.Tasks; using Infrastructure.Settings; + using Microsoft.Extensions.Logging; using NServiceBus.Extensibility; - using NServiceBus.Logging; using NServiceBus.Transport; using Persistence; @@ -14,11 +14,13 @@ public class ImportFailedAudits public ImportFailedAudits( IFailedAuditStorage failedAuditStore, AuditIngestor auditIngestor, - Settings settings) + Settings settings, + ILogger logger) { this.settings = settings; this.failedAuditStore = failedAuditStore; this.auditIngestor = auditIngestor; + this.logger = logger; } public async Task Run(CancellationToken cancellationToken = default) @@ -50,37 +52,34 @@ await failedAuditStore.ProcessFailedMessages( await markComplete(token); succeeded++; - if (Logger.IsDebugEnabled) - { - Logger.Debug($"Successfully re-imported failed audit message {transportMessage.Id}."); - } + logger.LogDebug("Successfully re-imported failed audit message {transportMessageId}.", transportMessage.Id); } catch (OperationCanceledException e) when (token.IsCancellationRequested) { - Logger.Info("Cancelled", e); + logger.LogInformation(e, "Cancelled"); } catch (Exception e) { - Logger.Error($"Error while attempting to re-import failed audit message {transportMessage.Id}.", e); + logger.LogError(e, "Error while attempting to re-import failed audit message {transportMessageId}.", transportMessage.Id); failed++; } }, cancellationToken); - Logger.Info($"Done re-importing failed audits. Successfully re-imported {succeeded} messages. Failed re-importing {failed} messages."); + logger.LogInformation("Done re-importing failed audits. Successfully re-imported {succeeded} messages. Failed re-importing {failed} messages.", succeeded, failed); if (failed > 0) { - Logger.Warn($"{failed} messages could not be re-imported. This could indicate a problem with the data. Contact Particular support if you need help with recovering the messages."); + logger.LogWarning("{failed} messages could not be re-imported. This could indicate a problem with the data. Contact Particular support if you need help with recovering the messages.", failed); } } readonly IFailedAuditStorage failedAuditStore; readonly AuditIngestor auditIngestor; readonly Settings settings; + readonly ILogger logger; static readonly TransportTransaction EmptyTransaction = new TransportTransaction(); static readonly ContextBag EmptyContextBag = new ContextBag(); - static readonly ILog Logger = LogManager.GetLogger(typeof(ImportFailedAudits)); } } \ No newline at end of file diff --git a/src/ServiceControl.Audit/HostApplicationBuilderExtensions.cs b/src/ServiceControl.Audit/HostApplicationBuilderExtensions.cs index ccacf5db1c..6c05cac611 100644 --- a/src/ServiceControl.Audit/HostApplicationBuilderExtensions.cs +++ b/src/ServiceControl.Audit/HostApplicationBuilderExtensions.cs @@ -15,15 +15,14 @@ namespace ServiceControl.Audit; using Microsoft.Extensions.Hosting.WindowsServices; using Microsoft.Extensions.Logging; using Monitoring; -using NLog.Extensions.Logging; using NServiceBus; using NServiceBus.Configuration.AdvancedExtensibility; -using NServiceBus.Logging; using NServiceBus.Transport; using Persistence; using Transports; using OpenTelemetry.Metrics; using OpenTelemetry.Resources; +using ServiceControl.Infrastructure; static class HostApplicationBuilderExtensions { @@ -40,8 +39,7 @@ public static void AddServiceControlAudit(this IHostApplicationBuilder builder, RecordStartup(settings, configuration, persistenceConfiguration); builder.Logging.ClearProviders(); - builder.Logging.AddNLog(); - builder.Logging.SetMinimumLevel(settings.LoggingSettings.ToHostLogLevel()); + builder.Logging.BuildLogger(settings.LoggingSettings.ToHostLogLevel()); var services = builder.Services; var transportSettings = settings.ToTransportSettings(); @@ -120,8 +118,8 @@ public static void AddMetrics(this IHostApplicationBuilder builder, Settings set } }); - var logger = LogManager.GetLogger(typeof(HostApplicationBuilderExtensions)); - logger.InfoFormat("OpenTelemetry metrics exporter enabled: {0}", settings.OtlpEndpointUrl); + var logger = LoggerUtil.CreateStaticLogger(typeof(HostApplicationBuilderExtensions), settings.LoggingSettings.ToHostLogLevel()); + logger.LogInformation("OpenTelemetry metrics exporter enabled: {OtlpEndpointUrl}", settings.OtlpEndpointUrl); } } @@ -138,8 +136,9 @@ static void RecordStartup(Settings settings, EndpointConfiguration endpointConfi Persistence: {persistenceConfiguration.Name} -------------------------------------------------------------"; - var logger = LogManager.GetLogger(typeof(HostApplicationBuilderExtensions)); - logger.Info(startupMessage); + var logger = LoggerUtil.CreateStaticLogger(typeof(HostApplicationBuilderExtensions), settings.LoggingSettings.ToHostLogLevel()); + logger.LogInformation(startupMessage); endpointConfiguration.GetSettings().AddStartupDiagnosticsSection("Startup", new { Settings = settings }); } + } \ No newline at end of file diff --git a/src/ServiceControl.Audit/Infrastructure/Hosting/Commands/ImportFailedAuditsCommand.cs b/src/ServiceControl.Audit/Infrastructure/Hosting/Commands/ImportFailedAuditsCommand.cs index 3ddc7ef055..a4d65b2c85 100644 --- a/src/ServiceControl.Audit/Infrastructure/Hosting/Commands/ImportFailedAuditsCommand.cs +++ b/src/ServiceControl.Audit/Infrastructure/Hosting/Commands/ImportFailedAuditsCommand.cs @@ -6,14 +6,12 @@ using Auditing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; + using Microsoft.Extensions.Logging; using NServiceBus; - using NServiceBus.Logging; using Settings; - class ImportFailedAuditsCommand : AbstractCommand + class ImportFailedAuditsCommand(ILogger logger) : AbstractCommand { - readonly ILog logger = LogManager.GetLogger(); - public override async Task Execute(HostArguments args, Settings settings) { settings.IngestAuditMessages = false; @@ -42,7 +40,7 @@ public override async Task Execute(HostArguments args, Settings settings) } catch (OperationCanceledException e) when (tokenSource.IsCancellationRequested) { - logger.Info("Cancelled", e); + logger.LogInformation(e, "Cancelled"); } finally { diff --git a/src/ServiceControl.Audit/Infrastructure/Hosting/Commands/SetupCommand.cs b/src/ServiceControl.Audit/Infrastructure/Hosting/Commands/SetupCommand.cs index 2f03b767a8..d48c01be03 100644 --- a/src/ServiceControl.Audit/Infrastructure/Hosting/Commands/SetupCommand.cs +++ b/src/ServiceControl.Audit/Infrastructure/Hosting/Commands/SetupCommand.cs @@ -4,11 +4,11 @@ using System.Runtime.InteropServices; using System.Threading.Tasks; using Microsoft.Extensions.Hosting; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using Settings; using Transports; - class SetupCommand : AbstractCommand + class SetupCommand(ILogger logger) : AbstractCommand { public override async Task Execute(HostArguments args, Settings settings) { @@ -16,7 +16,7 @@ public override async Task Execute(HostArguments args, Settings settings) { if (args.SkipQueueCreation) { - Logger.Info("Skipping queue creation"); + logger.LogInformation("Skipping queue creation"); } else { @@ -47,7 +47,5 @@ public override async Task Execute(HostArguments args, Settings settings) await host.StartAsync(); await host.StopAsync(); } - - static readonly ILog Logger = LogManager.GetLogger(); } } \ No newline at end of file diff --git a/src/ServiceControl.Audit/Infrastructure/Settings/Settings.cs b/src/ServiceControl.Audit/Infrastructure/Settings/Settings.cs index b5488c36a1..4bd0352edb 100644 --- a/src/ServiceControl.Audit/Infrastructure/Settings/Settings.cs +++ b/src/ServiceControl.Audit/Infrastructure/Settings/Settings.cs @@ -5,8 +5,8 @@ using System.Runtime.Loader; using System.Text.Json.Serialization; using Configuration; + using Microsoft.Extensions.Logging; using NLog.Common; - using NServiceBus.Logging; using NServiceBus.Transport; using ServiceControl.Infrastructure; using Transports; @@ -75,14 +75,14 @@ void LoadAuditQueueInformation() if (IngestAuditMessages == false) { - logger.Info("Audit ingestion disabled."); + logger.LogInformation("Audit ingestion disabled."); } AuditLogQueue = SettingsReader.Read(serviceBusRootNamespace, "AuditLogQueue", null); if (AuditLogQueue == null) { - logger.Info("No settings found for audit log queue to import, default name will be used"); + logger.LogInformation("No settings found for audit log queue to import, default name will be used"); AuditLogQueue = Subscope(AuditQueue); } } @@ -141,7 +141,7 @@ public int MaxBodySizeToStore { if (maxBodySizeToStore <= 0) { - logger.Error($"MaxBodySizeToStore settings is invalid, {1} is the minimum value. Defaulting to {MaxBodySizeToStoreDefault}"); + logger.LogError("MaxBodySizeToStore settings is invalid, 1 is the minimum value. Defaulting to {MaxBodySizeToStoreDefault}", MaxBodySizeToStoreDefault); return MaxBodySizeToStoreDefault; } @@ -266,6 +266,7 @@ TimeSpan GetAuditRetentionPeriod() else { message = "AuditRetentionPeriod settings is invalid, please make sure it is a TimeSpan."; + //TODO: should these InternalLoggers (NLog) be replaced? InternalLogger.Fatal(message); throw new Exception(message); } @@ -288,7 +289,7 @@ static string Subscope(string address) } // logger is intentionally not static to prevent it from being initialized before LoggingConfigurator.ConfigureLogging has been called - readonly ILog logger = LogManager.GetLogger(typeof(Settings)); + readonly ILogger logger = LoggerUtil.CreateStaticLogger(); int maxBodySizeToStore = SettingsReader.Read(SettingsRootNamespace, "MaxBodySizeToStore", MaxBodySizeToStoreDefault); diff --git a/src/ServiceControl.Audit/Program.cs b/src/ServiceControl.Audit/Program.cs index 1d9e094d8f..19e1989234 100644 --- a/src/ServiceControl.Audit/Program.cs +++ b/src/ServiceControl.Audit/Program.cs @@ -1,15 +1,16 @@ using System; using System.Reflection; -using NServiceBus.Logging; +using Microsoft.Extensions.Logging; using ServiceControl.Audit.Infrastructure.Hosting; using ServiceControl.Audit.Infrastructure.Hosting.Commands; using ServiceControl.Audit.Infrastructure.Settings; using ServiceControl.Configuration; using ServiceControl.Infrastructure; +var logger = LoggerUtil.CreateStaticLogger(typeof(Program)); try { - AppDomain.CurrentDomain.UnhandledException += (s, e) => LogManager.GetLogger(typeof(Program)).Error("Unhandled exception was caught.", e.ExceptionObject as Exception); + AppDomain.CurrentDomain.UnhandledException += (s, e) => logger.LogError(e.ExceptionObject as Exception, "Unhandled exception was caught."); // Hack: See https://github.com/Particular/ServiceControl/issues/4392 var exitCode = await IntegratedSetup.Run(); @@ -40,12 +41,12 @@ } catch (Exception ex) { - NLog.LogManager.GetCurrentClassLogger().Fatal(ex, "Unrecoverable error"); + logger.LogCritical(ex, "Unrecoverable error"); throw; } finally { // The following log statement is meant to leave a trail in the logs to determine if the process was killed - NLog.LogManager.GetCurrentClassLogger().Info("Shutdown complete"); + logger.LogInformation("Shutdown complete"); NLog.LogManager.Shutdown(); } \ No newline at end of file diff --git a/src/ServiceControl.Audit/ServiceControl.Audit.csproj b/src/ServiceControl.Audit/ServiceControl.Audit.csproj index ba7d5110d5..7ea57b06f7 100644 --- a/src/ServiceControl.Audit/ServiceControl.Audit.csproj +++ b/src/ServiceControl.Audit/ServiceControl.Audit.csproj @@ -32,6 +32,7 @@ + diff --git a/src/ServiceControl.Infrastructure.Tests/WatchdogTests.cs b/src/ServiceControl.Infrastructure.Tests/WatchdogTests.cs index 3a430ecc72..ea786ed314 100644 --- a/src/ServiceControl.Infrastructure.Tests/WatchdogTests.cs +++ b/src/ServiceControl.Infrastructure.Tests/WatchdogTests.cs @@ -3,14 +3,14 @@ using System; using System.Threading; using System.Threading.Tasks; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using NUnit.Framework; using ServiceControl.Infrastructure; [TestFixture] public class WatchdogTests { - static ILog log = LogManager.GetLogger(); + static ILogger log = LoggerUtil.CreateStaticLogger(); [Test] public async Task It_shuts_down_gracefully() diff --git a/src/ServiceControl.Infrastructure/LoggerUtil.cs b/src/ServiceControl.Infrastructure/LoggerUtil.cs new file mode 100644 index 0000000000..039d0b4938 --- /dev/null +++ b/src/ServiceControl.Infrastructure/LoggerUtil.cs @@ -0,0 +1,29 @@ +namespace ServiceControl.Infrastructure +{ + using System; + using Microsoft.Extensions.Logging; + using NLog.Extensions.Logging; + + public static class LoggerUtil + { + public static void BuildLogger(this ILoggingBuilder loggingBuilder, LogLevel level) + { + //TODO: can we get these from settings too? + loggingBuilder.AddNLog(); + loggingBuilder.AddSeq(); + loggingBuilder.SetMinimumLevel(level); + } + + public static ILogger CreateStaticLogger(LogLevel level = LogLevel.Information) + { + var factory = LoggerFactory.Create(configure => configure.BuildLogger(level)); + return factory.CreateLogger(); + } + + public static ILogger CreateStaticLogger(Type type, LogLevel level = LogLevel.Information) + { + var factory = LoggerFactory.Create(configure => configure.BuildLogger(level)); + return factory.CreateLogger(type); + } + } +} \ No newline at end of file diff --git a/src/ServiceControl.Infrastructure/ServiceControl.Infrastructure.csproj b/src/ServiceControl.Infrastructure/ServiceControl.Infrastructure.csproj index ea352f1711..123180a850 100644 --- a/src/ServiceControl.Infrastructure/ServiceControl.Infrastructure.csproj +++ b/src/ServiceControl.Infrastructure/ServiceControl.Infrastructure.csproj @@ -12,6 +12,7 @@ + \ No newline at end of file diff --git a/src/ServiceControl.Infrastructure/Watchdog.cs b/src/ServiceControl.Infrastructure/Watchdog.cs index 56d111cf78..8c397c3a9e 100644 --- a/src/ServiceControl.Infrastructure/Watchdog.cs +++ b/src/ServiceControl.Infrastructure/Watchdog.cs @@ -3,7 +3,7 @@ using System; using System.Threading; using System.Threading.Tasks; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; public class Watchdog { @@ -14,7 +14,7 @@ public class Watchdog Task watchdog; CancellationTokenSource shutdownTokenSource = new(); TimeSpan timeToWaitBetweenStartupAttempts; - ILog log; + ILogger log; string taskName; public Watchdog( @@ -23,7 +23,7 @@ public Watchdog( Func ensureStopped, Action reportFailure, Action clearFailure, TimeSpan timeToWaitBetweenStartupAttempts, - ILog log + ILogger log ) { this.taskName = taskName; @@ -45,7 +45,7 @@ public Task Start(Action onFailedOnStartup, CancellationToken cancellationToken) { watchdog = Task.Run(async () => { - log.Debug($"Starting watching {taskName}"); + log.LogDebug("Starting watching {taskName}", taskName); bool startup = true; @@ -60,14 +60,14 @@ public Task Start(Action onFailedOnStartup, CancellationToken cancellationToken) using var cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(shutdownTokenSource.Token); cancellationTokenSource.CancelAfter(MaxStartDurationMs); - log.Debug($"Ensuring {taskName} is running"); + log.LogDebug("Ensuring {taskName} is running", taskName); await ensureStarted(cancellationTokenSource.Token).ConfigureAwait(false); clearFailure(); startup = false; } catch (OperationCanceledException e) when (shutdownTokenSource.IsCancellationRequested) { - log.Debug("Cancelled", e); + log.LogDebug(e, "Cancelled"); return; } catch (Exception e) @@ -76,12 +76,12 @@ public Task Start(Action onFailedOnStartup, CancellationToken cancellationToken) if (startup) { - log.Error($"Error during initial startup attempt for {taskName}.", e); + log.LogError(e, "Error during initial startup attempt for {taskName}.", taskName); onFailedOnStartup(); return; } - log.Error($"Error while trying to start {taskName}. Starting will be retried in {timeToWaitBetweenStartupAttempts}.", e); + log.LogError(e, "Error while trying to start {taskName}. Starting will be retried in {timeToWaitBetweenStartupAttempts}.", taskName, timeToWaitBetweenStartupAttempts); } try { @@ -101,13 +101,13 @@ public async Task Stop(CancellationToken cancellationToken) { try { - log.Debug($"Stopping watching process {taskName}"); + log.LogDebug("Starting watching {taskName}", taskName); await shutdownTokenSource.CancelAsync().ConfigureAwait(false); await watchdog.ConfigureAwait(false); } catch (Exception e) { - log.Error($"Error while trying to stop {taskName}.", e); + log.LogError(e, "Ensuring {taskName} is running", taskName); throw; } finally diff --git a/src/ServiceControl.Monitoring/App.config b/src/ServiceControl.Monitoring/App.config index 8ce3bdf576..4268a45f09 100644 --- a/src/ServiceControl.Monitoring/App.config +++ b/src/ServiceControl.Monitoring/App.config @@ -10,13 +10,13 @@ These settings are only here so that we can debug ServiceControl while developin - + - + @@ -25,7 +25,7 @@ These settings are only here so that we can debug ServiceControl while developin - + @@ -43,7 +43,7 @@ These settings are only here so that we can debug ServiceControl while developin - + diff --git a/src/ServiceControl.Persistence.Tests/Recoverability/EditMessageTests.cs b/src/ServiceControl.Persistence.Tests/Recoverability/EditMessageTests.cs index 9a4f74c807..f28c43a214 100644 --- a/src/ServiceControl.Persistence.Tests/Recoverability/EditMessageTests.cs +++ b/src/ServiceControl.Persistence.Tests/Recoverability/EditMessageTests.cs @@ -28,7 +28,7 @@ sealed class EditMessageTests : PersistenceTestBase public EditMessageTests() => RegisterServices = services => services .AddSingleton(dispatcher) - .AddSingleton(errorQueueNameCache) + .AddSingleton(errorQueueNameCache) .AddTransient(); [SetUp] diff --git a/src/ServiceControl/App.config b/src/ServiceControl/App.config index a99b7b9afe..56ca406180 100644 --- a/src/ServiceControl/App.config +++ b/src/ServiceControl/App.config @@ -13,13 +13,13 @@ These settings are only here so that we can debug ServiceControl while developin - + - + @@ -29,7 +29,7 @@ These settings are only here so that we can debug ServiceControl while developin - + @@ -46,8 +46,8 @@ These settings are only here so that we can debug ServiceControl while developin - - + + diff --git a/src/ServiceControl/Operations/ErrorIngestion.cs b/src/ServiceControl/Operations/ErrorIngestion.cs index 5f0ed7f4ee..8ea52094dc 100644 --- a/src/ServiceControl/Operations/ErrorIngestion.cs +++ b/src/ServiceControl/Operations/ErrorIngestion.cs @@ -9,8 +9,8 @@ using Infrastructure; using Infrastructure.Metrics; using Microsoft.Extensions.Hosting; + using Microsoft.Extensions.Logging; using NServiceBus; - using NServiceBus.Logging; using NServiceBus.Transport; using Persistence; using Persistence.UnitOfWork; @@ -66,7 +66,7 @@ public ErrorIngestion( ingestionState.ReportError, ingestionState.Clear, settings.TimeToRestartErrorIngestionAfterFailure, - Logger + logger ); } @@ -109,11 +109,11 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) if (e is OperationCanceledException && stoppingToken.IsCancellationRequested) { - Logger.Info("Batch cancelled", e); + logger.LogInformation(e, "Batch cancelled"); break; } - Logger.Info("Ingesting messages failed", e); + logger.LogInformation(e, "Ingesting messages failed"); } finally { @@ -146,7 +146,7 @@ public override async Task StopAsync(CancellationToken cancellationToken) } catch (OperationCanceledException e) when (cancellationToken.IsCancellationRequested) { - Logger.Info("Shutdown cancelled", e); + logger.LogInformation(e, "Shutdown cancelled"); } } } @@ -160,7 +160,7 @@ async Task EnsureStarted(CancellationToken cancellationToken = default) var canIngest = unitOfWorkFactory.CanIngestMore(); - Logger.DebugFormat("Ensure started {0}", canIngest); + logger.LogDebug("Ensure started {CanIngest}", canIngest); if (canIngest) { @@ -194,13 +194,13 @@ async Task SetUpAndStartInfrastructure(CancellationToken cancellationToken) { if (messageReceiver != null) { - Logger.Debug("Infrastructure already Started"); + logger.LogDebug("Infrastructure already Started"); return; } try { - Logger.Info("Starting infrastructure"); + logger.LogInformation("Starting infrastructure"); transportInfrastructure = await transportCustomization.CreateTransportInfrastructure( errorQueue, transportSettings, @@ -219,11 +219,11 @@ async Task SetUpAndStartInfrastructure(CancellationToken cancellationToken) await messageReceiver.StartReceive(cancellationToken); - Logger.Info(LogMessages.StartedInfrastructure); + logger.LogInformation(LogMessages.StartedInfrastructure); } catch (Exception e) { - Logger.Error("Failed to start infrastructure", e); + logger.LogError(e, "Failed to start infrastructure"); throw; } } @@ -231,12 +231,12 @@ async Task StopAndTeardownInfrastructure(CancellationToken cancellationToken) { if (transportInfrastructure == null) { - Logger.Debug("Infrastructure already Stopped"); + logger.LogDebug("Infrastructure already Stopped"); return; } try { - Logger.Info("Stopping infrastructure"); + logger.LogInformation("Stopping infrastructure"); try { if (messageReceiver != null) @@ -252,11 +252,11 @@ async Task StopAndTeardownInfrastructure(CancellationToken cancellationToken) messageReceiver = null; transportInfrastructure = null; - Logger.Info(LogMessages.StoppedInfrastructure); + logger.LogInformation(LogMessages.StoppedInfrastructure); } catch (Exception e) { - Logger.Error("Failed to stop infrastructure", e); + logger.LogError(e, "Failed to stop infrastructure"); throw; } } @@ -284,7 +284,7 @@ async Task OnMessage(MessageContext messageContext, CancellationToken cancellati Task OnCriticalError(string failure, Exception exception) { - Logger.Fatal($"OnCriticalError. '{failure}'", exception); + logger.LogCritical(exception, "OnCriticalError. '{FailureMessage}'", failure); return watchdog.OnFailure(failure); } @@ -322,7 +322,7 @@ async Task EnsureStopped(CancellationToken cancellationToken = default) readonly IIngestionUnitOfWorkFactory unitOfWorkFactory; readonly IHostApplicationLifetime applicationLifetime; - static readonly ILog Logger = LogManager.GetLogger(); + static readonly ILogger logger; internal static class LogMessages { diff --git a/src/ServiceControl/ServiceControl.csproj b/src/ServiceControl/ServiceControl.csproj index 04f5956ccf..35b07b77cb 100644 --- a/src/ServiceControl/ServiceControl.csproj +++ b/src/ServiceControl/ServiceControl.csproj @@ -32,6 +32,7 @@ + diff --git a/src/ServiceControlInstaller.Engine/Unattended/UnattendServiceControlInstaller.cs b/src/ServiceControlInstaller.Engine/Unattended/UnattendServiceControlInstaller.cs index 2dfcb9570d..72c8e8e376 100644 --- a/src/ServiceControlInstaller.Engine/Unattended/UnattendServiceControlInstaller.cs +++ b/src/ServiceControlInstaller.Engine/Unattended/UnattendServiceControlInstaller.cs @@ -70,6 +70,7 @@ public async Task Add(ServiceControlNewInstance details, Func Date: Tue, 10 Jun 2025 07:17:43 +0800 Subject: [PATCH 02/56] revert app.config checkins --- src/ServiceControl.Audit/App.config | 7 +++---- src/ServiceControl.Monitoring/App.config | 8 ++++---- src/ServiceControl/App.config | 8 ++++---- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/ServiceControl.Audit/App.config b/src/ServiceControl.Audit/App.config index a2c5ced58d..00a70ad0a2 100644 --- a/src/ServiceControl.Audit/App.config +++ b/src/ServiceControl.Audit/App.config @@ -9,13 +9,13 @@ These settings are only here so that we can debug ServiceControl while developin - + - + @@ -27,7 +27,7 @@ These settings are only here so that we can debug ServiceControl while developin - + @@ -46,7 +46,6 @@ These settings are only here so that we can debug ServiceControl while developin - diff --git a/src/ServiceControl.Monitoring/App.config b/src/ServiceControl.Monitoring/App.config index 4268a45f09..8ce3bdf576 100644 --- a/src/ServiceControl.Monitoring/App.config +++ b/src/ServiceControl.Monitoring/App.config @@ -10,13 +10,13 @@ These settings are only here so that we can debug ServiceControl while developin - + - + @@ -25,7 +25,7 @@ These settings are only here so that we can debug ServiceControl while developin - + @@ -43,7 +43,7 @@ These settings are only here so that we can debug ServiceControl while developin - + diff --git a/src/ServiceControl/App.config b/src/ServiceControl/App.config index 56ca406180..5f489017b7 100644 --- a/src/ServiceControl/App.config +++ b/src/ServiceControl/App.config @@ -13,13 +13,13 @@ These settings are only here so that we can debug ServiceControl while developin - + - + @@ -29,7 +29,7 @@ These settings are only here so that we can debug ServiceControl while developin - + @@ -47,7 +47,7 @@ These settings are only here so that we can debug ServiceControl while developin - + From ad7cc4ae87a82326e2c8f2918fe5ba851edd17e9 Mon Sep 17 00:00:00 2001 From: Phil Bastian <155411597+PhilBastian@users.noreply.github.com> Date: Tue, 10 Jun 2025 07:49:58 +0800 Subject: [PATCH 03/56] use pascal case for structured logging --- src/ServiceControl.Audit/Auditing/AuditIngestion.cs | 4 ++-- src/ServiceControl.Audit/Auditing/AuditPersister.cs | 10 +++++----- .../Auditing/ImportFailedAudits.cs | 8 ++++---- src/ServiceControl.Infrastructure/Watchdog.cs | 10 +++++----- src/ServiceControl/App.config | 2 +- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/ServiceControl.Audit/Auditing/AuditIngestion.cs b/src/ServiceControl.Audit/Auditing/AuditIngestion.cs index 182d7a4771..ea417c25a8 100644 --- a/src/ServiceControl.Audit/Auditing/AuditIngestion.cs +++ b/src/ServiceControl.Audit/Auditing/AuditIngestion.cs @@ -70,7 +70,7 @@ ILogger logger Task OnCriticalError(string failure, Exception exception) { - logger.LogCritical(exception, "OnCriticalError. '{failure}'", failure); + logger.LogCritical(exception, "OnCriticalError. '{Failure}'", failure); return watchdog.OnFailure(failure); } @@ -82,7 +82,7 @@ async Task EnsureStarted(CancellationToken cancellationToken) var canIngest = unitOfWorkFactory.CanIngestMore(); - logger.LogDebug("Ensure started {canIngest}", canIngest); + logger.LogDebug("Ensure started {CanIngest}", canIngest); if (canIngest) { diff --git a/src/ServiceControl.Audit/Auditing/AuditPersister.cs b/src/ServiceControl.Audit/Auditing/AuditPersister.cs index 3677f2e7b4..a37e5a4f56 100644 --- a/src/ServiceControl.Audit/Auditing/AuditPersister.cs +++ b/src/ServiceControl.Audit/Auditing/AuditPersister.cs @@ -73,7 +73,7 @@ public async Task> Persist(IReadOnlyList(metadata)); - logger.LogDebug("Emitting {commandsToEmitCount} commands and {messagesToEmitCount} control messages.", commandsToEmit.Count, messagesToEmit.Count); + logger.LogDebug("Emitting {CommandsToEmitCount} commands and {MessagesToEmitCount} control messages.", commandsToEmit.Count, messagesToEmit.Count); foreach (var commandToEmit in commandsToEmit) { @@ -198,7 +198,7 @@ async Task ProcessAuditMessage(MessageContext context) await messageDispatcher.Value.Dispatch(new TransportOperations(messagesToEmit.ToArray()), new TransportTransaction()); //Do not hook into the incoming transaction - logger.LogDebug("{commandsToEmitCount} commands and {messagesToEmitCount} control messages emitted.", commandsToEmit.Count, messagesToEmit.Count); + logger.LogDebug("{CommandsToEmitCount} commands and {MessagesToEmitCount} control messages emitted.", commandsToEmit.Count, messagesToEmit.Count); if (metadata.TryGetValue("SendingEndpoint", out var sendingEndpoint)) { @@ -215,7 +215,7 @@ await messageDispatcher.Value.Dispatch(new TransportOperations(messagesToEmit.To } catch (Exception e) { - logger.LogWarning(e, "Processing of message '{messageId}' failed.", messageId); + logger.LogWarning(e, "Processing of message '{MessageId}' failed.", messageId); // releasing the failed message context early so that they can be retried outside the current batch context.GetTaskCompletionSource().TrySetException(e); diff --git a/src/ServiceControl.Audit/Auditing/ImportFailedAudits.cs b/src/ServiceControl.Audit/Auditing/ImportFailedAudits.cs index 070bdee325..99321dc69f 100644 --- a/src/ServiceControl.Audit/Auditing/ImportFailedAudits.cs +++ b/src/ServiceControl.Audit/Auditing/ImportFailedAudits.cs @@ -52,7 +52,7 @@ await failedAuditStore.ProcessFailedMessages( await markComplete(token); succeeded++; - logger.LogDebug("Successfully re-imported failed audit message {transportMessageId}.", transportMessage.Id); + logger.LogDebug("Successfully re-imported failed audit message {MessageId}.", transportMessage.Id); } catch (OperationCanceledException e) when (token.IsCancellationRequested) { @@ -60,17 +60,17 @@ await failedAuditStore.ProcessFailedMessages( } catch (Exception e) { - logger.LogError(e, "Error while attempting to re-import failed audit message {transportMessageId}.", transportMessage.Id); + logger.LogError(e, "Error while attempting to re-import failed audit message {MessageId}.", transportMessage.Id); failed++; } }, cancellationToken); - logger.LogInformation("Done re-importing failed audits. Successfully re-imported {succeeded} messages. Failed re-importing {failed} messages.", succeeded, failed); + logger.LogInformation("Done re-importing failed audits. Successfully re-imported {SuccessCount} messages. Failed re-importing {FailureCount} messages.", succeeded, failed); if (failed > 0) { - logger.LogWarning("{failed} messages could not be re-imported. This could indicate a problem with the data. Contact Particular support if you need help with recovering the messages.", failed); + logger.LogWarning("{FailureCount} messages could not be re-imported. This could indicate a problem with the data. Contact Particular support if you need help with recovering the messages.", failed); } } diff --git a/src/ServiceControl.Infrastructure/Watchdog.cs b/src/ServiceControl.Infrastructure/Watchdog.cs index 8c397c3a9e..7b0431117d 100644 --- a/src/ServiceControl.Infrastructure/Watchdog.cs +++ b/src/ServiceControl.Infrastructure/Watchdog.cs @@ -60,7 +60,7 @@ public Task Start(Action onFailedOnStartup, CancellationToken cancellationToken) using var cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(shutdownTokenSource.Token); cancellationTokenSource.CancelAfter(MaxStartDurationMs); - log.LogDebug("Ensuring {taskName} is running", taskName); + log.LogDebug("Ensuring {TaskName} is running", taskName); await ensureStarted(cancellationTokenSource.Token).ConfigureAwait(false); clearFailure(); startup = false; @@ -76,12 +76,12 @@ public Task Start(Action onFailedOnStartup, CancellationToken cancellationToken) if (startup) { - log.LogError(e, "Error during initial startup attempt for {taskName}.", taskName); + log.LogError(e, "Error during initial startup attempt for {TaskName}.", taskName); onFailedOnStartup(); return; } - log.LogError(e, "Error while trying to start {taskName}. Starting will be retried in {timeToWaitBetweenStartupAttempts}.", taskName, timeToWaitBetweenStartupAttempts); + log.LogError(e, "Error while trying to start {TaskName}. Starting will be retried in {TimeToWaitBetweenStartupAttempts}.", taskName, timeToWaitBetweenStartupAttempts); } try { @@ -101,13 +101,13 @@ public async Task Stop(CancellationToken cancellationToken) { try { - log.LogDebug("Starting watching {taskName}", taskName); + log.LogDebug("Starting watching {TaskName}", taskName); await shutdownTokenSource.CancelAsync().ConfigureAwait(false); await watchdog.ConfigureAwait(false); } catch (Exception e) { - log.LogError(e, "Ensuring {taskName} is running", taskName); + log.LogError(e, "Ensuring {TaskName} is running", taskName); throw; } finally diff --git a/src/ServiceControl/App.config b/src/ServiceControl/App.config index 5f489017b7..a99b7b9afe 100644 --- a/src/ServiceControl/App.config +++ b/src/ServiceControl/App.config @@ -46,7 +46,7 @@ These settings are only here so that we can debug ServiceControl while developin - + From 3534fd2ee133a166aa628eea06968cb367f0eebf Mon Sep 17 00:00:00 2001 From: Phil Bastian Date: Tue, 10 Jun 2025 12:07:48 +0800 Subject: [PATCH 04/56] revert accidental checkin for primary instance --- .../Operations/ErrorIngestion.cs | 32 +++++++++---------- src/ServiceControl/ServiceControl.csproj | 1 - 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/ServiceControl/Operations/ErrorIngestion.cs b/src/ServiceControl/Operations/ErrorIngestion.cs index 8ea52094dc..5f0ed7f4ee 100644 --- a/src/ServiceControl/Operations/ErrorIngestion.cs +++ b/src/ServiceControl/Operations/ErrorIngestion.cs @@ -9,8 +9,8 @@ using Infrastructure; using Infrastructure.Metrics; using Microsoft.Extensions.Hosting; - using Microsoft.Extensions.Logging; using NServiceBus; + using NServiceBus.Logging; using NServiceBus.Transport; using Persistence; using Persistence.UnitOfWork; @@ -66,7 +66,7 @@ public ErrorIngestion( ingestionState.ReportError, ingestionState.Clear, settings.TimeToRestartErrorIngestionAfterFailure, - logger + Logger ); } @@ -109,11 +109,11 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) if (e is OperationCanceledException && stoppingToken.IsCancellationRequested) { - logger.LogInformation(e, "Batch cancelled"); + Logger.Info("Batch cancelled", e); break; } - logger.LogInformation(e, "Ingesting messages failed"); + Logger.Info("Ingesting messages failed", e); } finally { @@ -146,7 +146,7 @@ public override async Task StopAsync(CancellationToken cancellationToken) } catch (OperationCanceledException e) when (cancellationToken.IsCancellationRequested) { - logger.LogInformation(e, "Shutdown cancelled"); + Logger.Info("Shutdown cancelled", e); } } } @@ -160,7 +160,7 @@ async Task EnsureStarted(CancellationToken cancellationToken = default) var canIngest = unitOfWorkFactory.CanIngestMore(); - logger.LogDebug("Ensure started {CanIngest}", canIngest); + Logger.DebugFormat("Ensure started {0}", canIngest); if (canIngest) { @@ -194,13 +194,13 @@ async Task SetUpAndStartInfrastructure(CancellationToken cancellationToken) { if (messageReceiver != null) { - logger.LogDebug("Infrastructure already Started"); + Logger.Debug("Infrastructure already Started"); return; } try { - logger.LogInformation("Starting infrastructure"); + Logger.Info("Starting infrastructure"); transportInfrastructure = await transportCustomization.CreateTransportInfrastructure( errorQueue, transportSettings, @@ -219,11 +219,11 @@ async Task SetUpAndStartInfrastructure(CancellationToken cancellationToken) await messageReceiver.StartReceive(cancellationToken); - logger.LogInformation(LogMessages.StartedInfrastructure); + Logger.Info(LogMessages.StartedInfrastructure); } catch (Exception e) { - logger.LogError(e, "Failed to start infrastructure"); + Logger.Error("Failed to start infrastructure", e); throw; } } @@ -231,12 +231,12 @@ async Task StopAndTeardownInfrastructure(CancellationToken cancellationToken) { if (transportInfrastructure == null) { - logger.LogDebug("Infrastructure already Stopped"); + Logger.Debug("Infrastructure already Stopped"); return; } try { - logger.LogInformation("Stopping infrastructure"); + Logger.Info("Stopping infrastructure"); try { if (messageReceiver != null) @@ -252,11 +252,11 @@ async Task StopAndTeardownInfrastructure(CancellationToken cancellationToken) messageReceiver = null; transportInfrastructure = null; - logger.LogInformation(LogMessages.StoppedInfrastructure); + Logger.Info(LogMessages.StoppedInfrastructure); } catch (Exception e) { - logger.LogError(e, "Failed to stop infrastructure"); + Logger.Error("Failed to stop infrastructure", e); throw; } } @@ -284,7 +284,7 @@ async Task OnMessage(MessageContext messageContext, CancellationToken cancellati Task OnCriticalError(string failure, Exception exception) { - logger.LogCritical(exception, "OnCriticalError. '{FailureMessage}'", failure); + Logger.Fatal($"OnCriticalError. '{failure}'", exception); return watchdog.OnFailure(failure); } @@ -322,7 +322,7 @@ async Task EnsureStopped(CancellationToken cancellationToken = default) readonly IIngestionUnitOfWorkFactory unitOfWorkFactory; readonly IHostApplicationLifetime applicationLifetime; - static readonly ILogger logger; + static readonly ILog Logger = LogManager.GetLogger(); internal static class LogMessages { diff --git a/src/ServiceControl/ServiceControl.csproj b/src/ServiceControl/ServiceControl.csproj index 35b07b77cb..04f5956ccf 100644 --- a/src/ServiceControl/ServiceControl.csproj +++ b/src/ServiceControl/ServiceControl.csproj @@ -32,7 +32,6 @@ - From b6505e6ec8b2d179368c924268adce4c44c3f65a Mon Sep 17 00:00:00 2001 From: Phil Bastian <155411597+PhilBastian@users.noreply.github.com> Date: Tue, 10 Jun 2025 12:12:16 +0800 Subject: [PATCH 05/56] Apply suggestions from code review --- src/ServiceControl.Infrastructure/Watchdog.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ServiceControl.Infrastructure/Watchdog.cs b/src/ServiceControl.Infrastructure/Watchdog.cs index 7b0431117d..efdb739f8c 100644 --- a/src/ServiceControl.Infrastructure/Watchdog.cs +++ b/src/ServiceControl.Infrastructure/Watchdog.cs @@ -45,7 +45,7 @@ public Task Start(Action onFailedOnStartup, CancellationToken cancellationToken) { watchdog = Task.Run(async () => { - log.LogDebug("Starting watching {taskName}", taskName); + log.LogDebug("Starting watching {TaskName}", taskName); bool startup = true; From 2a0db48b2e2fee30efa8ecc85b69bbea84760218 Mon Sep 17 00:00:00 2001 From: Phil Bastian Date: Tue, 10 Jun 2025 12:17:09 +0800 Subject: [PATCH 06/56] fix build error --- src/ServiceControl/Operations/ErrorIngestion.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ServiceControl/Operations/ErrorIngestion.cs b/src/ServiceControl/Operations/ErrorIngestion.cs index 5f0ed7f4ee..f4ee49693b 100644 --- a/src/ServiceControl/Operations/ErrorIngestion.cs +++ b/src/ServiceControl/Operations/ErrorIngestion.cs @@ -66,7 +66,8 @@ public ErrorIngestion( ingestionState.ReportError, ingestionState.Clear, settings.TimeToRestartErrorIngestionAfterFailure, - Logger + //TODO replace when converting this class to ILogger Logger + LoggerUtil.CreateStaticLogger() ); } From 1041b4efe4495288384fa55123b12fd7a6291512 Mon Sep 17 00:00:00 2001 From: Phil Bastian Date: Tue, 10 Jun 2025 12:37:10 +0800 Subject: [PATCH 07/56] revert setupcommand to having a parameterless constructor for activator creation --- .../TestSupport/ServiceControlComponentRunner.cs | 2 +- .../Infrastructure/When_instance_is_setup.cs | 2 +- .../Infrastructure/Hosting/Commands/SetupCommand.cs | 5 +++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/ServiceControl.Audit.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs b/src/ServiceControl.Audit.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs index eb3bbaaf32..0866b504db 100644 --- a/src/ServiceControl.Audit.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs +++ b/src/ServiceControl.Audit.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs @@ -98,7 +98,7 @@ async Task InitializeServiceControl(ScenarioContext context) using (new DiagnosticTimer($"Creating infrastructure for {instanceName}")) { - var setupCommand = new SetupCommand(LoggerUtil.CreateStaticLogger()); + var setupCommand = new SetupCommand(); await setupCommand.Execute(new HostArguments([]), settings); } diff --git a/src/ServiceControl.Audit.UnitTests/Infrastructure/When_instance_is_setup.cs b/src/ServiceControl.Audit.UnitTests/Infrastructure/When_instance_is_setup.cs index 1828bc21d5..274cdaf033 100644 --- a/src/ServiceControl.Audit.UnitTests/Infrastructure/When_instance_is_setup.cs +++ b/src/ServiceControl.Audit.UnitTests/Infrastructure/When_instance_is_setup.cs @@ -42,7 +42,7 @@ public async Task Should_provision_queues() AssemblyLoadContextResolver = static _ => AssemblyLoadContext.Default }; - var setupCommand = new SetupCommand(LoggerUtil.CreateStaticLogger()); + var setupCommand = new SetupCommand(); await setupCommand.Execute(new HostArguments([]), settings); Assert.That(FakeTransport.QueuesCreated, Is.EquivalentTo(new[] diff --git a/src/ServiceControl.Audit/Infrastructure/Hosting/Commands/SetupCommand.cs b/src/ServiceControl.Audit/Infrastructure/Hosting/Commands/SetupCommand.cs index d48c01be03..7837fbd684 100644 --- a/src/ServiceControl.Audit/Infrastructure/Hosting/Commands/SetupCommand.cs +++ b/src/ServiceControl.Audit/Infrastructure/Hosting/Commands/SetupCommand.cs @@ -5,10 +5,11 @@ using System.Threading.Tasks; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; + using ServiceControl.Infrastructure; using Settings; using Transports; - class SetupCommand(ILogger logger) : AbstractCommand + class SetupCommand() : AbstractCommand { public override async Task Execute(HostArguments args, Settings settings) { @@ -16,7 +17,7 @@ public override async Task Execute(HostArguments args, Settings settings) { if (args.SkipQueueCreation) { - logger.LogInformation("Skipping queue creation"); + LoggerUtil.CreateStaticLogger().LogInformation("Skipping queue creation"); } else { From 4f25d490375bab54faaf1b8b590a4322f1cf0ae1 Mon Sep 17 00:00:00 2001 From: Phil Bastian Date: Thu, 12 Jun 2025 10:49:57 +0800 Subject: [PATCH 08/56] replace NServiceBus.logging in Audit.Persistence with Microsoft.Extensions.Logging --- .../ServiceControlComponentRunner.cs | 7 ++++--- .../InMemoryAuditIngestionUnitOfWorkFactory.cs | 11 +---------- .../InMemoryPersistence.cs | 1 + .../IndexSetupTests.cs | 1 - .../BodyStorageEnricher.cs | 7 +++---- .../PersistenceManifest.cs | 11 ++++++----- .../BodyStorage/BodyStorageEnricherTests.cs | 17 +++++++++-------- .../Infrastructure/When_instance_is_setup.cs | 1 - 8 files changed, 24 insertions(+), 32 deletions(-) diff --git a/src/ServiceControl.Audit.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs b/src/ServiceControl.Audit.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs index 0866b504db..301d9b51a0 100644 --- a/src/ServiceControl.Audit.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs +++ b/src/ServiceControl.Audit.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs @@ -17,6 +17,7 @@ namespace ServiceControl.Audit.AcceptanceTests.TestSupport using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.Hosting; + using Microsoft.Extensions.Logging; using NServiceBus; using NServiceBus.AcceptanceTesting; using NServiceBus.AcceptanceTesting.Support; @@ -55,9 +56,9 @@ async Task InitializeServiceControl(ScenarioContext context) { var id = messageContext.NativeMessageId; var headers = messageContext.Headers; - var log = NServiceBus.Logging.LogManager.GetLogger(); + var log = LoggerUtil.CreateStaticLogger(); headers.TryGetValue(Headers.MessageId, out var originalMessageId); - log.Debug($"OnMessage for message '{id}'({originalMessageId ?? string.Empty})."); + log.LogDebug("OnMessage for message '{MessageId}'({OriginalMessageId}).", id, originalMessageId ?? string.Empty); //Do not filter out CC, SA and HB messages as they can't be stamped if (headers.TryGetValue(Headers.EnclosedMessageTypes, out var messageTypes) @@ -76,7 +77,7 @@ async Task InitializeServiceControl(ScenarioContext context) var currentSession = context.TestRunId.ToString(); if (!headers.TryGetValue("SC.SessionID", out var session) || session != currentSession) { - log.Debug($"Discarding message '{id}'({originalMessageId ?? string.Empty}) because it's session id is '{session}' instead of '{currentSession}'."); + log.LogDebug("Discarding message '{MessageId}'({OriginalMessageId}) because it's session id is '{SessionId}' instead of '{CurrentSessionId}'.", id, originalMessageId ?? string.Empty, session, currentSession); return true; } diff --git a/src/ServiceControl.Audit.Persistence.InMemory/InMemoryAuditIngestionUnitOfWorkFactory.cs b/src/ServiceControl.Audit.Persistence.InMemory/InMemoryAuditIngestionUnitOfWorkFactory.cs index f07e7036de..fb1f3a0c66 100644 --- a/src/ServiceControl.Audit.Persistence.InMemory/InMemoryAuditIngestionUnitOfWorkFactory.cs +++ b/src/ServiceControl.Audit.Persistence.InMemory/InMemoryAuditIngestionUnitOfWorkFactory.cs @@ -5,14 +5,8 @@ using ServiceControl.Audit.Auditing.BodyStorage; using ServiceControl.Audit.Persistence.UnitOfWork; - class InMemoryAuditIngestionUnitOfWorkFactory : IAuditIngestionUnitOfWorkFactory + class InMemoryAuditIngestionUnitOfWorkFactory(InMemoryAuditDataStore dataStore, BodyStorageEnricher bodyStorageEnricher) : IAuditIngestionUnitOfWorkFactory { - public InMemoryAuditIngestionUnitOfWorkFactory(InMemoryAuditDataStore dataStore, IBodyStorage bodyStorage, PersistenceSettings settings) - { - this.dataStore = dataStore; - bodyStorageEnricher = new BodyStorageEnricher(bodyStorage, settings); - } - public ValueTask StartNew(int batchSize, CancellationToken cancellationToken) { //The batchSize argument is ignored: the in-memory storage implementation doesn't support batching. @@ -20,8 +14,5 @@ public ValueTask StartNew(int batchSize, Cancellation } public bool CanIngestMore() => true; - - InMemoryAuditDataStore dataStore; - BodyStorageEnricher bodyStorageEnricher; } } \ No newline at end of file diff --git a/src/ServiceControl.Audit.Persistence.InMemory/InMemoryPersistence.cs b/src/ServiceControl.Audit.Persistence.InMemory/InMemoryPersistence.cs index 4a5b349caa..368191f50a 100644 --- a/src/ServiceControl.Audit.Persistence.InMemory/InMemoryPersistence.cs +++ b/src/ServiceControl.Audit.Persistence.InMemory/InMemoryPersistence.cs @@ -14,6 +14,7 @@ public void AddPersistence(IServiceCollection services) services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); } public void AddInstaller(IServiceCollection services) diff --git a/src/ServiceControl.Audit.Persistence.Tests.RavenDB/IndexSetupTests.cs b/src/ServiceControl.Audit.Persistence.Tests.RavenDB/IndexSetupTests.cs index 678915f391..b31c3288a9 100644 --- a/src/ServiceControl.Audit.Persistence.Tests.RavenDB/IndexSetupTests.cs +++ b/src/ServiceControl.Audit.Persistence.Tests.RavenDB/IndexSetupTests.cs @@ -1,7 +1,6 @@ namespace ServiceControl.Audit.Persistence.Tests; using System; -using System.Threading; using System.Threading.Tasks; using NUnit.Framework; using Persistence.RavenDB; diff --git a/src/ServiceControl.Audit.Persistence/BodyStorageEnricher.cs b/src/ServiceControl.Audit.Persistence/BodyStorageEnricher.cs index 03e4ae479f..c7794e30ba 100644 --- a/src/ServiceControl.Audit.Persistence/BodyStorageEnricher.cs +++ b/src/ServiceControl.Audit.Persistence/BodyStorageEnricher.cs @@ -5,12 +5,12 @@ using System.Text; using System.Threading; using System.Threading.Tasks; + using Microsoft.Extensions.Logging; using NServiceBus; - using NServiceBus.Logging; using ServiceControl.Audit.Persistence; using ServiceControl.Infrastructure; - public class BodyStorageEnricher(IBodyStorage bodyStorage, PersistenceSettings settings) + public class BodyStorageEnricher(IBodyStorage bodyStorage, PersistenceSettings settings, ILogger logger) { public async ValueTask StoreAuditMessageBody(ReadOnlyMemory body, ProcessedMessage processedMessage, CancellationToken cancellationToken) { @@ -66,7 +66,7 @@ async ValueTask TryStoreBody(ReadOnlyMemory body, ProcessedMessage p catch (DecoderFallbackException e) { useBodyStore = true; - log.Info($"Body for {bodyId} could not be stored embedded, fallback to body storage ({e.Message})"); + logger.LogInformation("Body for {BodyId} could not be stored embedded, fallback to body storage ({ErrorMessage})", bodyId, e.Message); } } @@ -111,7 +111,6 @@ static bool IsBinary(IReadOnlyDictionary headers) } static readonly Encoding enc = new UTF8Encoding(true, true); - static readonly ILog log = LogManager.GetLogger(); // large object heap starts above 85000 bytes and not above 85 KB! public const int LargeObjectHeapThreshold = 85 * 1000; diff --git a/src/ServiceControl.Audit.Persistence/PersistenceManifest.cs b/src/ServiceControl.Audit.Persistence/PersistenceManifest.cs index 6638cda025..8ff8bcfb16 100644 --- a/src/ServiceControl.Audit.Persistence/PersistenceManifest.cs +++ b/src/ServiceControl.Audit.Persistence/PersistenceManifest.cs @@ -5,7 +5,8 @@ using System.IO; using System.Linq; using System.Text.Json; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; + using ServiceControl.Infrastructure; public class PersistenceManifest { @@ -51,7 +52,7 @@ static PersistenceManifestLibrary() } catch (Exception ex) { - logger.Warn($"Failed to load persistence manifests from {assemblyDirectory}", ex); + logger.LogWarning(ex, "Failed to load persistence manifests from {AssemblyDirectory}", assemblyDirectory); } try @@ -66,10 +67,10 @@ static PersistenceManifestLibrary() } catch (Exception ex) { - logger.Warn($"Failed to load persistence manifests from development locations", ex); + logger.LogWarning(ex, "Failed to load persistence manifests from development locations"); } - PersistenceManifests.ForEach(m => logger.Info($"Found persistence manifest for {m.DisplayName}")); + PersistenceManifests.ForEach(m => logger.LogInformation("Found persistence manifest for {ManifestDisplayName}", m.DisplayName)); } static string GetAssemblyDirectory() @@ -90,7 +91,7 @@ public static PersistenceManifest Find(string persistenceType) return persistenceManifest; } - static readonly ILog logger = LogManager.GetLogger(typeof(PersistenceManifestLibrary)); + static readonly ILogger logger = LoggerUtil.CreateStaticLogger(typeof(PersistenceManifestLibrary)); } } diff --git a/src/ServiceControl.Audit.UnitTests/BodyStorage/BodyStorageEnricherTests.cs b/src/ServiceControl.Audit.UnitTests/BodyStorage/BodyStorageEnricherTests.cs index 05ce6871cc..87e1bbe9db 100644 --- a/src/ServiceControl.Audit.UnitTests/BodyStorage/BodyStorageEnricherTests.cs +++ b/src/ServiceControl.Audit.UnitTests/BodyStorage/BodyStorageEnricherTests.cs @@ -11,6 +11,7 @@ namespace ServiceControl.UnitTests.BodyStorage using NServiceBus; using NUnit.Framework; using ServiceControl.Audit.Persistence; + using ServiceControl.Infrastructure; [TestFixture] public class BodyStorageEnricherTests @@ -21,7 +22,7 @@ public async Task Should_remove_body_when_above_threshold() var fakeStorage = new FakeBodyStorage(); var maxBodySizeToStore = 20000; - var enricher = new BodyStorageEnricher(fakeStorage, new PersistenceSettings(TimeSpan.FromHours(1), true, maxBodySizeToStore)); + var enricher = new BodyStorageEnricher(fakeStorage, new PersistenceSettings(TimeSpan.FromHours(1), true, maxBodySizeToStore), LoggerUtil.CreateStaticLogger()); var body = Encoding.UTF8.GetBytes(new string('a', maxBodySizeToStore + 1)); var metadata = new Dictionary(); @@ -51,7 +52,7 @@ public async Task Should_remove_body_when_above_threshold_and_binary() var fakeStorage = new FakeBodyStorage(); var maxBodySizeToStore = 20000; - var enricher = new BodyStorageEnricher(fakeStorage, new PersistenceSettings(TimeSpan.FromHours(1), true, maxBodySizeToStore)); + var enricher = new BodyStorageEnricher(fakeStorage, new PersistenceSettings(TimeSpan.FromHours(1), true, maxBodySizeToStore), LoggerUtil.CreateStaticLogger()); var body = Encoding.UTF8.GetBytes(new string('a', maxBodySizeToStore + 1)); var metadata = new Dictionary(); var headers = new Dictionary @@ -81,7 +82,7 @@ public async Task Should_store_body_in_metadata_when_below_large_object_heap_and var fakeStorage = new FakeBodyStorage(); var maxBodySizeToStore = 100000; - var enricher = new BodyStorageEnricher(fakeStorage, new PersistenceSettings(TimeSpan.FromHours(1), true, maxBodySizeToStore)); + var enricher = new BodyStorageEnricher(fakeStorage, new PersistenceSettings(TimeSpan.FromHours(1), true, maxBodySizeToStore), LoggerUtil.CreateStaticLogger()); var expectedBodySize = BodyStorageEnricher.LargeObjectHeapThreshold - 1; var body = Encoding.UTF8.GetBytes(new string('a', expectedBodySize)); var metadata = new Dictionary(); @@ -113,7 +114,7 @@ public async Task Should_store_body_in_body_property_when_full_text_disabled_and var fakeStorage = new FakeBodyStorage(); var maxBodySizeToStore = 100000; - var enricher = new BodyStorageEnricher(fakeStorage, new PersistenceSettings(TimeSpan.FromHours(1), false, maxBodySizeToStore)); + var enricher = new BodyStorageEnricher(fakeStorage, new PersistenceSettings(TimeSpan.FromHours(1), false, maxBodySizeToStore), LoggerUtil.CreateStaticLogger()); var expectedBodySize = BodyStorageEnricher.LargeObjectHeapThreshold - 1; var body = Encoding.UTF8.GetBytes(new string('a', expectedBodySize)); var metadata = new Dictionary(); @@ -145,7 +146,7 @@ public async Task Should_store_body_in_storage_when_above_large_object_heap_but_ var fakeStorage = new FakeBodyStorage(); var maxBodySizeToStore = 100000; - var enricher = new BodyStorageEnricher(fakeStorage, new PersistenceSettings(TimeSpan.FromHours(1), true, maxBodySizeToStore)); + var enricher = new BodyStorageEnricher(fakeStorage, new PersistenceSettings(TimeSpan.FromHours(1), true, maxBodySizeToStore), LoggerUtil.CreateStaticLogger()); var expectedBodySize = BodyStorageEnricher.LargeObjectHeapThreshold + 1; var body = Encoding.UTF8.GetBytes(new string('a', expectedBodySize)); var metadata = new Dictionary(); @@ -177,7 +178,7 @@ public async Task Should_store_body_in_storage_when_below_threshold_and_binary() var fakeStorage = new FakeBodyStorage(); var maxBodySizeToStore = 100000; - var enricher = new BodyStorageEnricher(fakeStorage, new PersistenceSettings(TimeSpan.FromHours(1), true, maxBodySizeToStore)); + var enricher = new BodyStorageEnricher(fakeStorage, new PersistenceSettings(TimeSpan.FromHours(1), true, maxBodySizeToStore), LoggerUtil.CreateStaticLogger()); var expectedBodySize = BodyStorageEnricher.LargeObjectHeapThreshold + 1; var body = Encoding.UTF8.GetBytes(new string('a', expectedBodySize)); var metadata = new Dictionary(); @@ -208,7 +209,7 @@ public async Task Should_store_body_in_storage_when_below_threshold() var fakeStorage = new FakeBodyStorage(); var maxBodySizeToStore = 100000; - var enricher = new BodyStorageEnricher(fakeStorage, new PersistenceSettings(TimeSpan.FromHours(1), true, maxBodySizeToStore)); + var enricher = new BodyStorageEnricher(fakeStorage, new PersistenceSettings(TimeSpan.FromHours(1), true, maxBodySizeToStore), LoggerUtil.CreateStaticLogger()); var expectedBodySize = BodyStorageEnricher.LargeObjectHeapThreshold + 1; var body = Encoding.UTF8.GetBytes(new string('a', expectedBodySize)); var metadata = new Dictionary(); @@ -239,7 +240,7 @@ public async Task Should_store_body_in_storage_when_encoding_fails() var fakeStorage = new FakeBodyStorage(); var maxBodySizeToStore = 100000; - var enricher = new BodyStorageEnricher(fakeStorage, new PersistenceSettings(TimeSpan.FromHours(1), true, maxBodySizeToStore)); + var enricher = new BodyStorageEnricher(fakeStorage, new PersistenceSettings(TimeSpan.FromHours(1), true, maxBodySizeToStore), LoggerUtil.CreateStaticLogger()); var body = new byte[] { 0x00, 0xDE }; var metadata = new Dictionary(); diff --git a/src/ServiceControl.Audit.UnitTests/Infrastructure/When_instance_is_setup.cs b/src/ServiceControl.Audit.UnitTests/Infrastructure/When_instance_is_setup.cs index 274cdaf033..f01c4595ea 100644 --- a/src/ServiceControl.Audit.UnitTests/Infrastructure/When_instance_is_setup.cs +++ b/src/ServiceControl.Audit.UnitTests/Infrastructure/When_instance_is_setup.cs @@ -12,7 +12,6 @@ using NServiceBus; using NServiceBus.Transport; using NUnit.Framework; - using ServiceControl.Infrastructure; using Transports; class When_instance_is_setup From a8c746f7cbb41a50ab400fb97c796e63f938a8b9 Mon Sep 17 00:00:00 2001 From: Phil Bastian Date: Thu, 12 Jun 2025 15:43:12 +0800 Subject: [PATCH 09/56] convert SC transports from NServiceBus.Logging to Microsoft.Extensions.Logging --- .../DeadLetterQueueCheck.cs | 17 +++++----- .../QueueLengthProvider.cs | 16 +++++----- .../QueueLengthProvider.cs | 19 ++++++----- .../QueueLengthProvider.cs | 15 +++++---- .../DeadLetterQueueCheck.cs | 32 ++++++++----------- .../TransportTestsConfiguration.cs | 3 +- .../PostgreSqlTransportCustomization.cs | 8 ++--- .../QueueLengthProvider.cs | 11 ++++--- .../QueueLengthProvider.cs | 12 ++++--- .../TransportTestsConfiguration.cs | 3 +- .../QueueLengthProvider.cs | 20 ++++++------ .../SQSTransportCustomization.cs | 10 +++--- .../TransportTestsConfiguration.cs | 3 +- .../QueueLengthProvider.cs | 11 ++++--- .../SqlServerTransportCustomization.cs | 8 ++--- .../ServiceControl.Transports.csproj | 1 + .../TransportManifest.cs | 11 ++++--- 17 files changed, 102 insertions(+), 98 deletions(-) diff --git a/src/ServiceControl.Transports.ASBS/DeadLetterQueueCheck.cs b/src/ServiceControl.Transports.ASBS/DeadLetterQueueCheck.cs index abcc4fd05c..e44be27ca8 100644 --- a/src/ServiceControl.Transports.ASBS/DeadLetterQueueCheck.cs +++ b/src/ServiceControl.Transports.ASBS/DeadLetterQueueCheck.cs @@ -4,14 +4,15 @@ using System.Threading; using System.Threading.Tasks; using Azure.Messaging.ServiceBus.Administration; + using Microsoft.Extensions.Logging; using NServiceBus.CustomChecks; - using NServiceBus.Logging; + using ServiceControl.Infrastructure; public class DeadLetterQueueCheck : CustomCheck { public DeadLetterQueueCheck(TransportSettings settings) : base(id: "Dead Letter Queue", category: "Transport", repeatAfter: TimeSpan.FromHours(1)) { - Logger.Debug("Azure Service Bus Dead Letter Queue custom check starting"); + Logger.LogDebug("Azure Service Bus Dead Letter Queue custom check starting"); connectionString = settings.ConnectionString; stagingQueue = $"{settings.EndpointName}.staging"; @@ -25,7 +26,7 @@ public override async Task PerformCheck(CancellationToken cancellat return CheckResult.Pass; } - Logger.Debug("Checking Dead Letter Queue length"); + Logger.LogDebug("Checking Dead Letter Queue length"); var managementClient = new ServiceBusAdministrationClient(connectionString); var queueRuntimeInfo = await managementClient.GetQueueRuntimePropertiesAsync(stagingQueue, cancellationToken); @@ -33,13 +34,11 @@ public override async Task PerformCheck(CancellationToken cancellat if (deadLetterMessageCount > 0) { - var result = $"{deadLetterMessageCount} messages in the Dead Letter Queue '{stagingQueue}'. This could indicate a problem with ServiceControl's retries. Please submit a support ticket to Particular if you would like help from our engineers to ensure no message loss while resolving these dead letter messages."; - - Logger.Warn(result); - return CheckResult.Failed(result); + Logger.LogWarning("{DeadLetterMessageCount} messages in the Dead Letter Queue '{StagingQueue}'. This could indicate a problem with ServiceControl's retries. Please submit a support ticket to Particular if you would like help from our engineers to ensure no message loss while resolving these dead letter messages.", deadLetterMessageCount, stagingQueue); + return CheckResult.Failed($"{deadLetterMessageCount} messages in the Dead Letter Queue '{stagingQueue}'. This could indicate a problem with ServiceControl's retries. Please submit a support ticket to Particular if you would like help from our engineers to ensure no message loss while resolving these dead letter messages."); } - Logger.Debug("No messages in Dead Letter Queue"); + Logger.LogDebug("No messages in Dead Letter Queue"); return CheckResult.Pass; } @@ -49,6 +48,6 @@ public override async Task PerformCheck(CancellationToken cancellat bool runCheck; - static readonly ILog Logger = LogManager.GetLogger(typeof(DeadLetterQueueCheck)); + static readonly ILogger Logger = LoggerUtil.CreateStaticLogger(typeof(DeadLetterQueueCheck)); } } \ No newline at end of file diff --git a/src/ServiceControl.Transports.ASBS/QueueLengthProvider.cs b/src/ServiceControl.Transports.ASBS/QueueLengthProvider.cs index 24021da49a..f6fb44e593 100644 --- a/src/ServiceControl.Transports.ASBS/QueueLengthProvider.cs +++ b/src/ServiceControl.Transports.ASBS/QueueLengthProvider.cs @@ -6,17 +6,18 @@ namespace ServiceControl.Transports.ASBS using System.Threading; using System.Threading.Tasks; using Azure.Messaging.ServiceBus.Administration; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; class QueueLengthProvider : AbstractQueueLengthProvider { - public QueueLengthProvider(TransportSettings settings, Action store) : base(settings, store) + public QueueLengthProvider(TransportSettings settings, Action store, ILogger logger) : base(settings, store) { var connectionSettings = ConnectionStringParser.Parse(ConnectionString); queryDelayInterval = connectionSettings.QueryDelayInterval ?? TimeSpan.FromMilliseconds(500); managementClient = connectionSettings.AuthenticationMethod.BuildManagementClient(); + this.logger = logger; } public override void TrackEndpointInputQueue(EndpointToQueueMapping queueToTrack) => @@ -32,14 +33,14 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) { try { - Logger.Debug("Waiting for next interval"); + logger.LogDebug("Waiting for next interval"); await Task.Delay(queryDelayInterval, stoppingToken); - Logger.DebugFormat("Querying management client."); + logger.LogDebug("Querying management client."); var queueRuntimeInfos = await GetQueueList(stoppingToken); - Logger.DebugFormat("Retrieved details of {0} queues", queueRuntimeInfos.Count); + logger.LogDebug("Retrieved details of {QueueCount} queues", queueRuntimeInfos.Count); UpdateAllQueueLengths(queueRuntimeInfos); } @@ -49,7 +50,7 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) } catch (Exception e) { - Logger.Error("Error querying Azure Service Bus queue sizes.", e); + logger.LogError(e, "Error querying Azure Service Bus queue sizes."); } } } @@ -109,7 +110,6 @@ void UpdateQueueLength(KeyValuePair monitoredEndpoint, IReadOnly readonly ConcurrentDictionary endpointQueueMappings = new ConcurrentDictionary(); readonly ServiceBusAdministrationClient managementClient; readonly TimeSpan queryDelayInterval; - - static readonly ILog Logger = LogManager.GetLogger(); + readonly ILogger logger; } } \ No newline at end of file diff --git a/src/ServiceControl.Transports.ASQ/QueueLengthProvider.cs b/src/ServiceControl.Transports.ASQ/QueueLengthProvider.cs index 58a7b5783d..48ebcf6a6d 100644 --- a/src/ServiceControl.Transports.ASQ/QueueLengthProvider.cs +++ b/src/ServiceControl.Transports.ASQ/QueueLengthProvider.cs @@ -1,19 +1,22 @@ namespace ServiceControl.Transports.ASQ { using System; - using System.Linq; - using System.Threading.Tasks; using System.Collections.Concurrent; + using System.Linq; using System.Threading; - using NServiceBus.Logging; + using System.Threading.Tasks; using Azure.Storage.Queues; using Azure.Storage.Queues.Models; + using Microsoft.Extensions.Logging; class QueueLengthProvider : AbstractQueueLengthProvider { - public QueueLengthProvider(TransportSettings settings, Action store) + public QueueLengthProvider(TransportSettings settings, Action store, ILogger logger) : base(settings, store) - => connectionString = ConnectionString.RemoveCustomConnectionStringParts(out _); + { + connectionString = ConnectionString.RemoveCustomConnectionStringParts(out _); + this.logger = logger; + } public override void TrackEndpointInputQueue(EndpointToQueueMapping queueToTrack) { @@ -48,7 +51,7 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) } catch (Exception e) { - Logger.Error("Error querying sql queue sizes.", e); + logger.LogError(e, "Error querying sql queue sizes."); } } } @@ -76,7 +79,7 @@ async Task FetchLength(QueueLengthValue queueLength, CancellationToken cancellat // simple "log once" approach to do not flood logs if (problematicQueuesNames.TryAdd(queueLength.QueueName, queueLength.QueueName)) { - Logger.Error($"Obtaining Azure Storage Queue count failed for '{queueLength.QueueName}'", ex); + logger.LogError(ex, "Obtaining Azure Storage Queue count failed for '{QueueName}'", queueLength.QueueName); } } } @@ -102,7 +105,7 @@ void UpdateQueueLengthStore() readonly ConcurrentDictionary queueLengths = new ConcurrentDictionary(); readonly ConcurrentDictionary problematicQueuesNames = new ConcurrentDictionary(); - static readonly ILog Logger = LogManager.GetLogger(); + readonly ILogger logger; static readonly TimeSpan QueryDelayInterval = TimeSpan.FromMilliseconds(200); class QueueLengthValue diff --git a/src/ServiceControl.Transports.Learning/QueueLengthProvider.cs b/src/ServiceControl.Transports.Learning/QueueLengthProvider.cs index 68959ada38..93bc2fcc41 100644 --- a/src/ServiceControl.Transports.Learning/QueueLengthProvider.cs +++ b/src/ServiceControl.Transports.Learning/QueueLengthProvider.cs @@ -7,14 +7,17 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using ServiceControl.Transports.Learning; class QueueLengthProvider : AbstractQueueLengthProvider { - public QueueLengthProvider(TransportSettings settings, Action store) - : base(settings, store) => + public QueueLengthProvider(TransportSettings settings, Action store, ILogger logger) + : base(settings, store) + { rootFolder = LearningTransportCustomization.FindStoragePath(ConnectionString); + this.logger = logger; + } public override void TrackEndpointInputQueue(EndpointToQueueMapping queueToTrack) => endpointsHash.AddOrUpdate(queueToTrack, queueToTrack, (_, __) => queueToTrack); @@ -36,7 +39,7 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) } catch (Exception ex) { - Log.Warn("Problem getting learning transport queue length", ex); + logger.LogWarning(ex, "Problem getting learning transport queue length"); } } } @@ -60,7 +63,7 @@ void UpdateStore(ILookup queueLengths) } else { - Log.Warn($"Queue Length data missing for queue {instance.InputQueue} (Endpoint {instance.EndpointName})"); + logger.LogWarning("Queue Length data missing for queue {InputQueue} (Endpoint {EndpointName})", instance.InputQueue, instance.EndpointName); } } } @@ -87,7 +90,7 @@ void UpdateStore(ILookup queueLengths) readonly ConcurrentDictionary endpointsHash = new ConcurrentDictionary(); static readonly TimeSpan QueryDelayInterval = TimeSpan.FromMilliseconds(200); - static readonly ILog Log = LogManager.GetLogger(); + readonly ILogger logger; } } \ No newline at end of file diff --git a/src/ServiceControl.Transports.Msmq/DeadLetterQueueCheck.cs b/src/ServiceControl.Transports.Msmq/DeadLetterQueueCheck.cs index 7f229048f6..61c5378d4d 100644 --- a/src/ServiceControl.Transports.Msmq/DeadLetterQueueCheck.cs +++ b/src/ServiceControl.Transports.Msmq/DeadLetterQueueCheck.cs @@ -5,13 +5,13 @@ using System.Diagnostics; using System.Threading; using System.Threading.Tasks; + using Microsoft.Extensions.Logging; using NServiceBus.CustomChecks; - using NServiceBus.Logging; using Transports; public class DeadLetterQueueCheck : CustomCheck { - public DeadLetterQueueCheck(TransportSettings settings) : + public DeadLetterQueueCheck(TransportSettings settings, ILogger logger) : base("Dead Letter Queue", "Transport", TimeSpan.FromHours(1)) { runCheck = settings.RunCustomChecks; @@ -20,7 +20,7 @@ public DeadLetterQueueCheck(TransportSettings settings) : return; } - Logger.Debug("MSMQ Dead Letter Queue custom check starting"); + logger.LogDebug("MSMQ Dead Letter Queue custom check starting"); categoryName = Read("Msmq/PerformanceCounterCategoryName", "MSMQ Queue"); counterName = Read("Msmq/PerformanceCounterName", "Messages in Queue"); @@ -32,8 +32,10 @@ public DeadLetterQueueCheck(TransportSettings settings) : } catch (InvalidOperationException ex) { - Logger.Error(CounterMightBeLocalized(categoryName, counterName, counterInstanceName), ex); + logger.LogError(ex, CounterMightBeLocalized("CategoryName", "CounterName", "CounterInstanceName"), categoryName, counterName, counterInstanceName); } + + this.logger = logger; } public override Task PerformCheck(CancellationToken cancellationToken = default) @@ -43,9 +45,8 @@ public override Task PerformCheck(CancellationToken cancellationTok return CheckResult.Pass; } - Logger.Debug("Checking Dead Letter Queue length"); + logger.LogDebug("Checking Dead Letter Queue length"); float currentValue; - string result; try { if (dlqPerformanceCounter == null) @@ -57,25 +58,18 @@ public override Task PerformCheck(CancellationToken cancellationTok } catch (InvalidOperationException ex) { - result = CounterMightBeLocalized(categoryName, counterName, counterInstanceName); - Logger.Warn(result, ex); - return CheckResult.Failed(result); + logger.LogWarning(ex, CounterMightBeLocalized("CategoryName", "CounterName", "CounterInstanceName"), categoryName, counterName, counterInstanceName); + return CheckResult.Failed(CounterMightBeLocalized(categoryName, counterName, counterInstanceName)); } if (currentValue <= 0) { - Logger.Debug("No messages in Dead Letter Queue"); + logger.LogDebug("No messages in Dead Letter Queue"); return CheckResult.Pass; } - result = MessagesInDeadLetterQueue(currentValue); - Logger.Warn(result); - return CheckResult.Failed(result); - } - - static string MessagesInDeadLetterQueue(float currentValue) - { - return $"{currentValue} messages in the Dead Letter Queue on {Environment.MachineName}. This could indicate a problem with ServiceControl's retries. Please submit a support ticket to Particular if you would like help from our engineers to ensure no message loss while resolving these dead letter messages."; + logger.LogWarning("{DeadLetterMessageCount} messages in the Dead Letter Queue on {MachineName}. This could indicate a problem with ServiceControl's retries. Please submit a support ticket to Particular if you would like help from our engineers to ensure no message loss while resolving these dead letter messages.", currentValue, Environment.MachineName); + return CheckResult.Failed($"{currentValue} messages in the Dead Letter Queue on {Environment.MachineName}. This could indicate a problem with ServiceControl's retries. Please submit a support ticket to Particular if you would like help from our engineers to ensure no message loss while resolving these dead letter messages."); } static string CounterMightBeLocalized(string categoryName, string counterName, string counterInstanceName) @@ -123,6 +117,6 @@ static bool TryRead(string root, string name, out string value) string counterInstanceName; bool runCheck; - static readonly ILog Logger = LogManager.GetLogger(typeof(DeadLetterQueueCheck)); + readonly ILogger logger; } } \ No newline at end of file diff --git a/src/ServiceControl.Transports.PostgreSql.Tests/TransportTestsConfiguration.cs b/src/ServiceControl.Transports.PostgreSql.Tests/TransportTestsConfiguration.cs index 819248c612..2d6c34b86c 100644 --- a/src/ServiceControl.Transports.PostgreSql.Tests/TransportTestsConfiguration.cs +++ b/src/ServiceControl.Transports.PostgreSql.Tests/TransportTestsConfiguration.cs @@ -2,6 +2,7 @@ { using System; using System.Threading.Tasks; + using ServiceControl.Infrastructure; using ServiceControl.Transports.PostgreSql; using Transports; @@ -13,7 +14,7 @@ partial class TransportTestsConfiguration public Task Configure() { - TransportCustomization = new PostgreSqlTransportCustomization(); + TransportCustomization = new PostgreSqlTransportCustomization(LoggerUtil.CreateStaticLogger()); ConnectionString = Environment.GetEnvironmentVariable(ConnectionStringKey); if (string.IsNullOrEmpty(ConnectionString)) diff --git a/src/ServiceControl.Transports.PostgreSql/PostgreSqlTransportCustomization.cs b/src/ServiceControl.Transports.PostgreSql/PostgreSqlTransportCustomization.cs index 934bee47a1..c5f878f21f 100644 --- a/src/ServiceControl.Transports.PostgreSql/PostgreSqlTransportCustomization.cs +++ b/src/ServiceControl.Transports.PostgreSql/PostgreSqlTransportCustomization.cs @@ -4,11 +4,11 @@ using System.Runtime.CompilerServices; using BrokerThroughput; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using NServiceBus; -using NServiceBus.Logging; using NServiceBus.Transport.PostgreSql; -public class PostgreSqlTransportCustomization : TransportCustomization +public class PostgreSqlTransportCustomization(ILogger logger) : TransportCustomization { protected override void CustomizeTransportForPrimaryEndpoint(EndpointConfiguration endpointConfiguration, PostgreSqlTransport transportDefinition, TransportSettings transportSettings) { @@ -66,7 +66,7 @@ protected override PostgreSqlTransport CreateTransport(TransportSettings transpo if (transportSettings.GetOrDefault("TransportSettings.EnableDtc")) { - Logger.Error("The EnableDtc setting is no longer supported natively within ServiceControl. If you require distributed transactions, you will have to use a Transport Adapter (https://docs.particular.net/servicecontrol/transport-adapter/)"); + logger.LogError("The EnableDtc setting is no longer supported natively within ServiceControl. If you require distributed transactions, you will have to use a Transport Adapter (https://docs.particular.net/servicecontrol/transport-adapter/)"); } DisableDelayedDelivery(transport) = true; @@ -93,6 +93,4 @@ protected override string ToTransportQualifiedQueueNameCore(string queueName) static extern ref bool DisableDelayedDelivery(PostgreSqlTransport transport); const string DefaultSubscriptionTableName = "SubscriptionRouting"; - - static readonly ILog Logger = LogManager.GetLogger(typeof(PostgreSqlTransportCustomization)); } \ No newline at end of file diff --git a/src/ServiceControl.Transports.PostgreSql/QueueLengthProvider.cs b/src/ServiceControl.Transports.PostgreSql/QueueLengthProvider.cs index d58b5c526c..79b128032d 100644 --- a/src/ServiceControl.Transports.PostgreSql/QueueLengthProvider.cs +++ b/src/ServiceControl.Transports.PostgreSql/QueueLengthProvider.cs @@ -6,17 +6,18 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; using Npgsql; -using NServiceBus.Logging; class QueueLengthProvider : AbstractQueueLengthProvider { - public QueueLengthProvider(TransportSettings settings, Action store) : base(settings, store) + public QueueLengthProvider(TransportSettings settings, Action store, ILogger logger) : base(settings, store) { connectionString = ConnectionString .RemoveCustomConnectionStringParts(out var customSchema, out _); defaultSchema = customSchema ?? "public"; + this.logger = logger; } public override void TrackEndpointInputQueue(EndpointToQueueMapping queueToTrack) { @@ -55,7 +56,7 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) } catch (Exception e) { - Logger.Error("Error querying sql queue sizes.", e); + logger.LogError(e, "Error querying SQL queue sizes."); } } } @@ -113,7 +114,7 @@ async Task UpdateChunk(NpgsqlConnection connection, KeyValuePair(); + readonly ILogger logger; static readonly TimeSpan QueryDelayInterval = TimeSpan.FromMilliseconds(200); diff --git a/src/ServiceControl.Transports.RabbitMQ/QueueLengthProvider.cs b/src/ServiceControl.Transports.RabbitMQ/QueueLengthProvider.cs index 3c60019abe..311a408aa9 100644 --- a/src/ServiceControl.Transports.RabbitMQ/QueueLengthProvider.cs +++ b/src/ServiceControl.Transports.RabbitMQ/QueueLengthProvider.cs @@ -4,12 +4,12 @@ using System.Collections.Concurrent; using System.Threading; using System.Threading.Tasks; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using NServiceBus.Transport.RabbitMQ.ManagementApi; class QueueLengthProvider : AbstractQueueLengthProvider { - public QueueLengthProvider(TransportSettings settings, Action store, ITransportCustomization transportCustomization) : base(settings, store) + public QueueLengthProvider(TransportSettings settings, Action store, ITransportCustomization transportCustomization, ILogger logger) : base(settings, store) { if (transportCustomization is IManagementClientProvider provider) { @@ -19,6 +19,8 @@ public QueueLengthProvider(TransportSettings settings, Action @@ -50,7 +52,7 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) } catch (Exception e) { - Logger.Error("Queue length query loop failure.", e); + logger.LogError(e, "Queue length query loop failure."); } } } @@ -91,7 +93,7 @@ async Task FetchQueueLengths(CancellationToken cancellationToken) } catch (Exception e) { - Logger.Warn($"Error querying queue length for {queueName}", e); + logger.LogWarning(e, "Error querying queue length for {QueueName}", queueName); } } } @@ -101,7 +103,7 @@ async Task FetchQueueLengths(CancellationToken cancellationToken) readonly ConcurrentDictionary endpointQueues = new(); readonly ConcurrentDictionary sizes = new(); - static readonly ILog Logger = LogManager.GetLogger(); + readonly ILogger logger; readonly Lazy managementClient; } diff --git a/src/ServiceControl.Transports.SQS.Tests/TransportTestsConfiguration.cs b/src/ServiceControl.Transports.SQS.Tests/TransportTestsConfiguration.cs index c64f5d1bca..c931ef2f58 100644 --- a/src/ServiceControl.Transports.SQS.Tests/TransportTestsConfiguration.cs +++ b/src/ServiceControl.Transports.SQS.Tests/TransportTestsConfiguration.cs @@ -2,6 +2,7 @@ { using System; using System.Threading.Tasks; + using ServiceControl.Infrastructure; using Transports; using Transports.SQS; @@ -13,7 +14,7 @@ partial class TransportTestsConfiguration public Task Configure() { - TransportCustomization = new SQSTransportCustomization(); + TransportCustomization = new SQSTransportCustomization(LoggerUtil.CreateStaticLogger()); ConnectionString = Environment.GetEnvironmentVariable(ConnectionStringKey); if (string.IsNullOrEmpty(ConnectionString)) diff --git a/src/ServiceControl.Transports.SQS/QueueLengthProvider.cs b/src/ServiceControl.Transports.SQS/QueueLengthProvider.cs index 431d5358ac..ea8901fca9 100644 --- a/src/ServiceControl.Transports.SQS/QueueLengthProvider.cs +++ b/src/ServiceControl.Transports.SQS/QueueLengthProvider.cs @@ -1,19 +1,19 @@ namespace ServiceControl.Transports.SQS { using System; - using System.Linq; - using System.Threading.Tasks; - using System.Data.Common; using System.Collections.Concurrent; using System.Collections.Generic; + using System.Data.Common; + using System.Linq; using System.Threading; + using System.Threading.Tasks; using Amazon.Runtime; using Amazon.SQS; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; class QueueLengthProvider : AbstractQueueLengthProvider { - public QueueLengthProvider(TransportSettings settings, Action store) : base(settings, store) + public QueueLengthProvider(TransportSettings settings, Action store, ILogger logger) : base(settings, store) { var builder = new DbConnectionStringBuilder { ConnectionString = ConnectionString }; if (builder.ContainsKey("AccessKeyId") || builder.ContainsKey("SecretAccessKey")) @@ -24,13 +24,15 @@ public QueueLengthProvider(TransportSettings settings, Action clientFactory = () => new AmazonSQSClient(); - static readonly ILog Logger = LogManager.GetLogger(); + readonly ILogger logger; } } diff --git a/src/ServiceControl.Transports.SQS/SQSTransportCustomization.cs b/src/ServiceControl.Transports.SQS/SQSTransportCustomization.cs index 8c17902b53..4ae8e6a82e 100644 --- a/src/ServiceControl.Transports.SQS/SQSTransportCustomization.cs +++ b/src/ServiceControl.Transports.SQS/SQSTransportCustomization.cs @@ -2,7 +2,6 @@ { using System; using System.Linq; - using System.Runtime.CompilerServices; using Amazon; using Amazon.Runtime; using Amazon.S3; @@ -10,11 +9,11 @@ using Amazon.SQS; using BrokerThroughput; using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Logging; using NServiceBus; using NServiceBus.Configuration.AdvancedExtensibility; - using NServiceBus.Logging; - public class SQSTransportCustomization : TransportCustomization + public class SQSTransportCustomization(ILogger logger) : TransportCustomization { protected override void CustomizeTransportForPrimaryEndpoint(EndpointConfiguration endpointConfiguration, SqsTransport transportDefinition, TransportSettings transportSettings) { @@ -65,7 +64,7 @@ protected override SqsTransport CreateTransport(TransportSettings transportSetti else { //See https://docs.aws.amazon.com/sdk-for-net/v3/developer-guide/net-dg-config-creds.html#creds-assign - log.Info( + logger.LogInformation( "BasicAWSCredentials have not been supplied in the connection string. Attempting to use existing environment or IAM role credentials for SQS Client."); sqsClient = new AmazonSQSClient(); snsClient = new AmazonSimpleNotificationServiceClient(); @@ -101,7 +100,7 @@ protected override SqsTransport CreateTransport(TransportSettings transportSetti } else { - log.Info( + logger.LogInformation( "BasicAWSCredentials have not been supplied in the connection string. Attempting to use existing environment or IAM role credentials for S3 Client."); s3Client = new AmazonS3Client(); } @@ -121,6 +120,5 @@ static void PromoteEnvironmentVariableFromConnectionString(string value, string environmentVariableName) => Environment.SetEnvironmentVariable(environmentVariableName, value, EnvironmentVariableTarget.Process); - static readonly ILog log = LogManager.GetLogger(); } } \ No newline at end of file diff --git a/src/ServiceControl.Transports.SqlServer.Tests/TransportTestsConfiguration.cs b/src/ServiceControl.Transports.SqlServer.Tests/TransportTestsConfiguration.cs index 9cf82c6dde..abcad12793 100644 --- a/src/ServiceControl.Transports.SqlServer.Tests/TransportTestsConfiguration.cs +++ b/src/ServiceControl.Transports.SqlServer.Tests/TransportTestsConfiguration.cs @@ -2,6 +2,7 @@ { using System; using System.Threading.Tasks; + using ServiceControl.Infrastructure; using Transports; using Transports.SqlServer; @@ -13,7 +14,7 @@ partial class TransportTestsConfiguration public Task Configure() { - TransportCustomization = new SqlServerTransportCustomization(); + TransportCustomization = new SqlServerTransportCustomization(LoggerUtil.CreateStaticLogger()); ConnectionString = Environment.GetEnvironmentVariable(ConnectionStringKey); if (string.IsNullOrEmpty(ConnectionString)) diff --git a/src/ServiceControl.Transports.SqlServer/QueueLengthProvider.cs b/src/ServiceControl.Transports.SqlServer/QueueLengthProvider.cs index 196905a678..b9fe29a227 100644 --- a/src/ServiceControl.Transports.SqlServer/QueueLengthProvider.cs +++ b/src/ServiceControl.Transports.SqlServer/QueueLengthProvider.cs @@ -7,16 +7,17 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Data.SqlClient; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; class QueueLengthProvider : AbstractQueueLengthProvider { - public QueueLengthProvider(TransportSettings settings, Action store) : base(settings, store) + public QueueLengthProvider(TransportSettings settings, Action store, ILogger logger) : base(settings, store) { connectionString = ConnectionString .RemoveCustomConnectionStringParts(out var customSchema, out _); defaultSchema = customSchema ?? "dbo"; + this.logger = logger; } public override void TrackEndpointInputQueue(EndpointToQueueMapping queueToTrack) { @@ -53,7 +54,7 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) } catch (Exception e) { - Logger.Error("Error querying sql queue sizes.", e); + logger.LogError(e, "Error querying sql queue sizes."); } } } @@ -111,7 +112,7 @@ async Task UpdateChunk(SqlConnection connection, KeyValuePair[] c if (queueLength == -1) { - Logger.Warn($"Table {chunkPair.Key} does not exist."); + logger.LogWarning("Table {TableName} does not exist.", chunkPair.Key); } else { @@ -128,7 +129,7 @@ async Task UpdateChunk(SqlConnection connection, KeyValuePair[] c readonly string connectionString; readonly string defaultSchema; - static readonly ILog Logger = LogManager.GetLogger(); + readonly ILogger logger; static readonly TimeSpan QueryDelayInterval = TimeSpan.FromMilliseconds(200); diff --git a/src/ServiceControl.Transports.SqlServer/SqlServerTransportCustomization.cs b/src/ServiceControl.Transports.SqlServer/SqlServerTransportCustomization.cs index 24d3dec0f3..a89ee8fecc 100644 --- a/src/ServiceControl.Transports.SqlServer/SqlServerTransportCustomization.cs +++ b/src/ServiceControl.Transports.SqlServer/SqlServerTransportCustomization.cs @@ -4,12 +4,12 @@ using System.Runtime.CompilerServices; using BrokerThroughput; using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Logging; using NServiceBus; using NServiceBus.Configuration.AdvancedExtensibility; - using NServiceBus.Logging; using NServiceBus.Transport.SqlServer; - public class SqlServerTransportCustomization : TransportCustomization + public class SqlServerTransportCustomization(ILogger logger) : TransportCustomization { protected override void CustomizeTransportForPrimaryEndpoint(EndpointConfiguration endpointConfiguration, SqlServerTransport transportDefinition, TransportSettings transportSettings) { @@ -73,7 +73,7 @@ protected override SqlServerTransport CreateTransport(TransportSettings transpor if (transportSettings.GetOrDefault("TransportSettings.EnableDtc")) { - Logger.Error("The EnableDtc setting is no longer supported natively within ServiceControl. If you require distributed transactions, you will have to use a Transport Adapter (https://docs.particular.net/servicecontrol/transport-adapter/)"); + logger.LogError("The EnableDtc setting is no longer supported natively within ServiceControl. If you require distributed transactions, you will have to use a Transport Adapter (https://docs.particular.net/servicecontrol/transport-adapter/)"); } DisableDelayedDelivery(transport) = true; @@ -87,7 +87,5 @@ protected override SqlServerTransport CreateTransport(TransportSettings transpor static extern ref bool DisableDelayedDelivery(SqlServerTransport transport); const string defaultSubscriptionTableName = "SubscriptionRouting"; - - static readonly ILog Logger = LogManager.GetLogger(typeof(SqlServerTransportCustomization)); } } \ No newline at end of file diff --git a/src/ServiceControl.Transports/ServiceControl.Transports.csproj b/src/ServiceControl.Transports/ServiceControl.Transports.csproj index 435491c160..263429e5d4 100644 --- a/src/ServiceControl.Transports/ServiceControl.Transports.csproj +++ b/src/ServiceControl.Transports/ServiceControl.Transports.csproj @@ -9,6 +9,7 @@ + diff --git a/src/ServiceControl.Transports/TransportManifest.cs b/src/ServiceControl.Transports/TransportManifest.cs index c37538867a..429d80db9b 100644 --- a/src/ServiceControl.Transports/TransportManifest.cs +++ b/src/ServiceControl.Transports/TransportManifest.cs @@ -5,7 +5,8 @@ using System.IO; using System.Linq; using System.Text.Json; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; + using ServiceControl.Infrastructure; public class TransportManifest { @@ -60,7 +61,7 @@ static TransportManifestLibrary() } catch (Exception ex) { - logger.Warn($"Failed to load transport manifests from {assemblyDirectory}", ex); + logger.LogWarning(ex, "Failed to load transport manifests from {AssemblyDirectory}", assemblyDirectory); } try @@ -79,10 +80,10 @@ static TransportManifestLibrary() } catch (Exception ex) { - logger.Warn($"Failed to load transport manifests from development locations", ex); + logger.LogWarning(ex, "Failed to load transport manifests from development locations"); } - TransportManifests.SelectMany(t => t.Definitions).ToList().ForEach(m => logger.Info($"Found transport manifest for {m.DisplayName}")); + TransportManifests.SelectMany(t => t.Definitions).ToList().ForEach(m => logger.LogInformation("Found transport manifest for {TransportManifestDisplayName}", m.DisplayName)); } static string GetAssemblyDirectory() @@ -105,7 +106,7 @@ public static TransportManifestDefinition Find(string transportType) return transportManifestDefinition; } - static readonly ILog logger = LogManager.GetLogger(typeof(TransportManifestLibrary)); + static readonly ILogger logger = LoggerUtil.CreateStaticLogger(typeof(TransportManifestLibrary)); } } From 42d01e7d03328ebdfa00a8ccc050bbd485a29147 Mon Sep 17 00:00:00 2001 From: Phil Bastian Date: Mon, 16 Jun 2025 07:20:35 +0800 Subject: [PATCH 10/56] remove signedassembly requirement so that infrastructure can be imported --- src/ServiceControl.Transports/ServiceControl.Transports.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ServiceControl.Transports/ServiceControl.Transports.csproj b/src/ServiceControl.Transports/ServiceControl.Transports.csproj index 263429e5d4..263249e023 100644 --- a/src/ServiceControl.Transports/ServiceControl.Transports.csproj +++ b/src/ServiceControl.Transports/ServiceControl.Transports.csproj @@ -2,7 +2,6 @@ net8.0 - true ..\NServiceBus.snk From 96ec1242a80d3658cc1c788440dcb398fae22f7d Mon Sep 17 00:00:00 2001 From: Phil Bastian Date: Mon, 16 Jun 2025 07:39:31 +0800 Subject: [PATCH 11/56] revert previous change and instead propogate signing back to servicecontrol.infrastructure --- .../ServiceControl.Configuration.csproj | 2 ++ .../ServiceControl.Infrastructure.csproj | 2 ++ src/ServiceControl.Transports/ServiceControl.Transports.csproj | 1 + 3 files changed, 5 insertions(+) diff --git a/src/ServiceControl.Configuration/ServiceControl.Configuration.csproj b/src/ServiceControl.Configuration/ServiceControl.Configuration.csproj index 2a585451b7..302ef7cbea 100644 --- a/src/ServiceControl.Configuration/ServiceControl.Configuration.csproj +++ b/src/ServiceControl.Configuration/ServiceControl.Configuration.csproj @@ -2,6 +2,8 @@ net8.0 + true + ..\NServiceBus.snk diff --git a/src/ServiceControl.Infrastructure/ServiceControl.Infrastructure.csproj b/src/ServiceControl.Infrastructure/ServiceControl.Infrastructure.csproj index 123180a850..a686479039 100644 --- a/src/ServiceControl.Infrastructure/ServiceControl.Infrastructure.csproj +++ b/src/ServiceControl.Infrastructure/ServiceControl.Infrastructure.csproj @@ -2,6 +2,8 @@ net8.0 + true + ..\NServiceBus.snk diff --git a/src/ServiceControl.Transports/ServiceControl.Transports.csproj b/src/ServiceControl.Transports/ServiceControl.Transports.csproj index 263249e023..263429e5d4 100644 --- a/src/ServiceControl.Transports/ServiceControl.Transports.csproj +++ b/src/ServiceControl.Transports/ServiceControl.Transports.csproj @@ -2,6 +2,7 @@ net8.0 + true ..\NServiceBus.snk From 5aaabe6af15a776920f5ec7ab0406ab28a7827b7 Mon Sep 17 00:00:00 2001 From: Phil Bastian Date: Mon, 16 Jun 2025 08:13:00 +0800 Subject: [PATCH 12/56] fix signature of customisation classes that are dynamically created --- .../PostgreSqlTransportCustomization.cs | 5 ++++- .../SQSTransportCustomization.cs | 5 ++++- .../SqlServerTransportCustomization.cs | 5 ++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/ServiceControl.Transports.PostgreSql/PostgreSqlTransportCustomization.cs b/src/ServiceControl.Transports.PostgreSql/PostgreSqlTransportCustomization.cs index c5f878f21f..4523792f18 100644 --- a/src/ServiceControl.Transports.PostgreSql/PostgreSqlTransportCustomization.cs +++ b/src/ServiceControl.Transports.PostgreSql/PostgreSqlTransportCustomization.cs @@ -7,8 +7,9 @@ using Microsoft.Extensions.Logging; using NServiceBus; using NServiceBus.Transport.PostgreSql; +using ServiceControl.Infrastructure; -public class PostgreSqlTransportCustomization(ILogger logger) : TransportCustomization +public class PostgreSqlTransportCustomization() : TransportCustomization { protected override void CustomizeTransportForPrimaryEndpoint(EndpointConfiguration endpointConfiguration, PostgreSqlTransport transportDefinition, TransportSettings transportSettings) { @@ -93,4 +94,6 @@ protected override string ToTransportQualifiedQueueNameCore(string queueName) static extern ref bool DisableDelayedDelivery(PostgreSqlTransport transport); const string DefaultSubscriptionTableName = "SubscriptionRouting"; + + static readonly ILogger logger = LoggerUtil.CreateStaticLogger(); } \ No newline at end of file diff --git a/src/ServiceControl.Transports.SQS/SQSTransportCustomization.cs b/src/ServiceControl.Transports.SQS/SQSTransportCustomization.cs index 4ae8e6a82e..8aa9a0d530 100644 --- a/src/ServiceControl.Transports.SQS/SQSTransportCustomization.cs +++ b/src/ServiceControl.Transports.SQS/SQSTransportCustomization.cs @@ -12,8 +12,9 @@ using Microsoft.Extensions.Logging; using NServiceBus; using NServiceBus.Configuration.AdvancedExtensibility; + using ServiceControl.Infrastructure; - public class SQSTransportCustomization(ILogger logger) : TransportCustomization + public class SQSTransportCustomization() : TransportCustomization { protected override void CustomizeTransportForPrimaryEndpoint(EndpointConfiguration endpointConfiguration, SqsTransport transportDefinition, TransportSettings transportSettings) { @@ -120,5 +121,7 @@ static void PromoteEnvironmentVariableFromConnectionString(string value, string environmentVariableName) => Environment.SetEnvironmentVariable(environmentVariableName, value, EnvironmentVariableTarget.Process); + static readonly ILogger logger = LoggerUtil.CreateStaticLogger(); + } } \ No newline at end of file diff --git a/src/ServiceControl.Transports.SqlServer/SqlServerTransportCustomization.cs b/src/ServiceControl.Transports.SqlServer/SqlServerTransportCustomization.cs index a89ee8fecc..034a23dc9c 100644 --- a/src/ServiceControl.Transports.SqlServer/SqlServerTransportCustomization.cs +++ b/src/ServiceControl.Transports.SqlServer/SqlServerTransportCustomization.cs @@ -8,8 +8,9 @@ using NServiceBus; using NServiceBus.Configuration.AdvancedExtensibility; using NServiceBus.Transport.SqlServer; + using ServiceControl.Infrastructure; - public class SqlServerTransportCustomization(ILogger logger) : TransportCustomization + public class SqlServerTransportCustomization() : TransportCustomization { protected override void CustomizeTransportForPrimaryEndpoint(EndpointConfiguration endpointConfiguration, SqlServerTransport transportDefinition, TransportSettings transportSettings) { @@ -87,5 +88,7 @@ protected override SqlServerTransport CreateTransport(TransportSettings transpor static extern ref bool DisableDelayedDelivery(SqlServerTransport transport); const string defaultSubscriptionTableName = "SubscriptionRouting"; + + static readonly ILogger logger = LoggerUtil.CreateStaticLogger(); } } \ No newline at end of file From 67920ff323507faca9b36f50018aefded54ed10a Mon Sep 17 00:00:00 2001 From: Phil Bastian Date: Mon, 16 Jun 2025 08:49:17 +0800 Subject: [PATCH 13/56] add ilogger to test services and remove direct construction with logger --- .../TransportTestsConfiguration.cs | 3 +-- .../TransportTestsConfiguration.cs | 3 +-- .../TransportTestsConfiguration.cs | 3 +-- src/ServiceControl.Transports.Tests/TransportTestFixture.cs | 2 ++ 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/ServiceControl.Transports.PostgreSql.Tests/TransportTestsConfiguration.cs b/src/ServiceControl.Transports.PostgreSql.Tests/TransportTestsConfiguration.cs index 2d6c34b86c..819248c612 100644 --- a/src/ServiceControl.Transports.PostgreSql.Tests/TransportTestsConfiguration.cs +++ b/src/ServiceControl.Transports.PostgreSql.Tests/TransportTestsConfiguration.cs @@ -2,7 +2,6 @@ { using System; using System.Threading.Tasks; - using ServiceControl.Infrastructure; using ServiceControl.Transports.PostgreSql; using Transports; @@ -14,7 +13,7 @@ partial class TransportTestsConfiguration public Task Configure() { - TransportCustomization = new PostgreSqlTransportCustomization(LoggerUtil.CreateStaticLogger()); + TransportCustomization = new PostgreSqlTransportCustomization(); ConnectionString = Environment.GetEnvironmentVariable(ConnectionStringKey); if (string.IsNullOrEmpty(ConnectionString)) diff --git a/src/ServiceControl.Transports.SQS.Tests/TransportTestsConfiguration.cs b/src/ServiceControl.Transports.SQS.Tests/TransportTestsConfiguration.cs index c931ef2f58..c64f5d1bca 100644 --- a/src/ServiceControl.Transports.SQS.Tests/TransportTestsConfiguration.cs +++ b/src/ServiceControl.Transports.SQS.Tests/TransportTestsConfiguration.cs @@ -2,7 +2,6 @@ { using System; using System.Threading.Tasks; - using ServiceControl.Infrastructure; using Transports; using Transports.SQS; @@ -14,7 +13,7 @@ partial class TransportTestsConfiguration public Task Configure() { - TransportCustomization = new SQSTransportCustomization(LoggerUtil.CreateStaticLogger()); + TransportCustomization = new SQSTransportCustomization(); ConnectionString = Environment.GetEnvironmentVariable(ConnectionStringKey); if (string.IsNullOrEmpty(ConnectionString)) diff --git a/src/ServiceControl.Transports.SqlServer.Tests/TransportTestsConfiguration.cs b/src/ServiceControl.Transports.SqlServer.Tests/TransportTestsConfiguration.cs index abcad12793..9cf82c6dde 100644 --- a/src/ServiceControl.Transports.SqlServer.Tests/TransportTestsConfiguration.cs +++ b/src/ServiceControl.Transports.SqlServer.Tests/TransportTestsConfiguration.cs @@ -2,7 +2,6 @@ { using System; using System.Threading.Tasks; - using ServiceControl.Infrastructure; using Transports; using Transports.SqlServer; @@ -14,7 +13,7 @@ partial class TransportTestsConfiguration public Task Configure() { - TransportCustomization = new SqlServerTransportCustomization(LoggerUtil.CreateStaticLogger()); + TransportCustomization = new SqlServerTransportCustomization(); ConnectionString = Environment.GetEnvironmentVariable(ConnectionStringKey); if (string.IsNullOrEmpty(ConnectionString)) diff --git a/src/ServiceControl.Transports.Tests/TransportTestFixture.cs b/src/ServiceControl.Transports.Tests/TransportTestFixture.cs index 0f6d9027e1..cd8c301137 100644 --- a/src/ServiceControl.Transports.Tests/TransportTestFixture.cs +++ b/src/ServiceControl.Transports.Tests/TransportTestFixture.cs @@ -20,6 +20,7 @@ class TransportTestFixture [SetUp] public virtual async Task Setup() { + //TODO remove LogManager usage LogManager.UseFactory(new TestContextAppenderFactory()); configuration = new TransportTestsConfiguration(); testCancellationTokenSource = Debugger.IsAttached ? new CancellationTokenSource() : new CancellationTokenSource(TestTimeout); @@ -102,6 +103,7 @@ protected async Task StartQueueLengthProvider(string queueName configuration.TransportCustomization.CustomizeMonitoringEndpoint(new EndpointConfiguration("queueName"), transportSettings); serviceCollection.AddSingleton>((qlt, _) => onQueueLengthReported(qlt.First())); + serviceCollection.AddLogging(); var serviceProvider = serviceCollection.BuildServiceProvider(); queueLengthProvider = serviceProvider.GetRequiredService(); From b3c690a6c198c3976157c4b48351ce76e69157a4 Mon Sep 17 00:00:00 2001 From: Phil Bastian Date: Tue, 17 Jun 2025 07:48:10 +0800 Subject: [PATCH 14/56] get tests to use ilogger --- .../LoggerUtil.cs | 14 ++- .../FullEndpointTestFixture.cs | 2 + .../TestContextAppender.cs | 86 +++---------------- .../TestContextAppenderFactory.cs | 13 ++- .../TransportManifestLibraryTests.cs | 7 ++ .../TransportTestFixture.cs | 3 +- 6 files changed, 46 insertions(+), 79 deletions(-) diff --git a/src/ServiceControl.Infrastructure/LoggerUtil.cs b/src/ServiceControl.Infrastructure/LoggerUtil.cs index 039d0b4938..0757d17fa0 100644 --- a/src/ServiceControl.Infrastructure/LoggerUtil.cs +++ b/src/ServiceControl.Infrastructure/LoggerUtil.cs @@ -6,8 +6,18 @@ public static class LoggerUtil { + /// + /// used for tests + /// + public static ILoggerFactory LoggerFactory { private get; set; } + public static void BuildLogger(this ILoggingBuilder loggingBuilder, LogLevel level) { + if (LoggerFactory != null) + { + return; + } + //TODO: can we get these from settings too? loggingBuilder.AddNLog(); loggingBuilder.AddSeq(); @@ -16,13 +26,13 @@ public static void BuildLogger(this ILoggingBuilder loggingBuilder, LogLevel lev public static ILogger CreateStaticLogger(LogLevel level = LogLevel.Information) { - var factory = LoggerFactory.Create(configure => configure.BuildLogger(level)); + var factory = LoggerFactory ?? Microsoft.Extensions.Logging.LoggerFactory.Create(configure => configure.BuildLogger(level)); return factory.CreateLogger(); } public static ILogger CreateStaticLogger(Type type, LogLevel level = LogLevel.Information) { - var factory = LoggerFactory.Create(configure => configure.BuildLogger(level)); + var factory = LoggerFactory ?? Microsoft.Extensions.Logging.LoggerFactory.Create(configure => configure.BuildLogger(level)); return factory.CreateLogger(type); } } diff --git a/src/ServiceControl.Transports.Tests/FullEndpointTestFixture.cs b/src/ServiceControl.Transports.Tests/FullEndpointTestFixture.cs index 55f7f24383..f2c4d13313 100644 --- a/src/ServiceControl.Transports.Tests/FullEndpointTestFixture.cs +++ b/src/ServiceControl.Transports.Tests/FullEndpointTestFixture.cs @@ -4,6 +4,7 @@ using System.Threading.Tasks; using NServiceBus.AcceptanceTesting.Customization; using NUnit.Framework; + using ServiceControl.Infrastructure; [TestFixture] class FullEndpointTestFixture @@ -11,6 +12,7 @@ class FullEndpointTestFixture [SetUp] public virtual async Task Setup() { + LoggerUtil.LoggerFactory = new TestContextAppenderFactory(); configuration = new TransportTestsConfiguration(); var queueSuffix = $"-{System.IO.Path.GetRandomFileName().Replace(".", string.Empty)}"; diff --git a/src/ServiceControl.Transports.Tests/TestContextAppender.cs b/src/ServiceControl.Transports.Tests/TestContextAppender.cs index 26a3a5645c..e3b9524253 100644 --- a/src/ServiceControl.Transports.Tests/TestContextAppender.cs +++ b/src/ServiceControl.Transports.Tests/TestContextAppender.cs @@ -1,87 +1,29 @@ namespace ServiceControl.Transport.Tests { using System; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using NUnit.Framework; - class TestContextAppender : ILog + class TestContextAppender(string categoryName) : ILogger { - public bool IsDebugEnabled => false; - public bool IsInfoEnabled => false; - public bool IsWarnEnabled => true; - public bool IsErrorEnabled => true; - public bool IsFatalEnabled => true; - - public void Debug(string message) => Log(message, LogLevel.Debug); - - public void Debug(string message, Exception exception) - { - var fullMessage = $"{message} {exception}"; - Log(fullMessage, LogLevel.Debug); - } - - public void DebugFormat(string format, params object[] args) + public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) { - var fullMessage = string.Format(format, args); - Log(fullMessage, LogLevel.Debug); + if (IsEnabled(logLevel)) + { + TestContext.Out.WriteLine($"{categoryName}: {formatter(state, exception)}"); + } } + public bool IsEnabled(LogLevel logLevel) => logLevel >= LogLevel.Warning; - public void Info(string message) => Log(message, LogLevel.Info); + public IDisposable BeginScope(TState state) where TState : notnull => Disposable.Instance; - public void Info(string message, Exception exception) + class Disposable : IDisposable { - var fullMessage = $"{message} {exception}"; - Log(fullMessage, LogLevel.Info); - } + public static Disposable Instance = new(); - public void InfoFormat(string format, params object[] args) - { - var fullMessage = string.Format(format, args); - Log(fullMessage, LogLevel.Info); + public void Dispose() + { + } } - - public void Warn(string message) => Log(message, LogLevel.Warn); - - public void Warn(string message, Exception exception) - { - var fullMessage = $"{message} {exception}"; - Log(fullMessage, LogLevel.Warn); - } - - public void WarnFormat(string format, params object[] args) - { - var fullMessage = string.Format(format, args); - Log(fullMessage, LogLevel.Warn); - } - - public void Error(string message) => Log(message, LogLevel.Error); - - public void Error(string message, Exception exception) - { - var fullMessage = $"{message} {exception}"; - Log(fullMessage, LogLevel.Error); - } - - public void ErrorFormat(string format, params object[] args) - { - var fullMessage = string.Format(format, args); - Log(fullMessage, LogLevel.Error); - } - - public void Fatal(string message) => Log(message, LogLevel.Fatal); - - public void Fatal(string message, Exception exception) - { - var fullMessage = $"{message} {exception}"; - Log(fullMessage, LogLevel.Fatal); - } - - public void FatalFormat(string format, params object[] args) - { - var fullMessage = string.Format(format, args); - Log(fullMessage, LogLevel.Fatal); - } - - static void Log(string message, LogLevel _) => TestContext.Out.WriteLine(message); } } \ No newline at end of file diff --git a/src/ServiceControl.Transports.Tests/TestContextAppenderFactory.cs b/src/ServiceControl.Transports.Tests/TestContextAppenderFactory.cs index 75d8dbfcef..9c5b4da728 100644 --- a/src/ServiceControl.Transports.Tests/TestContextAppenderFactory.cs +++ b/src/ServiceControl.Transports.Tests/TestContextAppenderFactory.cs @@ -1,12 +1,17 @@ namespace ServiceControl.Transport.Tests { - using System; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; class TestContextAppenderFactory : ILoggerFactory { - public ILog GetLogger(Type type) => GetLogger(type.FullName); + public void AddProvider(ILoggerProvider provider) + { + } - public ILog GetLogger(string name) => new TestContextAppender(); + public ILogger CreateLogger(string categoryName) => new TestContextAppender(categoryName); + + public void Dispose() + { + } } } \ No newline at end of file diff --git a/src/ServiceControl.Transports.Tests/TransportManifestLibraryTests.cs b/src/ServiceControl.Transports.Tests/TransportManifestLibraryTests.cs index aa678c8b01..78a6aea1d7 100644 --- a/src/ServiceControl.Transports.Tests/TransportManifestLibraryTests.cs +++ b/src/ServiceControl.Transports.Tests/TransportManifestLibraryTests.cs @@ -7,6 +7,7 @@ using System.Runtime.InteropServices; using NUnit.Framework; using Particular.Approvals; + using ServiceControl.Infrastructure; using ServiceControl.Transports; [TestFixture] @@ -16,6 +17,12 @@ public class TransportManifestLibraryTests const string transportType = "ServiceControl.Transports.ASBS.ASBSTransportCustomization, ServiceControl.Transports.ASBS"; const string transportAlias = "ServiceControl.Transports.AzureServiceBus.AzureServiceBusTransport, ServiceControl.Transports.AzureServiceBus"; + [SetUp] + public void SetUp() + { + LoggerUtil.LoggerFactory = new TestContextAppenderFactory(); + } + [Test] public void Should_find_transport_manifest_by_name() { diff --git a/src/ServiceControl.Transports.Tests/TransportTestFixture.cs b/src/ServiceControl.Transports.Tests/TransportTestFixture.cs index cd8c301137..4a769f63bb 100644 --- a/src/ServiceControl.Transports.Tests/TransportTestFixture.cs +++ b/src/ServiceControl.Transports.Tests/TransportTestFixture.cs @@ -9,6 +9,7 @@ using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using NServiceBus; + using NServiceBus.Extensions.Logging; using NServiceBus.Logging; using NServiceBus.Transport; using NUnit.Framework; @@ -21,7 +22,7 @@ class TransportTestFixture public virtual async Task Setup() { //TODO remove LogManager usage - LogManager.UseFactory(new TestContextAppenderFactory()); + LogManager.UseFactory(new ExtensionsLoggerFactory(new TestContextAppenderFactory())); configuration = new TransportTestsConfiguration(); testCancellationTokenSource = Debugger.IsAttached ? new CancellationTokenSource() : new CancellationTokenSource(TestTimeout); registrations = []; From 66aaa0225579fce5193958868a94003f123b153a Mon Sep 17 00:00:00 2001 From: JasonTaylorDev Date: Tue, 10 Jun 2025 10:34:26 +1000 Subject: [PATCH 15/56] Switch to .NET logging --- .../CustomChecks/CheckDirtyMemory.cs | 14 ++++---- .../CustomChecks/CheckFreeDiskSpace.cs | 32 ++++++++--------- ...CheckMinimumStorageRequiredForIngestion.cs | 35 +++++++++---------- .../CustomChecks/CheckRavenDBIndexLag.cs | 20 ++++++----- .../RavenEmbeddedPersistenceLifecycle.cs | 8 ++--- .../RavenPersistenceConfiguration.cs | 22 +++++++----- .../LoggerUtil.cs | 27 ++++++++++++++ .../ServiceControlComponentRunner.cs | 3 +- .../Hosting/Commands/SetupCommand.cs | 8 ++--- .../MonitoredEndpointMessageTypeParser.cs | 7 ++-- .../Licensing/ActiveLicense.cs | 14 +++++--- .../Licensing/LicenseCheckHostedService.cs | 7 ++-- src/ServiceControl.Monitoring/Program.cs | 11 +++--- .../LegacyQueueLengthReportHandler.cs | 15 ++------ .../ServiceControl.Monitoring.csproj | 1 - 15 files changed, 118 insertions(+), 106 deletions(-) create mode 100644 src/ServiceControl.Infrastructure/LoggerUtil.cs diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckDirtyMemory.cs b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckDirtyMemory.cs index 37731858d8..409b3d6df1 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckDirtyMemory.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckDirtyMemory.cs @@ -3,26 +3,24 @@ namespace ServiceControl.Audit.Persistence.RavenDB.CustomChecks; using System; using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; using NServiceBus.CustomChecks; -using NServiceBus.Logging; -class CheckDirtyMemory(MemoryInformationRetriever memoryInformationRetriever) : CustomCheck("RavenDB dirty memory", "ServiceControl.Audit Health", TimeSpan.FromMinutes(5)) +class CheckDirtyMemory(MemoryInformationRetriever memoryInformationRetriever, ILogger logger) : CustomCheck("RavenDB dirty memory", "ServiceControl.Audit Health", TimeSpan.FromMinutes(5)) { + public override async Task PerformCheck(CancellationToken cancellationToken = default) { var (isHighDirty, dirtyMemory) = await memoryInformationRetriever.GetMemoryInformation(cancellationToken); - Log.Debug($"RavenDB dirty memory value: {dirtyMemory}."); + logger.LogDebug("RavenDB dirty memory value: {DirtyMemory}.", dirtyMemory); if (isHighDirty) { - var message = $"There is a high level of RavenDB dirty memory ({dirtyMemory}). See https://docs.particular.net/servicecontrol/troubleshooting#ravendb-dirty-memory for guidance on how to mitigate the issue."; - Log.Warn(message); - return CheckResult.Failed(message); + logger.LogWarning("There is a high level of RavenDB dirty memory ({DirtyMemory}). See https://docs.particular.net/servicecontrol/troubleshooting#ravendb-dirty-memory for guidance on how to mitigate the issue.", dirtyMemory); + return CheckResult.Failed($"There is a high level of RavenDB dirty memory ({dirtyMemory}). See https://docs.particular.net/servicecontrol/troubleshooting#ravendb-dirty-memory for guidance on how to mitigate the issue."); } return CheckResult.Pass; } - - static readonly ILog Log = LogManager.GetLogger(); } \ No newline at end of file diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs index 18705af5b9..923b6208d6 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs @@ -5,17 +5,18 @@ using System.IO; using System.Threading; using System.Threading.Tasks; + using Microsoft.Extensions.Logging; using NServiceBus.CustomChecks; - using NServiceBus.Logging; using RavenDB; + using ServiceControl.Infrastructure; - class CheckFreeDiskSpace(DatabaseConfiguration databaseConfiguration) : CustomCheck("ServiceControl.Audit database", "Storage space", TimeSpan.FromMinutes(5)) + class CheckFreeDiskSpace(DatabaseConfiguration databaseConfiguration, ILogger logger) : CustomCheck("ServiceControl.Audit database", "Storage space", TimeSpan.FromMinutes(5)) { public override Task PerformCheck(CancellationToken cancellationToken = default) { - if (Logger.IsDebugEnabled) + if (logger.IsEnabled(LogLevel.Debug)) { - Logger.Debug($"Check ServiceControl data drive space remaining custom check starting. Threshold {percentageThreshold:P0}"); + logger.LogDebug("Check ServiceControl data drive space remaining custom check starting. Threshold {PercentageThreshold:P0}", percentageThreshold); } if (!databaseConfiguration.ServerConfiguration.UseEmbeddedServer) @@ -34,9 +35,9 @@ public override Task PerformCheck(CancellationToken cancellationTok var percentRemaining = (decimal)dataDriveInfo.AvailableFreeSpace / dataDriveInfo.TotalSize; - if (Logger.IsDebugEnabled) + if (logger.IsEnabled(LogLevel.Debug)) { - Logger.Debug($"Free space: {availableFreeSpace:N0}B | Total: {totalSpace:N0}B | Percent remaining {percentRemaining:P1}"); + logger.LogDebug("Free space: {AvailableFreeSpace:N0}B | Total: {TotalSpace:N0}B | Percent remaining {PercentRemaining:P1}", availableFreeSpace, totalSpace, percentRemaining); } return percentRemaining > percentageThreshold @@ -51,26 +52,22 @@ public static int Parse(IDictionary settings) thresholdValue = $"{DataSpaceRemainingThresholdDefault}"; } - string message; if (!int.TryParse(thresholdValue, out var threshold)) { - message = $"{RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey} must be an integer."; - Logger.Fatal(message); - throw new Exception(message); + Logger.LogCritical("{RavenPersistenceConfigurationDataSpaceRemainingThresholdKey} must be an integer.", RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey); + throw new Exception($"{RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey} must be an integer."); } if (threshold < 0) { - message = $"{RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey} is invalid, minimum value is 0."; - Logger.Fatal(message); - throw new Exception(message); + Logger.LogCritical("{RavenPersistenceConfigurationDataSpaceRemainingThresholdKey} is invalid, minimum value is 0.", RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey); + throw new Exception($"{RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey} is invalid, minimum value is 0."); } if (threshold > 100) { - message = $"{RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey} is invalid, maximum value is 100."; - Logger.Fatal(message); - throw new Exception(message); + Logger.LogCritical("{RavenPersistenceConfigurationDataSpaceRemainingThresholdKey} is invalid, maximum value is 100.", RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey); + throw new Exception($"{RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey} is invalid, maximum value is 100."); } return threshold; @@ -78,8 +75,7 @@ public static int Parse(IDictionary settings) readonly string dataPathRoot = Path.GetPathRoot(databaseConfiguration.ServerConfiguration.DbPath); readonly decimal percentageThreshold = databaseConfiguration.DataSpaceRemainingThreshold / 100m; - + static readonly ILogger Logger = LoggerUtil.CreateStaticLogger(); public const int DataSpaceRemainingThresholdDefault = 20; - static readonly ILog Logger = LogManager.GetLogger(typeof(CheckFreeDiskSpace)); } } \ No newline at end of file diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs index 6d2fccbc38..56153b3169 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs @@ -5,19 +5,20 @@ using System.IO; using System.Threading; using System.Threading.Tasks; + using Microsoft.Extensions.Logging; using NServiceBus.CustomChecks; - using NServiceBus.Logging; using RavenDB; + using ServiceControl.Infrastructure; - class CheckMinimumStorageRequiredForIngestion(MinimumRequiredStorageState stateHolder, DatabaseConfiguration databaseConfiguration) : CustomCheck("Audit Message Ingestion Process", "ServiceControl.Audit Health", TimeSpan.FromSeconds(5)) + class CheckMinimumStorageRequiredForIngestion(MinimumRequiredStorageState stateHolder, DatabaseConfiguration databaseConfiguration, ILogger logger) : CustomCheck("Audit Message Ingestion Process", "ServiceControl.Audit Health", TimeSpan.FromSeconds(5)) { public override Task PerformCheck(CancellationToken cancellationToken = default) { var percentageThreshold = databaseConfiguration.MinimumStorageLeftRequiredForIngestion / 100m; - if (Logger.IsDebugEnabled) + if (logger.IsEnabled(LogLevel.Debug)) { - Logger.Debug($"Check ServiceControl data drive space starting. Threshold {percentageThreshold:P0}"); + logger.LogDebug("Check ServiceControl data drive space starting. Threshold {PercentageThreshold:P0}", percentageThreshold); } // Should be checking UseEmbeddedServer but need to check DbPath instead for the ATT hack to work @@ -35,9 +36,9 @@ public override Task PerformCheck(CancellationToken cancellationTok var percentRemaining = (decimal)dataDriveInfo.AvailableFreeSpace / dataDriveInfo.TotalSize; - if (Logger.IsDebugEnabled) + if (logger.IsEnabled(LogLevel.Debug)) { - Logger.Debug($"Free space: {availableFreeSpace} | Total: {totalSpace} | Percent remaining {percentRemaining:P0}"); + logger.LogDebug("Free space: {AvailableFreeSpace} | Total: {TotalSpace} | Percent remaining {PercentRemaining:P0}", availableFreeSpace, totalSpace, percentRemaining); } if (percentRemaining > percentageThreshold) @@ -46,10 +47,9 @@ public override Task PerformCheck(CancellationToken cancellationTok return SuccessResult; } - var message = $"Audit message ingestion stopped! {percentRemaining:P0} disk space remaining on data drive '{dataDriveInfo.VolumeLabel} ({dataDriveInfo.RootDirectory})' on '{Environment.MachineName}'. This is less than {percentageThreshold}% - the minimal required space configured. The threshold can be set using the {RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey} configuration setting."; - Logger.Warn(message); + logger.LogWarning("Audit message ingestion stopped! {PercentRemaining:P0} disk space remaining on data drive '{DataDriveInfoVolumeLabel} ({DataDriveInfoRootDirectory})' on '{EnvironmentMachineName}'. This is less than {PercentageThreshold}% - the minimal required space configured. The threshold can be set using the {RavenPersistenceConfigurationMinimumStorageLeftRequiredForIngestionKey} configuration setting.", percentRemaining, dataDriveInfo.VolumeLabel, dataDriveInfo.RootDirectory, Environment.MachineName, percentageThreshold, RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey); stateHolder.CanIngestMore = false; - return CheckResult.Failed(message); + return CheckResult.Failed($"Audit message ingestion stopped! {percentRemaining:P0} disk space remaining on data drive '{dataDriveInfo.VolumeLabel} ({dataDriveInfo.RootDirectory})' on '{Environment.MachineName}'. This is less than {percentageThreshold}% - the minimal required space configured. The threshold can be set using the {RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey} configuration setting."); } public static int Parse(IDictionary settings) @@ -61,23 +61,20 @@ public static int Parse(IDictionary settings) if (!int.TryParse(thresholdValue, out var threshold)) { - var message = $"{RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey} must be an integer."; - Logger.Fatal(message); - throw new Exception(message); + Logger.LogCritical("{RavenPersistenceConfigurationMinimumStorageLeftRequiredForIngestionKey} must be an integer.", RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey); + throw new Exception($"{RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey} must be an integer."); } if (threshold < 0) { - var message = $"{RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey} is invalid, minimum value is 0."; - Logger.Fatal(message); - throw new Exception(message); + Logger.LogCritical("{RavenPersistenceConfigurationMinimumStorageLeftRequiredForIngestionKey} is invalid, minimum value is 0.", RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey); + throw new Exception($"{RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey} is invalid, minimum value is 0."); } if (threshold > 100) { - var message = $"{RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey} is invalid, maximum value is 100."; - Logger.Fatal(message); - throw new Exception(message); + Logger.LogCritical("{RavenPersistenceConfigurationMinimumStorageLeftRequiredForIngestionKey} is invalid, maximum value is 100.", RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey); + throw new Exception($"{RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey} is invalid, maximum value is 100."); } return threshold; @@ -85,6 +82,6 @@ public static int Parse(IDictionary settings) public const int MinimumStorageLeftRequiredForIngestionDefault = 5; static readonly Task SuccessResult = Task.FromResult(CheckResult.Pass); - static readonly ILog Logger = LogManager.GetLogger(typeof(CheckMinimumStorageRequiredForIngestion)); + static readonly ILogger Logger = LoggerUtil.CreateStaticLogger(); } } \ No newline at end of file diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexLag.cs b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexLag.cs index 41f4347a71..193e384f2d 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexLag.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexLag.cs @@ -5,12 +5,13 @@ using System.Text; using System.Threading; using System.Threading.Tasks; + using Microsoft.Extensions.Logging; using NServiceBus.CustomChecks; - using NServiceBus.Logging; using Raven.Client.Documents.Operations; using ServiceControl.Audit.Persistence.RavenDB; + using ServiceControl.Infrastructure; - class CheckRavenDBIndexLag(IRavenDocumentStoreProvider documentStoreProvider) : CustomCheck("Audit Database Index Lag", "ServiceControl.Audit Health", TimeSpan.FromMinutes(5)) + class CheckRavenDBIndexLag(IRavenDocumentStoreProvider documentStoreProvider, ILogger logger) : CustomCheck("Audit Database Index Lag", "ServiceControl.Audit Health", TimeSpan.FromMinutes(5)) { public override async Task PerformCheck(CancellationToken cancellationToken = default) { @@ -20,7 +21,7 @@ public override async Task PerformCheck(CancellationToken cancellat CreateDiagnosticsLogEntry(statistics, indexes); - var indexCountWithTooMuchLag = CheckAndReportIndexesWithTooMuchIndexLag(indexes); + var indexCountWithTooMuchLag = CheckAndReportIndexesWithTooMuchIndexLag(indexes, logger); if (indexCountWithTooMuchLag > 0) { @@ -30,7 +31,7 @@ public override async Task PerformCheck(CancellationToken cancellat return CheckResult.Pass; } - static int CheckAndReportIndexesWithTooMuchIndexLag(IndexInformation[] indexes) + static int CheckAndReportIndexesWithTooMuchIndexLag(IndexInformation[] indexes, ILogger logger) { int indexCountWithTooMuchLag = 0; @@ -43,12 +44,12 @@ static int CheckAndReportIndexesWithTooMuchIndexLag(IndexInformation[] indexes) if (indexLag > IndexLagThresholdError) { indexCountWithTooMuchLag++; - Log.Error($"Index [{indexStats.Name}] IndexingLag {indexLag} is above error threshold ({IndexLagThresholdError}). Launch in maintenance mode to let indexes catch up."); + logger.LogError("Index [{IndexStatsName}] IndexingLag {IndexLag} is above error threshold ({IndexLagThresholdError}). Launch in maintenance mode to let indexes catch up.", indexStats.Name, indexLag, IndexLagThresholdError); } else if (indexLag > IndexLagThresholdWarning) { indexCountWithTooMuchLag++; - Log.Warn($"Index [{indexStats.Name}] IndexingLag {indexLag} is above warning threshold ({IndexLagThresholdWarning}). Launch in maintenance mode to let indexes catch up."); + logger.LogWarning("Index [{IndexStatsName}] IndexingLag {IndexLag} is above warning threshold ({IndexLagThresholdWarning}). Launch in maintenance mode to let indexes catch up.", indexStats.Name, indexLag, IndexLagThresholdWarning); } } } @@ -58,7 +59,7 @@ static int CheckAndReportIndexesWithTooMuchIndexLag(IndexInformation[] indexes) static void CreateDiagnosticsLogEntry(DatabaseStatistics statistics, IndexInformation[] indexes) { - if (!Log.IsDebugEnabled) + if (!Logger.IsEnabled(LogLevel.Debug)) { return; } @@ -72,11 +73,12 @@ static void CreateDiagnosticsLogEntry(DatabaseStatistics statistics, IndexInform { report.AppendLine($"- Index [{indexStats.Name,-44}] State: {indexStats.State}, Stale: {indexStats.IsStale,-5}, Priority: {indexStats.Priority,-6}, LastIndexingTime: {indexStats.LastIndexingTime:u}"); } - Log.Debug(report.ToString()); + + Logger.LogDebug(report.ToString()); } static readonly TimeSpan IndexLagThresholdWarning = TimeSpan.FromMinutes(1); static readonly TimeSpan IndexLagThresholdError = TimeSpan.FromMinutes(10); - static readonly ILog Log = LogManager.GetLogger(); + static readonly ILogger Logger = LoggerUtil.CreateStaticLogger(); } } \ No newline at end of file diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/RavenEmbeddedPersistenceLifecycle.cs b/src/ServiceControl.Audit.Persistence.RavenDB/RavenEmbeddedPersistenceLifecycle.cs index f7f1ecee16..80bf05b742 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/RavenEmbeddedPersistenceLifecycle.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/RavenEmbeddedPersistenceLifecycle.cs @@ -6,12 +6,12 @@ namespace ServiceControl.Audit.Persistence.RavenDB using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Hosting; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using Raven.Client.Documents; using Raven.Client.Exceptions.Database; using ServiceControl.RavenDB; - sealed class RavenEmbeddedPersistenceLifecycle(DatabaseConfiguration databaseConfiguration, IHostApplicationLifetime lifetime) : IRavenPersistenceLifecycle, IRavenDocumentStoreProvider, IDisposable + sealed class RavenEmbeddedPersistenceLifecycle(DatabaseConfiguration databaseConfiguration, IHostApplicationLifetime lifetime, ILogger logger) : IRavenPersistenceLifecycle, IRavenDocumentStoreProvider, IDisposable { public async ValueTask GetDocumentStore(CancellationToken cancellationToken = default) { @@ -61,7 +61,7 @@ public async Task Initialize(CancellationToken cancellationToken = default) } catch (DatabaseLoadTimeoutException e) { - Log.Warn("Connecting to the embedded RavenDB database timed out. Retrying in 500ms...", e); + logger.LogWarning(e, "Connecting to the embedded RavenDB database timed out. Retrying in 500ms..."); await Task.Delay(500, cancellationToken); } } @@ -83,7 +83,5 @@ public void Dispose() IDocumentStore? documentStore; EmbeddedDatabase? database; readonly SemaphoreSlim initializeSemaphore = new(1, 1); - - static readonly ILog Log = LogManager.GetLogger(typeof(RavenEmbeddedPersistenceLifecycle)); } } diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/RavenPersistenceConfiguration.cs b/src/ServiceControl.Audit.Persistence.RavenDB/RavenPersistenceConfiguration.cs index b22003ceae..fc8aa2f281 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/RavenPersistenceConfiguration.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/RavenPersistenceConfiguration.cs @@ -5,7 +5,8 @@ using System.IO; using System.Reflection; using CustomChecks; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; + using ServiceControl.Infrastructure; public class RavenPersistenceConfiguration : IPersistenceConfiguration { @@ -141,15 +142,17 @@ static int GetExpirationProcessTimerInSeconds(PersistenceSettings settings) expirationProcessTimerInSeconds = int.Parse(expirationProcessTimerInSecondsString); } + var maxExpirationProcessTimerInSeconds = TimeSpan.FromHours(3).TotalSeconds; + if (expirationProcessTimerInSeconds < 0) { - Logger.Error($"ExpirationProcessTimerInSeconds cannot be negative. Defaulting to {ExpirationProcessTimerInSecondsDefault}"); + Logger.LogError("ExpirationProcessTimerInSeconds cannot be negative. Defaulting to {ExpirationProcessTimerInSecondsDefault}", ExpirationProcessTimerInSecondsDefault); return ExpirationProcessTimerInSecondsDefault; } - if (expirationProcessTimerInSeconds > TimeSpan.FromHours(3).TotalSeconds) + if (expirationProcessTimerInSeconds > maxExpirationProcessTimerInSeconds) { - Logger.Error($"ExpirationProcessTimerInSeconds cannot be larger than {TimeSpan.FromHours(3).TotalSeconds}. Defaulting to {ExpirationProcessTimerInSecondsDefault}"); + Logger.LogError("ExpirationProcessTimerInSeconds cannot be larger than {MaxExpirationProcessTimerInSeconds}. Defaulting to {ExpirationProcessTimerInSecondsDefault}", maxExpirationProcessTimerInSeconds, ExpirationProcessTimerInSecondsDefault); return ExpirationProcessTimerInSecondsDefault; } @@ -165,15 +168,17 @@ static int GetBulkInsertCommitTimeout(PersistenceSettings settings) bulkInsertCommitTimeoutInSeconds = int.Parse(bulkInsertCommitTimeoutString); } + var maxBulkInsertCommitTimeoutInSeconds = TimeSpan.FromHours(1).TotalSeconds; + if (bulkInsertCommitTimeoutInSeconds < 0) { - Logger.Error($"BulkInsertCommitTimeout cannot be negative. Defaulting to {BulkInsertCommitTimeoutInSecondsDefault}"); + Logger.LogError("BulkInsertCommitTimeout cannot be negative. Defaulting to {BulkInsertCommitTimeoutInSecondsDefault}", BulkInsertCommitTimeoutInSecondsDefault); return BulkInsertCommitTimeoutInSecondsDefault; } - if (bulkInsertCommitTimeoutInSeconds > TimeSpan.FromHours(1).TotalSeconds) + if (bulkInsertCommitTimeoutInSeconds > maxBulkInsertCommitTimeoutInSeconds) { - Logger.Error($"BulkInsertCommitTimeout cannot be larger than {TimeSpan.FromHours(1).TotalSeconds}. Defaulting to {BulkInsertCommitTimeoutInSecondsDefault}"); + Logger.LogError("BulkInsertCommitTimeout cannot be larger than {MaxBulkInsertCommitTimeoutInSeconds}. Defaulting to {BulkInsertCommitTimeoutInSecondsDefault}", maxBulkInsertCommitTimeoutInSeconds, BulkInsertCommitTimeoutInSecondsDefault); return BulkInsertCommitTimeoutInSecondsDefault; } @@ -193,9 +198,8 @@ static string GetLogPath(PersistenceSettings settings) return logPath; } - static readonly ILog Logger = LogManager.GetLogger(typeof(RavenPersistenceConfiguration)); - const int ExpirationProcessTimerInSecondsDefault = 600; const int BulkInsertCommitTimeoutInSecondsDefault = 60; + static readonly ILogger Logger = LoggerUtil.CreateStaticLogger(); } } diff --git a/src/ServiceControl.Infrastructure/LoggerUtil.cs b/src/ServiceControl.Infrastructure/LoggerUtil.cs new file mode 100644 index 0000000000..98aeb7d865 --- /dev/null +++ b/src/ServiceControl.Infrastructure/LoggerUtil.cs @@ -0,0 +1,27 @@ +namespace ServiceControl.Infrastructure +{ + using System; + using Microsoft.Extensions.Logging; + using NLog.Extensions.Logging; + + public static class LoggerUtil + { + public static void BuildLogger(this ILoggingBuilder loggingBuilder, LogLevel level) + { + loggingBuilder.AddNLog(); + loggingBuilder.SetMinimumLevel(level); + } + + public static ILogger CreateStaticLogger(LogLevel level = LogLevel.Information) + { + var factory = LoggerFactory.Create(configure => configure.BuildLogger(level)); + return factory.CreateLogger(); + } + + public static ILogger CreateStaticLogger(Type type, LogLevel level = LogLevel.Information) + { + var factory = LoggerFactory.Create(configure => configure.BuildLogger(level)); + return factory.CreateLogger(type); + } + } +} \ No newline at end of file diff --git a/src/ServiceControl.Monitoring.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs b/src/ServiceControl.Monitoring.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs index debc3ed629..212f1e03a1 100644 --- a/src/ServiceControl.Monitoring.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs +++ b/src/ServiceControl.Monitoring.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs @@ -18,6 +18,7 @@ namespace ServiceControl.Monitoring.AcceptanceTests.TestSupport using NServiceBus.AcceptanceTesting; using NServiceBus.AcceptanceTesting.Support; using NServiceBus.Logging; + using ServiceControl.Infrastructure; class ServiceControlComponentRunner( ITransportIntegration transportToUse, @@ -72,7 +73,7 @@ async Task InitializeServiceControl(ScenarioContext context) using (new DiagnosticTimer($"Creating infrastructure for {settings.InstanceName}")) { - var setupCommand = new SetupCommand(); + var setupCommand = new SetupCommand(LoggerUtil.CreateStaticLogger()); await setupCommand.Execute(new HostArguments([]), settings); } diff --git a/src/ServiceControl.Monitoring/Hosting/Commands/SetupCommand.cs b/src/ServiceControl.Monitoring/Hosting/Commands/SetupCommand.cs index 3bd7830438..d585434197 100644 --- a/src/ServiceControl.Monitoring/Hosting/Commands/SetupCommand.cs +++ b/src/ServiceControl.Monitoring/Hosting/Commands/SetupCommand.cs @@ -1,16 +1,16 @@ namespace ServiceControl.Monitoring { using System.Threading.Tasks; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using Transports; - class SetupCommand : AbstractCommand + class SetupCommand(ILogger logger) : AbstractCommand { public override Task Execute(HostArguments args, Settings settings) { if (args.SkipQueueCreation) { - Logger.Info("Skipping queue creation"); + logger.LogInformation("Skipping queue creation"); return Task.CompletedTask; } @@ -19,7 +19,5 @@ public override Task Execute(HostArguments args, Settings settings) var transportCustomization = TransportFactory.Create(transportSettings); return transportCustomization.ProvisionQueues(transportSettings, []); } - - static readonly ILog Logger = LogManager.GetLogger(); } } \ No newline at end of file diff --git a/src/ServiceControl.Monitoring/Http/Diagrams/MonitoredEndpointMessageTypeParser.cs b/src/ServiceControl.Monitoring/Http/Diagrams/MonitoredEndpointMessageTypeParser.cs index 3faa1e81c7..f089104b4f 100644 --- a/src/ServiceControl.Monitoring/Http/Diagrams/MonitoredEndpointMessageTypeParser.cs +++ b/src/ServiceControl.Monitoring/Http/Diagrams/MonitoredEndpointMessageTypeParser.cs @@ -3,7 +3,8 @@ namespace ServiceControl.Monitoring.Http.Diagrams using System; using System.Linq; using System.Reflection; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; + using ServiceControl.Infrastructure; public static class MonitoredEndpointMessageTypeParser { @@ -40,7 +41,7 @@ public static MonitoredEndpointMessageType Parse(string typeName) } catch (Exception e) { - Logger.Warn($"Error parsing message type: {typeName}.", e); + LoggerUtil.CreateStaticLogger(typeof(MonitoredEndpointMessageTypeParser)).LogWarning(e, "Error parsing message type: {typeName}.", typeName); } } @@ -50,7 +51,5 @@ public static MonitoredEndpointMessageType Parse(string typeName) TypeName = typeName }; } - - static readonly ILog Logger = LogManager.GetLogger(typeof(MonitoredEndpointMessageTypeParser)); } } \ No newline at end of file diff --git a/src/ServiceControl.Monitoring/Licensing/ActiveLicense.cs b/src/ServiceControl.Monitoring/Licensing/ActiveLicense.cs index a3a001e0ad..f5ca3be8bc 100644 --- a/src/ServiceControl.Monitoring/Licensing/ActiveLicense.cs +++ b/src/ServiceControl.Monitoring/Licensing/ActiveLicense.cs @@ -1,11 +1,15 @@ namespace ServiceControl.Monitoring.Licensing { - using global::ServiceControl.LicenseManagement; - using NServiceBus.Logging; + using ServiceControl.LicenseManagement; + using Microsoft.Extensions.Logging; public class ActiveLicense { - public ActiveLicense() => Refresh(); + public ActiveLicense(ILogger logger) + { + this.logger = logger; + Refresh(); + } public bool IsValid { get; set; } @@ -13,7 +17,7 @@ public class ActiveLicense public void Refresh() { - Logger.Debug("Refreshing ActiveLicense"); + logger.LogDebug("Refreshing ActiveLicense"); var detectedLicense = LicenseManager.FindLicense(); @@ -22,6 +26,6 @@ public void Refresh() Details = detectedLicense.Details; } - static readonly ILog Logger = LogManager.GetLogger(typeof(ActiveLicense)); + readonly ILogger logger; } } \ No newline at end of file diff --git a/src/ServiceControl.Monitoring/Licensing/LicenseCheckHostedService.cs b/src/ServiceControl.Monitoring/Licensing/LicenseCheckHostedService.cs index a5b10f73b5..b29e47fd05 100644 --- a/src/ServiceControl.Monitoring/Licensing/LicenseCheckHostedService.cs +++ b/src/ServiceControl.Monitoring/Licensing/LicenseCheckHostedService.cs @@ -4,10 +4,10 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Hosting; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using ServiceControl.Infrastructure.BackgroundTasks; - class LicenseCheckHostedService(ActiveLicense activeLicense, IAsyncTimer scheduler) : IHostedService + class LicenseCheckHostedService(ActiveLicense activeLicense, IAsyncTimer scheduler, ILogger logger) : IHostedService { public Task StartAsync(CancellationToken cancellationToken) { @@ -16,7 +16,7 @@ public Task StartAsync(CancellationToken cancellationToken) { activeLicense.Refresh(); return ScheduleNextExecutionTask; - }, due, due, ex => Logger.Error("Unhandled error while refreshing the license.", ex)); + }, due, due, ex => logger.LogError(ex, "Unhandled error while refreshing the license.")); return Task.CompletedTask; } @@ -24,7 +24,6 @@ public Task StartAsync(CancellationToken cancellationToken) TimerJob timer; - static readonly ILog Logger = LogManager.GetLogger(); static readonly Task ScheduleNextExecutionTask = Task.FromResult(TimerJobExecutionResult.ScheduleNextExecution); } } \ No newline at end of file diff --git a/src/ServiceControl.Monitoring/Program.cs b/src/ServiceControl.Monitoring/Program.cs index 8620eba3cc..fa34bf4978 100644 --- a/src/ServiceControl.Monitoring/Program.cs +++ b/src/ServiceControl.Monitoring/Program.cs @@ -1,13 +1,13 @@ using System; using System.Reflection; -using NServiceBus.Logging; +using Microsoft.Extensions.Logging; using ServiceControl.Configuration; using ServiceControl.Infrastructure; using ServiceControl.Monitoring; try { - AppDomain.CurrentDomain.UnhandledException += (s, e) => LogManager.GetLogger(typeof(Program)).Error("Unhandled exception was caught.", e.ExceptionObject as Exception); + AppDomain.CurrentDomain.UnhandledException += (s, e) => LoggerUtil.CreateStaticLogger().LogError(e.ExceptionObject as Exception, "Unhandled exception was caught."); // Hack: See https://github.com/Particular/ServiceControl/issues/4392 var exitCode = await IntegratedSetup.Run(); @@ -32,12 +32,11 @@ } catch (Exception ex) { - NLog.LogManager.GetCurrentClassLogger().Fatal(ex, "Unrecoverable error"); + LoggerUtil.CreateStaticLogger().LogCritical(ex, "Unrecoverable error"); throw; } finally { // The following log statement is meant to leave a trail in the logs to determine if the process was killed - NLog.LogManager.GetCurrentClassLogger().Info("Shutdown complete"); - NLog.LogManager.Shutdown(); -} \ No newline at end of file + LoggerUtil.CreateStaticLogger().LogInformation("Shutdown complete"); +} diff --git a/src/ServiceControl.Monitoring/QueueLength/LegacyQueueLengthReportHandler.cs b/src/ServiceControl.Monitoring/QueueLength/LegacyQueueLengthReportHandler.cs index 82a72e4a8b..93d905558d 100644 --- a/src/ServiceControl.Monitoring/QueueLength/LegacyQueueLengthReportHandler.cs +++ b/src/ServiceControl.Monitoring/QueueLength/LegacyQueueLengthReportHandler.cs @@ -5,33 +5,24 @@ using System.Threading; using System.Threading.Tasks; using Infrastructure; + using Microsoft.Extensions.Logging; using NServiceBus; - using NServiceBus.Logging; using NServiceBus.Metrics; - class LegacyQueueLengthReportHandler : IHandleMessages + class LegacyQueueLengthReportHandler(LegacyQueueLengthReportHandler.LegacyQueueLengthEndpoints legacyEndpoints, ILogger logger) : IHandleMessages { - public LegacyQueueLengthReportHandler(LegacyQueueLengthEndpoints legacyEndpoints) - { - this.legacyEndpoints = legacyEndpoints; - } - public Task Handle(MetricReport message, IMessageHandlerContext context) { var endpointInstanceId = EndpointInstanceId.From(context.MessageHeaders); if (legacyEndpoints.TryAdd(endpointInstanceId.InstanceId)) { - Logger.Warn($"Legacy queue length report received from {endpointInstanceId.InstanceName} instance of {endpointInstanceId.EndpointName}"); + logger.LogWarning("Legacy queue length report received from {EndpointInstanceIdInstanceName} instance of {EndpointInstanceIdEndpointName}", endpointInstanceId.InstanceName, endpointInstanceId.EndpointName); } return Task.CompletedTask; } - LegacyQueueLengthEndpoints legacyEndpoints; - - static readonly ILog Logger = LogManager.GetLogger(typeof(LegacyQueueLengthReportHandler)); - public class LegacyQueueLengthEndpoints { public bool TryAdd(string id) diff --git a/src/ServiceControl.Monitoring/ServiceControl.Monitoring.csproj b/src/ServiceControl.Monitoring/ServiceControl.Monitoring.csproj index 35246ea1b8..1a9b705469 100644 --- a/src/ServiceControl.Monitoring/ServiceControl.Monitoring.csproj +++ b/src/ServiceControl.Monitoring/ServiceControl.Monitoring.csproj @@ -24,7 +24,6 @@ - From e2196e6fbb2f591e82a276e2687acd6ca070022e Mon Sep 17 00:00:00 2001 From: JasonTaylorDev Date: Thu, 12 Jun 2025 17:08:39 +1000 Subject: [PATCH 16/56] Work in progress --- src/Directory.Packages.props | 4 +- .../ServiceControlComponentRunner.cs | 2 +- .../ServiceControlComponentRunner.cs | 3 +- .../CustomChecks/CheckFreeDiskSpace.cs | 10 ++-- .../RavenPersistenceConfiguration.cs | 2 +- .../HostApplicationBuilderExtensions.cs | 2 +- .../Infrastructure/WebApi/RootController.cs | 2 +- .../LoggerUtil.cs | 5 +- .../LoggingConfigurator.cs | 10 +++- .../LoggingSettings.cs | 55 +++++++++++-------- .../ServiceControl.Infrastructure.csproj | 2 + .../ServiceControlComponentRunner.cs | 3 +- .../HostApplicationBuilderExtensions.cs | 6 +- .../Hosting/Commands/SetupCommand.cs | 5 +- src/ServiceControl.Monitoring/Program.cs | 8 ++- .../ServiceControl.Monitoring.csproj | 1 + .../HostApplicationBuilderExtensions.cs | 2 +- .../Infrastructure/Api/ConfigurationApi.cs | 2 +- 18 files changed, 72 insertions(+), 52 deletions(-) diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index 60eb7072c9..dfd35a5f78 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -24,6 +24,7 @@ + @@ -63,6 +64,7 @@ + @@ -91,4 +93,4 @@ - + \ No newline at end of file diff --git a/src/ServiceControl.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs b/src/ServiceControl.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs index 19bbe6b57a..f1b3e58a01 100644 --- a/src/ServiceControl.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs +++ b/src/ServiceControl.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs @@ -15,7 +15,7 @@ using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; - using NLog; + using Microsoft.Extensions.Logging; using NServiceBus; using NServiceBus.AcceptanceTesting; using NServiceBus.AcceptanceTesting.Support; diff --git a/src/ServiceControl.Audit.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs b/src/ServiceControl.Audit.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs index 0866b504db..ce71680748 100644 --- a/src/ServiceControl.Audit.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs +++ b/src/ServiceControl.Audit.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs @@ -17,6 +17,7 @@ namespace ServiceControl.Audit.AcceptanceTests.TestSupport using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.Hosting; + using Microsoft.Extensions.Logging; using NServiceBus; using NServiceBus.AcceptanceTesting; using NServiceBus.AcceptanceTesting.Support; @@ -43,7 +44,7 @@ async Task InitializeServiceControl(ScenarioContext context) var logPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); Directory.CreateDirectory(logPath); - var loggingSettings = new LoggingSettings(Settings.SettingsRootNamespace, defaultLevel: NLog.LogLevel.Debug, logPath: logPath); + var loggingSettings = new LoggingSettings(Settings.SettingsRootNamespace, defaultLevel: LogLevel.Debug, logPath: logPath); settings = new Settings(transportToUse.TypeName, persistenceToUse.PersistenceType, loggingSettings) { diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs index 923b6208d6..45efbac8e0 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs @@ -8,7 +8,6 @@ using Microsoft.Extensions.Logging; using NServiceBus.CustomChecks; using RavenDB; - using ServiceControl.Infrastructure; class CheckFreeDiskSpace(DatabaseConfiguration databaseConfiguration, ILogger logger) : CustomCheck("ServiceControl.Audit database", "Storage space", TimeSpan.FromMinutes(5)) { @@ -45,7 +44,7 @@ public override Task PerformCheck(CancellationToken cancellationTok : CheckResult.Failed($"{percentRemaining:P0} disk space remaining on data drive '{dataDriveInfo.VolumeLabel} ({dataDriveInfo.RootDirectory})' on '{Environment.MachineName}'."); } - public static int Parse(IDictionary settings) + public static int Parse(IDictionary settings, ILogger logger) { if (!settings.TryGetValue(RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey, out var thresholdValue)) { @@ -54,19 +53,19 @@ public static int Parse(IDictionary settings) if (!int.TryParse(thresholdValue, out var threshold)) { - Logger.LogCritical("{RavenPersistenceConfigurationDataSpaceRemainingThresholdKey} must be an integer.", RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey); + logger.LogCritical("{RavenPersistenceConfigurationDataSpaceRemainingThresholdKey} must be an integer.", RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey); throw new Exception($"{RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey} must be an integer."); } if (threshold < 0) { - Logger.LogCritical("{RavenPersistenceConfigurationDataSpaceRemainingThresholdKey} is invalid, minimum value is 0.", RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey); + logger.LogCritical("{RavenPersistenceConfigurationDataSpaceRemainingThresholdKey} is invalid, minimum value is 0.", RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey); throw new Exception($"{RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey} is invalid, minimum value is 0."); } if (threshold > 100) { - Logger.LogCritical("{RavenPersistenceConfigurationDataSpaceRemainingThresholdKey} is invalid, maximum value is 100.", RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey); + logger.LogCritical("{RavenPersistenceConfigurationDataSpaceRemainingThresholdKey} is invalid, maximum value is 100.", RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey); throw new Exception($"{RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey} is invalid, maximum value is 100."); } @@ -75,7 +74,6 @@ public static int Parse(IDictionary settings) readonly string dataPathRoot = Path.GetPathRoot(databaseConfiguration.ServerConfiguration.DbPath); readonly decimal percentageThreshold = databaseConfiguration.DataSpaceRemainingThreshold / 100m; - static readonly ILogger Logger = LoggerUtil.CreateStaticLogger(); public const int DataSpaceRemainingThresholdDefault = 20; } } \ No newline at end of file diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/RavenPersistenceConfiguration.cs b/src/ServiceControl.Audit.Persistence.RavenDB/RavenPersistenceConfiguration.cs index fc8aa2f281..3611a3f646 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/RavenPersistenceConfiguration.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/RavenPersistenceConfiguration.cs @@ -114,7 +114,7 @@ internal static DatabaseConfiguration GetDatabaseConfiguration(PersistenceSettin serverConfiguration = new ServerConfiguration(dbPath, serverUrl, logPath, logsMode); } - var dataSpaceRemainingThreshold = CheckFreeDiskSpace.Parse(settings.PersisterSpecificSettings); + var dataSpaceRemainingThreshold = CheckFreeDiskSpace.Parse(settings.PersisterSpecificSettings, Logger); var minimumStorageLeftRequiredForIngestion = CheckMinimumStorageRequiredForIngestion.Parse(settings.PersisterSpecificSettings); var expirationProcessTimerInSeconds = GetExpirationProcessTimerInSeconds(settings); diff --git a/src/ServiceControl.Audit/HostApplicationBuilderExtensions.cs b/src/ServiceControl.Audit/HostApplicationBuilderExtensions.cs index ccacf5db1c..f1bbebb1d7 100644 --- a/src/ServiceControl.Audit/HostApplicationBuilderExtensions.cs +++ b/src/ServiceControl.Audit/HostApplicationBuilderExtensions.cs @@ -41,7 +41,7 @@ public static void AddServiceControlAudit(this IHostApplicationBuilder builder, builder.Logging.ClearProviders(); builder.Logging.AddNLog(); - builder.Logging.SetMinimumLevel(settings.LoggingSettings.ToHostLogLevel()); + builder.Logging.SetMinimumLevel(settings.LoggingSettings.LogLevel); var services = builder.Services; var transportSettings = settings.ToTransportSettings(); diff --git a/src/ServiceControl.Audit/Infrastructure/WebApi/RootController.cs b/src/ServiceControl.Audit/Infrastructure/WebApi/RootController.cs index 42c53825d3..159e8c6d49 100644 --- a/src/ServiceControl.Audit/Infrastructure/WebApi/RootController.cs +++ b/src/ServiceControl.Audit/Infrastructure/WebApi/RootController.cs @@ -51,7 +51,7 @@ public OkObjectResult Config() Logging = new { settings.LoggingSettings.LogPath, - LoggingLevel = settings.LoggingSettings.LogLevel.Name + LoggingLevel = settings.LoggingSettings.LogLevel } }, DataRetention = new diff --git a/src/ServiceControl.Infrastructure/LoggerUtil.cs b/src/ServiceControl.Infrastructure/LoggerUtil.cs index 98aeb7d865..3fac64d05a 100644 --- a/src/ServiceControl.Infrastructure/LoggerUtil.cs +++ b/src/ServiceControl.Infrastructure/LoggerUtil.cs @@ -9,13 +9,16 @@ public static class LoggerUtil public static void BuildLogger(this ILoggingBuilder loggingBuilder, LogLevel level) { loggingBuilder.AddNLog(); + loggingBuilder.AddSeq(); loggingBuilder.SetMinimumLevel(level); } public static ILogger CreateStaticLogger(LogLevel level = LogLevel.Information) { var factory = LoggerFactory.Create(configure => configure.BuildLogger(level)); - return factory.CreateLogger(); + var logger = factory.CreateLogger(); + logger.LogError("JTD: This is a test log message."); + return logger; } public static ILogger CreateStaticLogger(Type type, LogLevel level = LogLevel.Information) diff --git a/src/ServiceControl.Infrastructure/LoggingConfigurator.cs b/src/ServiceControl.Infrastructure/LoggingConfigurator.cs index f32c84918c..1e505963da 100644 --- a/src/ServiceControl.Infrastructure/LoggingConfigurator.cs +++ b/src/ServiceControl.Infrastructure/LoggingConfigurator.cs @@ -60,11 +60,15 @@ public static void ConfigureLogging(LoggingSettings loggingSettings) nlogConfig.LoggingRules.Add(aspNetCoreRule); nlogConfig.LoggingRules.Add(httpClientRule); - nlogConfig.LoggingRules.Add(new LoggingRule("*", loggingSettings.LogLevel, consoleTarget)); + // HACK: Fix LogLevel to Info for testing purposes only. + // nlogConfig.LoggingRules.Add(new LoggingRule("*", loggingSettings.LogLevel, consoleTarget)); + nlogConfig.LoggingRules.Add(new LoggingRule("*", LogLevel.Info, consoleTarget)); if (!AppEnvironment.RunningInContainer) { - nlogConfig.LoggingRules.Add(new LoggingRule("*", loggingSettings.LogLevel, fileTarget)); + // HACK: Fix LogLevel to Info for testing purposes only. + //nlogConfig.LoggingRules.Add(new LoggingRule("*", loggingSettings.LogLevel, fileTarget)); + nlogConfig.LoggingRules.Add(new LoggingRule("*", LogLevel.Info, fileTarget)); } NLog.LogManager.Configuration = nlogConfig; @@ -74,7 +78,7 @@ public static void ConfigureLogging(LoggingSettings loggingSettings) var logger = LogManager.GetLogger("LoggingConfiguration"); var logEventInfo = new LogEventInfo { TimeStamp = DateTime.UtcNow }; var loggingTo = AppEnvironment.RunningInContainer ? "console" : fileTarget.FileName.Render(logEventInfo); - logger.InfoFormat("Logging to {0} with LogLevel '{1}'", loggingTo, loggingSettings.LogLevel.Name); + logger.InfoFormat("Logging to {0} with LogLevel '{1}'", loggingTo, LogLevel.Info.Name); } const long megaByte = 1024 * 1024; diff --git a/src/ServiceControl.Infrastructure/LoggingSettings.cs b/src/ServiceControl.Infrastructure/LoggingSettings.cs index 55282759a3..dd9fc18008 100644 --- a/src/ServiceControl.Infrastructure/LoggingSettings.cs +++ b/src/ServiceControl.Infrastructure/LoggingSettings.cs @@ -1,21 +1,19 @@ namespace ServiceControl.Infrastructure; using System; +using System.Collections.Generic; using System.IO; -using NLog; -using NLog.Common; +using Microsoft.Extensions.Logging; using ServiceControl.Configuration; -public class LoggingSettings(SettingsRootNamespace rootNamespace, LogLevel defaultLevel = null, string logPath = null) +public class LoggingSettings(SettingsRootNamespace rootNamespace, LogLevel defaultLevel = LogLevel.Information, string logPath = null) { public LogLevel LogLevel { get; } = InitializeLogLevel(rootNamespace, defaultLevel); - public string LogPath { get; } = SettingsReader.Read(rootNamespace, "LogPath", Environment.ExpandEnvironmentVariables(logPath ?? DefaultLogLocation())); + public string LogPath { get; } = SettingsReader.Read(rootNamespace, logPathKey, Environment.ExpandEnvironmentVariables(logPath ?? DefaultLogLocation())); static LogLevel InitializeLogLevel(SettingsRootNamespace rootNamespace, LogLevel defaultLevel) { - defaultLevel ??= LogLevel.Info; - var levelText = SettingsReader.Read(rootNamespace, logLevelKey); if (string.IsNullOrWhiteSpace(levelText)) @@ -23,31 +21,40 @@ static LogLevel InitializeLogLevel(SettingsRootNamespace rootNamespace, LogLevel return defaultLevel; } - try - { - return LogLevel.FromString(levelText); - } - catch - { - InternalLogger.Warn($"Failed to parse {logLevelKey} setting. Defaulting to {defaultLevel.Name}."); - return defaultLevel; - } + return ParseLogLevel(levelText, defaultLevel); } // SC installer always populates LogPath in app.config on installation/change/upgrade so this will only be used when // debugging or if the entry is removed manually. In those circumstances default to the folder containing the exe static string DefaultLogLocation() => Path.Combine(AppContext.BaseDirectory, ".logs"); - public Microsoft.Extensions.Logging.LogLevel ToHostLogLevel() => LogLevel switch + // This is not a complete mapping of NLog levels, just the ones that are different. + static readonly Dictionary NLogAliases = + new(StringComparer.OrdinalIgnoreCase) + { + ["info"] = LogLevel.Information, + ["warn"] = LogLevel.Warning, + ["fatal"] = LogLevel.Critical, + ["off"] = LogLevel.None + }; + + static LogLevel ParseLogLevel(string value, LogLevel defaultLevel) { - _ when LogLevel == LogLevel.Trace => Microsoft.Extensions.Logging.LogLevel.Trace, - _ when LogLevel == LogLevel.Debug => Microsoft.Extensions.Logging.LogLevel.Debug, - _ when LogLevel == LogLevel.Info => Microsoft.Extensions.Logging.LogLevel.Information, - _ when LogLevel == LogLevel.Warn => Microsoft.Extensions.Logging.LogLevel.Warning, - _ when LogLevel == LogLevel.Error => Microsoft.Extensions.Logging.LogLevel.Error, - _ when LogLevel == LogLevel.Fatal => Microsoft.Extensions.Logging.LogLevel.Critical, - _ => Microsoft.Extensions.Logging.LogLevel.None - }; + if (Enum.TryParse(value, ignoreCase: true, out LogLevel parsedLevel)) + { + return parsedLevel; + } + + if (NLogAliases.TryGetValue(value.Trim(), out parsedLevel)) + { + return parsedLevel; + } + + LoggerUtil.CreateStaticLogger().LogWarning("Failed to parse {LogLevelKey} setting. Defaulting to {DefaultLevel}.", logLevelKey, defaultLevel); + + return defaultLevel; + } const string logLevelKey = "LogLevel"; + const string logPathKey = "LogPath"; } \ No newline at end of file diff --git a/src/ServiceControl.Infrastructure/ServiceControl.Infrastructure.csproj b/src/ServiceControl.Infrastructure/ServiceControl.Infrastructure.csproj index ea352f1711..37332ed734 100644 --- a/src/ServiceControl.Infrastructure/ServiceControl.Infrastructure.csproj +++ b/src/ServiceControl.Infrastructure/ServiceControl.Infrastructure.csproj @@ -9,9 +9,11 @@ + + \ No newline at end of file diff --git a/src/ServiceControl.Monitoring.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs b/src/ServiceControl.Monitoring.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs index 212f1e03a1..debc3ed629 100644 --- a/src/ServiceControl.Monitoring.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs +++ b/src/ServiceControl.Monitoring.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs @@ -18,7 +18,6 @@ namespace ServiceControl.Monitoring.AcceptanceTests.TestSupport using NServiceBus.AcceptanceTesting; using NServiceBus.AcceptanceTesting.Support; using NServiceBus.Logging; - using ServiceControl.Infrastructure; class ServiceControlComponentRunner( ITransportIntegration transportToUse, @@ -73,7 +72,7 @@ async Task InitializeServiceControl(ScenarioContext context) using (new DiagnosticTimer($"Creating infrastructure for {settings.InstanceName}")) { - var setupCommand = new SetupCommand(LoggerUtil.CreateStaticLogger()); + var setupCommand = new SetupCommand(); await setupCommand.Execute(new HostArguments([]), settings); } diff --git a/src/ServiceControl.Monitoring/HostApplicationBuilderExtensions.cs b/src/ServiceControl.Monitoring/HostApplicationBuilderExtensions.cs index 90adce523d..7bda9a78ab 100644 --- a/src/ServiceControl.Monitoring/HostApplicationBuilderExtensions.cs +++ b/src/ServiceControl.Monitoring/HostApplicationBuilderExtensions.cs @@ -22,6 +22,7 @@ namespace ServiceControl.Monitoring; using NServiceBus.Features; using NServiceBus.Transport; using QueueLength; +using ServiceControl.Infrastructure; using Timings; using Transports; @@ -31,9 +32,8 @@ public static void AddServiceControlMonitoring(this IHostApplicationBuilder host Func onCriticalError, Settings settings, EndpointConfiguration endpointConfiguration) { - hostBuilder.Logging.ClearProviders(); - hostBuilder.Logging.AddNLog(); - hostBuilder.Logging.SetMinimumLevel(settings.LoggingSettings.ToHostLogLevel()); + hostBuilder.Services.AddLogging(); + hostBuilder.Logging.BuildLogger(settings.LoggingSettings.LogLevel); var services = hostBuilder.Services; diff --git a/src/ServiceControl.Monitoring/Hosting/Commands/SetupCommand.cs b/src/ServiceControl.Monitoring/Hosting/Commands/SetupCommand.cs index d585434197..22a84b27f7 100644 --- a/src/ServiceControl.Monitoring/Hosting/Commands/SetupCommand.cs +++ b/src/ServiceControl.Monitoring/Hosting/Commands/SetupCommand.cs @@ -2,15 +2,16 @@ namespace ServiceControl.Monitoring { using System.Threading.Tasks; using Microsoft.Extensions.Logging; + using ServiceControl.Infrastructure; using Transports; - class SetupCommand(ILogger logger) : AbstractCommand + class SetupCommand : AbstractCommand { public override Task Execute(HostArguments args, Settings settings) { if (args.SkipQueueCreation) { - logger.LogInformation("Skipping queue creation"); + LoggerUtil.CreateStaticLogger().LogInformation("Skipping queue creation"); return Task.CompletedTask; } diff --git a/src/ServiceControl.Monitoring/Program.cs b/src/ServiceControl.Monitoring/Program.cs index fa34bf4978..5aaa6f8c35 100644 --- a/src/ServiceControl.Monitoring/Program.cs +++ b/src/ServiceControl.Monitoring/Program.cs @@ -5,9 +5,11 @@ using ServiceControl.Infrastructure; using ServiceControl.Monitoring; +var logger = LoggerUtil.CreateStaticLogger(); + try { - AppDomain.CurrentDomain.UnhandledException += (s, e) => LoggerUtil.CreateStaticLogger().LogError(e.ExceptionObject as Exception, "Unhandled exception was caught."); + AppDomain.CurrentDomain.UnhandledException += (s, e) => logger.LogError(e.ExceptionObject as Exception, "Unhandled exception was caught."); // Hack: See https://github.com/Particular/ServiceControl/issues/4392 var exitCode = await IntegratedSetup.Run(); @@ -32,11 +34,11 @@ } catch (Exception ex) { - LoggerUtil.CreateStaticLogger().LogCritical(ex, "Unrecoverable error"); + logger.LogCritical(ex, "Unrecoverable error"); throw; } finally { // The following log statement is meant to leave a trail in the logs to determine if the process was killed - LoggerUtil.CreateStaticLogger().LogInformation("Shutdown complete"); + logger.LogInformation("Shutdown complete"); } diff --git a/src/ServiceControl.Monitoring/ServiceControl.Monitoring.csproj b/src/ServiceControl.Monitoring/ServiceControl.Monitoring.csproj index 1a9b705469..9fbcf67af7 100644 --- a/src/ServiceControl.Monitoring/ServiceControl.Monitoring.csproj +++ b/src/ServiceControl.Monitoring/ServiceControl.Monitoring.csproj @@ -25,6 +25,7 @@ + diff --git a/src/ServiceControl/HostApplicationBuilderExtensions.cs b/src/ServiceControl/HostApplicationBuilderExtensions.cs index 50d0733fb9..76140a95ea 100644 --- a/src/ServiceControl/HostApplicationBuilderExtensions.cs +++ b/src/ServiceControl/HostApplicationBuilderExtensions.cs @@ -46,7 +46,7 @@ public static void AddServiceControl(this IHostApplicationBuilder hostBuilder, S logging.ClearProviders(); //HINT: configuration used by NLog comes from LoggingConfigurator.cs logging.AddNLog(); - logging.SetMinimumLevel(settings.LoggingSettings.ToHostLogLevel()); + logging.SetMinimumLevel(settings.LoggingSettings.LogLevel); var services = hostBuilder.Services; var transportSettings = settings.ToTransportSettings(); diff --git a/src/ServiceControl/Infrastructure/Api/ConfigurationApi.cs b/src/ServiceControl/Infrastructure/Api/ConfigurationApi.cs index fa06e80bc9..f8af272eb4 100644 --- a/src/ServiceControl/Infrastructure/Api/ConfigurationApi.cs +++ b/src/ServiceControl/Infrastructure/Api/ConfigurationApi.cs @@ -60,7 +60,7 @@ public Task GetConfig(CancellationToken cancellationToken) Logging = new { settings.LoggingSettings.LogPath, - LoggingLevel = settings.LoggingSettings.LogLevel.Name + LoggingLevel = settings.LoggingSettings.LogLevel } }, DataRetention = new From e9f287e1af3e39087ca5332410898b6d714de941 Mon Sep 17 00:00:00 2001 From: JasonTaylorDev Date: Fri, 13 Jun 2025 11:45:22 +1000 Subject: [PATCH 17/56] Remove test code --- src/ServiceControl.Infrastructure/LoggerUtil.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/ServiceControl.Infrastructure/LoggerUtil.cs b/src/ServiceControl.Infrastructure/LoggerUtil.cs index 3fac64d05a..623775e202 100644 --- a/src/ServiceControl.Infrastructure/LoggerUtil.cs +++ b/src/ServiceControl.Infrastructure/LoggerUtil.cs @@ -16,9 +16,7 @@ public static void BuildLogger(this ILoggingBuilder loggingBuilder, LogLevel lev public static ILogger CreateStaticLogger(LogLevel level = LogLevel.Information) { var factory = LoggerFactory.Create(configure => configure.BuildLogger(level)); - var logger = factory.CreateLogger(); - logger.LogError("JTD: This is a test log message."); - return logger; + return factory.CreateLogger(); } public static ILogger CreateStaticLogger(Type type, LogLevel level = LogLevel.Information) From 9b97c92d59daf0bc156f269bdc8ee47249e8552e Mon Sep 17 00:00:00 2001 From: JasonTaylorDev Date: Tue, 17 Jun 2025 10:06:13 +1000 Subject: [PATCH 18/56] Improve logging format for storage space details --- .../CustomChecks/CheckMinimumStorageRequiredForIngestion.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs index 56153b3169..033a99fbbe 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs @@ -38,7 +38,7 @@ public override Task PerformCheck(CancellationToken cancellationTok if (logger.IsEnabled(LogLevel.Debug)) { - logger.LogDebug("Free space: {AvailableFreeSpace} | Total: {TotalSpace} | Percent remaining {PercentRemaining:P0}", availableFreeSpace, totalSpace, percentRemaining); + logger.LogDebug("Free space: {AvailableFreeSpace:N0}B | Total: {TotalSpace:N0}B | Percent remaining {PercentRemaining:P0}", availableFreeSpace, totalSpace, percentRemaining); } if (percentRemaining > percentageThreshold) From 005968d492cc02852c676a1c41e146c52fe676bb Mon Sep 17 00:00:00 2001 From: JasonTaylorDev Date: Tue, 17 Jun 2025 10:10:46 +1000 Subject: [PATCH 19/56] Properly shutdown NLog in Program.cs --- src/ServiceControl.Monitoring/Program.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ServiceControl.Monitoring/Program.cs b/src/ServiceControl.Monitoring/Program.cs index 5aaa6f8c35..7a618a381f 100644 --- a/src/ServiceControl.Monitoring/Program.cs +++ b/src/ServiceControl.Monitoring/Program.cs @@ -41,4 +41,5 @@ { // The following log statement is meant to leave a trail in the logs to determine if the process was killed logger.LogInformation("Shutdown complete"); + NLog.LogManager.Shutdown(); } From 49ba86c1c1af137403b646ebd559811a8bfabea5 Mon Sep 17 00:00:00 2001 From: JasonTaylorDev Date: Tue, 17 Jun 2025 10:52:10 +1000 Subject: [PATCH 20/56] Remove Seq logging and prepare for .NET logging migration --- src/ServiceControl.Infrastructure/LoggerUtil.cs | 1 - .../LoggingConfigurator.cs | 11 +++++++---- .../ServiceControl.Infrastructure.csproj | 1 - .../ServiceControl.Monitoring.csproj | 1 - 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ServiceControl.Infrastructure/LoggerUtil.cs b/src/ServiceControl.Infrastructure/LoggerUtil.cs index 623775e202..98aeb7d865 100644 --- a/src/ServiceControl.Infrastructure/LoggerUtil.cs +++ b/src/ServiceControl.Infrastructure/LoggerUtil.cs @@ -9,7 +9,6 @@ public static class LoggerUtil public static void BuildLogger(this ILoggingBuilder loggingBuilder, LogLevel level) { loggingBuilder.AddNLog(); - loggingBuilder.AddSeq(); loggingBuilder.SetMinimumLevel(level); } diff --git a/src/ServiceControl.Infrastructure/LoggingConfigurator.cs b/src/ServiceControl.Infrastructure/LoggingConfigurator.cs index 1e505963da..5ca1c06c9b 100644 --- a/src/ServiceControl.Infrastructure/LoggingConfigurator.cs +++ b/src/ServiceControl.Infrastructure/LoggingConfigurator.cs @@ -12,6 +12,7 @@ namespace ServiceControl.Infrastructure using LogManager = NServiceBus.Logging.LogManager; + // TODO: Migrate from NLog to .NET logging public static class LoggingConfigurator { public static void ConfigureLogging(LoggingSettings loggingSettings) @@ -60,14 +61,16 @@ public static void ConfigureLogging(LoggingSettings loggingSettings) nlogConfig.LoggingRules.Add(aspNetCoreRule); nlogConfig.LoggingRules.Add(httpClientRule); - // HACK: Fix LogLevel to Info for testing purposes only. - // nlogConfig.LoggingRules.Add(new LoggingRule("*", loggingSettings.LogLevel, consoleTarget)); + // HACK: Fixed LogLevel to Info for testing purposes only. + // Migrate to .NET logging and change back to loggingSettings.LogLevel. + // nlogConfig.LoggingRules.Add(new LoggingRule("*", loggingSettings.LogLevel, consoleTarget)); nlogConfig.LoggingRules.Add(new LoggingRule("*", LogLevel.Info, consoleTarget)); if (!AppEnvironment.RunningInContainer) { - // HACK: Fix LogLevel to Info for testing purposes only. - //nlogConfig.LoggingRules.Add(new LoggingRule("*", loggingSettings.LogLevel, fileTarget)); + // HACK: Fixed LogLevel to Info for testing purposes only. + // Migrate to .NET logging and change back to loggingSettings.LogLevel. + // nlogConfig.LoggingRules.Add(new LoggingRule("*", loggingSettings.LogLevel, fileTarget)); nlogConfig.LoggingRules.Add(new LoggingRule("*", LogLevel.Info, fileTarget)); } diff --git a/src/ServiceControl.Infrastructure/ServiceControl.Infrastructure.csproj b/src/ServiceControl.Infrastructure/ServiceControl.Infrastructure.csproj index 37332ed734..29f38a7373 100644 --- a/src/ServiceControl.Infrastructure/ServiceControl.Infrastructure.csproj +++ b/src/ServiceControl.Infrastructure/ServiceControl.Infrastructure.csproj @@ -13,7 +13,6 @@ - \ No newline at end of file diff --git a/src/ServiceControl.Monitoring/ServiceControl.Monitoring.csproj b/src/ServiceControl.Monitoring/ServiceControl.Monitoring.csproj index 9fbcf67af7..1a9b705469 100644 --- a/src/ServiceControl.Monitoring/ServiceControl.Monitoring.csproj +++ b/src/ServiceControl.Monitoring/ServiceControl.Monitoring.csproj @@ -25,7 +25,6 @@ - From 938c963fe4cdf413c91586365141edf193fd7db4 Mon Sep 17 00:00:00 2001 From: JasonTaylorDev Date: Tue, 17 Jun 2025 12:05:17 +1000 Subject: [PATCH 21/56] Update LogLevel format --- .../APIApprovals.PlatformSampleSettings.approved.txt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/ServiceControl.Audit.UnitTests/ApprovalFiles/APIApprovals.PlatformSampleSettings.approved.txt b/src/ServiceControl.Audit.UnitTests/ApprovalFiles/APIApprovals.PlatformSampleSettings.approved.txt index f718f461aa..7113c06339 100644 --- a/src/ServiceControl.Audit.UnitTests/ApprovalFiles/APIApprovals.PlatformSampleSettings.approved.txt +++ b/src/ServiceControl.Audit.UnitTests/ApprovalFiles/APIApprovals.PlatformSampleSettings.approved.txt @@ -1,9 +1,6 @@ { "LoggingSettings": { - "LogLevel": { - "Name": "Info", - "Ordinal": 2 - }, + "LogLevel": "Information", "LogPath": "C:\\Logs" }, "MessageFilter": null, From fb7f77e2b255ca037398c6259dbced9678638096 Mon Sep 17 00:00:00 2001 From: JasonTaylorDev Date: Tue, 17 Jun 2025 12:22:18 +1000 Subject: [PATCH 22/56] Update LogLevel format in logging settings --- .../SettingsTests.PlatformSampleSettings.approved.txt | 5 +---- .../APIApprovals.PlatformSampleSettings.approved.txt | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/ServiceControl.Monitoring.UnitTests/ApprovalFiles/SettingsTests.PlatformSampleSettings.approved.txt b/src/ServiceControl.Monitoring.UnitTests/ApprovalFiles/SettingsTests.PlatformSampleSettings.approved.txt index 5d32f42fbb..070234384e 100644 --- a/src/ServiceControl.Monitoring.UnitTests/ApprovalFiles/SettingsTests.PlatformSampleSettings.approved.txt +++ b/src/ServiceControl.Monitoring.UnitTests/ApprovalFiles/SettingsTests.PlatformSampleSettings.approved.txt @@ -1,9 +1,6 @@ { "LoggingSettings": { - "LogLevel": { - "Name": "Info", - "Ordinal": 2 - }, + "LogLevel": "Information", "LogPath": "C:\\Logs" }, "InstanceName": "Particular.Monitoring", diff --git a/src/ServiceControl.UnitTests/ApprovalFiles/APIApprovals.PlatformSampleSettings.approved.txt b/src/ServiceControl.UnitTests/ApprovalFiles/APIApprovals.PlatformSampleSettings.approved.txt index a23480af26..246f3e5678 100644 --- a/src/ServiceControl.UnitTests/ApprovalFiles/APIApprovals.PlatformSampleSettings.approved.txt +++ b/src/ServiceControl.UnitTests/ApprovalFiles/APIApprovals.PlatformSampleSettings.approved.txt @@ -1,9 +1,6 @@ { "LoggingSettings": { - "LogLevel": { - "Name": "Info", - "Ordinal": 2 - }, + "LogLevel": "Information", "LogPath": "C:\\Logs" }, "NotificationsFilter": null, From 07d560604369a142746471b3834f1ee34f239771 Mon Sep 17 00:00:00 2001 From: Phil Bastian Date: Tue, 17 Jun 2025 15:38:53 +0800 Subject: [PATCH 23/56] enable adding test logging provider as part of loggerutils and create framework for settings driven logger selection --- .../LoggerUtil.cs | 35 +++++++++++++------ .../ServiceControl.Infrastructure.csproj | 1 + .../TestLogger}/TestContextAppender.cs | 2 +- .../TestLogger}/TestContextAppenderFactory.cs | 4 +-- .../TestLogger/TestContextProvider.cs | 14 ++++++++ .../FullEndpointTestFixture.cs | 2 +- .../ServiceControl.Transports.Tests.csproj | 1 + .../TransportManifestLibraryTests.cs | 2 +- .../TransportTestFixture.cs | 1 + 9 files changed, 46 insertions(+), 16 deletions(-) rename src/{ServiceControl.Transports.Tests => ServiceControl.Infrastructure/TestLogger}/TestContextAppender.cs (94%) rename src/{ServiceControl.Transports.Tests => ServiceControl.Infrastructure/TestLogger}/TestContextAppenderFactory.cs (71%) create mode 100644 src/ServiceControl.Infrastructure/TestLogger/TestContextProvider.cs diff --git a/src/ServiceControl.Infrastructure/LoggerUtil.cs b/src/ServiceControl.Infrastructure/LoggerUtil.cs index 0757d17fa0..34fc16beb1 100644 --- a/src/ServiceControl.Infrastructure/LoggerUtil.cs +++ b/src/ServiceControl.Infrastructure/LoggerUtil.cs @@ -1,38 +1,51 @@ namespace ServiceControl.Infrastructure { using System; + using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using NLog.Extensions.Logging; + using ServiceControl.Infrastructure.TestLogger; + + [Flags] + public enum Loggers + { + None = 0, + Test = 1 << 0, + NLog = 1 << 1, + Seq = 1 << 2, + } public static class LoggerUtil { - /// - /// used for tests - /// - public static ILoggerFactory LoggerFactory { private get; set; } + public static Loggers ActiveLoggers { private get; set; } = Loggers.None; public static void BuildLogger(this ILoggingBuilder loggingBuilder, LogLevel level) { - if (LoggerFactory != null) + if ((Loggers.Test & ActiveLoggers) == Loggers.Test) + { + loggingBuilder.Services.AddSingleton(new TestContextProvider()); + } + if ((Loggers.NLog & ActiveLoggers) == Loggers.NLog) + { + loggingBuilder.AddNLog(); + } + if ((Loggers.Seq & ActiveLoggers) == Loggers.Seq) { - return; + loggingBuilder.AddSeq(); } - //TODO: can we get these from settings too? - loggingBuilder.AddNLog(); - loggingBuilder.AddSeq(); loggingBuilder.SetMinimumLevel(level); } public static ILogger CreateStaticLogger(LogLevel level = LogLevel.Information) { - var factory = LoggerFactory ?? Microsoft.Extensions.Logging.LoggerFactory.Create(configure => configure.BuildLogger(level)); + var factory = LoggerFactory.Create(configure => configure.BuildLogger(level)); return factory.CreateLogger(); } public static ILogger CreateStaticLogger(Type type, LogLevel level = LogLevel.Information) { - var factory = LoggerFactory ?? Microsoft.Extensions.Logging.LoggerFactory.Create(configure => configure.BuildLogger(level)); + var factory = LoggerFactory.Create(configure => configure.BuildLogger(level)); return factory.CreateLogger(type); } } diff --git a/src/ServiceControl.Infrastructure/ServiceControl.Infrastructure.csproj b/src/ServiceControl.Infrastructure/ServiceControl.Infrastructure.csproj index 467cca8759..b32d80b1fa 100644 --- a/src/ServiceControl.Infrastructure/ServiceControl.Infrastructure.csproj +++ b/src/ServiceControl.Infrastructure/ServiceControl.Infrastructure.csproj @@ -15,6 +15,7 @@ + diff --git a/src/ServiceControl.Transports.Tests/TestContextAppender.cs b/src/ServiceControl.Infrastructure/TestLogger/TestContextAppender.cs similarity index 94% rename from src/ServiceControl.Transports.Tests/TestContextAppender.cs rename to src/ServiceControl.Infrastructure/TestLogger/TestContextAppender.cs index e3b9524253..c353a3b60a 100644 --- a/src/ServiceControl.Transports.Tests/TestContextAppender.cs +++ b/src/ServiceControl.Infrastructure/TestLogger/TestContextAppender.cs @@ -1,4 +1,4 @@ -namespace ServiceControl.Transport.Tests +namespace ServiceControl.Infrastructure.TestLogger { using System; using Microsoft.Extensions.Logging; diff --git a/src/ServiceControl.Transports.Tests/TestContextAppenderFactory.cs b/src/ServiceControl.Infrastructure/TestLogger/TestContextAppenderFactory.cs similarity index 71% rename from src/ServiceControl.Transports.Tests/TestContextAppenderFactory.cs rename to src/ServiceControl.Infrastructure/TestLogger/TestContextAppenderFactory.cs index 9c5b4da728..98e1d683fb 100644 --- a/src/ServiceControl.Transports.Tests/TestContextAppenderFactory.cs +++ b/src/ServiceControl.Infrastructure/TestLogger/TestContextAppenderFactory.cs @@ -1,8 +1,8 @@ -namespace ServiceControl.Transport.Tests +namespace ServiceControl.Infrastructure.TestLogger { using Microsoft.Extensions.Logging; - class TestContextAppenderFactory : ILoggerFactory + public class TestContextAppenderFactory : ILoggerFactory { public void AddProvider(ILoggerProvider provider) { diff --git a/src/ServiceControl.Infrastructure/TestLogger/TestContextProvider.cs b/src/ServiceControl.Infrastructure/TestLogger/TestContextProvider.cs new file mode 100644 index 0000000000..e879c814a3 --- /dev/null +++ b/src/ServiceControl.Infrastructure/TestLogger/TestContextProvider.cs @@ -0,0 +1,14 @@ +namespace ServiceControl.Infrastructure.TestLogger +{ + using Microsoft.Extensions.Logging; + + public class TestContextProvider : ILoggerProvider + { + public ILogger CreateLogger(string categoryName) => new TestContextAppender(categoryName); + + public void Dispose() + { + + } + } +} diff --git a/src/ServiceControl.Transports.Tests/FullEndpointTestFixture.cs b/src/ServiceControl.Transports.Tests/FullEndpointTestFixture.cs index f2c4d13313..c1034d05f2 100644 --- a/src/ServiceControl.Transports.Tests/FullEndpointTestFixture.cs +++ b/src/ServiceControl.Transports.Tests/FullEndpointTestFixture.cs @@ -12,7 +12,7 @@ class FullEndpointTestFixture [SetUp] public virtual async Task Setup() { - LoggerUtil.LoggerFactory = new TestContextAppenderFactory(); + LoggerUtil.ActiveLoggers = Loggers.Test; configuration = new TransportTestsConfiguration(); var queueSuffix = $"-{System.IO.Path.GetRandomFileName().Replace(".", string.Empty)}"; diff --git a/src/ServiceControl.Transports.Tests/ServiceControl.Transports.Tests.csproj b/src/ServiceControl.Transports.Tests/ServiceControl.Transports.Tests.csproj index 8c7d0e9e78..aedb05ec31 100644 --- a/src/ServiceControl.Transports.Tests/ServiceControl.Transports.Tests.csproj +++ b/src/ServiceControl.Transports.Tests/ServiceControl.Transports.Tests.csproj @@ -5,6 +5,7 @@ + diff --git a/src/ServiceControl.Transports.Tests/TransportManifestLibraryTests.cs b/src/ServiceControl.Transports.Tests/TransportManifestLibraryTests.cs index 78a6aea1d7..6345f0e618 100644 --- a/src/ServiceControl.Transports.Tests/TransportManifestLibraryTests.cs +++ b/src/ServiceControl.Transports.Tests/TransportManifestLibraryTests.cs @@ -20,7 +20,7 @@ public class TransportManifestLibraryTests [SetUp] public void SetUp() { - LoggerUtil.LoggerFactory = new TestContextAppenderFactory(); + LoggerUtil.ActiveLoggers = Loggers.Test; } [Test] diff --git a/src/ServiceControl.Transports.Tests/TransportTestFixture.cs b/src/ServiceControl.Transports.Tests/TransportTestFixture.cs index 4a769f63bb..ce312b76f6 100644 --- a/src/ServiceControl.Transports.Tests/TransportTestFixture.cs +++ b/src/ServiceControl.Transports.Tests/TransportTestFixture.cs @@ -13,6 +13,7 @@ using NServiceBus.Logging; using NServiceBus.Transport; using NUnit.Framework; + using ServiceControl.Infrastructure.TestLogger; using Transports; [TestFixture] From a843701c7fd7851c85bcce61d633291d6605d752 Mon Sep 17 00:00:00 2001 From: Phil Bastian Date: Tue, 17 Jun 2025 15:56:17 +0800 Subject: [PATCH 24/56] add ability to select logging provider from config --- src/ServiceControl.Audit/App.config | 3 +++ .../LoggingSettings.cs | 26 ++++++++++++++++--- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/ServiceControl.Audit/App.config b/src/ServiceControl.Audit/App.config index 00a70ad0a2..e8e4a84c26 100644 --- a/src/ServiceControl.Audit/App.config +++ b/src/ServiceControl.Audit/App.config @@ -21,6 +21,9 @@ These settings are only here so that we can debug ServiceControl while developin + + + diff --git a/src/ServiceControl.Infrastructure/LoggingSettings.cs b/src/ServiceControl.Infrastructure/LoggingSettings.cs index dd9fc18008..a005b64425 100644 --- a/src/ServiceControl.Infrastructure/LoggingSettings.cs +++ b/src/ServiceControl.Infrastructure/LoggingSettings.cs @@ -3,14 +3,33 @@ namespace ServiceControl.Infrastructure; using System; using System.Collections.Generic; using System.IO; +using System.Linq; using Microsoft.Extensions.Logging; using ServiceControl.Configuration; -public class LoggingSettings(SettingsRootNamespace rootNamespace, LogLevel defaultLevel = LogLevel.Information, string logPath = null) +public class LoggingSettings { - public LogLevel LogLevel { get; } = InitializeLogLevel(rootNamespace, defaultLevel); + public LoggingSettings(SettingsRootNamespace rootNamespace, LogLevel defaultLevel = LogLevel.Information, string logPath = null) + { + LogLevel = InitializeLogLevel(rootNamespace, defaultLevel); + LogPath = SettingsReader.Read(rootNamespace, logPathKey, Environment.ExpandEnvironmentVariables(logPath ?? DefaultLogLocation())); + + var loggingProviders = SettingsReader.Read(rootNamespace, loggingProvidersKey).Split(","); + var activeLoggers = Loggers.None; + if (loggingProviders.Contains("NLog")) + { + activeLoggers |= Loggers.NLog; + } + if (loggingProviders.Contains("Seq")) + { + activeLoggers |= Loggers.Seq; + } + LoggerUtil.ActiveLoggers = activeLoggers; + } + + public LogLevel LogLevel { get; } - public string LogPath { get; } = SettingsReader.Read(rootNamespace, logPathKey, Environment.ExpandEnvironmentVariables(logPath ?? DefaultLogLocation())); + public string LogPath { get; } static LogLevel InitializeLogLevel(SettingsRootNamespace rootNamespace, LogLevel defaultLevel) { @@ -57,4 +76,5 @@ static LogLevel ParseLogLevel(string value, LogLevel defaultLevel) const string logLevelKey = "LogLevel"; const string logPathKey = "LogPath"; + const string loggingProvidersKey = "LoggingProviders"; } \ No newline at end of file From 3e598862045512ad7d614f847d94508185752826 Mon Sep 17 00:00:00 2001 From: Phil Bastian Date: Wed, 18 Jun 2025 07:04:03 +0800 Subject: [PATCH 25/56] handle setting not existing --- src/ServiceControl.Infrastructure/LoggingSettings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ServiceControl.Infrastructure/LoggingSettings.cs b/src/ServiceControl.Infrastructure/LoggingSettings.cs index a005b64425..1a80ccb875 100644 --- a/src/ServiceControl.Infrastructure/LoggingSettings.cs +++ b/src/ServiceControl.Infrastructure/LoggingSettings.cs @@ -14,7 +14,7 @@ public LoggingSettings(SettingsRootNamespace rootNamespace, LogLevel defaultLeve LogLevel = InitializeLogLevel(rootNamespace, defaultLevel); LogPath = SettingsReader.Read(rootNamespace, logPathKey, Environment.ExpandEnvironmentVariables(logPath ?? DefaultLogLocation())); - var loggingProviders = SettingsReader.Read(rootNamespace, loggingProvidersKey).Split(","); + var loggingProviders = (SettingsReader.Read(rootNamespace, loggingProvidersKey) ?? "").Split(","); var activeLoggers = Loggers.None; if (loggingProviders.Contains("NLog")) { From ab580f69fc4288ec013855dbda990417967a88ed Mon Sep 17 00:00:00 2001 From: Phil Bastian Date: Wed, 18 Jun 2025 07:53:24 +0800 Subject: [PATCH 26/56] change logmanager logger factory to the standard one now used by the rest of SC --- src/ServiceControl.Infrastructure/LoggingConfigurator.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ServiceControl.Infrastructure/LoggingConfigurator.cs b/src/ServiceControl.Infrastructure/LoggingConfigurator.cs index 5ca1c06c9b..4845965394 100644 --- a/src/ServiceControl.Infrastructure/LoggingConfigurator.cs +++ b/src/ServiceControl.Infrastructure/LoggingConfigurator.cs @@ -2,15 +2,15 @@ namespace ServiceControl.Infrastructure { using System; using System.IO; + using Microsoft.Extensions.Logging; using NLog; using NLog.Config; - using NLog.Extensions.Logging; using NLog.Layouts; using NLog.Targets; using NServiceBus.Extensions.Logging; using ServiceControl.Configuration; - using LogManager = NServiceBus.Logging.LogManager; + using LogLevel = NLog.LogLevel; // TODO: Migrate from NLog to .NET logging public static class LoggingConfigurator @@ -76,7 +76,7 @@ public static void ConfigureLogging(LoggingSettings loggingSettings) NLog.LogManager.Configuration = nlogConfig; - LogManager.UseFactory(new ExtensionsLoggerFactory(new NLogLoggerFactory())); + LogManager.UseFactory(new ExtensionsLoggerFactory(LoggerFactory.Create(configure => configure.BuildLogger(loggingSettings.LogLevel)))); var logger = LogManager.GetLogger("LoggingConfiguration"); var logEventInfo = new LogEventInfo { TimeStamp = DateTime.UtcNow }; From 3e169708ad450c3c6a768bf433a372cf3e8303ef Mon Sep 17 00:00:00 2001 From: Phil Bastian Date: Wed, 18 Jun 2025 13:03:14 +0800 Subject: [PATCH 27/56] ensure logger for transport tests --- src/ServiceControl.Transports.Tests/TransportTestFixture.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ServiceControl.Transports.Tests/TransportTestFixture.cs b/src/ServiceControl.Transports.Tests/TransportTestFixture.cs index ce312b76f6..ac1501232b 100644 --- a/src/ServiceControl.Transports.Tests/TransportTestFixture.cs +++ b/src/ServiceControl.Transports.Tests/TransportTestFixture.cs @@ -13,6 +13,7 @@ using NServiceBus.Logging; using NServiceBus.Transport; using NUnit.Framework; + using ServiceControl.Infrastructure; using ServiceControl.Infrastructure.TestLogger; using Transports; @@ -24,6 +25,7 @@ public virtual async Task Setup() { //TODO remove LogManager usage LogManager.UseFactory(new ExtensionsLoggerFactory(new TestContextAppenderFactory())); + LoggerUtil.ActiveLoggers = Loggers.Test; configuration = new TransportTestsConfiguration(); testCancellationTokenSource = Debugger.IsAttached ? new CancellationTokenSource() : new CancellationTokenSource(TestTimeout); registrations = []; From a8a3061e5858b44c64c50f9af81b15c06f6adc0e Mon Sep 17 00:00:00 2001 From: Andreas Bednarz <110360248+abparticular@users.noreply.github.com> Date: Wed, 18 Jun 2025 15:17:05 +1000 Subject: [PATCH 28/56] Convert SC primary instance loggers to ILogger (#5019) * Convert SC primary instance loggers to ILogger * Register EmailSender in DI container since dependents now expect it to be injected * Use CreateStaticLogger for command loggers * Logging parameters converted to Pascal case * Remove unnecessary fields --- .../AuditThroughputCollectorHostedService.cs | 12 +-- .../BrokerThroughputCollectorHostedService.cs | 6 +- .../MonitoringThroughputHostedService.cs | 4 +- .../StartupModeTests.cs | 3 +- .../When_a_retry_fails_to_be_sent.cs | 3 +- .../ServiceControlComponentRunner.cs | 1 + .../Commands/ImportFailedAuditsCommand.cs | 5 +- .../Hosting/Commands/SetupCommand.cs | 2 +- .../MonitoringDataStoreTests.cs | 19 ++--- .../ReturnToSenderDequeuerTests.cs | 11 +-- .../RetryStateTests.cs | 66 +++++++++++----- .../API/APIApprovals.cs | 14 ++-- .../EndpointInstanceMonitoringTests.cs | 3 +- .../CorruptedReplyToHeaderStrategyTests.cs | 9 ++- .../Recoverability/RetryOperationTests.cs | 23 +++--- .../MessageView_ScatterGatherTest.cs | 8 +- .../GetAuditCountsForEndpointApi.cs | 8 +- .../Messages/GetAllMessagesApi.cs | 5 +- .../Messages/GetAllMessagesForEndpointApi.cs | 5 +- .../Messages/GetMessagesController.cs | 10 +-- .../Messages/MessagesByConversationApi.cs | 6 +- .../Messages/ScatterGatherApi.cs | 20 ++--- .../Messages/ScatterGatherApiMessageView.cs | 5 +- .../Messages/ScatterGatherRemoteOnly.cs | 5 +- .../CompositeViews/Messages/SearchApi.cs | 5 +- .../Messages/SearchEndpointApi.cs | 5 +- ...RemotePlatformConnectionDetailsProvider.cs | 12 +-- .../CustomCheckResultProcessor.cs | 10 +-- .../FailedErrorImportCustomCheck.cs | 10 +-- .../InternalCustomCheckManager.cs | 16 ++-- .../InternalCustomChecks.cs | 4 +- .../InternalCustomChecksHostedService.cs | 6 +- .../EventDispatcherHostedService.cs | 24 +++--- .../IntegrationEventWriter.cs | 17 ++--- .../RepeatedFailuresOverTimeCircuitBreaker.cs | 39 +++++++--- .../HostApplicationBuilderExtensions.cs | 6 +- .../Commands/ImportFailedErrorsCommand.cs | 7 +- .../Hosting/Commands/SetupCommand.cs | 7 +- .../Metrics/MetricsReporterHostedService.cs | 14 ++-- .../Infrastructure/Settings/Settings.cs | 34 ++++----- .../SignalR/MessageStreamerHub.cs | 14 ++-- src/ServiceControl/Licensing/ActiveLicense.cs | 8 +- .../Licensing/LicenseCheckHostedService.cs | 8 +- .../Api/EditFailedMessagesController.cs | 15 ++-- .../Api/RetryMessagesController.cs | 13 ++-- .../Monitoring/EndpointInstanceMonitor.cs | 9 ++- .../Monitoring/EndpointInstanceMonitoring.cs | 15 ++-- ...rtbeatEndpointSettingsSyncHostedService.cs | 14 ++-- .../HeartbeatMonitoringHostedService.cs | 15 ++-- .../Monitoring/Web/GetKnownEndpointsApi.cs | 7 +- .../Api/NotificationsController.cs | 4 +- .../Email/CustomChecksMailNotification.cs | 12 +-- .../EmailNotificationHostBuilderExtensions.cs | 1 + .../Notifications/Email/EmailSender.cs | 9 +-- .../Email/SendEmailNotificationHandler.cs | 20 ++--- .../Operations/ErrorIngestion.cs | 40 +++++----- .../Operations/ErrorIngestionFaultPolicy.cs | 9 ++- .../Operations/ErrorIngestor.cs | 44 ++++------- .../Operations/ErrorProcessor.cs | 28 +++---- src/ServiceControl/Program.cs | 10 ++- .../Archiving/ArchiveAllInGroupHandler.cs | 10 +-- .../Archiving/UnArchiveAllInGroupHandler.cs | 10 +-- .../Recoverability/Editing/EditHandler.cs | 15 ++-- .../Recoverability/RecoverabilityComponent.cs | 24 +++--- .../CorruptedReplyToHeaderStrategy.cs | 10 +-- .../Handlers/RetryAllInGroupHandler.cs | 11 +-- .../Recoverability/Retrying/InMemoryRetry.cs | 13 +++- .../Retrying/Infrastructure/ReturnToSender.cs | 35 +++------ .../Infrastructure/ReturnToSenderDequeuer.cs | 76 +++++++------------ .../Recoverability/Retrying/RetriesGateway.cs | 25 +++--- .../Retrying/RetryDocumentManager.cs | 16 ++-- .../Recoverability/Retrying/RetryProcessor.cs | 74 ++++++++---------- .../Retrying/RetryingManager.cs | 7 +- .../SagaAudit/GetSagaByIdApi.cs | 5 +- .../SagaAudit/SagaUpdatedHandler.cs | 13 ++-- 75 files changed, 566 insertions(+), 542 deletions(-) diff --git a/src/Particular.LicensingComponent/AuditThroughput/AuditThroughputCollectorHostedService.cs b/src/Particular.LicensingComponent/AuditThroughput/AuditThroughputCollectorHostedService.cs index e60a4531db..fed7540ac6 100644 --- a/src/Particular.LicensingComponent/AuditThroughput/AuditThroughputCollectorHostedService.cs +++ b/src/Particular.LicensingComponent/AuditThroughput/AuditThroughputCollectorHostedService.cs @@ -20,7 +20,7 @@ public class AuditThroughputCollectorHostedService( protected override async Task ExecuteAsync(CancellationToken cancellationToken) { - logger.LogInformation($"Starting {nameof(AuditThroughputCollectorHostedService)}"); + logger.LogInformation("Starting {ServiceName}", nameof(AuditThroughputCollectorHostedService)); try { @@ -42,14 +42,14 @@ protected override async Task ExecuteAsync(CancellationToken cancellationToken) } catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested) { - logger.LogInformation($"Stopping {nameof(AuditThroughputCollectorHostedService)}"); + logger.LogInformation("Stopping {ServiceName}", nameof(AuditThroughputCollectorHostedService)); } } async Task GatherThroughput(CancellationToken cancellationToken) { var utcYesterday = DateOnly.FromDateTime(timeProvider.GetUtcNow().DateTime).AddDays(-1); - logger.LogInformation($"Gathering throughput from audit for {utcYesterday.ToShortDateString()}"); + logger.LogInformation("Gathering throughput from audit for {AuditDate}", utcYesterday.ToShortDateString()); await VerifyAuditInstances(cancellationToken); @@ -115,18 +115,18 @@ async Task VerifyAuditInstances(CancellationToken cancellationToken) { if (remote.Status == "online" || remote.SemanticVersion is not null) { - logger.LogInformation($"ServiceControl Audit instance at {remote.ApiUri} detected running version {remote.SemanticVersion}"); + logger.LogInformation("ServiceControl Audit instance at {RemoteApiUri} detected running version {RemoteSemanticVersion}", remote.ApiUri, remote.SemanticVersion); } else { - logger.LogWarning($"Unable to determine the version of one or more ServiceControl Audit instances. For the instance with URI {remote.ApiUri}, the status was '{remote.Status}' and the version string returned was '{remote.VersionString}'."); + logger.LogWarning("Unable to determine the version of one or more ServiceControl Audit instances. For the instance with URI {RemoteApiUri}, the status was '{RemoteStatus}' and the version string returned was '{RemoteVersionString}'.", remote.ApiUri, remote.Status, remote.VersionString); } } var allHaveAuditCounts = remotesInfo.All(auditQuery.ValidRemoteInstances); if (!allHaveAuditCounts) { - logger.LogWarning($"At least one ServiceControl Audit instance is either not running the required version ({auditQuery.MinAuditCountsVersion}) or is not configured for at least 2 days of retention. Audit throughput will not be available."); + logger.LogWarning("At least one ServiceControl Audit instance is either not running the required version ({RequiredAuditVersion}) or is not configured for at least 2 days of retention. Audit throughput will not be available.", auditQuery.MinAuditCountsVersion); } } diff --git a/src/Particular.LicensingComponent/BrokerThroughput/BrokerThroughputCollectorHostedService.cs b/src/Particular.LicensingComponent/BrokerThroughput/BrokerThroughputCollectorHostedService.cs index 8bb88190fe..497f7eb2f3 100644 --- a/src/Particular.LicensingComponent/BrokerThroughput/BrokerThroughputCollectorHostedService.cs +++ b/src/Particular.LicensingComponent/BrokerThroughput/BrokerThroughputCollectorHostedService.cs @@ -29,11 +29,11 @@ static ReadOnlyDictionary LoadBrokerSettingValues(IEnumerable LoadBrokerSettingValues(IEnumerable Task.FromResult(ErrorHandleResult.Handled), (_, __) => Task.CompletedTask); await transportInfrastructure.Receivers[ServiceControlSettings.ServiceControlThroughputDataQueue].StartReceive(cancellationToken); @@ -32,7 +32,7 @@ public async Task StartAsync(CancellationToken cancellationToken) public async Task StopAsync(CancellationToken cancellationToken) { - logger.LogInformation($"Stopping {nameof(MonitoringThroughputHostedService)}"); + logger.LogInformation("Stopping {ServiceName}", nameof(MonitoringThroughputHostedService)); if (transportInfrastructure != null) { diff --git a/src/ServiceControl.AcceptanceTests.RavenDB/StartupModeTests.cs b/src/ServiceControl.AcceptanceTests.RavenDB/StartupModeTests.cs index 6aef55b25e..02f868009a 100644 --- a/src/ServiceControl.AcceptanceTests.RavenDB/StartupModeTests.cs +++ b/src/ServiceControl.AcceptanceTests.RavenDB/StartupModeTests.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using Hosting.Commands; using Microsoft.Extensions.Hosting; + using Microsoft.Extensions.Logging.Abstractions; using NServiceBus; using NUnit.Framework; using Particular.ServiceControl.Hosting; @@ -57,7 +58,7 @@ public async Task CanRunMaintenanceMode() public async Task CanRunImportFailedMessagesMode() => await new TestableImportFailedErrorsCommand().Execute(new HostArguments(Array.Empty()), settings); - class TestableImportFailedErrorsCommand : ImportFailedErrorsCommand + class TestableImportFailedErrorsCommand() : ImportFailedErrorsCommand() { protected override EndpointConfiguration CreateEndpointConfiguration(Settings settings) { diff --git a/src/ServiceControl.AcceptanceTests/Recoverability/MessageFailures/When_a_retry_fails_to_be_sent.cs b/src/ServiceControl.AcceptanceTests/Recoverability/MessageFailures/When_a_retry_fails_to_be_sent.cs index ff843ecd2c..3e4e4e89cd 100644 --- a/src/ServiceControl.AcceptanceTests/Recoverability/MessageFailures/When_a_retry_fails_to_be_sent.cs +++ b/src/ServiceControl.AcceptanceTests/Recoverability/MessageFailures/When_a_retry_fails_to_be_sent.cs @@ -8,6 +8,7 @@ using AcceptanceTesting.EndpointTemplates; using Infrastructure; using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Logging.Abstractions; using NServiceBus; using NServiceBus.AcceptanceTesting; using NServiceBus.Routing; @@ -146,7 +147,7 @@ public class MyContext : ScenarioContext public class MessageThatWillFail : ICommand; public class FakeReturnToSender(IErrorMessageDataStore errorMessageStore, MyContext myContext) - : ReturnToSender(errorMessageStore) + : ReturnToSender(errorMessageStore, NullLogger.Instance) { public override Task HandleMessage(MessageContext message, IMessageDispatcher sender, string errorQueueTransportAddress, CancellationToken cancellationToken = default) { diff --git a/src/ServiceControl.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs b/src/ServiceControl.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs index 19bbe6b57a..1b6cd03449 100644 --- a/src/ServiceControl.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs +++ b/src/ServiceControl.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs @@ -15,6 +15,7 @@ using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; + using Microsoft.Extensions.Logging.Abstractions; using NLog; using NServiceBus; using NServiceBus.AcceptanceTesting; diff --git a/src/ServiceControl.Audit/Infrastructure/Hosting/Commands/ImportFailedAuditsCommand.cs b/src/ServiceControl.Audit/Infrastructure/Hosting/Commands/ImportFailedAuditsCommand.cs index a4d65b2c85..c2b5926d58 100644 --- a/src/ServiceControl.Audit/Infrastructure/Hosting/Commands/ImportFailedAuditsCommand.cs +++ b/src/ServiceControl.Audit/Infrastructure/Hosting/Commands/ImportFailedAuditsCommand.cs @@ -8,9 +8,10 @@ using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using NServiceBus; + using ServiceControl.Infrastructure; using Settings; - class ImportFailedAuditsCommand(ILogger logger) : AbstractCommand + class ImportFailedAuditsCommand : AbstractCommand { public override async Task Execute(HostArguments args, Settings settings) { @@ -40,7 +41,7 @@ public override async Task Execute(HostArguments args, Settings settings) } catch (OperationCanceledException e) when (tokenSource.IsCancellationRequested) { - logger.LogInformation(e, "Cancelled"); + LoggerUtil.CreateStaticLogger().LogInformation(e, "Cancelled"); } finally { diff --git a/src/ServiceControl.Audit/Infrastructure/Hosting/Commands/SetupCommand.cs b/src/ServiceControl.Audit/Infrastructure/Hosting/Commands/SetupCommand.cs index 7837fbd684..73480e72e2 100644 --- a/src/ServiceControl.Audit/Infrastructure/Hosting/Commands/SetupCommand.cs +++ b/src/ServiceControl.Audit/Infrastructure/Hosting/Commands/SetupCommand.cs @@ -9,7 +9,7 @@ using Settings; using Transports; - class SetupCommand() : AbstractCommand + class SetupCommand : AbstractCommand { public override async Task Execute(HostArguments args, Settings settings) { diff --git a/src/ServiceControl.Persistence.Tests/MonitoringDataStoreTests.cs b/src/ServiceControl.Persistence.Tests/MonitoringDataStoreTests.cs index 68b58fe2c0..693832546e 100644 --- a/src/ServiceControl.Persistence.Tests/MonitoringDataStoreTests.cs +++ b/src/ServiceControl.Persistence.Tests/MonitoringDataStoreTests.cs @@ -3,6 +3,7 @@ using System; using System.Linq; using System.Threading.Tasks; + using Microsoft.Extensions.Logging.Abstractions; using NUnit.Framework; using ServiceControl.Monitoring; using ServiceControl.Operations; @@ -13,7 +14,7 @@ class MonitoringDataStoreTests : PersistenceTestBase [Test] public async Task Endpoints_load_from_dataStore_into_monitor() { - var endpointInstanceMonitoring = new EndpointInstanceMonitoring(new FakeDomainEvents()); + var endpointInstanceMonitoring = new EndpointInstanceMonitoring(new FakeDomainEvents(), NullLogger.Instance); var endpoint1 = new EndpointDetails() { HostId = Guid.NewGuid(), Host = "Host1", Name = "Name1" }; await MonitoringDataStore.CreateIfNotExists(endpoint1); @@ -26,7 +27,7 @@ public async Task Endpoints_load_from_dataStore_into_monitor() [Test] public async Task Endpoints_added_more_than_once_are_treated_as_same_endpoint() { - var endpointInstanceMonitoring = new EndpointInstanceMonitoring(new FakeDomainEvents()); + var endpointInstanceMonitoring = new EndpointInstanceMonitoring(new FakeDomainEvents(), NullLogger.Instance); var endpoint1 = new EndpointDetails() { HostId = Guid.NewGuid(), Host = "Host1", Name = "Name1" }; await MonitoringDataStore.CreateIfNotExists(endpoint1); await MonitoringDataStore.CreateIfNotExists(endpoint1); @@ -40,7 +41,7 @@ public async Task Endpoints_added_more_than_once_are_treated_as_same_endpoint() [Test] public async Task Updating_existing_endpoint_does_not_create_new_ones() { - var endpointInstanceMonitoring = new EndpointInstanceMonitoring(new FakeDomainEvents()); + var endpointInstanceMonitoring = new EndpointInstanceMonitoring(new FakeDomainEvents(), NullLogger.Instance); var endpoint1 = new EndpointDetails() { HostId = Guid.NewGuid(), Host = "Host1", Name = "Name1" }; await MonitoringDataStore.CreateIfNotExists(endpoint1); await MonitoringDataStore.CreateOrUpdate(endpoint1, endpointInstanceMonitoring); @@ -54,7 +55,7 @@ public async Task Updating_existing_endpoint_does_not_create_new_ones() [Test] public async Task Endpoint_is_created_if_doesnt_exist() { - var endpointInstanceMonitoring = new EndpointInstanceMonitoring(new FakeDomainEvents()); + var endpointInstanceMonitoring = new EndpointInstanceMonitoring(new FakeDomainEvents(), NullLogger.Instance); var endpoint1 = new EndpointDetails() { HostId = Guid.NewGuid(), Host = "Host1", Name = "Name1" }; var endpoint2 = new EndpointDetails() { HostId = Guid.NewGuid(), Host = "Host2", Name = "Name2" }; await MonitoringDataStore.CreateIfNotExists(endpoint1); @@ -69,7 +70,7 @@ public async Task Endpoint_is_created_if_doesnt_exist() [Test] public async Task Endpoint_is_created_if_doesnt_exist_on_update() { - var endpointInstanceMonitoring = new EndpointInstanceMonitoring(new FakeDomainEvents()); + var endpointInstanceMonitoring = new EndpointInstanceMonitoring(new FakeDomainEvents(), NullLogger.Instance); var endpoint1 = new EndpointDetails() { HostId = Guid.NewGuid(), Host = "Host1", Name = "Name1" }; var endpoint2 = new EndpointDetails() { HostId = Guid.NewGuid(), Host = "Host2", Name = "Name2" }; await MonitoringDataStore.CreateIfNotExists(endpoint1); @@ -84,7 +85,7 @@ public async Task Endpoint_is_created_if_doesnt_exist_on_update() [Test] public async Task Endpoint_is_updated() { - var endpointInstanceMonitoring = new EndpointInstanceMonitoring(new FakeDomainEvents()); + var endpointInstanceMonitoring = new EndpointInstanceMonitoring(new FakeDomainEvents(), NullLogger.Instance); var endpoint1 = new EndpointDetails() { HostId = Guid.NewGuid(), Host = "Host1", Name = "Name1" }; await MonitoringDataStore.CreateIfNotExists(endpoint1); @@ -93,7 +94,7 @@ public async Task Endpoint_is_updated() Assert.That(endpointInstanceMonitoring.IsMonitored(endpointInstanceMonitoring.GetEndpoints()[0].Id), Is.False); await MonitoringDataStore.UpdateEndpointMonitoring(endpoint1, true); - endpointInstanceMonitoring = new EndpointInstanceMonitoring(new FakeDomainEvents()); + endpointInstanceMonitoring = new EndpointInstanceMonitoring(new FakeDomainEvents(), NullLogger.Instance); CompleteDatabaseOperation(); await MonitoringDataStore.WarmupMonitoringFromPersistence(endpointInstanceMonitoring); @@ -104,7 +105,7 @@ public async Task Endpoint_is_updated() [Test] public async Task Endpoint_is_deleted() { - var endpointInstanceMonitoring = new EndpointInstanceMonitoring(new FakeDomainEvents()); + var endpointInstanceMonitoring = new EndpointInstanceMonitoring(new FakeDomainEvents(), NullLogger.Instance); var endpoint1 = new EndpointDetails() { HostId = Guid.NewGuid(), Host = "Host1", Name = "Name1" }; await MonitoringDataStore.CreateIfNotExists(endpoint1); @@ -114,7 +115,7 @@ public async Task Endpoint_is_deleted() await MonitoringDataStore.Delete(endpointInstanceMonitoring.GetEndpoints()[0].Id); - endpointInstanceMonitoring = new EndpointInstanceMonitoring(new FakeDomainEvents()); + endpointInstanceMonitoring = new EndpointInstanceMonitoring(new FakeDomainEvents(), NullLogger.Instance); CompleteDatabaseOperation(); await MonitoringDataStore.WarmupMonitoringFromPersistence(endpointInstanceMonitoring); diff --git a/src/ServiceControl.Persistence.Tests/Recoverability/ReturnToSenderDequeuerTests.cs b/src/ServiceControl.Persistence.Tests/Recoverability/ReturnToSenderDequeuerTests.cs index 6df26ed702..cecd9c9ddc 100644 --- a/src/ServiceControl.Persistence.Tests/Recoverability/ReturnToSenderDequeuerTests.cs +++ b/src/ServiceControl.Persistence.Tests/Recoverability/ReturnToSenderDequeuerTests.cs @@ -10,6 +10,7 @@ using MessageFailures; using MessageFailures.Api; using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Logging.Abstractions; using NServiceBus.Extensibility; using NServiceBus.Transport; using NUnit.Framework; @@ -47,7 +48,7 @@ public async Task It_removes_staging_id_header() }; var message = CreateMessage(Guid.NewGuid().ToString(), headers); - await new ReturnToSender(null).HandleMessage(message, sender, "error"); + await new ReturnToSender(null, NullLogger.Instance).HandleMessage(message, sender, "error"); Assert.That(sender.Message.Headers.ContainsKey("ServiceControl.Retry.StagingId"), Is.False); } @@ -66,7 +67,7 @@ public async Task It_fetches_the_body_from_storage_if_provided() }; var message = CreateMessage(Guid.NewGuid().ToString(), headers); - await new ReturnToSender(new FakeErrorMessageDataStore()).HandleMessage(message, sender, "error"); + await new ReturnToSender(new FakeErrorMessageDataStore(), NullLogger.Instance).HandleMessage(message, sender, "error"); Assert.That(Encoding.UTF8.GetString(sender.Message.Body.ToArray()), Is.EqualTo("MessageBodyId")); } @@ -84,7 +85,7 @@ public async Task It_uses_retry_to_if_provided() }; var message = CreateMessage(Guid.NewGuid().ToString(), headers); - await new ReturnToSender(null).HandleMessage(message, sender, "error"); + await new ReturnToSender(null, NullLogger.Instance).HandleMessage(message, sender, "error"); Assert.Multiple(() => { @@ -105,7 +106,7 @@ public async Task It_sends_directly_to_target_if_retry_to_is_not_provided() }; var message = CreateMessage(Guid.NewGuid().ToString(), headers); - await new ReturnToSender(null).HandleMessage(message, sender, "error"); + await new ReturnToSender(null, NullLogger.Instance).HandleMessage(message, sender, "error"); Assert.Multiple(() => { @@ -129,7 +130,7 @@ public async Task It_restores_body_id_and_target_addres_after_failure() try { - await new ReturnToSender(null).HandleMessage(message, sender, "error"); + await new ReturnToSender(null, NullLogger.Instance).HandleMessage(message, sender, "error"); } catch (Exception) { diff --git a/src/ServiceControl.Persistence.Tests/RetryStateTests.cs b/src/ServiceControl.Persistence.Tests/RetryStateTests.cs index 3c9f426086..c0c730cf68 100644 --- a/src/ServiceControl.Persistence.Tests/RetryStateTests.cs +++ b/src/ServiceControl.Persistence.Tests/RetryStateTests.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; + using Microsoft.Extensions.Logging.Abstractions; using NServiceBus.Transport; using NUnit.Framework; using ServiceBus.Management.Infrastructure.Settings; @@ -17,6 +18,7 @@ using ServiceControl.Persistence; using ServiceControl.Recoverability; using ServiceControl.Transports; + using static ServiceControl.Recoverability.RecoverabilityComponent; using QueueAddress = NServiceBus.Transport.QueueAddress; [NonParallelizable] @@ -26,7 +28,7 @@ class RetryStateTests : PersistenceTestBase public async Task When_a_group_is_processed_it_is_set_to_the_Preparing_state() { var domainEvents = new FakeDomainEvents(); - var retryManager = new RetryingManager(domainEvents); + var retryManager = new RetryingManager(domainEvents, NullLogger.Instance); await CreateAFailedMessageAndMarkAsPartOfRetryBatch(retryManager, "Test-group", true, 1); var status = retryManager.GetStatusForRetryOperation("Test-group", RetryType.FailureGroup); @@ -38,13 +40,13 @@ public async Task When_a_group_is_processed_it_is_set_to_the_Preparing_state() public async Task When_a_group_is_prepared_and_SC_is_started_the_group_is_marked_as_failed() { var domainEvents = new FakeDomainEvents(); - var retryManager = new RetryingManager(domainEvents); + var retryManager = new RetryingManager(domainEvents, NullLogger.Instance); await CreateAFailedMessageAndMarkAsPartOfRetryBatch(retryManager, "Test-group", false, 1); var documentManager = new CustomRetryDocumentManager(false, RetryStore, retryManager); - var orphanage = new RecoverabilityComponent.AdoptOrphanBatchesFromPreviousSessionHostedService(documentManager, new AsyncTimer()); + var orphanage = new AdoptOrphanBatchesFromPreviousSessionHostedService(documentManager, new AsyncTimer(), NullLogger.Instance); await orphanage.AdoptOrphanedBatchesAsync(); CompleteDatabaseOperation(); @@ -67,7 +69,7 @@ public async Task When_the_dequeuer_is_created_then_the_error_address_is_cached( var transportCustomization = new TestTransportCustomization { TransportInfrastructure = transportInfrastructure }; - var testReturnToSenderDequeuer = new TestReturnToSenderDequeuer(new ReturnToSender(ErrorStore), ErrorStore, domainEvents, "TestEndpoint", + var testReturnToSenderDequeuer = new TestReturnToSenderDequeuer(new ReturnToSender(ErrorStore, NullLogger.Instance), ErrorStore, domainEvents, "TestEndpoint", errorQueueNameCache, transportCustomization); await testReturnToSenderDequeuer.StartAsync(new CancellationToken()); @@ -79,12 +81,24 @@ public async Task When_the_dequeuer_is_created_then_the_error_address_is_cached( public async Task When_a_group_is_prepared_with_three_batches_and_SC_is_restarted_while_the_first_group_is_being_forwarded_then_the_count_still_matches() { var domainEvents = new FakeDomainEvents(); - var retryManager = new RetryingManager(domainEvents); + var retryManager = new RetryingManager(domainEvents, NullLogger.Instance); await CreateAFailedMessageAndMarkAsPartOfRetryBatch(retryManager, "Test-group", true, 2001); var sender = new TestSender(); - var processor = new RetryProcessor(RetryBatchesStore, domainEvents, new TestReturnToSenderDequeuer(new ReturnToSender(ErrorStore), ErrorStore, domainEvents, "TestEndpoint", new ErrorQueueNameCache(), new TestTransportCustomization()), retryManager, new Lazy(() => sender)); + var processor = new RetryProcessor( + RetryBatchesStore, + domainEvents, + new TestReturnToSenderDequeuer( + new ReturnToSender(ErrorStore, NullLogger.Instance), + ErrorStore, + domainEvents, + "TestEndpoint", + new ErrorQueueNameCache(), + new TestTransportCustomization()), + retryManager, + new Lazy(() => sender), + NullLogger.Instance); // Needs index RetryBatches_ByStatus_ReduceInitialBatchSize CompleteDatabaseOperation(); @@ -92,13 +106,25 @@ public async Task When_a_group_is_prepared_with_three_batches_and_SC_is_restarte await processor.ProcessBatches(); // mark ready // Simulate SC restart - retryManager = new RetryingManager(domainEvents); + retryManager = new RetryingManager(domainEvents, NullLogger.Instance); var documentManager = new CustomRetryDocumentManager(false, RetryStore, retryManager); await documentManager.RebuildRetryOperationState(); - processor = new RetryProcessor(RetryBatchesStore, domainEvents, new TestReturnToSenderDequeuer(new ReturnToSender(ErrorStore), ErrorStore, domainEvents, "TestEndpoint", new ErrorQueueNameCache(), new TestTransportCustomization()), retryManager, new Lazy(() => sender)); + processor = new RetryProcessor( + RetryBatchesStore, + domainEvents, + new TestReturnToSenderDequeuer( + new ReturnToSender(ErrorStore, NullLogger.Instance), + ErrorStore, + domainEvents, + "TestEndpoint", + new ErrorQueueNameCache(), + new TestTransportCustomization()), + retryManager, + new Lazy(() => sender), + NullLogger.Instance); await processor.ProcessBatches(); @@ -110,14 +136,14 @@ public async Task When_a_group_is_prepared_with_three_batches_and_SC_is_restarte public async Task When_a_group_is_forwarded_the_status_is_Completed() { var domainEvents = new FakeDomainEvents(); - var retryManager = new RetryingManager(domainEvents); + var retryManager = new RetryingManager(domainEvents, NullLogger.Instance); await CreateAFailedMessageAndMarkAsPartOfRetryBatch(retryManager, "Test-group", true, 1); var sender = new TestSender(); - var returnToSender = new TestReturnToSenderDequeuer(new ReturnToSender(ErrorStore), ErrorStore, domainEvents, "TestEndpoint", new ErrorQueueNameCache(), new TestTransportCustomization()); - var processor = new RetryProcessor(RetryBatchesStore, domainEvents, returnToSender, retryManager, new Lazy(() => sender)); + var returnToSender = new TestReturnToSenderDequeuer(new ReturnToSender(ErrorStore, NullLogger.Instance), ErrorStore, domainEvents, "TestEndpoint", new ErrorQueueNameCache(), new TestTransportCustomization()); + var processor = new RetryProcessor(RetryBatchesStore, domainEvents, returnToSender, retryManager, new Lazy(() => sender), NullLogger.Instance); await processor.ProcessBatches(); // mark ready await processor.ProcessBatches(); @@ -130,7 +156,7 @@ public async Task When_a_group_is_forwarded_the_status_is_Completed() public async Task When_there_is_one_poison_message_it_is_removed_from_batch_and_the_status_is_Complete() { var domainEvents = new FakeDomainEvents(); - var retryManager = new RetryingManager(domainEvents); + var retryManager = new RetryingManager(domainEvents, NullLogger.Instance); await CreateAFailedMessageAndMarkAsPartOfRetryBatch(retryManager, "Test-group", true, "A", "B", "C"); @@ -146,8 +172,8 @@ public async Task When_there_is_one_poison_message_it_is_removed_from_batch_and_ } }; - var returnToSender = new TestReturnToSenderDequeuer(new ReturnToSender(ErrorStore), ErrorStore, domainEvents, "TestEndpoint", new ErrorQueueNameCache(), new TestTransportCustomization()); - var processor = new RetryProcessor(RetryBatchesStore, domainEvents, returnToSender, retryManager, new Lazy(() => sender)); + var returnToSender = new TestReturnToSenderDequeuer(new ReturnToSender(ErrorStore, NullLogger.Instance), ErrorStore, domainEvents, "TestEndpoint", new ErrorQueueNameCache(), new TestTransportCustomization()); + var processor = new RetryProcessor(RetryBatchesStore, domainEvents, returnToSender, retryManager, new Lazy(() => sender), NullLogger.Instance); bool c; do @@ -179,15 +205,15 @@ public async Task When_there_is_one_poison_message_it_is_removed_from_batch_and_ public async Task When_a_group_has_one_batch_out_of_two_forwarded_the_status_is_Forwarding() { var domainEvents = new FakeDomainEvents(); - var retryManager = new RetryingManager(domainEvents); + var retryManager = new RetryingManager(domainEvents, NullLogger.Instance); await CreateAFailedMessageAndMarkAsPartOfRetryBatch(retryManager, "Test-group", true, 1001); - var returnToSender = new ReturnToSender(ErrorStore); + var returnToSender = new ReturnToSender(ErrorStore, NullLogger.Instance); var sender = new TestSender(); - var processor = new RetryProcessor(RetryBatchesStore, domainEvents, new TestReturnToSenderDequeuer(returnToSender, ErrorStore, domainEvents, "TestEndpoint", new ErrorQueueNameCache(), new TestTransportCustomization()), retryManager, new Lazy(() => sender)); + var processor = new RetryProcessor(RetryBatchesStore, domainEvents, new TestReturnToSenderDequeuer(returnToSender, ErrorStore, domainEvents, "TestEndpoint", new ErrorQueueNameCache(), new TestTransportCustomization()), retryManager, new Lazy(() => sender), NullLogger.Instance); CompleteDatabaseOperation(); @@ -253,7 +279,7 @@ async Task CreateAFailedMessageAndMarkAsPartOfRetryBatch(RetryingManager retryMa class CustomRetriesGateway : RetriesGateway { public CustomRetriesGateway(bool progressToStaged, IRetryDocumentDataStore store, RetryingManager retryManager) - : base(store, retryManager) + : base(store, retryManager, NullLogger.Instance) { this.progressToStaged = progressToStaged; } @@ -274,7 +300,7 @@ protected override Task MoveBatchToStaging(string batchDocumentId) class CustomRetryDocumentManager : RetryDocumentManager { public CustomRetryDocumentManager(bool progressToStaged, IRetryDocumentDataStore retryStore, RetryingManager retryManager) - : base(new FakeApplicationLifetime(), retryStore, retryManager) + : base(new FakeApplicationLifetime(), retryStore, retryManager, NullLogger.Instance) { RetrySessionId = Guid.NewGuid().ToString(); this.progressToStaged = progressToStaged; @@ -307,7 +333,7 @@ class TestReturnToSenderDequeuer : ReturnToSenderDequeuer { public TestReturnToSenderDequeuer(ReturnToSender returnToSender, IErrorMessageDataStore store, IDomainEvents domainEvents, string endpointName, ErrorQueueNameCache cache, ITransportCustomization transportCustomization) - : base(returnToSender, store, domainEvents, transportCustomization, null, new Settings { InstanceName = endpointName }, cache) + : base(returnToSender, store, domainEvents, transportCustomization, null, new Settings { InstanceName = endpointName }, cache, NullLogger.Instance) { } diff --git a/src/ServiceControl.UnitTests/API/APIApprovals.cs b/src/ServiceControl.UnitTests/API/APIApprovals.cs index d9d56c1361..1a75ce026f 100644 --- a/src/ServiceControl.UnitTests/API/APIApprovals.cs +++ b/src/ServiceControl.UnitTests/API/APIApprovals.cs @@ -12,6 +12,7 @@ using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.AspNetCore.Mvc.Routing; using Microsoft.AspNetCore.Routing; + using Microsoft.Extensions.Logging.Abstractions; using NServiceBus.CustomChecks; using NUnit.Framework; using Particular.Approvals; @@ -30,14 +31,13 @@ public async Task RootPathValue() var httpContext = new DefaultHttpContext { Request = { Scheme = "http", Host = new HostString("localhost") } }; var actionContext = new ActionContext { HttpContext = httpContext, RouteData = new RouteData(), ActionDescriptor = new ControllerActionDescriptor() }; var controllerContext = new ControllerContext(actionContext); + var configurationApi = new ConfigurationApi( + new ActiveLicense(null, NullLogger.Instance) { IsValid = true }, + new Settings(), + null, + new MassTransitConnectorHeartbeatStatus()); - var controller = new RootController(new ConfigurationApi( - new ActiveLicense(null) { IsValid = true }, - new Settings(), - null, - new MassTransitConnectorHeartbeatStatus() - ) - ) + var controller = new RootController(configurationApi) { ControllerContext = controllerContext, Url = new UrlHelper(actionContext) diff --git a/src/ServiceControl.UnitTests/Monitoring/EndpointInstanceMonitoringTests.cs b/src/ServiceControl.UnitTests/Monitoring/EndpointInstanceMonitoringTests.cs index a0662eafa3..9ab5eac338 100644 --- a/src/ServiceControl.UnitTests/Monitoring/EndpointInstanceMonitoringTests.cs +++ b/src/ServiceControl.UnitTests/Monitoring/EndpointInstanceMonitoringTests.cs @@ -3,6 +3,7 @@ using System; using System.Threading; using System.Threading.Tasks; + using Microsoft.Extensions.Logging.Abstractions; using NUnit.Framework; using ServiceControl.Infrastructure.DomainEvents; using ServiceControl.Monitoring; @@ -13,7 +14,7 @@ class EndpointInstanceMonitoringTests [Test] public async Task When_endpoint_removed_should_stay_removed() { - var monitor = new EndpointInstanceMonitoring(new FakeDomainEvents()); + var monitor = new EndpointInstanceMonitoring(new FakeDomainEvents(), NullLogger.Instance); var monitoredEndpoint = new EndpointInstanceId("MonitoredEndpoint", "HostName", Guid.NewGuid()); var lastHeartbeat = DateTime.UtcNow; diff --git a/src/ServiceControl.UnitTests/Recoverability/CorruptedReplyToHeaderStrategyTests.cs b/src/ServiceControl.UnitTests/Recoverability/CorruptedReplyToHeaderStrategyTests.cs index 452a088315..e377045922 100644 --- a/src/ServiceControl.UnitTests/Recoverability/CorruptedReplyToHeaderStrategyTests.cs +++ b/src/ServiceControl.UnitTests/Recoverability/CorruptedReplyToHeaderStrategyTests.cs @@ -1,6 +1,7 @@ namespace ServiceControl.UnitTests.Recoverability { using System.Collections.Generic; + using Microsoft.Extensions.Logging.Abstractions; using NServiceBus; using NUnit.Framework; using ServiceControl.Recoverability; @@ -12,7 +13,7 @@ class CorruptedReplyToHeaderStrategyTests public void Handle_corrupted_header() { // Arrange - var strategy = new CorruptedReplyToHeaderStrategy(ServiceControlMachineName); + var strategy = new CorruptedReplyToHeaderStrategy(ServiceControlMachineName, NullLogger.Instance); var corruptedReplyToAddress = $"SomeEndpoint@{ServiceControlMachineName}"; @@ -34,7 +35,7 @@ public void Handle_corrupted_header() public void Handle_non_corupted_header() { // Arrange - var strategy = new CorruptedReplyToHeaderStrategy(ServiceControlMachineName); + var strategy = new CorruptedReplyToHeaderStrategy(ServiceControlMachineName, NullLogger.Instance); var nonCorruptedReplyToAddress = $"SomeEndpoint@{SendingMachineName}"; @@ -56,7 +57,7 @@ public void Handle_non_corupted_header() public void Handle_no_OriginatingMachine() { // Arrange - var strategy = new CorruptedReplyToHeaderStrategy(ServiceControlMachineName); + var strategy = new CorruptedReplyToHeaderStrategy(ServiceControlMachineName, NullLogger.Instance); var maybeCorruptedReplyToAddress = $"SomeEndpoint@{ServiceControlMachineName}"; @@ -77,7 +78,7 @@ public void Handle_no_OriginatingMachine() public void Handle_no_machine_name_in_header() { // Arrange - var strategy = new CorruptedReplyToHeaderStrategy(ServiceControlMachineName); + var strategy = new CorruptedReplyToHeaderStrategy(ServiceControlMachineName, NullLogger.Instance); var replyToAddressWithNoMachineName = "SomeEndpoint"; diff --git a/src/ServiceControl.UnitTests/Recoverability/RetryOperationTests.cs b/src/ServiceControl.UnitTests/Recoverability/RetryOperationTests.cs index 04bb05beee..0945406a9d 100644 --- a/src/ServiceControl.UnitTests/Recoverability/RetryOperationTests.cs +++ b/src/ServiceControl.UnitTests/Recoverability/RetryOperationTests.cs @@ -2,6 +2,7 @@ { using System; using System.Threading.Tasks; + using Microsoft.Extensions.Logging.Abstractions; using NUnit.Framework; using ServiceControl.Persistence; using ServiceControl.Recoverability; @@ -12,7 +13,7 @@ public class RetryOperationTests [Test] public async Task Wait_should_set_wait_state() { - var summary = new InMemoryRetry("abc123", RetryType.FailureGroup, new FakeDomainEvents()); + var summary = new InMemoryRetry("abc123", RetryType.FailureGroup, new FakeDomainEvents(), NullLogger.Instance); await summary.Wait(DateTime.UtcNow, "FailureGroup1"); Assert.Multiple(() => { @@ -28,7 +29,7 @@ public async Task Wait_should_set_wait_state() [Test] public void Fail_should_set_failed() { - var summary = new InMemoryRetry("abc123", RetryType.FailureGroup, new FakeDomainEvents()); + var summary = new InMemoryRetry("abc123", RetryType.FailureGroup, new FakeDomainEvents(), NullLogger.Instance); summary.Fail(); Assert.That(summary.Failed, Is.True); } @@ -36,7 +37,7 @@ public void Fail_should_set_failed() [Test] public async Task Prepare_should_set_prepare_state() { - var summary = new InMemoryRetry("abc123", RetryType.FailureGroup, new FakeDomainEvents()); + var summary = new InMemoryRetry("abc123", RetryType.FailureGroup, new FakeDomainEvents(), NullLogger.Instance); await summary.Prepare(1000); Assert.Multiple(() => { @@ -49,7 +50,7 @@ public async Task Prepare_should_set_prepare_state() [Test] public async Task Prepared_batch_should_set_prepare_state() { - var summary = new InMemoryRetry("abc123", RetryType.FailureGroup, new FakeDomainEvents()); + var summary = new InMemoryRetry("abc123", RetryType.FailureGroup, new FakeDomainEvents(), NullLogger.Instance); await summary.Prepare(1000); await summary.PrepareBatch(1000); Assert.Multiple(() => @@ -63,7 +64,7 @@ public async Task Prepared_batch_should_set_prepare_state() [Test] public async Task Forwarding_should_set_forwarding_state() { - var summary = new InMemoryRetry("abc123", RetryType.FailureGroup, new FakeDomainEvents()); + var summary = new InMemoryRetry("abc123", RetryType.FailureGroup, new FakeDomainEvents(), NullLogger.Instance); await summary.Prepare(1000); await summary.PrepareBatch(1000); await summary.Forwarding(); @@ -79,7 +80,7 @@ public async Task Forwarding_should_set_forwarding_state() [Test] public async Task Batch_forwarded_should_set_forwarding_state() { - var summary = new InMemoryRetry("abc123", RetryType.FailureGroup, new FakeDomainEvents()); + var summary = new InMemoryRetry("abc123", RetryType.FailureGroup, new FakeDomainEvents(), NullLogger.Instance); await summary.Prepare(1000); await summary.PrepareBatch(1000); await summary.Forwarding(); @@ -97,7 +98,7 @@ public async Task Batch_forwarded_should_set_forwarding_state() public async Task Should_raise_domain_events() { var domainEvents = new FakeDomainEvents(); - var summary = new InMemoryRetry("abc123", RetryType.FailureGroup, domainEvents); + var summary = new InMemoryRetry("abc123", RetryType.FailureGroup, domainEvents, NullLogger.Instance); await summary.Prepare(1000); await summary.PrepareBatch(1000); await summary.Forwarding(); @@ -116,7 +117,7 @@ public async Task Should_raise_domain_events() [Test] public async Task Batch_forwarded_all_forwarded_should_set_completed_state() { - var summary = new InMemoryRetry("abc123", RetryType.FailureGroup, new FakeDomainEvents()); + var summary = new InMemoryRetry("abc123", RetryType.FailureGroup, new FakeDomainEvents(), NullLogger.Instance); await summary.Prepare(1000); await summary.PrepareBatch(1000); await summary.Forwarding(); @@ -133,7 +134,7 @@ public async Task Batch_forwarded_all_forwarded_should_set_completed_state() [Test] public async Task Skip_should_set_update_skipped_messages() { - var summary = new InMemoryRetry("abc123", RetryType.FailureGroup, new FakeDomainEvents()); + var summary = new InMemoryRetry("abc123", RetryType.FailureGroup, new FakeDomainEvents(), NullLogger.Instance); await summary.Wait(DateTime.UtcNow); await summary.Prepare(2000); await summary.PrepareBatch(1000); @@ -149,7 +150,7 @@ public async Task Skip_should_set_update_skipped_messages() [Test] public async Task Skip_should_complete_when_all_skipped() { - var summary = new InMemoryRetry("abc123", RetryType.FailureGroup, new FakeDomainEvents()); + var summary = new InMemoryRetry("abc123", RetryType.FailureGroup, new FakeDomainEvents(), NullLogger.Instance); await summary.Wait(DateTime.UtcNow); await summary.Prepare(1000); await summary.PrepareBatch(1000); @@ -165,7 +166,7 @@ public async Task Skip_should_complete_when_all_skipped() [Test] public async Task Skip_and_forward_combination_should_complete_when_done() { - var summary = new InMemoryRetry("abc123", RetryType.FailureGroup, new FakeDomainEvents()); + var summary = new InMemoryRetry("abc123", RetryType.FailureGroup, new FakeDomainEvents(), NullLogger.Instance); await summary.Wait(DateTime.UtcNow); await summary.Prepare(2000); await summary.PrepareBatch(1000); diff --git a/src/ServiceControl.UnitTests/ScatterGather/MessageView_ScatterGatherTest.cs b/src/ServiceControl.UnitTests/ScatterGather/MessageView_ScatterGatherTest.cs index d74e2cac8c..22eee8c632 100644 --- a/src/ServiceControl.UnitTests/ScatterGather/MessageView_ScatterGatherTest.cs +++ b/src/ServiceControl.UnitTests/ScatterGather/MessageView_ScatterGatherTest.cs @@ -6,6 +6,8 @@ using System.Net.Http; using System.Threading.Tasks; using CompositeViews.Messages; + using Microsoft.Extensions.Logging; + using Microsoft.Extensions.Logging.Abstractions; using NUnit.Framework; using Persistence.Infrastructure; using ServiceBus.Management.Infrastructure.Settings; @@ -15,7 +17,7 @@ abstract class MessageView_ScatterGatherTest [SetUp] public void SetUp() { - var api = new TestApi(null, null, null); + var api = new TestApi(null, null, null, NullLogger.Instance); Results = api.AggregateResults(new ScatterGatherApiMessageViewContext(new PagingInfo(), new SortInfo()), GetData()); } @@ -66,8 +68,8 @@ protected IEnumerable RemoteData() class TestApi : ScatterGatherApiMessageView { - public TestApi(object dataStore, Settings settings, IHttpClientFactory httpClientFactory) - : base(dataStore, settings, httpClientFactory) + public TestApi(object dataStore, Settings settings, IHttpClientFactory httpClientFactory, ILogger logger) + : base(dataStore, settings, httpClientFactory, logger) { } diff --git a/src/ServiceControl/CompositeViews/AuditCounts/GetAuditCountsForEndpointApi.cs b/src/ServiceControl/CompositeViews/AuditCounts/GetAuditCountsForEndpointApi.cs index 278804b90c..b260282a01 100644 --- a/src/ServiceControl/CompositeViews/AuditCounts/GetAuditCountsForEndpointApi.cs +++ b/src/ServiceControl/CompositeViews/AuditCounts/GetAuditCountsForEndpointApi.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using Api.Contracts; using Messages; + using Microsoft.Extensions.Logging; using Persistence; using Persistence.Infrastructure; using ServiceBus.Management.Infrastructure.Settings; @@ -19,10 +20,9 @@ public record AuditCountsForEndpointContext(PagingInfo PagingInfo, string Endpoi public class GetAuditCountsForEndpointApi( IErrorMessageDataStore dataStore, Settings settings, - IHttpClientFactory httpClientFactory - ) - : ScatterGatherApi>(dataStore, settings, - httpClientFactory) + IHttpClientFactory httpClientFactory, + ILogger logger) + : ScatterGatherApi>(dataStore, settings, httpClientFactory, logger) { static readonly IList Empty = new List(0).AsReadOnly(); diff --git a/src/ServiceControl/CompositeViews/Messages/GetAllMessagesApi.cs b/src/ServiceControl/CompositeViews/Messages/GetAllMessagesApi.cs index 37d83ac49d..f3affe59e2 100644 --- a/src/ServiceControl/CompositeViews/Messages/GetAllMessagesApi.cs +++ b/src/ServiceControl/CompositeViews/Messages/GetAllMessagesApi.cs @@ -3,14 +3,15 @@ namespace ServiceControl.CompositeViews.Messages using System.Collections.Generic; using System.Net.Http; using System.Threading.Tasks; + using Microsoft.Extensions.Logging; using Persistence; using Persistence.Infrastructure; using ServiceBus.Management.Infrastructure.Settings; public class GetAllMessagesApi : ScatterGatherApiMessageView { - public GetAllMessagesApi(IErrorMessageDataStore dataStore, Settings settings, - IHttpClientFactory httpClientFactory) : base(dataStore, settings, httpClientFactory) + public GetAllMessagesApi(IErrorMessageDataStore dataStore, Settings settings, IHttpClientFactory httpClientFactory, ILogger logger) + : base(dataStore, settings, httpClientFactory, logger) { } diff --git a/src/ServiceControl/CompositeViews/Messages/GetAllMessagesForEndpointApi.cs b/src/ServiceControl/CompositeViews/Messages/GetAllMessagesForEndpointApi.cs index 1fdd327913..20870b9fbf 100644 --- a/src/ServiceControl/CompositeViews/Messages/GetAllMessagesForEndpointApi.cs +++ b/src/ServiceControl/CompositeViews/Messages/GetAllMessagesForEndpointApi.cs @@ -3,6 +3,7 @@ namespace ServiceControl.CompositeViews.Messages using System.Collections.Generic; using System.Net.Http; using System.Threading.Tasks; + using Microsoft.Extensions.Logging; using Persistence; using Persistence.Infrastructure; using ServiceBus.Management.Infrastructure.Settings; @@ -17,8 +18,8 @@ public record AllMessagesForEndpointContext( public class GetAllMessagesForEndpointApi : ScatterGatherApiMessageView { - public GetAllMessagesForEndpointApi(IErrorMessageDataStore dataStore, Settings settings, - IHttpClientFactory httpClientFactory) : base(dataStore, settings, httpClientFactory) + public GetAllMessagesForEndpointApi(IErrorMessageDataStore dataStore, Settings settings, IHttpClientFactory httpClientFactory, ILogger logger) + : base(dataStore, settings, httpClientFactory, logger) { } diff --git a/src/ServiceControl/CompositeViews/Messages/GetMessagesController.cs b/src/ServiceControl/CompositeViews/Messages/GetMessagesController.cs index 95c82bf5ac..e7133ba20a 100644 --- a/src/ServiceControl/CompositeViews/Messages/GetMessagesController.cs +++ b/src/ServiceControl/CompositeViews/Messages/GetMessagesController.cs @@ -10,7 +10,7 @@ namespace ServiceControl.CompositeViews.Messages using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Extensions; using Microsoft.AspNetCore.Mvc; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using Operations.BodyStorage; using Persistence.Infrastructure; using ServiceBus.Management.Infrastructure.Settings; @@ -29,7 +29,8 @@ public class GetMessagesController( GetAllMessagesForEndpointApi allMessagesForEndpointApi, GetAuditCountsForEndpointApi auditCountsForEndpointApi, SearchApi api, - SearchEndpointApi endpointApi) + SearchEndpointApi endpointApi, + ILogger logger) : ControllerBase { [Route("messages")] @@ -106,7 +107,8 @@ public async Task Get(string id, [FromQuery(Name = "instance_id") var forwarderError = await forwarder.SendAsync(HttpContext, remote.BaseAddress, httpMessageInvoker); if (forwarderError != ForwarderError.None && HttpContext.GetForwarderErrorFeature()?.Exception is { } exception) { - logger.Warn($"Failed to forward the request to remote instance at {remote.BaseAddress}{HttpContext.Request.GetEncodedPathAndQuery()}.", exception); + logger.LogWarning(exception, "Failed to forward the request to remote instance at {RemoteInstanceUrl}", + remote.BaseAddress + HttpContext.Request.GetEncodedPathAndQuery()); } return Empty; @@ -160,7 +162,5 @@ public async Task> SearchByKeyword([FromQuery] PagingInfo pa Response.WithQueryStatsAndPagingInfo(result.QueryStats, pagingInfo); return result.Results; } - - static ILog logger = LogManager.GetLogger(typeof(GetMessagesController)); } } \ No newline at end of file diff --git a/src/ServiceControl/CompositeViews/Messages/MessagesByConversationApi.cs b/src/ServiceControl/CompositeViews/Messages/MessagesByConversationApi.cs index 86fba81417..90837d3439 100644 --- a/src/ServiceControl/CompositeViews/Messages/MessagesByConversationApi.cs +++ b/src/ServiceControl/CompositeViews/Messages/MessagesByConversationApi.cs @@ -3,6 +3,7 @@ namespace ServiceControl.CompositeViews.Messages using System.Collections.Generic; using System.Net.Http; using System.Threading.Tasks; + using Microsoft.Extensions.Logging; using Persistence; using Persistence.Infrastructure; using ServiceBus.Management.Infrastructure.Settings; @@ -16,9 +17,8 @@ public record MessagesByConversationContext( public class MessagesByConversationApi : ScatterGatherApiMessageView { - public MessagesByConversationApi(IErrorMessageDataStore dataStore, Settings settings, - IHttpClientFactory httpClientFactory) : base(dataStore, settings, - httpClientFactory) + public MessagesByConversationApi(IErrorMessageDataStore dataStore, Settings settings, IHttpClientFactory httpClientFactory, ILogger logger) + : base(dataStore, settings, httpClientFactory, logger) { } diff --git a/src/ServiceControl/CompositeViews/Messages/ScatterGatherApi.cs b/src/ServiceControl/CompositeViews/Messages/ScatterGatherApi.cs index c55b777db7..d9fc9cb535 100644 --- a/src/ServiceControl/CompositeViews/Messages/ScatterGatherApi.cs +++ b/src/ServiceControl/CompositeViews/Messages/ScatterGatherApi.cs @@ -7,7 +7,7 @@ namespace ServiceControl.CompositeViews.Messages using System.Net.Http; using System.Threading.Tasks; using Infrastructure.WebApi; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using Persistence.Infrastructure; using ServiceBus.Management.Infrastructure.Settings; using JsonSerializer = System.Text.Json.JsonSerializer; @@ -27,12 +27,12 @@ public abstract class ScatterGatherApi : ScatterGatherApi where TIn : ScatterGatherContext where TOut : class { - protected ScatterGatherApi(TDataStore store, Settings settings, IHttpClientFactory httpClientFactory) + protected ScatterGatherApi(TDataStore store, Settings settings, IHttpClientFactory httpClientFactory, ILogger logger) { DataStore = store; Settings = settings; HttpClientFactory = httpClientFactory; - logger = LogManager.GetLogger(GetType()); + this.logger = logger; } protected TDataStore DataStore { get; } @@ -120,19 +120,21 @@ async Task> FetchAndParse(HttpClient httpClient, string pathAn catch (HttpRequestException httpRequestException) { remoteInstanceSetting.TemporarilyUnavailable = true; - logger.Warn( - $"An HttpRequestException occurred when querying remote instance at {remoteInstanceSetting.BaseAddress}. The instance at uri: {remoteInstanceSetting.BaseAddress} will be temporarily disabled.", - httpRequestException); + logger.LogWarning( + httpRequestException, + "An HttpRequestException occurred when querying remote instance at {RemoteInstanceBaseAddress}. The instance at uri: {RemoteInstanceBaseAddress} will be temporarily disabled", + remoteInstanceSetting.BaseAddress, + remoteInstanceSetting.BaseAddress); return QueryResult.Empty(); } catch (OperationCanceledException) // Intentional, used to gracefully handle timeout { - logger.Warn($"Failed to query remote instance at {remoteInstanceSetting.BaseAddress} due to a timeout"); + logger.LogWarning("Failed to query remote instance at {RemoteInstanceBaseAddress} due to a timeout", remoteInstanceSetting.BaseAddress); return QueryResult.Empty(); } catch (Exception exception) { - logger.Warn($"Failed to query remote instance at {remoteInstanceSetting.BaseAddress}.", exception); + logger.LogWarning(exception, "Failed to query remote instance at {RemoteInstanceBaseAddress}", remoteInstanceSetting.BaseAddress); return QueryResult.Empty(); } } @@ -162,6 +164,6 @@ static async Task> ParseResult(HttpResponseMessage responseMes return new QueryResult(remoteResults, new QueryStatsInfo(etag, totalCount, isStale: false)); } - readonly ILog logger; + readonly ILogger logger; } } \ No newline at end of file diff --git a/src/ServiceControl/CompositeViews/Messages/ScatterGatherApiMessageView.cs b/src/ServiceControl/CompositeViews/Messages/ScatterGatherApiMessageView.cs index 542ba6daba..667338cb28 100644 --- a/src/ServiceControl/CompositeViews/Messages/ScatterGatherApiMessageView.cs +++ b/src/ServiceControl/CompositeViews/Messages/ScatterGatherApiMessageView.cs @@ -3,6 +3,7 @@ namespace ServiceControl.CompositeViews.Messages using System.Collections.Generic; using System.Linq; using System.Net.Http; + using Microsoft.Extensions.Logging; using Persistence.Infrastructure; using ServiceBus.Management.Infrastructure.Settings; @@ -17,8 +18,8 @@ public record ScatterGatherApiMessageViewContext(PagingInfo PagingInfo, SortInfo public abstract class ScatterGatherApiMessageView : ScatterGatherApi> where TInput : ScatterGatherApiMessageViewContext { - protected ScatterGatherApiMessageView(TDataStore dataStore, Settings settings, - IHttpClientFactory httpClientFactory) : base(dataStore, settings, httpClientFactory) + protected ScatterGatherApiMessageView(TDataStore dataStore, Settings settings, IHttpClientFactory httpClientFactory, ILogger logger) + : base(dataStore, settings, httpClientFactory, logger) { } diff --git a/src/ServiceControl/CompositeViews/Messages/ScatterGatherRemoteOnly.cs b/src/ServiceControl/CompositeViews/Messages/ScatterGatherRemoteOnly.cs index 600e44df2b..3394ceb49e 100644 --- a/src/ServiceControl/CompositeViews/Messages/ScatterGatherRemoteOnly.cs +++ b/src/ServiceControl/CompositeViews/Messages/ScatterGatherRemoteOnly.cs @@ -2,11 +2,12 @@ namespace ServiceControl.CompositeViews.Messages { using System.Net.Http; using System.Threading.Tasks; + using Microsoft.Extensions.Logging; using Persistence.Infrastructure; using ServiceBus.Management.Infrastructure.Settings; - public abstract class ScatterGatherRemoteOnly(Settings settings, IHttpClientFactory httpClientFactory) - : ScatterGatherApi(NoOpStore.Instance, settings, httpClientFactory) + public abstract class ScatterGatherRemoteOnly(Settings settings, IHttpClientFactory httpClientFactory, ILogger logger) + : ScatterGatherApi(NoOpStore.Instance, settings, httpClientFactory, logger) where TIn : ScatterGatherContext where TOut : class { diff --git a/src/ServiceControl/CompositeViews/Messages/SearchApi.cs b/src/ServiceControl/CompositeViews/Messages/SearchApi.cs index dd6ba8afb3..462879cfa5 100644 --- a/src/ServiceControl/CompositeViews/Messages/SearchApi.cs +++ b/src/ServiceControl/CompositeViews/Messages/SearchApi.cs @@ -3,6 +3,7 @@ namespace ServiceControl.CompositeViews.Messages using System.Collections.Generic; using System.Net.Http; using System.Threading.Tasks; + using Microsoft.Extensions.Logging; using Persistence; using Persistence.Infrastructure; using ServiceBus.Management.Infrastructure.Settings; @@ -16,8 +17,8 @@ public record SearchApiContext( public class SearchApi : ScatterGatherApiMessageView { - public SearchApi(IErrorMessageDataStore dataStore, Settings settings, IHttpClientFactory httpClientFactory) : - base(dataStore, settings, httpClientFactory) + public SearchApi(IErrorMessageDataStore dataStore, Settings settings, IHttpClientFactory httpClientFactory, ILogger logger) + : base(dataStore, settings, httpClientFactory, logger) { } diff --git a/src/ServiceControl/CompositeViews/Messages/SearchEndpointApi.cs b/src/ServiceControl/CompositeViews/Messages/SearchEndpointApi.cs index 990beae427..11444b8734 100644 --- a/src/ServiceControl/CompositeViews/Messages/SearchEndpointApi.cs +++ b/src/ServiceControl/CompositeViews/Messages/SearchEndpointApi.cs @@ -3,6 +3,7 @@ namespace ServiceControl.CompositeViews.Messages using System.Collections.Generic; using System.Net.Http; using System.Threading.Tasks; + using Microsoft.Extensions.Logging; using Persistence; using Persistence.Infrastructure; using ServiceBus.Management.Infrastructure.Settings; @@ -17,8 +18,8 @@ public record SearchEndpointContext( public class SearchEndpointApi : ScatterGatherApiMessageView { - public SearchEndpointApi(IErrorMessageDataStore dataStore, Settings settings, - IHttpClientFactory httpClientFactory) : base(dataStore, settings, httpClientFactory) + public SearchEndpointApi(IErrorMessageDataStore dataStore, Settings settings, IHttpClientFactory httpClientFactory, ILogger logger) + : base(dataStore, settings, httpClientFactory, logger) { } diff --git a/src/ServiceControl/Connection/RemotePlatformConnectionDetailsProvider.cs b/src/ServiceControl/Connection/RemotePlatformConnectionDetailsProvider.cs index f5235d6a0a..a0b8df6089 100644 --- a/src/ServiceControl/Connection/RemotePlatformConnectionDetailsProvider.cs +++ b/src/ServiceControl/Connection/RemotePlatformConnectionDetailsProvider.cs @@ -5,10 +5,10 @@ using System.Net.Http; using System.Text.Json; using System.Threading.Tasks; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using ServiceBus.Management.Infrastructure.Settings; - class RemotePlatformConnectionDetailsProvider(Settings settings, IHttpClientFactory clientFactory) + class RemotePlatformConnectionDetailsProvider(Settings settings, IHttpClientFactory clientFactory, ILogger logger) : IProvidePlatformConnectionDetails { public Task ProvideConnectionDetails(PlatformConnectionDetails connection) => @@ -32,14 +32,10 @@ async Task UpdateFromRemote(RemoteInstanceSetting remote, PlatformConnectionDeta catch (Exception ex) { var remoteConnectionUri = $"{remote.BaseAddress.TrimEnd('/')}/connection"; - var message = $"Unable to get connection details from ServiceControl Audit instance at {remoteConnectionUri}."; - connection.Errors.Add(message); - - Log.Error(message, ex); + connection.Errors.Add($"Unable to get connection details from ServiceControl Audit instance at {remoteConnectionUri}."); + logger.LogError(ex, "Unable to get connection details from ServiceControl Audit instance at {RemoteInstanceUrl}", remoteConnectionUri); } } - - static readonly ILog Log = LogManager.GetLogger(); } } \ No newline at end of file diff --git a/src/ServiceControl/CustomChecks/CustomCheckResultProcessor.cs b/src/ServiceControl/CustomChecks/CustomCheckResultProcessor.cs index 7cff349e67..1e7a3d6727 100644 --- a/src/ServiceControl/CustomChecks/CustomCheckResultProcessor.cs +++ b/src/ServiceControl/CustomChecks/CustomCheckResultProcessor.cs @@ -4,15 +4,16 @@ namespace ServiceControl.CustomChecks using System.Threading.Tasks; using Contracts.CustomChecks; using Infrastructure.DomainEvents; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using ServiceControl.Persistence; class CustomCheckResultProcessor { - public CustomCheckResultProcessor(IDomainEvents domainEvents, ICustomChecksDataStore store) + public CustomCheckResultProcessor(IDomainEvents domainEvents, ICustomChecksDataStore store, ILogger logger) { this.domainEvents = domainEvents; this.store = store; + this.logger = logger; } public async Task ProcessResult(CustomCheckDetail checkDetail) @@ -37,7 +38,7 @@ await domainEvents.Raise(new CustomChecksUpdated } catch (Exception ex) { - Logger.Warn("Failed to update periodic check status.", ex); + logger.LogWarning(ex, "Failed to update periodic check status"); } } @@ -75,9 +76,8 @@ await domainEvents.Raise(new CustomCheckSucceeded readonly IDomainEvents domainEvents; readonly ICustomChecksDataStore store; - int lastCount; - static ILog Logger = LogManager.GetLogger(); + readonly ILogger logger; } } \ No newline at end of file diff --git a/src/ServiceControl/CustomChecks/FailedErrorImportCustomCheck.cs b/src/ServiceControl/CustomChecks/FailedErrorImportCustomCheck.cs index 4e895d9089..e8000d18f4 100644 --- a/src/ServiceControl/CustomChecks/FailedErrorImportCustomCheck.cs +++ b/src/ServiceControl/CustomChecks/FailedErrorImportCustomCheck.cs @@ -3,16 +3,17 @@ using System; using System.Threading; using System.Threading.Tasks; + using Microsoft.Extensions.Logging; using NServiceBus.CustomChecks; - using NServiceBus.Logging; using Persistence; class FailedErrorImportCustomCheck : CustomCheck { - public FailedErrorImportCustomCheck(IFailedErrorImportDataStore store) + public FailedErrorImportCustomCheck(IFailedErrorImportDataStore store, ILogger logger) : base("Error Message Ingestion", "ServiceControl Health", TimeSpan.FromHours(1)) { this.store = store; + this.logger = logger; } public override async Task PerformCheck(CancellationToken cancellationToken = default) @@ -21,7 +22,7 @@ public override async Task PerformCheck(CancellationToken cancellat if (hasFailedImports) { - Logger.Warn(Message); + logger.LogWarning(Message); return CheckResult.Failed(Message); } @@ -29,10 +30,9 @@ public override async Task PerformCheck(CancellationToken cancellat } readonly IFailedErrorImportDataStore store; - const string Message = @"One or more error messages have failed to import properly into ServiceControl and have been stored in the ServiceControl database. The import of these messages could have failed for a number of reasons and ServiceControl is not able to automatically reimport them. For guidance on how to resolve this see https://docs.particular.net/servicecontrol/import-failed-messages"; - static readonly ILog Logger = LogManager.GetLogger(typeof(FailedErrorImportCustomCheck)); + readonly ILogger logger; } } \ No newline at end of file diff --git a/src/ServiceControl/CustomChecks/InternalCustomChecks/InternalCustomCheckManager.cs b/src/ServiceControl/CustomChecks/InternalCustomChecks/InternalCustomCheckManager.cs index e3443cd2e0..a2442771f6 100644 --- a/src/ServiceControl/CustomChecks/InternalCustomChecks/InternalCustomCheckManager.cs +++ b/src/ServiceControl/CustomChecks/InternalCustomChecks/InternalCustomCheckManager.cs @@ -4,8 +4,8 @@ using System.Threading; using System.Threading.Tasks; using Infrastructure.BackgroundTasks; + using Microsoft.Extensions.Logging; using NServiceBus.CustomChecks; - using NServiceBus.Logging; using ServiceControl.Contracts.CustomChecks; using ServiceControl.Operations; @@ -15,12 +15,14 @@ public InternalCustomCheckManager( ICustomCheck check, EndpointDetails localEndpointDetails, IAsyncTimer scheduler, - CustomCheckResultProcessor checkResultProcessor) + CustomCheckResultProcessor checkResultProcessor, + ILogger logger) { this.check = check; this.localEndpointDetails = localEndpointDetails; this.scheduler = scheduler; this.checkResultProcessor = checkResultProcessor; + this.logger = logger; } public void Start() @@ -42,13 +44,14 @@ async Task Run(CancellationToken cancellationToken) } catch (OperationCanceledException e) when (cancellationToken.IsCancellationRequested) { - Logger.Info("Cancelled", e); + logger.LogInformation(e, "Cancelled"); } catch (Exception ex) { - var reason = $"`{check.GetType()}` implementation failed to run."; + var customCheckType = check.GetType(); + var reason = $"`{customCheckType}` implementation failed to run."; result = CheckResult.Failed(reason); - Logger.Error(reason, ex); + logger.LogError(ex, "`{CustomCheckType}` implementation failed to run", customCheckType); } var detail = new CustomCheckDetail @@ -74,7 +77,6 @@ async Task Run(CancellationToken cancellationToken) readonly EndpointDetails localEndpointDetails; readonly IAsyncTimer scheduler; readonly CustomCheckResultProcessor checkResultProcessor; - - static ILog Logger = LogManager.GetLogger(); + readonly ILogger logger; } } \ No newline at end of file diff --git a/src/ServiceControl/CustomChecks/InternalCustomChecks/InternalCustomChecks.cs b/src/ServiceControl/CustomChecks/InternalCustomChecks/InternalCustomChecks.cs index 1a02710541..cc840c6e76 100644 --- a/src/ServiceControl/CustomChecks/InternalCustomChecks/InternalCustomChecks.cs +++ b/src/ServiceControl/CustomChecks/InternalCustomChecks/InternalCustomChecks.cs @@ -4,6 +4,7 @@ using Infrastructure.BackgroundTasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; + using Microsoft.Extensions.Logging; using NServiceBus.CustomChecks; using NServiceBus.Hosting; using Operations; @@ -24,7 +25,8 @@ public static IHostApplicationBuilder AddInternalCustomChecks(this IHostApplicat provider.GetRequiredService(), provider.GetRequiredService(), provider.GetRequiredService(), - provider.GetRequiredService().InstanceName)); + provider.GetRequiredService().InstanceName, + provider.GetRequiredService>())); return hostBuilder; } } diff --git a/src/ServiceControl/CustomChecks/InternalCustomChecks/InternalCustomChecksHostedService.cs b/src/ServiceControl/CustomChecks/InternalCustomChecks/InternalCustomChecksHostedService.cs index e33b68e3a5..b75804e2d1 100644 --- a/src/ServiceControl/CustomChecks/InternalCustomChecks/InternalCustomChecksHostedService.cs +++ b/src/ServiceControl/CustomChecks/InternalCustomChecks/InternalCustomChecksHostedService.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using Infrastructure.BackgroundTasks; using Microsoft.Extensions.Hosting; + using Microsoft.Extensions.Logging; using NServiceBus.CustomChecks; using NServiceBus.Hosting; using ServiceControl.Operations; @@ -15,14 +16,15 @@ class InternalCustomChecksHostedService( HostInformation hostInfo, IAsyncTimer scheduler, CustomCheckResultProcessor checkResultProcessor, - string endpointName) + string endpointName, + ILogger logger) : IHostedService { public Task StartAsync(CancellationToken cancellationToken) { foreach (var check in customChecks) { - var checkManager = new InternalCustomCheckManager(check, localEndpointDetails, scheduler, checkResultProcessor); + var checkManager = new InternalCustomCheckManager(check, localEndpointDetails, scheduler, checkResultProcessor, logger); checkManager.Start(); managers.Add(checkManager); diff --git a/src/ServiceControl/ExternalIntegrations/EventDispatcherHostedService.cs b/src/ServiceControl/ExternalIntegrations/EventDispatcherHostedService.cs index 10678284f7..ad6b91141c 100644 --- a/src/ServiceControl/ExternalIntegrations/EventDispatcherHostedService.cs +++ b/src/ServiceControl/ExternalIntegrations/EventDispatcherHostedService.cs @@ -6,8 +6,8 @@ using System.Threading.Tasks; using Infrastructure.DomainEvents; using Microsoft.Extensions.Hosting; + using Microsoft.Extensions.Logging; using NServiceBus; - using NServiceBus.Logging; using Persistence; class EventDispatcherHostedService : IHostedService @@ -16,13 +16,14 @@ public EventDispatcherHostedService( IExternalIntegrationRequestsDataStore store, IDomainEvents domainEvents, IEnumerable eventPublishers, - IMessageSession messageSession - ) + IMessageSession messageSession, + ILogger logger) { this.store = store; this.eventPublishers = eventPublishers; this.domainEvents = domainEvents; this.messageSession = messageSession; + this.logger = logger; } public Task StartAsync(CancellationToken cancellationToken) @@ -43,10 +44,7 @@ async Task TryDispatchEventBatch(object[] allContexts) foreach (var eventToBePublished in eventsToBePublished) { - if (Logger.IsDebugEnabled) - { - Logger.Debug("Publishing external event on the bus."); - } + logger.LogDebug("Publishing external event on the bus."); try { @@ -54,7 +52,7 @@ async Task TryDispatchEventBatch(object[] allContexts) } catch (Exception e) { - Logger.Error("Failed dispatching external integration event.", e); + logger.LogError(e, "Failed dispatching external integration event."); var m = new ExternalIntegrationEventFailedToBePublished { @@ -79,11 +77,11 @@ public Task StopAsync(CancellationToken cancellationToken) return store.StopAsync(cancellationToken); } - IMessageSession messageSession; - IEnumerable eventPublishers; - IExternalIntegrationRequestsDataStore store; - IDomainEvents domainEvents; + readonly IMessageSession messageSession; + readonly IEnumerable eventPublishers; + readonly IExternalIntegrationRequestsDataStore store; + readonly IDomainEvents domainEvents; - static ILog Logger = LogManager.GetLogger(typeof(EventDispatcherHostedService)); + readonly ILogger logger; } } \ No newline at end of file diff --git a/src/ServiceControl/ExternalIntegrations/IntegrationEventWriter.cs b/src/ServiceControl/ExternalIntegrations/IntegrationEventWriter.cs index e4af301c7c..26881dd36f 100644 --- a/src/ServiceControl/ExternalIntegrations/IntegrationEventWriter.cs +++ b/src/ServiceControl/ExternalIntegrations/IntegrationEventWriter.cs @@ -5,15 +5,19 @@ using System.Threading; using System.Threading.Tasks; using Infrastructure.DomainEvents; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using ServiceControl.Persistence; class IntegrationEventWriter : IDomainHandler { - public IntegrationEventWriter(IExternalIntegrationRequestsDataStore store, IEnumerable eventPublishers) + public IntegrationEventWriter( + IExternalIntegrationRequestsDataStore store, + IEnumerable eventPublishers, + ILogger logger) { this.store = store; this.eventPublishers = eventPublishers; + this.logger = logger; } public async Task Handle(IDomainEvent message, CancellationToken cancellationToken) @@ -28,23 +32,18 @@ public async Task Handle(IDomainEvent message, CancellationToken cancellationTok return; } - if (Logger.IsDebugEnabled) - { - Logger.Debug("Storing dispatch requests"); - } + logger.LogDebug("Storing dispatch requests"); var dispatchRequests = dispatchContexts.Select(dispatchContext => new ExternalIntegrationDispatchRequest { DispatchContext = dispatchContext }).ToList(); - await store.StoreDispatchRequest(dispatchRequests); } readonly IExternalIntegrationRequestsDataStore store; readonly IEnumerable eventPublishers; - - static readonly ILog Logger = LogManager.GetLogger(typeof(IntegrationEventWriter)); + readonly ILogger logger; } } \ No newline at end of file diff --git a/src/ServiceControl/ExternalIntegrations/RepeatedFailuresOverTimeCircuitBreaker.cs b/src/ServiceControl/ExternalIntegrations/RepeatedFailuresOverTimeCircuitBreaker.cs index ad14c5c97e..3977af150b 100644 --- a/src/ServiceControl/ExternalIntegrations/RepeatedFailuresOverTimeCircuitBreaker.cs +++ b/src/ServiceControl/ExternalIntegrations/RepeatedFailuresOverTimeCircuitBreaker.cs @@ -3,16 +3,22 @@ namespace NServiceBus using System; using System.Threading; using System.Threading.Tasks; - using Logging; + using Microsoft.Extensions.Logging; class RepeatedFailuresOverTimeCircuitBreaker : IDisposable { - public RepeatedFailuresOverTimeCircuitBreaker(string name, TimeSpan timeToWaitBeforeTriggering, Action triggerAction, TimeSpan delayAfterFailure) + public RepeatedFailuresOverTimeCircuitBreaker( + string name, + TimeSpan timeToWaitBeforeTriggering, + Action triggerAction, + TimeSpan delayAfterFailure, + ILogger logger) { - this.delayAfterFailure = delayAfterFailure; this.name = name; - this.triggerAction = triggerAction; this.timeToWaitBeforeTriggering = timeToWaitBeforeTriggering; + this.triggerAction = triggerAction; + this.delayAfterFailure = delayAfterFailure; + this.logger = logger; timer = new Timer(CircuitBreakerTriggered); } @@ -32,8 +38,14 @@ public void Success() return; } - timer.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite); - Logger.InfoFormat("The circuit breaker for {0} is now disarmed", name); + if (timer.Change(Timeout.Infinite, Timeout.Infinite)) + { + logger.LogInformation("The circuit breaker for {CircuitBreakerName} is now disarmed", name); + } + else + { + logger.LogError("Attempted to disarm circuit breaker for {CircuitBreakerName} but failed", name); + } } public Task Failure(Exception exception) @@ -43,8 +55,14 @@ public Task Failure(Exception exception) if (newValue == 1) { - timer.Change(timeToWaitBeforeTriggering, NoPeriodicTriggering); - Logger.WarnFormat("The circuit breaker for {0} is now in the armed state", name); + if (timer.Change(timeToWaitBeforeTriggering, NoPeriodicTriggering)) + { + logger.LogWarning("The circuit breaker for {CircuitBreakerName} is now in the armed state", name); + } + else + { + logger.LogError("Attempted to arm circuit breaker for {CircuitBreakerName} but failed", name); + } } return Task.Delay(delayAfterFailure); @@ -54,13 +72,12 @@ void CircuitBreakerTriggered(object state) { if (Interlocked.Read(ref failureCount) > 0) { - Logger.WarnFormat("The circuit breaker for {0} will now be triggered", name); + logger.LogWarning("The circuit breaker for {CircuitBreakerName} will now be triggered", name); triggerAction(lastException); } } readonly TimeSpan delayAfterFailure; - long failureCount; Exception lastException; @@ -70,6 +87,6 @@ void CircuitBreakerTriggered(object state) readonly Action triggerAction; static readonly TimeSpan NoPeriodicTriggering = TimeSpan.FromMilliseconds(-1); - static readonly ILog Logger = LogManager.GetLogger(); + readonly ILogger logger; } } \ No newline at end of file diff --git a/src/ServiceControl/HostApplicationBuilderExtensions.cs b/src/ServiceControl/HostApplicationBuilderExtensions.cs index 50d0733fb9..39d550f3e6 100644 --- a/src/ServiceControl/HostApplicationBuilderExtensions.cs +++ b/src/ServiceControl/HostApplicationBuilderExtensions.cs @@ -6,6 +6,7 @@ namespace Particular.ServiceControl using global::ServiceControl.CustomChecks; using global::ServiceControl.ExternalIntegrations; using global::ServiceControl.Hosting; + using global::ServiceControl.Infrastructure; using global::ServiceControl.Infrastructure.BackgroundTasks; using global::ServiceControl.Infrastructure.DomainEvents; using global::ServiceControl.Infrastructure.Metrics; @@ -23,7 +24,6 @@ namespace Particular.ServiceControl using NLog.Extensions.Logging; using NServiceBus; using NServiceBus.Configuration.AdvancedExtensibility; - using NServiceBus.Logging; using NServiceBus.Transport; using ServiceBus.Management.Infrastructure; using ServiceBus.Management.Infrastructure.Installers; @@ -127,8 +127,8 @@ Audit Retention Period (optional): {settings.AuditRetentionPeriod} Selected Transport Customization: {settings.TransportType} -------------------------------------------------------------"; - var logger = LogManager.GetLogger(typeof(HostApplicationBuilderExtensions)); - logger.Info(startupMessage); + var logger = LoggerUtil.CreateStaticLogger(typeof(HostApplicationBuilderExtensions), settings.LoggingSettings.ToHostLogLevel()); + logger.LogInformation(startupMessage); endpointConfiguration.GetSettings().AddStartupDiagnosticsSection("Startup", new { Settings = settings, diff --git a/src/ServiceControl/Hosting/Commands/ImportFailedErrorsCommand.cs b/src/ServiceControl/Hosting/Commands/ImportFailedErrorsCommand.cs index e9b89213e0..4adafa724f 100644 --- a/src/ServiceControl/Hosting/Commands/ImportFailedErrorsCommand.cs +++ b/src/ServiceControl/Hosting/Commands/ImportFailedErrorsCommand.cs @@ -6,17 +6,16 @@ using Infrastructure.WebApi; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; + using Microsoft.Extensions.Logging; using NServiceBus; - using NServiceBus.Logging; using Operations; using Particular.ServiceControl; using Particular.ServiceControl.Hosting; using ServiceBus.Management.Infrastructure.Settings; + using ServiceControl.Infrastructure; class ImportFailedErrorsCommand : AbstractCommand { - readonly ILog Log = LogManager.GetLogger(); - public override async Task Execute(HostArguments args, Settings settings) { settings.IngestErrorMessages = false; @@ -43,7 +42,7 @@ public override async Task Execute(HostArguments args, Settings settings) } catch (OperationCanceledException e) when (tokenSource.IsCancellationRequested) { - Log.Info("Cancelled", e); + LoggerUtil.CreateStaticLogger().LogInformation(e, "Cancelled"); } finally { diff --git a/src/ServiceControl/Hosting/Commands/SetupCommand.cs b/src/ServiceControl/Hosting/Commands/SetupCommand.cs index 41ef355fd4..3fdc2e7e11 100644 --- a/src/ServiceControl/Hosting/Commands/SetupCommand.cs +++ b/src/ServiceControl/Hosting/Commands/SetupCommand.cs @@ -3,11 +3,12 @@ using System.Runtime.InteropServices; using System.Threading.Tasks; using Microsoft.Extensions.Hosting; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using Particular.ServiceControl; using Particular.ServiceControl.Hosting; using ServiceBus.Management.Infrastructure.Installers; using ServiceBus.Management.Infrastructure.Settings; + using ServiceControl.Infrastructure; using Transports; class SetupCommand : AbstractCommand @@ -35,7 +36,7 @@ public override async Task Execute(HostArguments args, Settings settings) if (args.SkipQueueCreation) { - Logger.Info("Skipping queue creation"); + LoggerUtil.CreateStaticLogger().LogInformation("Skipping queue creation"); } else { @@ -48,7 +49,5 @@ public override async Task Execute(HostArguments args, Settings settings) await host.StopAsync(); } - - static readonly ILog Logger = LogManager.GetLogger(); } } \ No newline at end of file diff --git a/src/ServiceControl/Infrastructure/Metrics/MetricsReporterHostedService.cs b/src/ServiceControl/Infrastructure/Metrics/MetricsReporterHostedService.cs index bf886d712f..5992b7c0fe 100644 --- a/src/ServiceControl/Infrastructure/Metrics/MetricsReporterHostedService.cs +++ b/src/ServiceControl/Infrastructure/Metrics/MetricsReporterHostedService.cs @@ -4,20 +4,24 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Hosting; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; class MetricsReporterHostedService : IHostedService { readonly Metrics metrics; + readonly ILogger logger; + MetricsReporter reporter; - public MetricsReporterHostedService(Metrics metrics) => this.metrics = metrics; + public MetricsReporterHostedService(Metrics metrics, ILogger logger) + { + this.metrics = metrics; + this.logger = logger; + } public Task StartAsync(CancellationToken cancellationToken) { - var metricsLog = LogManager.GetLogger("Metrics"); - - reporter = new MetricsReporter(metrics, x => metricsLog.Info(x), TimeSpan.FromSeconds(5)); + reporter = new MetricsReporter(metrics, x => logger.LogInformation(x), TimeSpan.FromSeconds(5)); reporter.Start(); diff --git a/src/ServiceControl/Infrastructure/Settings/Settings.cs b/src/ServiceControl/Infrastructure/Settings/Settings.cs index cf6dbeffe7..772d33203d 100644 --- a/src/ServiceControl/Infrastructure/Settings/Settings.cs +++ b/src/ServiceControl/Infrastructure/Settings/Settings.cs @@ -6,8 +6,8 @@ namespace ServiceBus.Management.Infrastructure.Settings using System.Linq; using System.Runtime.Loader; using System.Text.Json.Serialization; + using Microsoft.Extensions.Logging; using NLog.Common; - using NServiceBus.Logging; using NServiceBus.Transport; using ServiceControl.Configuration; using ServiceControl.Infrastructure; @@ -145,7 +145,7 @@ public TimeSpan HeartbeatGracePeriod } catch (Exception ex) { - logger.Error($"HeartbeatGracePeriod settings invalid - {ex}. Defaulting HeartbeatGracePeriod to '00:00:40'"); + logger.LogError(ex, "HeartbeatGracePeriod settings invalid. Defaulting HeartbeatGracePeriod to '00:00:40'"); return TimeSpan.FromSeconds(40); } } @@ -234,15 +234,15 @@ TimeSpan GetEventRetentionPeriod() string message; if (ValidateConfiguration && result < TimeSpan.FromHours(1)) { - message = "EventRetentionPeriod settings is invalid, value should be minimum 1 hour."; - logger.Fatal(message); + message = "EventRetentionPeriod settings is invalid, value should be minimum 1 hour"; + logger.LogCritical(message); throw new Exception(message); } if (ValidateConfiguration && result > TimeSpan.FromDays(200)) { - message = "EventRetentionPeriod settings is invalid, value should be maximum 200 days."; - logger.Fatal(message); + message = "EventRetentionPeriod settings is invalid, value should be maximum 200 days"; + logger.LogCritical(message); throw new Exception(message); } @@ -259,8 +259,8 @@ TimeSpan GetErrorRetentionPeriod() var valueRead = SettingsReader.Read(SettingsRootNamespace, "ErrorRetentionPeriod"); if (valueRead == null) { - message = "ErrorRetentionPeriod settings is missing, please make sure it is included."; - logger.Fatal(message); + message = "ErrorRetentionPeriod settings is missing, please make sure it is included"; + logger.LogCritical(message); throw new Exception(message); } @@ -268,22 +268,22 @@ TimeSpan GetErrorRetentionPeriod() { if (ValidateConfiguration && result < TimeSpan.FromDays(5)) { - message = "ErrorRetentionPeriod settings is invalid, value should be minimum 5 days."; - logger.Fatal(message); + message = "ErrorRetentionPeriod settings is invalid, value should be minimum 5 days"; + logger.LogCritical(message); throw new Exception(message); } if (ValidateConfiguration && result > TimeSpan.FromDays(45)) { - message = "ErrorRetentionPeriod settings is invalid, value should be maximum 45 days."; - logger.Fatal(message); + message = "ErrorRetentionPeriod settings is invalid, value should be maximum 45 days"; + logger.LogCritical(message); throw new Exception(message); } } else { - message = "ErrorRetentionPeriod settings is invalid, please make sure it is a TimeSpan."; - logger.Fatal(message); + message = "ErrorRetentionPeriod settings is invalid, please make sure it is a TimeSpan"; + logger.LogCritical(message); throw new Exception(message); } @@ -402,20 +402,20 @@ void LoadErrorIngestionSettings() if (!IngestErrorMessages) { - logger.Info("Error ingestion disabled."); + logger.LogInformation("Error ingestion disabled"); } ErrorLogQueue = SettingsReader.Read(serviceBusRootNamespace, "ErrorLogQueue", null); if (ErrorLogQueue == null) { - logger.Info("No settings found for error log queue to import, default name will be used"); + logger.LogInformation("No settings found for error log queue to import, default name will be used"); ErrorLogQueue = Subscope(ErrorQueue); } } // logger is intentionally not static to prevent it from being initialized before LoggingConfigurator.ConfigureLogging has been called - readonly ILog logger = LogManager.GetLogger(typeof(Settings)); + readonly ILogger logger = LoggerUtil.CreateStaticLogger(); public const string DEFAULT_INSTANCE_NAME = "Particular.ServiceControl"; public static readonly SettingsRootNamespace SettingsRootNamespace = new("ServiceControl"); diff --git a/src/ServiceControl/Infrastructure/SignalR/MessageStreamerHub.cs b/src/ServiceControl/Infrastructure/SignalR/MessageStreamerHub.cs index 7f398e35dd..208e5fb7a2 100644 --- a/src/ServiceControl/Infrastructure/SignalR/MessageStreamerHub.cs +++ b/src/ServiceControl/Infrastructure/SignalR/MessageStreamerHub.cs @@ -7,24 +7,28 @@ using System.Text.Json.Nodes; using System.Threading.Tasks; using Microsoft.AspNetCore.SignalR; + using Microsoft.Extensions.Logging; using NServiceBus; - using NServiceBus.Logging; using NServiceBus.Routing; using NServiceBus.Settings; using NServiceBus.Transport; class MessageStreamerHub : Hub { - public MessageStreamerHub(IMessageDispatcher sender, IReadOnlySettings settings, ReceiveAddresses receiveAddresses) + public MessageStreamerHub( + IMessageDispatcher sender, + IReadOnlySettings settings, + ReceiveAddresses receiveAddresses, + ILogger logger) { var conventions = settings.Get(); this.sender = sender; - messageTypes = settings.GetAvailableTypes() .Where(conventions.IsMessageType) .GroupBy(x => x.Name) .ToDictionary(x => x.Key, x => x.FirstOrDefault().AssemblyQualifiedName); localAddress = receiveAddresses.MainReceiveAddress; + this.logger = logger; } public async Task SendMessage(string data) @@ -47,7 +51,7 @@ public async Task SendMessage(string data) } catch (Exception ex) { - Log.Error($"Failed to process SignalR message. AuditMessage={data}", ex); + logger.LogError(ex, "Failed to process SignalR message. AuditMessage={AuditMessage}", data); throw; } } @@ -56,6 +60,6 @@ public async Task SendMessage(string data) readonly IMessageDispatcher sender; string localAddress; - static readonly ILog Log = LogManager.GetLogger(typeof(MessageStreamerHub)); + readonly ILogger logger; } } \ No newline at end of file diff --git a/src/ServiceControl/Licensing/ActiveLicense.cs b/src/ServiceControl/Licensing/ActiveLicense.cs index d50a5bdb38..eed4880136 100644 --- a/src/ServiceControl/Licensing/ActiveLicense.cs +++ b/src/ServiceControl/Licensing/ActiveLicense.cs @@ -5,9 +5,9 @@ using System.Threading.Tasks; using global::ServiceControl.LicenseManagement; using global::ServiceControl.Persistence; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; - public class ActiveLicense(ITrialLicenseDataProvider trialLicenseDataProvider) + public class ActiveLicense(ITrialLicenseDataProvider trialLicenseDataProvider, ILogger logger) { public bool IsValid { get; set; } public bool IsEvaluation { get; set; } @@ -16,7 +16,7 @@ public class ActiveLicense(ITrialLicenseDataProvider trialLicenseDataProvider) public async Task Refresh(CancellationToken cancellationToken) { - Logger.Debug("Refreshing ActiveLicense"); + logger.LogDebug("Refreshing ActiveLicense"); var detectedLicense = LicenseManager.FindLicense(); @@ -58,7 +58,5 @@ internal static async Task ValidateTrialLicense(LicenseDetails l return licenseDetails; } static readonly int MaxTrialPeriodInDays = 14; - - static readonly ILog Logger = LogManager.GetLogger(typeof(ActiveLicense)); } } \ No newline at end of file diff --git a/src/ServiceControl/Licensing/LicenseCheckHostedService.cs b/src/ServiceControl/Licensing/LicenseCheckHostedService.cs index 3afcc3c2ba..52a7b41a5a 100644 --- a/src/ServiceControl/Licensing/LicenseCheckHostedService.cs +++ b/src/ServiceControl/Licensing/LicenseCheckHostedService.cs @@ -5,9 +5,9 @@ using System.Threading.Tasks; using global::ServiceControl.Infrastructure.BackgroundTasks; using Microsoft.Extensions.Hosting; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; - class LicenseCheckHostedService(ActiveLicense activeLicense, IAsyncTimer scheduler) : IHostedService + class LicenseCheckHostedService(ActiveLicense activeLicense, IAsyncTimer scheduler, ILogger logger) : IHostedService { public Task StartAsync(CancellationToken cancellationToken) { @@ -17,14 +17,12 @@ public Task StartAsync(CancellationToken cancellationToken) await activeLicense.Refresh(cancellationToken); return TimerJobExecutionResult.ScheduleNextExecution; - }, TimeSpan.FromTicks(0), due, ex => Logger.Error("Unhandled error while refreshing the license.", ex)); + }, TimeSpan.FromTicks(0), due, ex => logger.LogError(ex, "Unhandled error while refreshing the license")); return Task.CompletedTask; } public Task StopAsync(CancellationToken cancellationToken) => timer.Stop(cancellationToken); TimerJob timer; - - static readonly ILog Logger = LogManager.GetLogger(); } } \ No newline at end of file diff --git a/src/ServiceControl/MessageFailures/Api/EditFailedMessagesController.cs b/src/ServiceControl/MessageFailures/Api/EditFailedMessagesController.cs index f4c797390f..9c0413cbac 100644 --- a/src/ServiceControl/MessageFailures/Api/EditFailedMessagesController.cs +++ b/src/ServiceControl/MessageFailures/Api/EditFailedMessagesController.cs @@ -6,8 +6,8 @@ using System.Text; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; + using Microsoft.Extensions.Logging; using NServiceBus; - using NServiceBus.Logging; using Persistence; using Recoverability; using ServiceBus.Management.Infrastructure.Settings; @@ -17,7 +17,8 @@ public class EditFailedMessagesController( Settings settings, IErrorMessageDataStore store, - IMessageSession session) + IMessageSession session, + ILogger logger) : ControllerBase { [Route("edit/config")] @@ -30,7 +31,7 @@ public async Task Edit(string failedMessageId, [FromBody] EditMes { if (!settings.AllowMessageEditing) { - Log.Info("Message edit-retry has not been enabled."); + logger.LogInformation("Message edit-retry has not been enabled"); return NotFound(); } @@ -38,7 +39,7 @@ public async Task Edit(string failedMessageId, [FromBody] EditMes if (failedMessage == null) { - Log.WarnFormat("The original failed message could not be loaded for id={0}", failedMessageId); + logger.LogWarning("The original failed message could not be loaded for id={FailedMessageId}", failedMessageId); return BadRequest(); } @@ -54,13 +55,13 @@ public async Task Edit(string failedMessageId, [FromBody] EditMes if (LockedHeaderModificationValidator.Check(GetEditConfiguration().LockedHeaders, edit.MessageHeaders, failedMessage.ProcessingAttempts.Last().Headers)) { - Log.WarnFormat("Locked headers have been modified on the edit-retry for MessageID {0}.", failedMessageId); + logger.LogWarning("Locked headers have been modified on the edit-retry for MessageID {FailedMessageId}", failedMessageId); return BadRequest(); } if (string.IsNullOrWhiteSpace(edit.MessageBody) || edit.MessageHeaders == null) { - Log.WarnFormat("There is no message body on the edit-retry for MessageID {0}.", failedMessageId); + logger.LogWarning("There is no message body on the edit-retry for MessageID {FailedMessageId}", failedMessageId); return BadRequest(); } @@ -121,8 +122,6 @@ EditConfigurationModel GetEditConfiguration() => "Header" } }; - - static readonly ILog Log = LogManager.GetLogger(typeof(EditFailedMessagesController)); } public class EditConfigurationModel diff --git a/src/ServiceControl/MessageFailures/Api/RetryMessagesController.cs b/src/ServiceControl/MessageFailures/Api/RetryMessagesController.cs index 3a55b27db2..c486129df9 100644 --- a/src/ServiceControl/MessageFailures/Api/RetryMessagesController.cs +++ b/src/ServiceControl/MessageFailures/Api/RetryMessagesController.cs @@ -8,15 +8,20 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Extensions; using Microsoft.AspNetCore.Mvc; + using Microsoft.Extensions.Logging; using NServiceBus; - using NServiceBus.Logging; using Recoverability; using ServiceBus.Management.Infrastructure.Settings; using Yarp.ReverseProxy.Forwarder; [ApiController] [Route("api")] - public class RetryMessagesController(Settings settings, HttpMessageInvoker httpMessageInvoker, IHttpForwarder forwarder, IMessageSession messageSession) : ControllerBase + public class RetryMessagesController( + Settings settings, + HttpMessageInvoker httpMessageInvoker, + IHttpForwarder forwarder, + IMessageSession messageSession, + ILogger logger) : ControllerBase { [Route("errors/{failedMessageId:required:minlength(1)}/retry")] [HttpPost] @@ -38,7 +43,7 @@ public async Task RetryMessageBy([FromQuery(Name = "instance_id") var forwarderError = await forwarder.SendAsync(HttpContext, remote.BaseAddress, httpMessageInvoker); if (forwarderError != ForwarderError.None && HttpContext.GetForwarderErrorFeature()?.Exception is { } exception) { - logger.Warn($"Failed to forward the request ot remote instance at {remote.BaseAddress + HttpContext.Request.GetEncodedPathAndQuery()}.", exception); + logger.LogWarning(exception, "Failed to forward the request to remote instance at {RemoteInstanceUrl}", remote.BaseAddress + HttpContext.Request.GetEncodedPathAndQuery()); } return Empty; @@ -88,7 +93,5 @@ public async Task RetryAllByEndpoint(string endpointName) return Accepted(); } - - static ILog logger = LogManager.GetLogger(typeof(RetryMessagesController)); } } \ No newline at end of file diff --git a/src/ServiceControl/Monitoring/EndpointInstanceMonitor.cs b/src/ServiceControl/Monitoring/EndpointInstanceMonitor.cs index 7a375746ed..5ec475da02 100644 --- a/src/ServiceControl/Monitoring/EndpointInstanceMonitor.cs +++ b/src/ServiceControl/Monitoring/EndpointInstanceMonitor.cs @@ -5,17 +5,18 @@ namespace ServiceControl.Monitoring using Contracts.HeartbeatMonitoring; using EndpointControl.Contracts; using Infrastructure.DomainEvents; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using ServiceControl.Operations; using ServiceControl.Persistence; class EndpointInstanceMonitor { - public EndpointInstanceMonitor(EndpointInstanceId endpointInstanceId, bool monitored, IDomainEvents domainEvents) + public EndpointInstanceMonitor(EndpointInstanceId endpointInstanceId, bool monitored, IDomainEvents domainEvents, ILogger logger) { Id = endpointInstanceId; Monitored = monitored; this.domainEvents = domainEvents; + this.logger = logger; } public EndpointInstanceId Id { get; } @@ -39,7 +40,7 @@ public async Task UpdateStatus(HeartbeatStatus newStatus, DateTime? latestTimest if (newStatus != status) { await RaiseStateChangeEvents(newStatus, latestTimestamp); - Log.DebugFormat("Endpoint {0} status updated from {1} to {2}", Id.LogicalName, status, newStatus); + logger.LogDebug("Endpoint {LogicalEndpointName} status updated from {OldHeartbeatStatus} to {NewHeartbeatStatus}", Id.LogicalName, status, newStatus); } lastSeen = latestTimestamp; @@ -134,7 +135,7 @@ public KnownEndpointsView GetKnownView() }; } - static readonly ILog Log = LogManager.GetLogger(); + readonly ILogger logger; IDomainEvents domainEvents; DateTime? lastSeen; diff --git a/src/ServiceControl/Monitoring/EndpointInstanceMonitoring.cs b/src/ServiceControl/Monitoring/EndpointInstanceMonitoring.cs index 0829135c43..39319fc6d3 100644 --- a/src/ServiceControl/Monitoring/EndpointInstanceMonitoring.cs +++ b/src/ServiceControl/Monitoring/EndpointInstanceMonitoring.cs @@ -8,19 +8,22 @@ namespace ServiceControl.Monitoring using Contracts.EndpointControl; using Contracts.HeartbeatMonitoring; using Infrastructure.DomainEvents; + using Microsoft.Extensions.Logging; using Operations; using Persistence; class EndpointInstanceMonitoring : IEndpointInstanceMonitoring { readonly IDomainEvents domainEvents; + readonly ILogger monitorLogger; readonly ConcurrentDictionary endpoints = new(); readonly ConcurrentDictionary heartbeats = new(); EndpointMonitoringStats previousStats; - public EndpointInstanceMonitoring(IDomainEvents domainEvents) + public EndpointInstanceMonitoring(IDomainEvents domainEvents, ILogger monitorLogger) { this.domainEvents = domainEvents; + this.monitorLogger = monitorLogger; } public void RecordHeartbeat(EndpointInstanceId endpointInstanceId, DateTime timestamp) => heartbeats.GetOrAdd(endpointInstanceId, id => new HeartbeatMonitor()).MarkAlive(timestamp); @@ -32,7 +35,7 @@ public async Task CheckEndpoints(DateTime threshold) var recordedHeartbeat = entry.Value.MarkDeadIfOlderThan(threshold); var endpointInstanceId = entry.Key; - var monitor = endpoints.GetOrAdd(endpointInstanceId.UniqueId, id => new EndpointInstanceMonitor(endpointInstanceId, true, domainEvents)); + var monitor = endpoints.GetOrAdd(endpointInstanceId.UniqueId, id => new EndpointInstanceMonitor(endpointInstanceId, true, domainEvents, monitorLogger)); await monitor.UpdateStatus(recordedHeartbeat.Status, recordedHeartbeat.Timestamp); } @@ -45,13 +48,13 @@ public bool IsNewInstance(EndpointDetails newEndpointDetails) { var endpointInstanceId = newEndpointDetails.ToInstanceId(); - return endpoints.TryAdd(endpointInstanceId.UniqueId, new EndpointInstanceMonitor(endpointInstanceId, false, domainEvents)); + return endpoints.TryAdd(endpointInstanceId.UniqueId, new EndpointInstanceMonitor(endpointInstanceId, false, domainEvents, monitorLogger)); } public async Task EndpointDetected(EndpointDetails newEndpointDetails) { var endpointInstanceId = newEndpointDetails.ToInstanceId(); - if (endpoints.TryAdd(endpointInstanceId.UniqueId, new EndpointInstanceMonitor(endpointInstanceId, false, domainEvents))) + if (endpoints.TryAdd(endpointInstanceId.UniqueId, new EndpointInstanceMonitor(endpointInstanceId, false, domainEvents, monitorLogger))) { await domainEvents.Raise(new EndpointDetected { @@ -64,7 +67,7 @@ await domainEvents.Raise(new EndpointDetected public async Task DetectEndpointFromHeartbeatStartup(EndpointDetails newEndpointDetails, DateTime startedAt) { var endpointInstanceId = newEndpointDetails.ToInstanceId(); - endpoints.GetOrAdd(endpointInstanceId.UniqueId, id => new EndpointInstanceMonitor(endpointInstanceId, true, domainEvents)); + endpoints.GetOrAdd(endpointInstanceId.UniqueId, id => new EndpointInstanceMonitor(endpointInstanceId, true, domainEvents, monitorLogger)); await domainEvents.Raise(new EndpointStarted { @@ -76,7 +79,7 @@ await domainEvents.Raise(new EndpointStarted public void DetectEndpointFromPersistentStore(EndpointDetails endpointDetails, bool monitored) { var endpointInstanceId = new EndpointInstanceId(endpointDetails.Name, endpointDetails.Host, endpointDetails.HostId); - endpoints.GetOrAdd(endpointInstanceId.UniqueId, id => new EndpointInstanceMonitor(endpointInstanceId, monitored, domainEvents)); + endpoints.GetOrAdd(endpointInstanceId.UniqueId, id => new EndpointInstanceMonitor(endpointInstanceId, monitored, domainEvents, monitorLogger)); } async Task Update(EndpointMonitoringStats stats) diff --git a/src/ServiceControl/Monitoring/HeartbeatEndpointSettingsSyncHostedService.cs b/src/ServiceControl/Monitoring/HeartbeatEndpointSettingsSyncHostedService.cs index 31898ecbbb..5f75cf5885 100644 --- a/src/ServiceControl/Monitoring/HeartbeatEndpointSettingsSyncHostedService.cs +++ b/src/ServiceControl/Monitoring/HeartbeatEndpointSettingsSyncHostedService.cs @@ -23,7 +23,7 @@ public class HeartbeatEndpointSettingsSyncHostedService( protected override async Task ExecuteAsync(CancellationToken cancellationToken) { - logger.LogInformation($"Starting {nameof(HeartbeatEndpointSettingsSyncHostedService)}"); + logger.LogInformation("Starting {ServiceName}", nameof(HeartbeatEndpointSettingsSyncHostedService)); try { @@ -35,7 +35,7 @@ protected override async Task ExecuteAsync(CancellationToken cancellationToken) { try { - logger.LogInformation($"Performing sync for {nameof(HeartbeatEndpointSettingsSyncHostedService)}"); + logger.LogInformation("Performing sync for {ServiceName}", nameof(HeartbeatEndpointSettingsSyncHostedService)); await PerformSync(cancellationToken); } catch (Exception ex) when (ex is not OperationCanceledException) @@ -47,7 +47,7 @@ protected override async Task ExecuteAsync(CancellationToken cancellationToken) } catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested) { - logger.LogInformation($"Stopping {nameof(HeartbeatEndpointSettingsSyncHostedService)}"); + logger.LogInformation("Stopping {ServiceName}", nameof(HeartbeatEndpointSettingsSyncHostedService)); } } @@ -80,7 +80,7 @@ async Task PurgeMonitoringDataThatDoesNotNeedToBeTracked(CancellationToken cance { endpointInstanceMonitoring.RemoveEndpoint(endpointId); await monitoringDataStore.Delete(endpointId); - logger.LogInformation($"Removed endpoint '{endpointSetting.Name}' from monitoring data."); + logger.LogInformation("Removed endpoint '{EndpointName}' from monitoring data", endpointSetting.Name); } } } @@ -108,7 +108,7 @@ async Task InitialiseSettings(HashSet monitorEndpoints, CancellationToke { await endpointSettingsStore.Delete(endpointSetting.Name, cancellationToken); logger.LogInformation( - $"Removed EndpointTracking setting for '{endpointSetting.Name}' endpoint, since this endpoint is no longer monitored."); + "Removed EndpointTracking setting for '{Setting}' endpoint, since this endpoint is no longer monitored", endpointSetting.Name); } settingsNames.Add(endpointSetting.Name); @@ -121,7 +121,7 @@ await endpointSettingsStore.UpdateEndpointSettings( new EndpointSettings { Name = string.Empty, TrackInstances = userSetTrackInstances }, cancellationToken); logger.LogInformation( - $"Initialized default value of EndpointTracking to {(userSetTrackInstances ? "tracking" : "not tracking")}."); + "Initialized default value of EndpointTracking to {TrackInstances}", userSetTrackInstances ? "tracking" : "not tracking"); } // Initialise settings for any missing endpoint @@ -131,7 +131,7 @@ await endpointSettingsStore.UpdateEndpointSettings( new EndpointSettings { Name = name, TrackInstances = userSetTrackInstances }, cancellationToken); logger.LogInformation( - $"Initialized '{name}' value of EndpointTracking to {(userSetTrackInstances ? "tracking" : "not tracking")}."); + "Initialized '{Setting}' value of EndpointTracking to {TrackInstances}", name, userSetTrackInstances ? "tracking" : "not tracking"); } } } \ No newline at end of file diff --git a/src/ServiceControl/Monitoring/HeartbeatMonitoringHostedService.cs b/src/ServiceControl/Monitoring/HeartbeatMonitoringHostedService.cs index 1f9d6edaa5..93f6818d74 100644 --- a/src/ServiceControl/Monitoring/HeartbeatMonitoringHostedService.cs +++ b/src/ServiceControl/Monitoring/HeartbeatMonitoringHostedService.cs @@ -5,23 +5,24 @@ using System.Threading.Tasks; using Infrastructure.BackgroundTasks; using Microsoft.Extensions.Hosting; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using ServiceBus.Management.Infrastructure.Settings; using ServiceControl.Persistence; class HeartbeatMonitoringHostedService : IHostedService { - public HeartbeatMonitoringHostedService(IEndpointInstanceMonitoring monitor, IMonitoringDataStore persistence, IAsyncTimer scheduler, Settings settings) + public HeartbeatMonitoringHostedService(IEndpointInstanceMonitoring monitor, IMonitoringDataStore persistence, IAsyncTimer scheduler, Settings settings, ILogger logger) { this.monitor = monitor; this.persistence = persistence; this.scheduler = scheduler; + this.logger = logger; gracePeriod = settings.HeartbeatGracePeriod; } public async Task StartAsync(CancellationToken cancellationToken) { await persistence.WarmupMonitoringFromPersistence(monitor); - timer = scheduler.Schedule(_ => CheckEndpoints(), TimeSpan.Zero, TimeSpan.FromSeconds(5), e => { log.Error("Exception occurred when monitoring endpoint instances", e); }); + timer = scheduler.Schedule(_ => CheckEndpoints(), TimeSpan.Zero, TimeSpan.FromSeconds(5), e => logger.LogError(e, "Exception occurred when monitoring endpoint instances")); } public Task StopAsync(CancellationToken cancellationToken) => timer.Stop(cancellationToken); @@ -29,10 +30,8 @@ public async Task StartAsync(CancellationToken cancellationToken) async Task CheckEndpoints() { var inactivityThreshold = DateTime.UtcNow - gracePeriod; - if (log.IsDebugEnabled) - { - log.Debug($"Monitoring Endpoint Instances. Inactivity Threshold = {inactivityThreshold}"); - } + + logger.LogDebug("Monitoring Endpoint Instances. Inactivity Threshold = {InactivityThreshold}", inactivityThreshold); await monitor.CheckEndpoints(inactivityThreshold); return TimerJobExecutionResult.ScheduleNextExecution; @@ -44,6 +43,6 @@ async Task CheckEndpoints() TimerJob timer; TimeSpan gracePeriod; - static ILog log = LogManager.GetLogger(); + readonly ILogger logger; } } \ No newline at end of file diff --git a/src/ServiceControl/Monitoring/Web/GetKnownEndpointsApi.cs b/src/ServiceControl/Monitoring/Web/GetKnownEndpointsApi.cs index f54afa862e..1beea8d85f 100644 --- a/src/ServiceControl/Monitoring/Web/GetKnownEndpointsApi.cs +++ b/src/ServiceControl/Monitoring/Web/GetKnownEndpointsApi.cs @@ -5,6 +5,7 @@ using System.Net.Http; using System.Threading.Tasks; using CompositeViews.Messages; + using Microsoft.Extensions.Logging; using Persistence; using Persistence.Infrastructure; using ServiceBus.Management.Infrastructure.Settings; @@ -12,9 +13,9 @@ public class GetKnownEndpointsApi( IEndpointInstanceMonitoring store, Settings settings, - IHttpClientFactory httpClientFactory) - : ScatterGatherApi>(store, - settings, httpClientFactory) + IHttpClientFactory httpClientFactory, + ILogger logger) + : ScatterGatherApi>(store, settings, httpClientFactory, logger) { protected override Task>> LocalQuery(ScatterGatherContext input) { diff --git a/src/ServiceControl/Notifications/Api/NotificationsController.cs b/src/ServiceControl/Notifications/Api/NotificationsController.cs index f422e27a32..af5f90cfe0 100644 --- a/src/ServiceControl/Notifications/Api/NotificationsController.cs +++ b/src/ServiceControl/Notifications/Api/NotificationsController.cs @@ -10,7 +10,7 @@ [ApiController] [Route("api")] - public class NotificationsController(IErrorMessageDataStore store, Settings settings) : ControllerBase + public class NotificationsController(IErrorMessageDataStore store, Settings settings, EmailSender emailSender) : ControllerBase { [Route("notifications/email")] [HttpGet] @@ -69,7 +69,7 @@ public async Task SendTestEmail() try { - await EmailSender.Send( + await emailSender.Send( notificationsSettings.Email, $"[{settings.InstanceName}] health check notification check successful", $"[{settings.InstanceName}] health check notification check successful."); diff --git a/src/ServiceControl/Notifications/Email/CustomChecksMailNotification.cs b/src/ServiceControl/Notifications/Email/CustomChecksMailNotification.cs index 5368119fbb..bbdaff35db 100644 --- a/src/ServiceControl/Notifications/Email/CustomChecksMailNotification.cs +++ b/src/ServiceControl/Notifications/Email/CustomChecksMailNotification.cs @@ -6,8 +6,8 @@ using System.Threading.Tasks; using Contracts.CustomChecks; using Infrastructure.DomainEvents; + using Microsoft.Extensions.Logging; using NServiceBus; - using NServiceBus.Logging; using ServiceBus.Management.Infrastructure.Settings; class CustomChecksMailNotification : IDomainHandler, IDomainHandler @@ -29,11 +29,11 @@ class CustomChecksMailNotification : IDomainHandler, IDomainH "Error Message Ingestion" }; - public CustomChecksMailNotification(IMessageSession messageSession, Settings settings, EmailThrottlingState throttlingState) + public CustomChecksMailNotification(IMessageSession messageSession, Settings settings, EmailThrottlingState throttlingState, ILogger logger) { this.messageSession = messageSession; this.throttlingState = throttlingState; - + this.logger = logger; instanceName = settings.InstanceName; instanceAddress = settings.ApiUrl; @@ -49,7 +49,7 @@ public Task Handle(CustomCheckFailed domainEvent, CancellationToken cancellation { if (throttlingState.IsThrottling()) { - log.Warn("Email notification throttled"); + logger.LogWarning("Email notification throttled"); return Task.CompletedTask; } @@ -74,7 +74,7 @@ public Task Handle(CustomCheckSucceeded domainEvent, CancellationToken cancellat { if (throttlingState.IsThrottling()) { - log.Warn("Email notification throttled"); + logger.LogWarning("Email notification throttled"); return Task.CompletedTask; } @@ -93,6 +93,6 @@ public Task Handle(CustomCheckSucceeded domainEvent, CancellationToken cancellat bool IsHealthCheck(string checkId) => serviceControlHealthCustomCheckIds.Any(id => string.Equals(id, checkId, StringComparison.InvariantCultureIgnoreCase)); - static ILog log = LogManager.GetLogger(); + readonly ILogger logger; } } diff --git a/src/ServiceControl/Notifications/Email/EmailNotificationHostBuilderExtensions.cs b/src/ServiceControl/Notifications/Email/EmailNotificationHostBuilderExtensions.cs index c4672a7437..a72bf6a17e 100644 --- a/src/ServiceControl/Notifications/Email/EmailNotificationHostBuilderExtensions.cs +++ b/src/ServiceControl/Notifications/Email/EmailNotificationHostBuilderExtensions.cs @@ -10,6 +10,7 @@ public static IHostApplicationBuilder AddEmailNotifications(this IHostApplicatio { var services = hostBuilder.Services; services.AddSingleton(); + services.AddSingleton(); services.AddDomainEventHandler(); services.AddHostedService(); return hostBuilder; diff --git a/src/ServiceControl/Notifications/Email/EmailSender.cs b/src/ServiceControl/Notifications/Email/EmailSender.cs index 5201183b6e..57e07375c5 100644 --- a/src/ServiceControl/Notifications/Email/EmailSender.cs +++ b/src/ServiceControl/Notifications/Email/EmailSender.cs @@ -4,11 +4,11 @@ using System.Net; using System.Net.Mail; using System.Threading.Tasks; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; - class EmailSender + public class EmailSender(ILogger logger) { - public static async Task Send(EmailNotifications settings, string subject, string body, string emailDropFolder = null) + public async Task Send(EmailNotifications settings, string subject, string body, string emailDropFolder = null) { try { @@ -20,7 +20,7 @@ public static async Task Send(EmailNotifications settings, string subject, strin } catch (Exception e) { - log.Warn("Failure sending email.", e); + logger.LogWarning(e, "Failure sending email"); throw; } } @@ -50,7 +50,6 @@ static SmtpClient CreateSmtpClient(EmailNotifications settings, string emailDrop return smtpClient; } - static ILog log = LogManager.GetLogger(); static int defaultTimeout = (int)TimeSpan.FromSeconds(10).TotalMilliseconds; } } \ No newline at end of file diff --git a/src/ServiceControl/Notifications/Email/SendEmailNotificationHandler.cs b/src/ServiceControl/Notifications/Email/SendEmailNotificationHandler.cs index d7510fa68c..26f4ac0036 100644 --- a/src/ServiceControl/Notifications/Email/SendEmailNotificationHandler.cs +++ b/src/ServiceControl/Notifications/Email/SendEmailNotificationHandler.cs @@ -2,22 +2,24 @@ { using System; using System.Threading.Tasks; + using Microsoft.Extensions.Logging; using NServiceBus; - using NServiceBus.Logging; using NServiceBus.Transport; using Persistence; using ServiceBus.Management.Infrastructure.Settings; - public class SendEmailNotificationHandler : IHandleMessages + class SendEmailNotificationHandler : IHandleMessages { readonly IErrorMessageDataStore store; readonly EmailThrottlingState throttlingState; + readonly EmailSender emailSender; - public SendEmailNotificationHandler(IErrorMessageDataStore store, Settings settings, EmailThrottlingState throttlingState) + public SendEmailNotificationHandler(IErrorMessageDataStore store, Settings settings, EmailThrottlingState throttlingState, EmailSender emailSender, ILogger logger) { this.store = store; this.throttlingState = throttlingState; - + this.emailSender = emailSender; + this.logger = logger; emailDropFolder = settings.EmailDropFolder; } @@ -32,7 +34,7 @@ public async Task Handle(SendEmailNotification message, IMessageHandlerContext c if (notifications == null || !notifications.Email.Enabled) { - log.Info("Skipping email sending. Notifications turned-off."); + logger.LogInformation("Skipping email sending. Notifications turned-off"); return; } @@ -46,7 +48,7 @@ public async Task Handle(SendEmailNotification message, IMessageHandlerContext c { if (throttlingState.IsThrottling()) { - log.Warn("Email notification throttled"); + logger.LogWarning("Email notification throttled"); return; } @@ -59,7 +61,7 @@ public async Task Handle(SendEmailNotification message, IMessageHandlerContext c "\n\nWARNING: Your SMTP server was temporarily unavailable. Make sure to check ServicePulse for a full list of health check notifications."; } - await EmailSender.Send(notifications.Email, message.Subject, message.Body, emailDropFolder); + await emailSender.Send(notifications.Email, message.Subject, message.Body, emailDropFolder); } catch (Exception e) when (e is not OperationCanceledException) { @@ -77,7 +79,7 @@ public async Task Handle(SendEmailNotification message, IMessageHandlerContext c } else { - log.Warn("Success notification skipped due to throttling."); + logger.LogWarning("Success notification skipped due to throttling"); } } finally @@ -91,7 +93,7 @@ public async Task Handle(SendEmailNotification message, IMessageHandlerContext c string emailDropFolder; - static ILog log = LogManager.GetLogger(); + readonly ILogger logger; static TimeSpan spinDelay = TimeSpan.FromSeconds(1); static TimeSpan throttlingDelay = TimeSpan.FromSeconds(30); static TimeSpan cacheTimeout = TimeSpan.FromMinutes(5); diff --git a/src/ServiceControl/Operations/ErrorIngestion.cs b/src/ServiceControl/Operations/ErrorIngestion.cs index f4ee49693b..ec04de2e72 100644 --- a/src/ServiceControl/Operations/ErrorIngestion.cs +++ b/src/ServiceControl/Operations/ErrorIngestion.cs @@ -9,8 +9,8 @@ using Infrastructure; using Infrastructure.Metrics; using Microsoft.Extensions.Hosting; + using Microsoft.Extensions.Logging; using NServiceBus; - using NServiceBus.Logging; using NServiceBus.Transport; using Persistence; using Persistence.UnitOfWork; @@ -30,7 +30,8 @@ public ErrorIngestion( ErrorIngestionCustomCheck.State ingestionState, ErrorIngestor ingestor, IIngestionUnitOfWorkFactory unitOfWorkFactory, - IHostApplicationLifetime applicationLifetime) + IHostApplicationLifetime applicationLifetime, + ILogger logger) { this.settings = settings; this.transportCustomization = transportCustomization; @@ -39,7 +40,7 @@ public ErrorIngestion( this.ingestor = ingestor; this.unitOfWorkFactory = unitOfWorkFactory; this.applicationLifetime = applicationLifetime; - + this.logger = logger; receivedMeter = metrics.GetCounter("Error ingestion - received"); batchSizeMeter = metrics.GetMeter("Error ingestion - batch size"); batchDurationMeter = metrics.GetMeter("Error ingestion - batch processing duration", FrequencyInMilliseconds); @@ -57,7 +58,7 @@ public ErrorIngestion( FullMode = BoundedChannelFullMode.Wait }); - errorHandlingPolicy = new ErrorIngestionFaultPolicy(dataStore, settings.LoggingSettings, OnCriticalError); + errorHandlingPolicy = new ErrorIngestionFaultPolicy(dataStore, settings.LoggingSettings, OnCriticalError, logger); watchdog = new Watchdog( "failed message ingestion", @@ -66,8 +67,7 @@ public ErrorIngestion( ingestionState.ReportError, ingestionState.Clear, settings.TimeToRestartErrorIngestionAfterFailure, - //TODO replace when converting this class to ILogger Logger - LoggerUtil.CreateStaticLogger() + logger ); } @@ -110,11 +110,11 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) if (e is OperationCanceledException && stoppingToken.IsCancellationRequested) { - Logger.Info("Batch cancelled", e); + logger.LogInformation(e, "Batch cancelled"); break; } - Logger.Info("Ingesting messages failed", e); + logger.LogInformation(e, "Ingesting messages failed"); } finally { @@ -147,7 +147,7 @@ public override async Task StopAsync(CancellationToken cancellationToken) } catch (OperationCanceledException e) when (cancellationToken.IsCancellationRequested) { - Logger.Info("Shutdown cancelled", e); + logger.LogInformation(e, "Shutdown cancelled"); } } } @@ -161,7 +161,7 @@ async Task EnsureStarted(CancellationToken cancellationToken = default) var canIngest = unitOfWorkFactory.CanIngestMore(); - Logger.DebugFormat("Ensure started {0}", canIngest); + logger.LogDebug("Ensure started {CanIngest}", canIngest); if (canIngest) { @@ -195,13 +195,13 @@ async Task SetUpAndStartInfrastructure(CancellationToken cancellationToken) { if (messageReceiver != null) { - Logger.Debug("Infrastructure already Started"); + logger.LogDebug("Infrastructure already Started"); return; } try { - Logger.Info("Starting infrastructure"); + logger.LogInformation("Starting infrastructure"); transportInfrastructure = await transportCustomization.CreateTransportInfrastructure( errorQueue, transportSettings, @@ -220,11 +220,11 @@ async Task SetUpAndStartInfrastructure(CancellationToken cancellationToken) await messageReceiver.StartReceive(cancellationToken); - Logger.Info(LogMessages.StartedInfrastructure); + logger.LogInformation(LogMessages.StartedInfrastructure); } catch (Exception e) { - Logger.Error("Failed to start infrastructure", e); + logger.LogError(e, "Failed to start infrastructure"); throw; } } @@ -232,12 +232,12 @@ async Task StopAndTeardownInfrastructure(CancellationToken cancellationToken) { if (transportInfrastructure == null) { - Logger.Debug("Infrastructure already Stopped"); + logger.LogDebug("Infrastructure already Stopped"); return; } try { - Logger.Info("Stopping infrastructure"); + logger.LogInformation("Stopping infrastructure"); try { if (messageReceiver != null) @@ -253,11 +253,11 @@ async Task StopAndTeardownInfrastructure(CancellationToken cancellationToken) messageReceiver = null; transportInfrastructure = null; - Logger.Info(LogMessages.StoppedInfrastructure); + logger.LogInformation(LogMessages.StoppedInfrastructure); } catch (Exception e) { - Logger.Error("Failed to stop infrastructure", e); + logger.LogError(e, "Failed to stop infrastructure"); throw; } } @@ -285,7 +285,7 @@ async Task OnMessage(MessageContext messageContext, CancellationToken cancellati Task OnCriticalError(string failure, Exception exception) { - Logger.Fatal($"OnCriticalError. '{failure}'", exception); + logger.LogCritical(exception, "OnCriticalError. '{FailureMessage}'", failure); return watchdog.OnFailure(failure); } @@ -323,7 +323,7 @@ async Task EnsureStopped(CancellationToken cancellationToken = default) readonly IIngestionUnitOfWorkFactory unitOfWorkFactory; readonly IHostApplicationLifetime applicationLifetime; - static readonly ILog Logger = LogManager.GetLogger(); + readonly ILogger logger; internal static class LogMessages { diff --git a/src/ServiceControl/Operations/ErrorIngestionFaultPolicy.cs b/src/ServiceControl/Operations/ErrorIngestionFaultPolicy.cs index 107fd831d8..6562e2e22f 100644 --- a/src/ServiceControl/Operations/ErrorIngestionFaultPolicy.cs +++ b/src/ServiceControl/Operations/ErrorIngestionFaultPolicy.cs @@ -9,7 +9,7 @@ using System.Threading.Tasks; using Configuration; using Infrastructure; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using NServiceBus.Transport; using Persistence; using ServiceBus.Management.Infrastructure.Installers; @@ -21,9 +21,10 @@ class ErrorIngestionFaultPolicy ImportFailureCircuitBreaker failureCircuitBreaker; - public ErrorIngestionFaultPolicy(IErrorMessageDataStore store, LoggingSettings loggingSettings, Func onCriticalError) + public ErrorIngestionFaultPolicy(IErrorMessageDataStore store, LoggingSettings loggingSettings, Func onCriticalError, ILogger logger) { this.store = store; + this.logger = logger; failureCircuitBreaker = new ImportFailureCircuitBreaker(onCriticalError); if (!AppEnvironment.RunningInContainer) @@ -71,7 +72,7 @@ async Task Handle(ErrorContext errorContext, CancellationToken cancellationToken async Task DoLogging(Exception exception, FailedErrorImport failure, CancellationToken cancellationToken) { - log.Error("Failed importing error message", exception); + logger.LogError(exception, "Failed importing error message"); // Write to data store await store.StoreFailedErrorImport(failure); @@ -98,6 +99,6 @@ static void WriteToEventLog(string message) EventLog.WriteEntry(EventSourceCreator.SourceName, message, EventLogEntryType.Error); } - static readonly ILog log = LogManager.GetLogger(); + readonly ILogger logger; } } \ No newline at end of file diff --git a/src/ServiceControl/Operations/ErrorIngestor.cs b/src/ServiceControl/Operations/ErrorIngestor.cs index 660dcafbb1..39f4f264f5 100644 --- a/src/ServiceControl/Operations/ErrorIngestor.cs +++ b/src/ServiceControl/Operations/ErrorIngestor.cs @@ -9,7 +9,7 @@ using Contracts.Operations; using Infrastructure.DomainEvents; using Infrastructure.Metrics; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using NServiceBus.Routing; using NServiceBus.Transport; using Recoverability; @@ -28,12 +28,13 @@ public ErrorIngestor(Metrics metrics, IIngestionUnitOfWorkFactory unitOfWorkFactory, Lazy messageDispatcher, ITransportCustomization transportCustomization, - Settings settings) + Settings settings, + ILogger logger) { this.unitOfWorkFactory = unitOfWorkFactory; this.messageDispatcher = messageDispatcher; this.settings = settings; - + this.logger = logger; bulkInsertDurationMeter = metrics.GetMeter("Error ingestion - bulk insert duration", FrequencyInMilliseconds); var ingestedMeter = metrics.GetCounter("Error ingestion - ingested"); @@ -45,7 +46,7 @@ public ErrorIngestor(Metrics metrics, }.Concat(errorEnrichers).ToArray(); - errorProcessor = new ErrorProcessor(enrichers, failedMessageEnrichers.ToArray(), domainEvents, ingestedMeter); + errorProcessor = new ErrorProcessor(enrichers, failedMessageEnrichers.ToArray(), domainEvents, ingestedMeter, logger); retryConfirmationProcessor = new RetryConfirmationProcessor(domainEvents); logQueueAddress = new UnicastAddressTag(transportCustomization.ToTransportQualifiedQueueName(this.settings.ErrorLogQueue)); } @@ -86,15 +87,11 @@ public async Task Ingest(List contexts, CancellationToken cancel if (settings.ForwardErrorMessages) { - if (Logger.IsDebugEnabled) - { - Logger.Debug($"Forwarding {storedFailed.Count} messages"); - } + logger.LogDebug("Forwarding {FailedMessageCount} messages", storedFailed.Count); + await Forward(storedFailed, cancellationToken); - if (Logger.IsDebugEnabled) - { - Logger.Debug("Forwarded messages"); - } + + logger.LogDebug("Forwarded messages"); } foreach (var context in contexts) @@ -104,10 +101,7 @@ public async Task Ingest(List contexts, CancellationToken cancel } catch (Exception e) { - if (Logger.IsWarnEnabled) - { - Logger.Warn("Forwarding messages failed", e); - } + logger.LogWarning(e, "Forwarding messages failed"); // making sure to rethrow so that all messages get marked as failed throw; @@ -118,10 +112,7 @@ async Task> PersistFailedMessages(List> PersistFailedMessages(List> PersistFailedMessages(List(); + readonly ILogger logger; } } \ No newline at end of file diff --git a/src/ServiceControl/Operations/ErrorProcessor.cs b/src/ServiceControl/Operations/ErrorProcessor.cs index 6ac04c8edd..a539042eba 100644 --- a/src/ServiceControl/Operations/ErrorProcessor.cs +++ b/src/ServiceControl/Operations/ErrorProcessor.cs @@ -8,8 +8,8 @@ using Infrastructure; using Infrastructure.DomainEvents; using Infrastructure.Metrics; + using Microsoft.Extensions.Logging; using NServiceBus; - using NServiceBus.Logging; using NServiceBus.Transport; using Recoverability; using ServiceControl.Persistence; @@ -17,12 +17,17 @@ class ErrorProcessor { - public ErrorProcessor(IEnrichImportedErrorMessages[] enrichers, IFailedMessageEnricher[] failedMessageEnrichers, IDomainEvents domainEvents, - Counter ingestedCounter) + public ErrorProcessor( + IEnrichImportedErrorMessages[] enrichers, + IFailedMessageEnricher[] failedMessageEnrichers, + IDomainEvents domainEvents, + Counter ingestedCounter, + ILogger logger) { this.enrichers = enrichers; this.domainEvents = domainEvents; this.ingestedCounter = ingestedCounter; + this.logger = logger; failedMessageFactory = new FailedMessageFactory(failedMessageEnrichers); } @@ -58,10 +63,7 @@ public async Task> Process(IReadOnlyList(); + readonly ILogger logger; } } \ No newline at end of file diff --git a/src/ServiceControl/Program.cs b/src/ServiceControl/Program.cs index 7c746ff60c..1c8778490f 100644 --- a/src/ServiceControl/Program.cs +++ b/src/ServiceControl/Program.cs @@ -1,15 +1,17 @@ using System; using System.Reflection; -using NServiceBus.Logging; +using Microsoft.Extensions.Logging; using Particular.ServiceControl.Hosting; using ServiceBus.Management.Infrastructure.Settings; using ServiceControl.Configuration; using ServiceControl.Hosting.Commands; using ServiceControl.Infrastructure; +var logger = LoggerUtil.CreateStaticLogger(typeof(Program)); + try { - AppDomain.CurrentDomain.UnhandledException += (s, e) => LogManager.GetLogger(typeof(Program)).Error("Unhandled exception was caught.", e.ExceptionObject as Exception); + AppDomain.CurrentDomain.UnhandledException += (s, e) => logger.LogError(e.ExceptionObject as Exception, "Unhandled exception was caught"); // Hack: See https://github.com/Particular/ServiceControl/issues/4392 var exitCode = await IntegratedSetup.Run(); @@ -40,12 +42,12 @@ } catch (Exception ex) { - NLog.LogManager.GetCurrentClassLogger().Fatal(ex, "Unrecoverable error"); + logger.LogCritical(ex, "Unrecoverable error"); throw; } finally { // The following log statement is meant to leave a trail in the logs to determine if the process was killed - NLog.LogManager.GetCurrentClassLogger().Info("Shutdown complete"); + logger.LogInformation("Shutdown complete"); NLog.LogManager.Shutdown(); } \ No newline at end of file diff --git a/src/ServiceControl/Recoverability/Archiving/ArchiveAllInGroupHandler.cs b/src/ServiceControl/Recoverability/Archiving/ArchiveAllInGroupHandler.cs index c695e220c1..cabaab602b 100644 --- a/src/ServiceControl/Recoverability/Archiving/ArchiveAllInGroupHandler.cs +++ b/src/ServiceControl/Recoverability/Archiving/ArchiveAllInGroupHandler.cs @@ -1,23 +1,24 @@ namespace ServiceControl.Recoverability { using System.Threading.Tasks; + using Microsoft.Extensions.Logging; using NServiceBus; - using NServiceBus.Logging; using ServiceControl.Persistence.Recoverability; class ArchiveAllInGroupHandler : IHandleMessages { - public ArchiveAllInGroupHandler(IArchiveMessages archiver, RetryingManager retryingManager) + public ArchiveAllInGroupHandler(IArchiveMessages archiver, RetryingManager retryingManager, ILogger logger) { this.archiver = archiver; this.retryingManager = retryingManager; + this.logger = logger; } public async Task Handle(ArchiveAllInGroup message, IMessageHandlerContext context) { if (retryingManager.IsRetryInProgressFor(message.GroupId)) { - Log.Warn($"Attempt to archive a group ({message.GroupId}) which is currently in the process of being retried"); + logger.LogWarning("Attempt to archive a group ({MessageGroupId}) which is currently in the process of being retried", message.GroupId); return; } @@ -26,7 +27,6 @@ public async Task Handle(ArchiveAllInGroup message, IMessageHandlerContext conte readonly IArchiveMessages archiver; readonly RetryingManager retryingManager; - - static ILog Log = LogManager.GetLogger(); + readonly ILogger logger; } } diff --git a/src/ServiceControl/Recoverability/Archiving/UnArchiveAllInGroupHandler.cs b/src/ServiceControl/Recoverability/Archiving/UnArchiveAllInGroupHandler.cs index 44eeebd731..fd853f5f65 100644 --- a/src/ServiceControl/Recoverability/Archiving/UnArchiveAllInGroupHandler.cs +++ b/src/ServiceControl/Recoverability/Archiving/UnArchiveAllInGroupHandler.cs @@ -1,23 +1,24 @@ namespace ServiceControl.Recoverability { using System.Threading.Tasks; + using Microsoft.Extensions.Logging; using NServiceBus; - using NServiceBus.Logging; using ServiceControl.Persistence.Recoverability; class UnarchiveAllInGroupHandler : IHandleMessages { - public UnarchiveAllInGroupHandler(IArchiveMessages archiver, RetryingManager retryingManager) + public UnarchiveAllInGroupHandler(IArchiveMessages archiver, RetryingManager retryingManager, ILogger logger) { this.archiver = archiver; this.retryingManager = retryingManager; + this.logger = logger; } public async Task Handle(UnarchiveAllInGroup message, IMessageHandlerContext context) { if (retryingManager.IsRetryInProgressFor(message.GroupId)) { - logger.Warn($"Attempt to unarchive a group ({message.GroupId}) which is currently in the process of being retried"); + logger.LogWarning("Attempt to unarchive a group ({MessageGroupId}) which is currently in the process of being retried", message.GroupId); return; } @@ -26,7 +27,6 @@ public async Task Handle(UnarchiveAllInGroup message, IMessageHandlerContext con IArchiveMessages archiver; RetryingManager retryingManager; - - static ILog logger = LogManager.GetLogger(); + readonly ILogger logger; } } \ No newline at end of file diff --git a/src/ServiceControl/Recoverability/Editing/EditHandler.cs b/src/ServiceControl/Recoverability/Editing/EditHandler.cs index d1e6bc4685..86d01b7454 100644 --- a/src/ServiceControl/Recoverability/Editing/EditHandler.cs +++ b/src/ServiceControl/Recoverability/Editing/EditHandler.cs @@ -4,8 +4,8 @@ using System.Linq; using System.Threading.Tasks; using MessageFailures; + using Microsoft.Extensions.Logging; using NServiceBus; - using NServiceBus.Logging; using NServiceBus.Routing; using NServiceBus.Support; using NServiceBus.Transport; @@ -14,13 +14,14 @@ class EditHandler : IHandleMessages { - public EditHandler(IErrorMessageDataStore store, IMessageRedirectsDataStore redirectsStore, IMessageDispatcher dispatcher, ErrorQueueNameCache errorQueueNameCache) + public EditHandler(IErrorMessageDataStore store, IMessageRedirectsDataStore redirectsStore, IMessageDispatcher dispatcher, ErrorQueueNameCache errorQueueNameCache, ILogger logger) { this.store = store; this.redirectsStore = redirectsStore; this.dispatcher = dispatcher; this.errorQueueNameCache = errorQueueNameCache; - corruptedReplyToHeaderStrategy = new CorruptedReplyToHeaderStrategy(RuntimeEnvironment.MachineName); + this.logger = logger; + corruptedReplyToHeaderStrategy = new CorruptedReplyToHeaderStrategy(RuntimeEnvironment.MachineName, logger); } @@ -33,7 +34,7 @@ public async Task Handle(EditAndSend message, IMessageHandlerContext context) if (failedMessage == null) { - log.WarnFormat("Discarding edit {0} because no message failure for id {1} has been found.", context.MessageId, message.FailedMessageId); + logger.LogWarning("Discarding edit {MessageId} because no message failure for id {FailedMessageId} has been found", context.MessageId, message.FailedMessageId); return; } @@ -42,7 +43,7 @@ public async Task Handle(EditAndSend message, IMessageHandlerContext context) { if (failedMessage.Status != FailedMessageStatus.Unresolved) { - log.WarnFormat("Discarding edit {0} because message failure {1} doesn't have state 'Unresolved'.", context.MessageId, message.FailedMessageId); + logger.LogWarning("Discarding edit {MessageId} because message failure {FailedMessageId} doesn't have state 'Unresolved'", context.MessageId, message.FailedMessageId); return; } @@ -51,7 +52,7 @@ public async Task Handle(EditAndSend message, IMessageHandlerContext context) } else if (editId != context.MessageId) { - log.WarnFormat($"Discarding edit & retry request because the failed message id {message.FailedMessageId} has already been edited by Message ID {editId}"); + logger.LogWarning("Discarding edit & retry request because the failed message id {FailedMessageId} has already been edited by Message ID {EditedMessageId}", message.FailedMessageId, editId); return; } @@ -120,6 +121,6 @@ Task DispatchEditedMessage(OutgoingMessage editedMessage, string address, IMessa readonly IMessageRedirectsDataStore redirectsStore; readonly IMessageDispatcher dispatcher; readonly ErrorQueueNameCache errorQueueNameCache; - static readonly ILog log = LogManager.GetLogger(); + readonly ILogger logger; } } \ No newline at end of file diff --git a/src/ServiceControl/Recoverability/RecoverabilityComponent.cs b/src/ServiceControl/Recoverability/RecoverabilityComponent.cs index 875619d35e..8c52e4577b 100644 --- a/src/ServiceControl/Recoverability/RecoverabilityComponent.cs +++ b/src/ServiceControl/Recoverability/RecoverabilityComponent.cs @@ -13,7 +13,7 @@ using Infrastructure.DomainEvents; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using Operations; using Particular.ServiceControl; using Persistence; @@ -159,17 +159,18 @@ public Task StopAsync(CancellationToken cancellationToken) class BulkRetryBatchCreationHostedService : IHostedService { - public BulkRetryBatchCreationHostedService(RetriesGateway retries, IAsyncTimer scheduler) + public BulkRetryBatchCreationHostedService(RetriesGateway retries, IAsyncTimer scheduler, ILogger logger) { this.retries = retries; this.scheduler = scheduler; + this.logger = logger; } public Task StartAsync(CancellationToken cancellationToken) { if (retries != null) { - timer = scheduler.Schedule(_ => ProcessRequestedBulkRetryOperations(), interval, interval, e => { log.Error("Unhandled exception while processing bulk retry operations", e); }); + timer = scheduler.Schedule(_ => ProcessRequestedBulkRetryOperations(), interval, interval, e => logger.LogError(e, "Unhandled exception while processing bulk retry operations")); } return Task.CompletedTask; @@ -187,7 +188,7 @@ async Task ProcessRequestedBulkRetryOperations() IAsyncTimer scheduler; TimerJob timer; static TimeSpan interval = TimeSpan.FromSeconds(5); - static ILog log = LogManager.GetLogger(); + readonly ILogger logger; } class RebuildRetryGroupStatusesHostedService : IHostedService @@ -212,10 +213,11 @@ public Task StopAsync(CancellationToken cancellationToken) internal class AdoptOrphanBatchesFromPreviousSessionHostedService : IHostedService { - public AdoptOrphanBatchesFromPreviousSessionHostedService(RetryDocumentManager retryDocumentManager, IAsyncTimer scheduler) + public AdoptOrphanBatchesFromPreviousSessionHostedService(RetryDocumentManager retryDocumentManager, IAsyncTimer scheduler, ILogger logger) { this.retryDocumentManager = retryDocumentManager; this.scheduler = scheduler; + this.logger = logger; } internal async Task AdoptOrphanedBatchesAsync() @@ -231,7 +233,7 @@ public Task StartAsync(CancellationToken cancellationToken) { var hasMoreWork = await AdoptOrphanedBatchesAsync(); return hasMoreWork ? TimerJobExecutionResult.ScheduleNextExecution : TimerJobExecutionResult.DoNotContinueExecuting; - }, TimeSpan.Zero, TimeSpan.FromMinutes(2), e => { log.Error("Unhandled exception while trying to adopt orphaned batches", e); }); + }, TimeSpan.Zero, TimeSpan.FromMinutes(2), e => logger.LogError(e, "Unhandled exception while trying to adopt orphaned batches")); return Task.CompletedTask; } @@ -240,7 +242,7 @@ public Task StartAsync(CancellationToken cancellationToken) TimerJob timer; readonly IAsyncTimer scheduler; readonly RetryDocumentManager retryDocumentManager; - static readonly ILog log = LogManager.GetLogger(); + readonly ILogger logger; } class ProcessRetryBatchesHostedService : IHostedService @@ -248,16 +250,18 @@ class ProcessRetryBatchesHostedService : IHostedService public ProcessRetryBatchesHostedService( RetryProcessor processor, Settings settings, - IAsyncTimer scheduler) + IAsyncTimer scheduler, + ILogger logger) { this.processor = processor; this.settings = settings; this.scheduler = scheduler; + this.logger = logger; } public Task StartAsync(CancellationToken cancellationToken) { - timer = scheduler.Schedule(Process, TimeSpan.Zero, settings.ProcessRetryBatchesFrequency, e => { log.Error("Unhandled exception while processing retry batches", e); }); + timer = scheduler.Schedule(Process, TimeSpan.Zero, settings.ProcessRetryBatchesFrequency, e => logger.LogError(e, "Unhandled exception while processing retry batches")); return Task.CompletedTask; } @@ -274,7 +278,7 @@ async Task Process(CancellationToken cancellationToken) TimerJob timer; RetryProcessor processor; - static ILog log = LogManager.GetLogger(typeof(ProcessRetryBatchesHostedService)); + readonly ILogger logger; } } } \ No newline at end of file diff --git a/src/ServiceControl/Recoverability/Retrying/CorruptedReplyToHeaderStrategy.cs b/src/ServiceControl/Recoverability/Retrying/CorruptedReplyToHeaderStrategy.cs index 44a42a0c8e..262b20a38c 100644 --- a/src/ServiceControl/Recoverability/Retrying/CorruptedReplyToHeaderStrategy.cs +++ b/src/ServiceControl/Recoverability/Retrying/CorruptedReplyToHeaderStrategy.cs @@ -1,14 +1,15 @@ namespace ServiceControl.Recoverability { using System.Collections.Generic; + using Microsoft.Extensions.Logging; using NServiceBus; - using NServiceBus.Logging; class CorruptedReplyToHeaderStrategy { - public CorruptedReplyToHeaderStrategy(string localMachineName) + public CorruptedReplyToHeaderStrategy(string localMachineName, ILogger logger) { this.localMachineName = localMachineName; + this.logger = logger; } public void FixCorruptedReplyToHeader(IDictionary headers) @@ -35,14 +36,13 @@ public void FixCorruptedReplyToHeader(IDictionary headers) if (machineName == localMachineName && machineName != originatingMachine) { var fixedReplyToAddress = $"{queueName}@{originatingMachine}"; - log.Info($"Detected corrupted ReplyToAddress `{replyToAddress}`. Correcting to `{fixedReplyToAddress}`."); + logger.LogInformation("Detected corrupted ReplyToAddress `{ReplyToAddress}`. Correcting to `{FixedReplyToAddress}`", replyToAddress, fixedReplyToAddress); headers["ServiceControl.OldReplyToAddress"] = replyToAddress; headers[Headers.ReplyToAddress] = fixedReplyToAddress; } } string localMachineName; - - static ILog log = LogManager.GetLogger(typeof(RetryProcessor)); + readonly ILogger logger; } } \ No newline at end of file diff --git a/src/ServiceControl/Recoverability/Retrying/Handlers/RetryAllInGroupHandler.cs b/src/ServiceControl/Recoverability/Retrying/Handlers/RetryAllInGroupHandler.cs index 4e753fff00..8f17182f23 100644 --- a/src/ServiceControl/Recoverability/Retrying/Handlers/RetryAllInGroupHandler.cs +++ b/src/ServiceControl/Recoverability/Retrying/Handlers/RetryAllInGroupHandler.cs @@ -2,8 +2,8 @@ namespace ServiceControl.Recoverability { using System; using System.Threading.Tasks; + using Microsoft.Extensions.Logging; using NServiceBus; - using NServiceBus.Logging; using ServiceControl.Persistence; using ServiceControl.Persistence.Recoverability; @@ -13,13 +13,13 @@ public async Task Handle(RetryAllInGroup message, IMessageHandlerContext context { if (retries == null) { - Log.Warn($"Attempt to retry a group ({message.GroupId}) when retries are disabled"); + logger.LogWarning("Attempt to retry a group ({MessageGroupId}) when retries are disabled", message.GroupId); return; } if (archiver.IsArchiveInProgressFor(message.GroupId)) { - Log.Warn($"Attempt to retry a group ({message.GroupId}) which is currently in the process of being archived"); + logger.LogWarning("Attempt to retry a group ({MessageGroupId}) which is currently in the process of being archived", message.GroupId); return; } @@ -43,18 +43,19 @@ public async Task Handle(RetryAllInGroup message, IMessageHandlerContext context )); } - public RetryAllInGroupHandler(RetriesGateway retries, RetryingManager retryingManager, IArchiveMessages archiver, IRetryDocumentDataStore dataStore) + public RetryAllInGroupHandler(RetriesGateway retries, RetryingManager retryingManager, IArchiveMessages archiver, IRetryDocumentDataStore dataStore, ILogger logger) { this.retries = retries; this.retryingManager = retryingManager; this.archiver = archiver; this.dataStore = dataStore; + this.logger = logger; } readonly RetriesGateway retries; readonly RetryingManager retryingManager; readonly IArchiveMessages archiver; readonly IRetryDocumentDataStore dataStore; - static readonly ILog Log = LogManager.GetLogger(typeof(RetryAllInGroupHandler)); + readonly ILogger logger; } } \ No newline at end of file diff --git a/src/ServiceControl/Recoverability/Retrying/InMemoryRetry.cs b/src/ServiceControl/Recoverability/Retrying/InMemoryRetry.cs index e234661a2d..81364cd320 100644 --- a/src/ServiceControl/Recoverability/Retrying/InMemoryRetry.cs +++ b/src/ServiceControl/Recoverability/Retrying/InMemoryRetry.cs @@ -3,16 +3,17 @@ using System; using System.Threading.Tasks; using Infrastructure.DomainEvents; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using ServiceControl.Persistence; public class InMemoryRetry { - public InMemoryRetry(string requestId, RetryType retryType, IDomainEvents domainEvents) + public InMemoryRetry(string requestId, RetryType retryType, IDomainEvents domainEvents, ILogger logger) { RequestId = requestId; this.retryType = retryType; this.domainEvents = domainEvents; + this.logger = logger; } public string RequestId { get; } @@ -177,7 +178,11 @@ await domainEvents.Raise(new MessagesSubmittedForRetry }); } - Log.Info($"Retry operation {RequestId} completed. {NumberOfMessagesSkipped} messages skipped, {NumberOfMessagesForwarded} forwarded. Total {TotalNumberOfMessages}."); + logger.LogInformation("Retry operation {RequestId} completed. {NumberOfMessagesSkipped} messages skipped, {NumberOfMessagesForwarded} forwarded. Total {TotalNumberOfMessages}", + RequestId, + NumberOfMessagesSkipped, + NumberOfMessagesForwarded, + TotalNumberOfMessages); } public RetryProgress GetProgress() @@ -203,6 +208,6 @@ public bool IsInProgress() readonly RetryType retryType; IDomainEvents domainEvents; - static readonly ILog Log = LogManager.GetLogger(typeof(InMemoryRetry)); + readonly ILogger logger; } } \ No newline at end of file diff --git a/src/ServiceControl/Recoverability/Retrying/Infrastructure/ReturnToSender.cs b/src/ServiceControl/Recoverability/Retrying/Infrastructure/ReturnToSender.cs index cacbdbd420..3b27006b4b 100644 --- a/src/ServiceControl/Recoverability/Retrying/Infrastructure/ReturnToSender.cs +++ b/src/ServiceControl/Recoverability/Retrying/Infrastructure/ReturnToSender.cs @@ -4,12 +4,12 @@ namespace ServiceControl.Recoverability using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using NServiceBus.Routing; using NServiceBus.Transport; using ServiceControl.Persistence; - class ReturnToSender(IErrorMessageDataStore errorMessageStore) + class ReturnToSender(IErrorMessageDataStore errorMessageStore, ILogger logger) { public virtual async Task HandleMessage(MessageContext message, IMessageDispatcher sender, string errorQueueTransportAddress, CancellationToken cancellationToken = default) { @@ -20,10 +20,8 @@ public virtual async Task HandleMessage(MessageContext message, IMessageDispatch byte[] body = null; var messageId = message.NativeMessageId; - if (Log.IsDebugEnabled) - { - Log.DebugFormat("{0}: Retrieving message body", messageId); - } + + logger.LogDebug("{MessageId}: Retrieving message body", messageId); if (outgoingHeaders.TryGetValue("ServiceControl.Retry.Attempt.MessageId", out var attemptMessageId)) { @@ -32,16 +30,14 @@ public virtual async Task HandleMessage(MessageContext message, IMessageDispatch } else { - Log.WarnFormat("{0}: Can't find message body. Missing header ServiceControl.Retry.Attempt.MessageId", messageId); + logger.LogWarning("{MessageId}: Can't find message body. Missing header ServiceControl.Retry.Attempt.MessageId", messageId); } var outgoingMessage = new OutgoingMessage(messageId, outgoingHeaders, body ?? EmptyBody); var destination = outgoingHeaders["ServiceControl.TargetEndpointAddress"]; - if (Log.IsDebugEnabled) - { - Log.DebugFormat("{0}: Forwarding message to {1}", messageId, destination); - } + + logger.LogDebug("{MessageId}: Forwarding message to {Destination}", messageId, destination); if (!outgoingHeaders.TryGetValue("ServiceControl.RetryTo", out var retryTo)) { @@ -50,20 +46,14 @@ public virtual async Task HandleMessage(MessageContext message, IMessageDispatch } else { - if (Log.IsDebugEnabled) - { - Log.DebugFormat("{0}: Found ServiceControl.RetryTo header. Rerouting to {1}", messageId, retryTo); - } + logger.LogDebug("{MessageId}: Found ServiceControl.RetryTo header. Rerouting to {RetryTo}", messageId, retryTo); } var transportOp = new TransportOperation(outgoingMessage, new UnicastAddressTag(retryTo)); await sender.Dispatch(new TransportOperations(transportOp), message.TransportTransaction, cancellationToken); - if (Log.IsDebugEnabled) - { - Log.DebugFormat("{0}: Forwarded message to {1}", messageId, retryTo); - } + logger.LogDebug("{MessageId}: Forwarded message to {RetryTo}", messageId, retryTo); } async Task FetchFromFailedMessage(Dictionary outgoingHeaders, string messageId, string attemptMessageId) @@ -73,17 +63,16 @@ async Task FetchFromFailedMessage(Dictionary outgoingHea if (body == null) { - Log.WarnFormat("{0}: Message Body not found in failed message with unique id {1} for attempt Id {1}", messageId, uniqueMessageId, attemptMessageId); + logger.LogWarning("{MessageId}: Message Body not found in failed message with unique id {UniqueMessageId} for attempt Id {AttemptMessageId}", messageId, uniqueMessageId, attemptMessageId); } - else if (Log.IsDebugEnabled) + else { - Log.DebugFormat("{0}: Body size: {1} bytes retrieved from failed message attachment", messageId, body.LongLength); + logger.LogDebug("{MessageId}: Body size: {MessageLength} bytes retrieved from failed message attachment", messageId, body.LongLength); } return body; } static readonly byte[] EmptyBody = Array.Empty(); - static readonly ILog Log = LogManager.GetLogger(typeof(ReturnToSender)); } } diff --git a/src/ServiceControl/Recoverability/Retrying/Infrastructure/ReturnToSenderDequeuer.cs b/src/ServiceControl/Recoverability/Retrying/Infrastructure/ReturnToSenderDequeuer.cs index 81ef5562f3..7bade70a97 100644 --- a/src/ServiceControl/Recoverability/Retrying/Infrastructure/ReturnToSenderDequeuer.cs +++ b/src/ServiceControl/Recoverability/Retrying/Infrastructure/ReturnToSenderDequeuer.cs @@ -5,8 +5,8 @@ namespace ServiceControl.Recoverability; using System.Threading.Tasks; using Infrastructure.DomainEvents; using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; using NServiceBus; -using NServiceBus.Logging; using NServiceBus.Transport; using Persistence; using ServiceBus.Management.Infrastructure.Settings; @@ -21,7 +21,8 @@ public ReturnToSenderDequeuer( ITransportCustomization transportCustomization, TransportSettings transportSettings, Settings settings, - ErrorQueueNameCache errorQueueNameCache + ErrorQueueNameCache errorQueueNameCache, + ILogger logger ) { InputAddress = transportCustomization.ToTransportQualifiedQueueName(settings.StagingQueue); @@ -30,8 +31,8 @@ ErrorQueueNameCache errorQueueNameCache this.transportCustomization = transportCustomization; this.transportSettings = transportSettings; this.errorQueueNameCache = errorQueueNameCache; - - faultManager = new CaptureIfMessageSendingFails(dataStore, domainEvents, IncrementCounterOrProlongTimer); + this.logger = logger; + faultManager = new CaptureIfMessageSendingFails(dataStore, domainEvents, IncrementCounterOrProlongTimer, logger); timer = new Timer(state => StopInternal().GetAwaiter().GetResult()); } @@ -59,11 +60,8 @@ public async Task StopAsync(CancellationToken cancellationToken) async Task Handle(MessageContext message, CancellationToken cancellationToken) { - if (Log.IsDebugEnabled) - { - var stagingId = message.Headers["ServiceControl.Retry.StagingId"]; - Log.DebugFormat("Handling message with id {0} and staging id {1} in input queue {2}", message.NativeMessageId, stagingId, InputAddress); - } + var stagingId = message.Headers["ServiceControl.Retry.StagingId"]; + logger.LogDebug("Handling message with id {NativeMessageId} and staging id {StagingId} in input queue {InputAddress}", message.NativeMessageId, stagingId, InputAddress); if (shouldProcess(message)) { @@ -72,7 +70,7 @@ async Task Handle(MessageContext message, CancellationToken cancellationToken) } else { - Log.WarnFormat("Rejecting message from staging queue as it's not part of a fully staged batch: {0}", message.NativeMessageId); + logger.LogWarning("Rejecting message from staging queue as it's not part of a fully staged batch: {NativeMessageId}", message.NativeMessageId); } } @@ -84,10 +82,7 @@ void IncrementCounterOrProlongTimer() } else { - if (Log.IsDebugEnabled) - { - Log.Debug("Resetting timer"); - } + logger.LogDebug("Resetting timer"); timer.Change(TimeSpan.FromSeconds(45), Timeout.InfiniteTimeSpan); } @@ -96,17 +91,12 @@ void IncrementCounterOrProlongTimer() void CountMessageAndStopIfReachedTarget() { var currentMessageCount = Interlocked.Increment(ref actualMessageCount); - if (Log.IsDebugEnabled) - { - Log.Debug($"Forwarding message {currentMessageCount} of {targetMessageCount}."); - } + + logger.LogDebug("Forwarding message {CurrentMessageCount} of {TargetMessageCount}", currentMessageCount, targetMessageCount); if (currentMessageCount >= targetMessageCount.GetValueOrDefault()) { - if (Log.IsDebugEnabled) - { - Log.DebugFormat("Target count reached. Shutting down forwarder"); - } + logger.LogDebug("Target count reached. Shutting down forwarder"); // NOTE: This needs to run on a different thread or a deadlock will happen trying to shut down the receiver _ = Task.Run(StopInternal); @@ -122,10 +112,7 @@ public virtual async Task Run(string forwardingBatchId, Predicate(TaskCreationOptions.RunContinuationsAsynchronously); stopCompletionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); @@ -133,30 +120,24 @@ public virtual async Task Run(string forwardingBatchId, Predicate logger; class CaptureIfMessageSendingFails { - public CaptureIfMessageSendingFails(IErrorMessageDataStore dataStore, IDomainEvents domainEvents, Action executeOnFailure) + public CaptureIfMessageSendingFails(IErrorMessageDataStore dataStore, IDomainEvents domainEvents, Action executeOnFailure, ILogger logger) { this.dataStore = dataStore; this.executeOnFailure = executeOnFailure; + this.logger = logger; this.domainEvents = domainEvents; } @@ -223,7 +200,7 @@ public async Task OnError(ErrorContext errorContext, Cancella var message = errorContext.Message; var destination = message.Headers["ServiceControl.TargetEndpointAddress"]; var messageUniqueId = message.Headers["ServiceControl.Retry.UniqueMessageId"]; - Log.Warn($"Failed to send '{messageUniqueId}' message to '{destination}' for retry. Attempting to revert message status to unresolved so it can be tried again.", errorContext.Exception); + logger.LogWarning(errorContext.Exception, "Failed to send '{UniqueMessageId}' message to '{Destination}' for retry. Attempting to revert message status to unresolved so it can be tried again", messageUniqueId, destination); await dataStore.RevertRetry(messageUniqueId); @@ -247,7 +224,7 @@ await domainEvents.Raise(new MessagesSubmittedForRetryFailed catch (Exception ex) { // If something goes wrong here we just ignore, not the end of the world! - Log.Error("A failure occurred when trying to handle a retry failure.", ex); + logger.LogError(ex, "A failure occurred when trying to handle a retry failure"); } finally { @@ -260,7 +237,6 @@ await domainEvents.Raise(new MessagesSubmittedForRetryFailed readonly Action executeOnFailure; readonly IErrorMessageDataStore dataStore; readonly IDomainEvents domainEvents; - static readonly ILog Log = LogManager.GetLogger(typeof(CaptureIfMessageSendingFails)); + readonly ILogger logger; } - } diff --git a/src/ServiceControl/Recoverability/Retrying/RetriesGateway.cs b/src/ServiceControl/Recoverability/Retrying/RetriesGateway.cs index c1ddb84baf..7c1f8941a7 100644 --- a/src/ServiceControl/Recoverability/Retrying/RetriesGateway.cs +++ b/src/ServiceControl/Recoverability/Retrying/RetriesGateway.cs @@ -7,20 +7,21 @@ namespace ServiceControl.Recoverability using System.Threading.Tasks; using Infrastructure; using MessageFailures; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using ServiceControl.Persistence; class RetriesGateway { - public RetriesGateway(IRetryDocumentDataStore store, RetryingManager operationManager) + public RetriesGateway(IRetryDocumentDataStore store, RetryingManager operationManager, ILogger logger) { this.store = store; this.operationManager = operationManager; + this.logger = logger; } public async Task StartRetryForSingleMessage(string uniqueMessageId) { - Log.Info($"Retrying a single message {uniqueMessageId}"); + logger.LogInformation("Retrying a single message {UniqueMessageId}", uniqueMessageId); var requestId = uniqueMessageId; var retryType = RetryType.SingleMessage; @@ -33,7 +34,7 @@ public async Task StartRetryForSingleMessage(string uniqueMessageId) public async Task StartRetryForMessageSelection(string[] uniqueMessageIds) { - Log.Info($"Retrying a selection of {uniqueMessageIds.Length} messages"); + logger.LogInformation("Retrying a selection of {MessageCount} messages", uniqueMessageIds.Length); var requestId = DeterministicGuid.MakeId(string.Join(string.Empty, uniqueMessageIds)).ToString(); var retryType = RetryType.MultipleMessages; @@ -48,7 +49,7 @@ async Task StageRetryByUniqueMessageIds(string requestId, RetryType retryType, s { if (messageIds == null || !messageIds.Any()) { - Log.Info($"Batch '{batchName}' contains no messages"); + logger.LogInformation("Batch '{BatchName}' contains no messages", batchName); return; } @@ -56,13 +57,13 @@ async Task StageRetryByUniqueMessageIds(string requestId, RetryType retryType, s var batchDocumentId = await store.CreateBatchDocument(RetryDocumentManager.RetrySessionId, requestId, retryType, failedMessageRetryIds, originator, startTime, last, batchName, classifier); - Log.Info($"Created Batch '{batchDocumentId}' with {messageIds.Length} messages for '{batchName}'."); + logger.LogInformation("Created Batch '{BatchDocumentId}' with {BatchMessageCount} messages for '{BatchName}'", batchDocumentId, messageIds.Length, batchName); await store.StageRetryByUniqueMessageIds(batchDocumentId, messageIds); await MoveBatchToStaging(batchDocumentId); - Log.Info($"Moved Batch '{batchDocumentId}' to Staging"); + logger.LogInformation("Moved Batch '{BatchDocumentId}' to Staging", batchDocumentId); } // Needs to be overridable by a test @@ -114,27 +115,27 @@ static string GetBatchName(int pageNum, int totalPages, string context) public void StartRetryForAllMessages() { var item = new RetryForAllMessages(); - Log.Info($"Enqueuing index based bulk retry '{item}'"); + logger.LogInformation("Enqueuing index based bulk retry '{Item}'", item); bulkRequests.Enqueue(item); } public void StartRetryForEndpoint(string endpoint) { var item = new RetryForEndpoint(endpoint); - Log.Info($"Enqueuing index based bulk retry '{item}'"); + logger.LogInformation("Enqueuing index based bulk retry '{Item}'", item); bulkRequests.Enqueue(item); } public void StartRetryForFailedQueueAddress(string failedQueueAddress, FailedMessageStatus status) { var item = new RetryForFailedQueueAddress(failedQueueAddress, status); - Log.Info($"Enqueuing index based bulk retry '{item}'"); + logger.LogInformation("Enqueuing index based bulk retry '{Item}'", item); bulkRequests.Enqueue(item); } public void EnqueueRetryForFailureGroup(RetryForFailureGroup item) { - Log.Info($"Enqueuing index based bulk retry '{item}'"); + logger.LogInformation("Enqueuing index based bulk retry '{Item}'", item); bulkRequests.Enqueue(item); } @@ -143,7 +144,7 @@ public void EnqueueRetryForFailureGroup(RetryForFailureGroup item) readonly ConcurrentQueue bulkRequests = new ConcurrentQueue(); const int BatchSize = 1000; - static readonly ILog Log = LogManager.GetLogger(typeof(RetriesGateway)); + readonly ILogger logger; public abstract class BulkRetryRequest { diff --git a/src/ServiceControl/Recoverability/Retrying/RetryDocumentManager.cs b/src/ServiceControl/Recoverability/Retrying/RetryDocumentManager.cs index a94d9d3e76..d7afc3e6c9 100644 --- a/src/ServiceControl/Recoverability/Retrying/RetryDocumentManager.cs +++ b/src/ServiceControl/Recoverability/Retrying/RetryDocumentManager.cs @@ -4,28 +4,29 @@ namespace ServiceControl.Recoverability using System.Linq; using System.Threading.Tasks; using Microsoft.Extensions.Hosting; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using ServiceControl.Persistence; class RetryDocumentManager { - public RetryDocumentManager(IHostApplicationLifetime applicationLifetime, IRetryDocumentDataStore store, RetryingManager operationManager) + public RetryDocumentManager(IHostApplicationLifetime applicationLifetime, IRetryDocumentDataStore store, RetryingManager operationManager, ILogger logger) { this.store = store; applicationLifetime?.ApplicationStopping.Register(() => { abort = true; }); this.operationManager = operationManager; + this.logger = logger; } public async Task AdoptOrphanedBatches() { var orphanedBatches = await store.QueryOrphanedBatches(RetrySessionId); - log.Info($"Found {orphanedBatches.Results.Count} orphaned retry batches from previous sessions."); + logger.LogInformation("Found {OrphanedBatchCount} orphaned retry batches from previous sessions", orphanedBatches.Results.Count); // let's leave Task.Run for now due to sync sends await Task.WhenAll(orphanedBatches.Results.Select(b => Task.Run(async () => { - log.Info($"Adopting retry batch {b.Id} with {b.FailureRetries.Count} messages."); + logger.LogInformation("Adopting retry batch {BatchId} with {BatchMessageCount} messages", b.Id, b.FailureRetries.Count); await MoveBatchToStaging(b.Id); }))); @@ -55,10 +56,7 @@ public async Task RebuildRetryOperationState() { if (!string.IsNullOrWhiteSpace(group.RequestId)) { - if (log.IsDebugEnabled) - { - log.DebugFormat("Rebuilt retry operation status for {0}/{1}. Aggregated batchsize: {2}", group.RetryType, group.RequestId, group.InitialBatchSize); - } + logger.LogDebug("Rebuilt retry operation status for {RetryType}/{RetryRequestId}. Aggregated batchsize: {RetryBatchSize}", group.RetryType, group.RequestId, group.InitialBatchSize); await operationManager.PreparedAdoptedBatch(group.RequestId, group.RetryType, group.InitialBatchSize, group.InitialBatchSize, group.Originator, group.Classifier, group.StartTime, group.Last); } @@ -70,6 +68,6 @@ public async Task RebuildRetryOperationState() bool abort; public static string RetrySessionId = Guid.NewGuid().ToString(); - static readonly ILog log = LogManager.GetLogger(typeof(RetryDocumentManager)); + readonly ILogger logger; } } \ No newline at end of file diff --git a/src/ServiceControl/Recoverability/Retrying/RetryProcessor.cs b/src/ServiceControl/Recoverability/Retrying/RetryProcessor.cs index b5868e1532..dbdeab6477 100644 --- a/src/ServiceControl/Recoverability/Retrying/RetryProcessor.cs +++ b/src/ServiceControl/Recoverability/Retrying/RetryProcessor.cs @@ -7,7 +7,7 @@ namespace ServiceControl.Recoverability using System.Threading.Tasks; using Infrastructure.DomainEvents; using MessageFailures; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using NServiceBus.Routing; using NServiceBus.Support; using NServiceBus.Transport; @@ -16,14 +16,21 @@ namespace ServiceControl.Recoverability class RetryProcessor { - public RetryProcessor(IRetryBatchesDataStore store, IDomainEvents domainEvents, ReturnToSenderDequeuer returnToSender, RetryingManager retryingManager, Lazy messageDispatcher) + public RetryProcessor( + IRetryBatchesDataStore store, + IDomainEvents domainEvents, + ReturnToSenderDequeuer returnToSender, + RetryingManager retryingManager, + Lazy messageDispatcher, + ILogger logger) { this.store = store; this.returnToSender = returnToSender; this.retryingManager = retryingManager; this.domainEvents = domainEvents; this.messageDispatcher = messageDispatcher; - corruptedReplyToHeaderStrategy = new CorruptedReplyToHeaderStrategy(RuntimeEnvironment.MachineName); + this.logger = logger; + corruptedReplyToHeaderStrategy = new CorruptedReplyToHeaderStrategy(RuntimeEnvironment.MachineName, logger); } Task Enqueue(TransportOperations outgoingMessages) @@ -47,10 +54,7 @@ async Task MoveStagedBatchesToForwardingBatch(IRetryBatchesManager manager { try { - if (Logger.IsDebugEnabled) - { - Logger.Debug("Looking for batch to stage."); - } + logger.LogDebug("Looking for batch to stage"); isRecoveringFromPrematureShutdown = false; @@ -58,7 +62,7 @@ async Task MoveStagedBatchesToForwardingBatch(IRetryBatchesManager manager if (stagingBatch != null) { - Logger.Info($"Staging batch {stagingBatch.Id}."); + logger.LogInformation("Staging batch {StagingBatchId}", stagingBatch.Id); redirects = await manager.GetOrCreateMessageRedirectsCollection(); var stagedMessages = await Stage(stagingBatch, manager); var skippedMessages = stagingBatch.InitialBatchSize - stagedMessages; @@ -66,7 +70,7 @@ async Task MoveStagedBatchesToForwardingBatch(IRetryBatchesManager manager if (stagedMessages > 0) { - Logger.Info($"Batch {stagingBatch.Id} with {stagedMessages} messages staged and {skippedMessages} skipped ready to be forwarded."); + logger.LogInformation("Batch {StagingBatchId} with {StagedMessages} messages staged and {SkippedMessages} skipped ready to be forwarded", stagingBatch.Id, stagedMessages, skippedMessages); await manager.Store(new RetryBatchNowForwarding { RetryBatchId = stagingBatch.Id @@ -76,7 +80,7 @@ await manager.Store(new RetryBatchNowForwarding return true; } - Logger.Debug("No batch found to stage."); + logger.LogDebug("No batch found to stage"); return false; } catch (RetryStagingException) @@ -87,51 +91,36 @@ await manager.Store(new RetryBatchNowForwarding async Task ForwardCurrentBatch(IRetryBatchesManager manager, CancellationToken cancellationToken) { - if (Logger.IsDebugEnabled) - { - Logger.Debug("Looking for batch to forward."); - } + logger.LogDebug("Looking for batch to forward"); var nowForwarding = await manager.GetRetryBatchNowForwarding(); if (nowForwarding != null) { - if (Logger.IsDebugEnabled) - { - Logger.Debug($"Loading batch {nowForwarding.RetryBatchId} for forwarding."); - } + logger.LogDebug("Loading batch {RetryBatchId} for forwarding", nowForwarding.RetryBatchId); var forwardingBatch = await manager.GetRetryBatch(nowForwarding.RetryBatchId, cancellationToken); if (forwardingBatch != null) { - if (Logger.IsDebugEnabled) - { - Logger.Info($"Forwarding batch {forwardingBatch.Id}."); - } + logger.LogInformation("Forwarding batch {RetryBatchId}", forwardingBatch.Id); await Forward(forwardingBatch, manager, cancellationToken); - if (Logger.IsDebugEnabled) - { - Logger.DebugFormat("Retry batch {0} forwarded.", forwardingBatch.Id); - } + logger.LogDebug("Retry batch {RetryBatchId} forwarded", forwardingBatch.Id); } else { - Logger.Warn($"Could not find retry batch {nowForwarding.RetryBatchId} to forward."); + logger.LogWarning("Could not find retry batch {RetryBatchId} to forward", nowForwarding.RetryBatchId); } - if (Logger.IsDebugEnabled) - { - Logger.Debug("Removing forwarding document."); - } + logger.LogDebug("Removing forwarding document"); manager.Delete(nowForwarding); return true; } - Logger.Debug("No batch found to forward."); + logger.LogDebug("No batch found to forward"); return false; } @@ -143,7 +132,7 @@ async Task Forward(RetryBatch forwardingBatch, IRetryBatchesManager manager, Can if (isRecoveringFromPrematureShutdown) { - Logger.Warn($"Recovering from premature shutdown. Starting forwarder for batch {forwardingBatch.Id} in timeout mode."); + logger.LogWarning("Recovering from premature shutdown. Starting forwarder for batch {ForwardingBatchId} in timeout mode", forwardingBatch.Id); await returnToSender.Run(forwardingBatch.Id, IsPartOfStagedBatch(forwardingBatch.StagingId), null, cancellationToken); await retryingManager.ForwardedBatch(forwardingBatch.RequestId, forwardingBatch.RetryType, forwardingBatch.InitialBatchSize); } @@ -151,11 +140,11 @@ async Task Forward(RetryBatch forwardingBatch, IRetryBatchesManager manager, Can { if (messageCount == 0) { - Logger.Info($"Skipping forwarding of batch {forwardingBatch.Id}: no messages to forward."); + logger.LogInformation("Skipping forwarding of batch {ForwardingBatchId}: no messages to forward", forwardingBatch.Id); } else { - Logger.Info($"Starting forwarder for batch {forwardingBatch.Id} with {messageCount} messages in counting mode."); + logger.LogInformation("Starting forwarder for batch {ForwardingBatchId} with {BatchMessageCount} messages in counting mode", forwardingBatch.Id, messageCount); await returnToSender.Run(forwardingBatch.Id, IsPartOfStagedBatch(forwardingBatch.StagingId), messageCount, cancellationToken); } @@ -164,7 +153,7 @@ async Task Forward(RetryBatch forwardingBatch, IRetryBatchesManager manager, Can manager.Delete(forwardingBatch); - Logger.Info($"Done forwarding batch {forwardingBatch.Id}."); + logger.LogInformation("Done forwarding batch {ForwardingBatchId}", forwardingBatch.Id); } static Predicate IsPartOfStagedBatch(string stagingId) @@ -197,7 +186,7 @@ async Task Stage(RetryBatch stagingBatch, IRetryBatchesManager manager) if (failedMessageRetriesById.Count == 0) { - Logger.Info($"Retry batch {stagingBatch.Id} cancelled as all matching unresolved messages are already marked for retry as part of another batch."); + logger.LogInformation("Retry batch {RetryBatchId} cancelled as all matching unresolved messages are already marked for retry as part of another batch", stagingBatch.Id); manager.Delete(stagingBatch); return 0; } @@ -205,7 +194,7 @@ async Task Stage(RetryBatch stagingBatch, IRetryBatchesManager manager) var failedMessagesDocs = await manager.GetFailedMessages(failedMessageRetriesById.Keys); var messages = failedMessagesDocs.Where(m => m != null).ToArray(); - Logger.Info($"Staging {messages.Length} messages for retry batch {stagingBatch.Id} with staging attempt Id {stagingId}."); + logger.LogInformation("Staging {MessageCount} messages for retry batch {RetryBatchId} with staging attempt Id {StagingId}", messages.Length, stagingBatch.Id, stagingId); var previousAttemptFailed = false; var transportOperations = new TransportOperation[messages.Length]; @@ -242,7 +231,7 @@ await domainEvents.Raise(new MessagesSubmittedForRetry stagingBatch.Status = RetryBatchStatus.Forwarding; stagingBatch.StagingId = stagingId; stagingBatch.FailureRetries = failedMessageRetriesById.Values.Where(x => msgLookup[x.FailedMessageId].Any()).Select(x => x.Id).ToArray(); - Logger.Info($"Retry batch {stagingBatch.Id} staged with Staging Id {stagingBatch.StagingId} and {stagingBatch.FailureRetries.Count} matching failure retries"); + logger.LogInformation("Retry batch {RetryBatchId} staged with Staging Id {StagingId} and {RetryFailureCount} matching failure retries", stagingBatch.Id, stagingBatch.StagingId, stagingBatch.FailureRetries.Count); return messages.Length; } @@ -292,13 +281,13 @@ async Task TryStageMessage(TransportOperation transportOperation, FailedMessageR if (incrementedAttempts < MaxStagingAttempts) { - Logger.Warn($"Attempt {incrementedAttempts} of {MaxStagingAttempts} to stage a retry message {uniqueMessageId} failed", e); + logger.LogWarning(e, "Attempt {StagingRetryAttempt} of {StagingRetryLimit} to stage a retry message {RetryMessageId} failed", incrementedAttempts, MaxStagingAttempts, uniqueMessageId); await store.IncrementAttemptCounter(failedMessageRetry); } else { - Logger.Error($"Retry message {uniqueMessageId} reached its staging retry limit ({MaxStagingAttempts}) and is going to be removed from the batch.", e); + logger.LogError(e, "Retry message {RetryMessageId} reached its staging retry limit ({StagingRetryLimit}) and is going to be removed from the batch", uniqueMessageId, MaxStagingAttempts); await store.DeleteFailedMessageRetry(uniqueMessageId); @@ -343,12 +332,11 @@ TransportOperation ToTransportOperation(FailedMessage message, string stagingId) readonly ReturnToSenderDequeuer returnToSender; readonly RetryingManager retryingManager; readonly Lazy messageDispatcher; - MessageRedirectsCollection redirects; bool isRecoveringFromPrematureShutdown = true; CorruptedReplyToHeaderStrategy corruptedReplyToHeaderStrategy; protected internal const int MaxStagingAttempts = 5; - static readonly ILog Logger = LogManager.GetLogger(typeof(RetryProcessor)); + readonly ILogger logger; } } \ No newline at end of file diff --git a/src/ServiceControl/Recoverability/Retrying/RetryingManager.cs b/src/ServiceControl/Recoverability/Retrying/RetryingManager.cs index 8f01ae56f0..95af86ae8f 100644 --- a/src/ServiceControl/Recoverability/Retrying/RetryingManager.cs +++ b/src/ServiceControl/Recoverability/Retrying/RetryingManager.cs @@ -5,13 +5,15 @@ using System.Linq; using System.Threading.Tasks; using Infrastructure.DomainEvents; + using Microsoft.Extensions.Logging; using ServiceControl.Persistence; public class RetryingManager { - public RetryingManager(IDomainEvents domainEvents) + public RetryingManager(IDomainEvents domainEvents, ILogger logger) { this.domainEvents = domainEvents; + this.logger = logger; } public Task Wait(string requestId, RetryType retryType, DateTime started, string originator = null, string classifier = null, DateTime? last = null) @@ -128,7 +130,7 @@ public async Task Skip(string requestId, RetryType retryType, int numberOfMessag InMemoryRetry GetOrCreate(RetryType retryType, string requestId) { var key = InMemoryRetry.MakeOperationId(requestId, retryType); - return retryOperations.GetOrAdd(key, _ => new InMemoryRetry(requestId, retryType, domainEvents)); + return retryOperations.GetOrAdd(key, _ => new InMemoryRetry(requestId, retryType, domainEvents, logger)); } public InMemoryRetry GetStatusForRetryOperation(string requestId, RetryType retryType) @@ -139,6 +141,7 @@ public InMemoryRetry GetStatusForRetryOperation(string requestId, RetryType retr } IDomainEvents domainEvents; + readonly ILogger logger; ConcurrentDictionary retryOperations = new ConcurrentDictionary(); } } \ No newline at end of file diff --git a/src/ServiceControl/SagaAudit/GetSagaByIdApi.cs b/src/ServiceControl/SagaAudit/GetSagaByIdApi.cs index 8d6d3eda9c..61dfaef988 100644 --- a/src/ServiceControl/SagaAudit/GetSagaByIdApi.cs +++ b/src/ServiceControl/SagaAudit/GetSagaByIdApi.cs @@ -4,13 +4,14 @@ namespace ServiceControl.SagaAudit using System.Linq; using System.Net.Http; using CompositeViews.Messages; + using Microsoft.Extensions.Logging; using Persistence.Infrastructure; using ServiceBus.Management.Infrastructure.Settings; public record SagaByIdContext(PagingInfo PagingInfo, Guid SagaId) : ScatterGatherContext(PagingInfo); - public class GetSagaByIdApi(Settings settings, IHttpClientFactory httpClientFactory) - : ScatterGatherRemoteOnly(settings, httpClientFactory) + public class GetSagaByIdApi(Settings settings, IHttpClientFactory httpClientFactory, ILogger logger) + : ScatterGatherRemoteOnly(settings, httpClientFactory, logger) { protected override SagaHistory ProcessResults(SagaByIdContext input, QueryResult[] results) { diff --git a/src/ServiceControl/SagaAudit/SagaUpdatedHandler.cs b/src/ServiceControl/SagaAudit/SagaUpdatedHandler.cs index d8d0bb36f9..47a7ba3b8e 100644 --- a/src/ServiceControl/SagaAudit/SagaUpdatedHandler.cs +++ b/src/ServiceControl/SagaAudit/SagaUpdatedHandler.cs @@ -5,12 +5,12 @@ using System.Threading; using System.Threading.Tasks; using EndpointPlugin.Messages.SagaState; + using Microsoft.Extensions.Logging; using NServiceBus; - using NServiceBus.Logging; using ServiceControl.Connection; using ServiceControl.Infrastructure; - class SagaUpdatedHandler(IPlatformConnectionBuilder connectionBuilder) + class SagaUpdatedHandler(IPlatformConnectionBuilder connectionBuilder, ILogger logger) : IHandleMessages { public async Task Handle(SagaUpdatedMessage message, IMessageHandlerContext context) @@ -28,7 +28,9 @@ public async Task Handle(SagaUpdatedMessage message, IMessageHandlerContext cont } var endpointName = context.MessageHeaders.TryGetValue(Headers.ReplyToAddress, out var val) ? val : "(Unknown Endpoint)"; - log.ErrorFormat($"Received a saga audit message in the ServiceControl queue that should have been sent to the audit queue. This indicates that the endpoint '{endpointName}' using the SagaAudit plugin is misconfigured and should be changed to use the system's audit queue instead. The message has been forwarded to the audit queue, but this may not be possible in a future version of ServiceControl."); + logger.LogError("Received a saga audit message in the ServiceControl queue that should have been sent to the audit queue. " + + "This indicates that the endpoint '{EndpointName}' using the SagaAudit plugin is misconfigured and should be changed to use the system's audit queue instead. " + + "The message has been forwarded to the audit queue, but this may not be possible in a future version of ServiceControl.", endpointName); await context.ForwardCurrentMessageTo(auditQueueName); } @@ -55,12 +57,12 @@ async Task RefreshAuditQueue() // Pick any audit queue, assume all instance are based on competing consumer auditQueueName = sagaAudit.GetProperty("SagaAuditQueue").GetString(); nextAuditQueueNameRefresh = DateTime.UtcNow.AddMinutes(5); - log.InfoFormat("Refreshed audit queue name '{0}' from ServiceControl Audit instance. Will continue to use this value for forwarding saga update messages for the next 5 minutes.", auditQueueName); + logger.LogInformation("Refreshed audit queue name '{AuditQueueName}' from ServiceControl Audit instance. Will continue to use this value for forwarding saga update messages for the next 5 minutes.", auditQueueName); } } catch (Exception x) { - log.WarnFormat("Unable to refresh audit queue name from ServiceControl Audit instance. Will continue to check at most every 15 seconds. Exception message: {0}", x.Message); + logger.LogWarning("Unable to refresh audit queue name from ServiceControl Audit instance. Will continue to check at most every 15 seconds. Exception message: {ExceptionMessage}", x.Message); nextAuditQueueNameRefresh = DateTime.UtcNow.AddSeconds(15); } finally @@ -72,6 +74,5 @@ async Task RefreshAuditQueue() static string auditQueueName; static DateTime nextAuditQueueNameRefresh; static readonly SemaphoreSlim semaphore = new(1); - static readonly ILog log = LogManager.GetLogger(); } } From c92f803edfa45d46d6bc8ed6d0eb73441baa457a Mon Sep 17 00:00:00 2001 From: Phil Bastian Date: Wed, 18 Jun 2025 14:12:15 +0800 Subject: [PATCH 29/56] domain events and persister loggers --- .../DiscardMessagesBehavior.cs | 12 +++++++--- .../RavenPersistenceConfiguration.cs | 2 +- .../DomainEvents.cs | 13 ++++------- .../ServiceControl.DomainEvents.csproj | 1 + .../RavenDbLogLevelToLogsModeMapper.cs | 3 ++- .../RepeatedFailuresOverTimeCircuitBreaker.cs | 23 +++++++++---------- .../ExternalIntegrationRequestsDataStore.cs | 21 +++++++++-------- .../RavenPersistenceConfiguration.cs | 3 ++- ...atedFailuresOverTimeCircuitBreakerTests.cs | 13 +++++++++++ 9 files changed, 55 insertions(+), 36 deletions(-) diff --git a/src/ServiceControl.AcceptanceTesting/DiscardMessagesBehavior.cs b/src/ServiceControl.AcceptanceTesting/DiscardMessagesBehavior.cs index ed2fd50768..134db9bdec 100644 --- a/src/ServiceControl.AcceptanceTesting/DiscardMessagesBehavior.cs +++ b/src/ServiceControl.AcceptanceTesting/DiscardMessagesBehavior.cs @@ -3,10 +3,11 @@ namespace ServiceControl.AcceptanceTesting using System; using System.Linq; using System.Threading.Tasks; + using Microsoft.Extensions.Logging; using NServiceBus; using NServiceBus.AcceptanceTesting; - using NServiceBus.Logging; using NServiceBus.Pipeline; + using ServiceControl.Infrastructure; public class DiscardMessagesBehavior : IBehavior { @@ -44,7 +45,13 @@ public Task Invoke(ITransportReceiveContext context, Func(); + logger.LogDebug("Discarding message '{MessageId}'({OriginalMessageId}) because it's session id is '{MessageSessionId}' instead of '{CurrentSessionId}' Message Types: {EnclosedMessageTypes}.", + context.Message.MessageId, + originalMessageId ?? string.Empty, + session, + currentSession, + enclosedMessageTypes); return Task.CompletedTask; } @@ -52,7 +59,6 @@ public Task Invoke(ITransportReceiveContext context, Func(); static string[] pluginMessages = { diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/RavenPersistenceConfiguration.cs b/src/ServiceControl.Audit.Persistence.RavenDB/RavenPersistenceConfiguration.cs index 3611a3f646..eced9e35b2 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/RavenPersistenceConfiguration.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/RavenPersistenceConfiguration.cs @@ -108,7 +108,7 @@ internal static DatabaseConfiguration GetDatabaseConfiguration(PersistenceSettin if (settings.PersisterSpecificSettings.TryGetValue(RavenDbLogLevelKey, out var ravenDbLogLevel)) { - logsMode = RavenDbLogLevelToLogsModeMapper.Map(ravenDbLogLevel); + logsMode = RavenDbLogLevelToLogsModeMapper.Map(ravenDbLogLevel, Logger); } serverConfiguration = new ServerConfiguration(dbPath, serverUrl, logPath, logsMode); diff --git a/src/ServiceControl.DomainEvents/DomainEvents.cs b/src/ServiceControl.DomainEvents/DomainEvents.cs index 5443c784d7..0367f199fb 100644 --- a/src/ServiceControl.DomainEvents/DomainEvents.cs +++ b/src/ServiceControl.DomainEvents/DomainEvents.cs @@ -4,15 +4,10 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; - public class DomainEvents : IDomainEvents + public class DomainEvents(IServiceProvider serviceProvider, ILogger logger) : IDomainEvents { - static readonly ILog Log = LogManager.GetLogger(); - - readonly IServiceProvider serviceProvider; - public DomainEvents(IServiceProvider serviceProvider) => this.serviceProvider = serviceProvider; - public async Task Raise(T domainEvent, CancellationToken cancellationToken) where T : IDomainEvent { var handlers = serviceProvider.GetServices>(); @@ -25,7 +20,7 @@ await handler.Handle(domainEvent, cancellationToken) } catch (Exception e) { - Log.Error($"Unexpected error publishing domain event {typeof(T)}", e); + logger.LogError(e, "Unexpected error publishing domain event {EventType}", typeof(T)); throw; } } @@ -40,7 +35,7 @@ await handler.Handle(domainEvent, cancellationToken) } catch (Exception e) { - Log.Error($"Unexpected error publishing domain event {typeof(T)}", e); + logger.LogError(e, "Unexpected error publishing domain event {EventType}", typeof(T)); throw; } } diff --git a/src/ServiceControl.DomainEvents/ServiceControl.DomainEvents.csproj b/src/ServiceControl.DomainEvents/ServiceControl.DomainEvents.csproj index 8b8037bc48..bb654606ec 100644 --- a/src/ServiceControl.DomainEvents/ServiceControl.DomainEvents.csproj +++ b/src/ServiceControl.DomainEvents/ServiceControl.DomainEvents.csproj @@ -6,6 +6,7 @@ + diff --git a/src/ServiceControl.Infrastructure/RavenDbLogLevelToLogsModeMapper.cs b/src/ServiceControl.Infrastructure/RavenDbLogLevelToLogsModeMapper.cs index 8711bc9854..16a99ab8f3 100644 --- a/src/ServiceControl.Infrastructure/RavenDbLogLevelToLogsModeMapper.cs +++ b/src/ServiceControl.Infrastructure/RavenDbLogLevelToLogsModeMapper.cs @@ -1,12 +1,13 @@ namespace ServiceControl { + using Microsoft.Extensions.Logging; using NServiceBus.Logging; public class RavenDbLogLevelToLogsModeMapper { static readonly ILog Logger = LogManager.GetLogger(typeof(RavenDbLogLevelToLogsModeMapper)); - public static string Map(string ravenDbLogLevel) + public static string Map(string ravenDbLogLevel, ILogger logger) { switch (ravenDbLogLevel.ToLower()) { diff --git a/src/ServiceControl.Infrastructure/RepeatedFailuresOverTimeCircuitBreaker.cs b/src/ServiceControl.Infrastructure/RepeatedFailuresOverTimeCircuitBreaker.cs index abd6c9a354..3ae3d1c879 100644 --- a/src/ServiceControl.Infrastructure/RepeatedFailuresOverTimeCircuitBreaker.cs +++ b/src/ServiceControl.Infrastructure/RepeatedFailuresOverTimeCircuitBreaker.cs @@ -5,7 +5,7 @@ namespace NServiceBus; using System; using System.Threading; using System.Threading.Tasks; -using Logging; +using Microsoft.Extensions.Logging; /// /// A circuit breaker that is armed on a failure and disarmed on success. After in the @@ -44,6 +44,7 @@ public RepeatedFailuresOverTimeCircuitBreaker( string name, TimeSpan timeToWaitBeforeTriggering, Action triggerAction, + ILogger logger, Action? armedAction = null, Action? disarmedAction = null, TimeSpan? timeToWaitWhenTriggered = default, @@ -51,6 +52,7 @@ public RepeatedFailuresOverTimeCircuitBreaker( { this.name = name; this.triggerAction = triggerAction; + this.logger = logger; this.armedAction = armedAction ?? (static () => { }); this.disarmedAction = disarmedAction ?? (static () => { }); this.timeToWaitBeforeTriggering = timeToWaitBeforeTriggering; @@ -82,14 +84,14 @@ public void Success() circuitBreakerState = Disarmed; _ = timer.Change(Timeout.Infinite, Timeout.Infinite); - Logger.InfoFormat("The circuit breaker for '{0}' is now disarmed.", name); + logger.LogInformation("The circuit breaker for '{BreakerName}' is now disarmed.", name); try { disarmedAction(); } catch (Exception ex) { - Logger.Error($"The circuit breaker for '{name}' was unable to execute the disarm action.", ex); + logger.LogError(ex, "The circuit breaker for '{BreakerName}' was unable to execute the disarm action.", name); throw; } } @@ -130,12 +132,12 @@ public Task Failure(Exception exception, CancellationToken cancellationToken = d } catch (Exception ex) { - Logger.Error($"The circuit breaker for '{name}' was unable to execute the arm action.", new AggregateException(ex, exception)); + logger.LogError(new AggregateException(ex, exception), "The circuit breaker for '{BreakerName}' was unable to execute the arm action.", name); throw; } _ = timer.Change(timeToWaitBeforeTriggering, NoPeriodicTriggering); - Logger.WarnFormat("The circuit breaker for '{0}' is now in the armed state due to '{1}' and might trigger in '{2}' when not disarmed.", name, exception, timeToWaitBeforeTriggering); + logger.LogWarning("The circuit breaker for '{BreakerName}' is now in the armed state due to '{BreakerCause}' and might trigger in '{BreakerTriggerTime}' when not disarmed.", name, exception, timeToWaitBeforeTriggering); } return Delay(); @@ -143,10 +145,7 @@ public Task Failure(Exception exception, CancellationToken cancellationToken = d Task Delay() { var timeToWait = previousState == Triggered ? timeToWaitWhenTriggered : timeToWaitWhenArmed; - if (Logger.IsDebugEnabled) - { - Logger.DebugFormat("The circuit breaker for '{0}' is delaying the operation by '{1}'.", name, timeToWait); - } + logger.LogDebug("The circuit breaker for '{BreakerName}' is delaying the operation by '{BreakerTriggerTime}'.", name, timeToWait); return Task.Delay(timeToWait, cancellationToken); } } @@ -173,7 +172,7 @@ void CircuitBreakerTriggered(object? state) } circuitBreakerState = Triggered; - Logger.WarnFormat("The circuit breaker for '{0}' will now be triggered with exception '{1}'.", name, lastException); + logger.LogWarning("The circuit breaker for '{BreakerName}' will now be triggered with exception '{BreakerCause}'.", name, lastException); try { @@ -181,7 +180,7 @@ void CircuitBreakerTriggered(object? state) } catch (Exception ex) { - Logger.Fatal($"The circuit breaker for '{name}' was unable to execute the trigger action.", new AggregateException(ex, lastException!)); + logger.LogCritical(new AggregateException(ex, lastException!), "The circuit breaker for '{BreakerName}' was unable to execute the trigger action.", name); } } } @@ -204,5 +203,5 @@ void CircuitBreakerTriggered(object? state) const int Triggered = 2; static readonly TimeSpan NoPeriodicTriggering = TimeSpan.FromMilliseconds(-1); - static readonly ILog Logger = LogManager.GetLogger(); + readonly ILogger logger; } \ No newline at end of file diff --git a/src/ServiceControl.Persistence.RavenDB/ExternalIntegrationRequestsDataStore.cs b/src/ServiceControl.Persistence.RavenDB/ExternalIntegrationRequestsDataStore.cs index 27762fc546..6f68141edc 100644 --- a/src/ServiceControl.Persistence.RavenDB/ExternalIntegrationRequestsDataStore.cs +++ b/src/ServiceControl.Persistence.RavenDB/ExternalIntegrationRequestsDataStore.cs @@ -8,8 +8,8 @@ using System.Threading.Tasks; using ExternalIntegrations; using Microsoft.Extensions.Hosting; + using Microsoft.Extensions.Logging; using NServiceBus; - using NServiceBus.Logging; using Raven.Client.Documents; using Raven.Client.Documents.Changes; using ServiceControl.Infrastructure; @@ -20,12 +20,17 @@ class ExternalIntegrationRequestsDataStore , IAsyncDisposable { - public ExternalIntegrationRequestsDataStore(RavenPersisterSettings settings, IRavenSessionProvider sessionProvider, IRavenDocumentStoreProvider documentStoreProvider, CriticalError criticalError) + public ExternalIntegrationRequestsDataStore( + RavenPersisterSettings settings, + IRavenSessionProvider sessionProvider, + IRavenDocumentStoreProvider documentStoreProvider, + CriticalError criticalError, + ILogger logger) { this.settings = settings; this.sessionProvider = sessionProvider; this.documentStoreProvider = documentStoreProvider; - + this.logger = logger; var timeToWait = TimeSpan.FromMinutes(5); var delayAfterFailure = TimeSpan.FromSeconds(20); @@ -33,6 +38,7 @@ public ExternalIntegrationRequestsDataStore(RavenPersisterSettings settings, IRa "EventDispatcher", timeToWait, ex => criticalError.Raise("Repeated failures when dispatching external integration events.", ex), + logger, timeToWaitWhenArmed: delayAfterFailure ); } @@ -97,7 +103,7 @@ async Task StartDispatcherTask(CancellationToken cancellationToken) } catch (Exception ex) { - Logger.Error("An exception occurred when dispatching external integration events", ex); + logger.LogError(ex, "An exception occurred when dispatching external integration events"); await circuitBreaker.Failure(ex, cancellationToken); if (!tokenSource.IsCancellationRequested) @@ -143,10 +149,7 @@ async Task TryDispatchEventBatch() } var allContexts = awaitingDispatching.Select(r => r.DispatchContext).ToArray(); - if (Logger.IsDebugEnabled) - { - Logger.Debug($"Dispatching {allContexts.Length} events."); - } + logger.LogDebug("Dispatching {EventCount} events.", allContexts.Length); await callback(allContexts); @@ -206,6 +209,6 @@ public async ValueTask DisposeAsync() Func callback; bool isDisposed; - static ILog Logger = LogManager.GetLogger(typeof(ExternalIntegrationRequestsDataStore)); + readonly ILogger logger; } } \ No newline at end of file diff --git a/src/ServiceControl.Persistence.RavenDB/RavenPersistenceConfiguration.cs b/src/ServiceControl.Persistence.RavenDB/RavenPersistenceConfiguration.cs index f9f66aa6ca..c9d03685e7 100644 --- a/src/ServiceControl.Persistence.RavenDB/RavenPersistenceConfiguration.cs +++ b/src/ServiceControl.Persistence.RavenDB/RavenPersistenceConfiguration.cs @@ -6,6 +6,7 @@ using Configuration; using CustomChecks; using Particular.LicensingComponent.Contracts; + using ServiceControl.Infrastructure; class RavenPersistenceConfiguration : IPersistenceConfiguration { @@ -29,7 +30,7 @@ static T GetRequiredSetting(SettingsRootNamespace settingsRootNamespace, stri } var ravenDbLogLevel = SettingsReader.Read(settingsRootNamespace, RavenBootstrapper.RavenDbLogLevelKey, "Warn"); - var logsMode = RavenDbLogLevelToLogsModeMapper.Map(ravenDbLogLevel); + var logsMode = RavenDbLogLevelToLogsModeMapper.Map(ravenDbLogLevel, LoggerUtil.CreateStaticLogger()); var settings = new RavenPersisterSettings { diff --git a/src/ServiceControl.UnitTests/RepeatedFailuresOverTimeCircuitBreakerTests.cs b/src/ServiceControl.UnitTests/RepeatedFailuresOverTimeCircuitBreakerTests.cs index 67e71198cc..e955646a88 100644 --- a/src/ServiceControl.UnitTests/RepeatedFailuresOverTimeCircuitBreakerTests.cs +++ b/src/ServiceControl.UnitTests/RepeatedFailuresOverTimeCircuitBreakerTests.cs @@ -6,12 +6,16 @@ using System.Threading; using System.Threading.Tasks; using NUnit.Framework; + using ServiceControl.Infrastructure; // Ideally the circuit breaker would use a time provider to allow for easier testing but that would require a significant refactor // and we want keep the changes to a minimum for now to allow backporting to older versions. [TestFixture] public class RepeatedFailuresOverTimeCircuitBreakerTests { + [SetUp] + public void Setup() => LoggerUtil.ActiveLoggers = Loggers.Test; + [Test] public async Task Should_disarm_on_success() { @@ -22,6 +26,7 @@ public async Task Should_disarm_on_success() "TestCircuitBreaker", TimeSpan.FromMilliseconds(100), ex => { }, + LoggerUtil.CreateStaticLogger(), () => armedActionCalled = true, () => disarmedActionCalled = true, TimeSpan.Zero, @@ -42,6 +47,7 @@ public async Task Should_rethrow_exception_on_success() "TestCircuitBreaker", TimeSpan.FromMilliseconds(100), ex => { }, + LoggerUtil.CreateStaticLogger(), () => { }, () => throw new Exception("Exception from disarmed action"), timeToWaitWhenTriggered: TimeSpan.Zero, @@ -64,6 +70,7 @@ public async Task Should_trigger_after_failure_timeout() "TestCircuitBreaker", TimeSpan.Zero, ex => { triggerActionCalled = true; lastTriggerException = ex; }, + LoggerUtil.CreateStaticLogger(), timeToWaitWhenTriggered: TimeSpan.Zero, timeToWaitWhenArmed: TimeSpan.FromMilliseconds(100) ); @@ -81,6 +88,7 @@ public void Should_rethrow_exception_on_failure() "TestCircuitBreaker", TimeSpan.FromMilliseconds(100), ex => { }, + LoggerUtil.CreateStaticLogger(), () => throw new Exception("Exception from armed action"), () => { }, timeToWaitWhenTriggered: TimeSpan.Zero, @@ -101,6 +109,7 @@ public async Task Should_delay_after_trigger_failure() "TestCircuitBreaker", TimeSpan.Zero, _ => { }, + LoggerUtil.CreateStaticLogger(), timeToWaitWhenTriggered: timeToWaitWhenTriggered, timeToWaitWhenArmed: timeToWaitWhenArmed ); @@ -124,6 +133,7 @@ public async Task Should_not_trigger_if_disarmed_before_timeout() "TestCircuitBreaker", TimeSpan.FromMilliseconds(100), ex => triggerActionCalled = true, + LoggerUtil.CreateStaticLogger(), timeToWaitWhenTriggered: TimeSpan.Zero, timeToWaitWhenArmed: TimeSpan.Zero ); @@ -145,6 +155,7 @@ public async Task Should_handle_concurrent_failure_and_success() "TestCircuitBreaker", TimeSpan.FromMilliseconds(100), ex => triggerActionCalled = true, + LoggerUtil.CreateStaticLogger(), () => armedActionCalled = true, () => disarmedActionCalled = true, TimeSpan.Zero, @@ -176,6 +187,7 @@ public async Task Should_handle_high_concurrent_failure_and_success() "TestCircuitBreaker", TimeSpan.FromSeconds(5), ex => Interlocked.Increment(ref triggerActionCalled), + LoggerUtil.CreateStaticLogger(), () => Interlocked.Increment(ref armedActionCalled), () => Interlocked.Increment(ref disarmedActionCalled), TimeSpan.Zero, @@ -209,6 +221,7 @@ public async Task Should_trigger_after_multiple_failures_and_timeout() "TestCircuitBreaker", TimeSpan.FromMilliseconds(50), ex => triggerActionCalled = true, + LoggerUtil.CreateStaticLogger(), timeToWaitWhenTriggered: TimeSpan.FromMilliseconds(50), timeToWaitWhenArmed: TimeSpan.FromMilliseconds(50) ); From cc33a71a6105b950af0c6e9f7683e2c9862d6c45 Mon Sep 17 00:00:00 2001 From: Phil Bastian <155411597+PhilBastian@users.noreply.github.com> Date: Wed, 18 Jun 2025 14:47:00 +0800 Subject: [PATCH 30/56] convert SC transports from NServiceBus.Logging to Microsoft.Extensions.Logging (#5009) * convert SC transports from NServiceBus.Logging to Microsoft.Extensions.Logging * remove signedassembly requirement so that infrastructure can be imported * revert previous change and instead propogate signing back to servicecontrol.infrastructure * fix signature of customisation classes that are dynamically created * add ilogger to test services and remove direct construction with logger * get tests to use ilogger * Switch to .NET logging * Work in progress * Remove test code * Improve logging format for storage space details * Properly shutdown NLog in Program.cs * Remove Seq logging and prepare for .NET logging migration * Update LogLevel format * Update LogLevel format in logging settings * enable adding test logging provider as part of loggerutils and create framework for settings driven logger selection * add ability to select logging provider from config * handle setting not existing * change logmanager logger factory to the standard one now used by the rest of SC * ensure logger for transport tests --------- Co-authored-by: JasonTaylorDev --- src/Directory.Packages.props | 1 + .../ServiceControlComponentRunner.cs | 3 +- .../ServiceControlComponentRunner.cs | 2 +- .../CustomChecks/CheckDirtyMemory.cs | 14 ++- .../CustomChecks/CheckFreeDiskSpace.cs | 32 +++---- ...CheckMinimumStorageRequiredForIngestion.cs | 35 ++++---- .../CustomChecks/CheckRavenDBIndexLag.cs | 20 +++-- .../RavenEmbeddedPersistenceLifecycle.cs | 8 +- .../RavenPersistenceConfiguration.cs | 24 ++--- ...rovals.PlatformSampleSettings.approved.txt | 5 +- src/ServiceControl.Audit/App.config | 3 + .../HostApplicationBuilderExtensions.cs | 6 +- .../Infrastructure/WebApi/RootController.cs | 2 +- .../ServiceControl.Configuration.csproj | 2 + .../LoggerUtil.cs | 29 ++++++- .../LoggingConfigurator.cs | 19 ++-- .../LoggingSettings.cs | 77 ++++++++++------ .../ServiceControl.Infrastructure.csproj | 4 + .../TestLogger/TestContextAppender.cs | 29 +++++++ .../TestLogger/TestContextAppenderFactory.cs | 17 ++++ .../TestLogger/TestContextProvider.cs | 14 +++ ...sTests.PlatformSampleSettings.approved.txt | 5 +- .../HostApplicationBuilderExtensions.cs | 6 +- .../Hosting/Commands/SetupCommand.cs | 7 +- .../MonitoredEndpointMessageTypeParser.cs | 7 +- .../Licensing/ActiveLicense.cs | 14 +-- .../Licensing/LicenseCheckHostedService.cs | 7 +- src/ServiceControl.Monitoring/Program.cs | 12 +-- .../LegacyQueueLengthReportHandler.cs | 15 +--- .../ServiceControl.Monitoring.csproj | 1 - .../DeadLetterQueueCheck.cs | 17 ++-- .../QueueLengthProvider.cs | 16 ++-- .../QueueLengthProvider.cs | 19 ++-- .../QueueLengthProvider.cs | 15 ++-- .../DeadLetterQueueCheck.cs | 32 +++---- .../PostgreSqlTransportCustomization.cs | 9 +- .../QueueLengthProvider.cs | 11 +-- .../QueueLengthProvider.cs | 12 +-- .../QueueLengthProvider.cs | 20 +++-- .../SQSTransportCustomization.cs | 13 +-- .../QueueLengthProvider.cs | 11 +-- .../SqlServerTransportCustomization.cs | 9 +- .../FullEndpointTestFixture.cs | 2 + .../ServiceControl.Transports.Tests.csproj | 1 + .../TestContextAppender.cs | 87 ------------------- .../TestContextAppenderFactory.cs | 12 --- .../TransportManifestLibraryTests.cs | 7 ++ .../TransportTestFixture.cs | 8 +- .../ServiceControl.Transports.csproj | 1 + .../TransportManifest.cs | 11 +-- ...rovals.PlatformSampleSettings.approved.txt | 5 +- .../HostApplicationBuilderExtensions.cs | 4 +- .../Infrastructure/Api/ConfigurationApi.cs | 2 +- 53 files changed, 387 insertions(+), 357 deletions(-) create mode 100644 src/ServiceControl.Infrastructure/TestLogger/TestContextAppender.cs create mode 100644 src/ServiceControl.Infrastructure/TestLogger/TestContextAppenderFactory.cs create mode 100644 src/ServiceControl.Infrastructure/TestLogger/TestContextProvider.cs delete mode 100644 src/ServiceControl.Transports.Tests/TestContextAppender.cs delete mode 100644 src/ServiceControl.Transports.Tests/TestContextAppenderFactory.cs diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index 866f264ba5..dfd35a5f78 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -24,6 +24,7 @@ + diff --git a/src/ServiceControl.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs b/src/ServiceControl.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs index 1b6cd03449..f1b3e58a01 100644 --- a/src/ServiceControl.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs +++ b/src/ServiceControl.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs @@ -15,8 +15,7 @@ using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; - using Microsoft.Extensions.Logging.Abstractions; - using NLog; + using Microsoft.Extensions.Logging; using NServiceBus; using NServiceBus.AcceptanceTesting; using NServiceBus.AcceptanceTesting.Support; diff --git a/src/ServiceControl.Audit.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs b/src/ServiceControl.Audit.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs index 301d9b51a0..65e1b4752f 100644 --- a/src/ServiceControl.Audit.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs +++ b/src/ServiceControl.Audit.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs @@ -44,7 +44,7 @@ async Task InitializeServiceControl(ScenarioContext context) var logPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); Directory.CreateDirectory(logPath); - var loggingSettings = new LoggingSettings(Settings.SettingsRootNamespace, defaultLevel: NLog.LogLevel.Debug, logPath: logPath); + var loggingSettings = new LoggingSettings(Settings.SettingsRootNamespace, defaultLevel: LogLevel.Debug, logPath: logPath); settings = new Settings(transportToUse.TypeName, persistenceToUse.PersistenceType, loggingSettings) { diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckDirtyMemory.cs b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckDirtyMemory.cs index 37731858d8..409b3d6df1 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckDirtyMemory.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckDirtyMemory.cs @@ -3,26 +3,24 @@ namespace ServiceControl.Audit.Persistence.RavenDB.CustomChecks; using System; using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; using NServiceBus.CustomChecks; -using NServiceBus.Logging; -class CheckDirtyMemory(MemoryInformationRetriever memoryInformationRetriever) : CustomCheck("RavenDB dirty memory", "ServiceControl.Audit Health", TimeSpan.FromMinutes(5)) +class CheckDirtyMemory(MemoryInformationRetriever memoryInformationRetriever, ILogger logger) : CustomCheck("RavenDB dirty memory", "ServiceControl.Audit Health", TimeSpan.FromMinutes(5)) { + public override async Task PerformCheck(CancellationToken cancellationToken = default) { var (isHighDirty, dirtyMemory) = await memoryInformationRetriever.GetMemoryInformation(cancellationToken); - Log.Debug($"RavenDB dirty memory value: {dirtyMemory}."); + logger.LogDebug("RavenDB dirty memory value: {DirtyMemory}.", dirtyMemory); if (isHighDirty) { - var message = $"There is a high level of RavenDB dirty memory ({dirtyMemory}). See https://docs.particular.net/servicecontrol/troubleshooting#ravendb-dirty-memory for guidance on how to mitigate the issue."; - Log.Warn(message); - return CheckResult.Failed(message); + logger.LogWarning("There is a high level of RavenDB dirty memory ({DirtyMemory}). See https://docs.particular.net/servicecontrol/troubleshooting#ravendb-dirty-memory for guidance on how to mitigate the issue.", dirtyMemory); + return CheckResult.Failed($"There is a high level of RavenDB dirty memory ({dirtyMemory}). See https://docs.particular.net/servicecontrol/troubleshooting#ravendb-dirty-memory for guidance on how to mitigate the issue."); } return CheckResult.Pass; } - - static readonly ILog Log = LogManager.GetLogger(); } \ No newline at end of file diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs index 18705af5b9..45efbac8e0 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs @@ -5,17 +5,17 @@ using System.IO; using System.Threading; using System.Threading.Tasks; + using Microsoft.Extensions.Logging; using NServiceBus.CustomChecks; - using NServiceBus.Logging; using RavenDB; - class CheckFreeDiskSpace(DatabaseConfiguration databaseConfiguration) : CustomCheck("ServiceControl.Audit database", "Storage space", TimeSpan.FromMinutes(5)) + class CheckFreeDiskSpace(DatabaseConfiguration databaseConfiguration, ILogger logger) : CustomCheck("ServiceControl.Audit database", "Storage space", TimeSpan.FromMinutes(5)) { public override Task PerformCheck(CancellationToken cancellationToken = default) { - if (Logger.IsDebugEnabled) + if (logger.IsEnabled(LogLevel.Debug)) { - Logger.Debug($"Check ServiceControl data drive space remaining custom check starting. Threshold {percentageThreshold:P0}"); + logger.LogDebug("Check ServiceControl data drive space remaining custom check starting. Threshold {PercentageThreshold:P0}", percentageThreshold); } if (!databaseConfiguration.ServerConfiguration.UseEmbeddedServer) @@ -34,9 +34,9 @@ public override Task PerformCheck(CancellationToken cancellationTok var percentRemaining = (decimal)dataDriveInfo.AvailableFreeSpace / dataDriveInfo.TotalSize; - if (Logger.IsDebugEnabled) + if (logger.IsEnabled(LogLevel.Debug)) { - Logger.Debug($"Free space: {availableFreeSpace:N0}B | Total: {totalSpace:N0}B | Percent remaining {percentRemaining:P1}"); + logger.LogDebug("Free space: {AvailableFreeSpace:N0}B | Total: {TotalSpace:N0}B | Percent remaining {PercentRemaining:P1}", availableFreeSpace, totalSpace, percentRemaining); } return percentRemaining > percentageThreshold @@ -44,33 +44,29 @@ public override Task PerformCheck(CancellationToken cancellationTok : CheckResult.Failed($"{percentRemaining:P0} disk space remaining on data drive '{dataDriveInfo.VolumeLabel} ({dataDriveInfo.RootDirectory})' on '{Environment.MachineName}'."); } - public static int Parse(IDictionary settings) + public static int Parse(IDictionary settings, ILogger logger) { if (!settings.TryGetValue(RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey, out var thresholdValue)) { thresholdValue = $"{DataSpaceRemainingThresholdDefault}"; } - string message; if (!int.TryParse(thresholdValue, out var threshold)) { - message = $"{RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey} must be an integer."; - Logger.Fatal(message); - throw new Exception(message); + logger.LogCritical("{RavenPersistenceConfigurationDataSpaceRemainingThresholdKey} must be an integer.", RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey); + throw new Exception($"{RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey} must be an integer."); } if (threshold < 0) { - message = $"{RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey} is invalid, minimum value is 0."; - Logger.Fatal(message); - throw new Exception(message); + logger.LogCritical("{RavenPersistenceConfigurationDataSpaceRemainingThresholdKey} is invalid, minimum value is 0.", RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey); + throw new Exception($"{RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey} is invalid, minimum value is 0."); } if (threshold > 100) { - message = $"{RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey} is invalid, maximum value is 100."; - Logger.Fatal(message); - throw new Exception(message); + logger.LogCritical("{RavenPersistenceConfigurationDataSpaceRemainingThresholdKey} is invalid, maximum value is 100.", RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey); + throw new Exception($"{RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey} is invalid, maximum value is 100."); } return threshold; @@ -78,8 +74,6 @@ public static int Parse(IDictionary settings) readonly string dataPathRoot = Path.GetPathRoot(databaseConfiguration.ServerConfiguration.DbPath); readonly decimal percentageThreshold = databaseConfiguration.DataSpaceRemainingThreshold / 100m; - public const int DataSpaceRemainingThresholdDefault = 20; - static readonly ILog Logger = LogManager.GetLogger(typeof(CheckFreeDiskSpace)); } } \ No newline at end of file diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs index 6d2fccbc38..033a99fbbe 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs @@ -5,19 +5,20 @@ using System.IO; using System.Threading; using System.Threading.Tasks; + using Microsoft.Extensions.Logging; using NServiceBus.CustomChecks; - using NServiceBus.Logging; using RavenDB; + using ServiceControl.Infrastructure; - class CheckMinimumStorageRequiredForIngestion(MinimumRequiredStorageState stateHolder, DatabaseConfiguration databaseConfiguration) : CustomCheck("Audit Message Ingestion Process", "ServiceControl.Audit Health", TimeSpan.FromSeconds(5)) + class CheckMinimumStorageRequiredForIngestion(MinimumRequiredStorageState stateHolder, DatabaseConfiguration databaseConfiguration, ILogger logger) : CustomCheck("Audit Message Ingestion Process", "ServiceControl.Audit Health", TimeSpan.FromSeconds(5)) { public override Task PerformCheck(CancellationToken cancellationToken = default) { var percentageThreshold = databaseConfiguration.MinimumStorageLeftRequiredForIngestion / 100m; - if (Logger.IsDebugEnabled) + if (logger.IsEnabled(LogLevel.Debug)) { - Logger.Debug($"Check ServiceControl data drive space starting. Threshold {percentageThreshold:P0}"); + logger.LogDebug("Check ServiceControl data drive space starting. Threshold {PercentageThreshold:P0}", percentageThreshold); } // Should be checking UseEmbeddedServer but need to check DbPath instead for the ATT hack to work @@ -35,9 +36,9 @@ public override Task PerformCheck(CancellationToken cancellationTok var percentRemaining = (decimal)dataDriveInfo.AvailableFreeSpace / dataDriveInfo.TotalSize; - if (Logger.IsDebugEnabled) + if (logger.IsEnabled(LogLevel.Debug)) { - Logger.Debug($"Free space: {availableFreeSpace} | Total: {totalSpace} | Percent remaining {percentRemaining:P0}"); + logger.LogDebug("Free space: {AvailableFreeSpace:N0}B | Total: {TotalSpace:N0}B | Percent remaining {PercentRemaining:P0}", availableFreeSpace, totalSpace, percentRemaining); } if (percentRemaining > percentageThreshold) @@ -46,10 +47,9 @@ public override Task PerformCheck(CancellationToken cancellationTok return SuccessResult; } - var message = $"Audit message ingestion stopped! {percentRemaining:P0} disk space remaining on data drive '{dataDriveInfo.VolumeLabel} ({dataDriveInfo.RootDirectory})' on '{Environment.MachineName}'. This is less than {percentageThreshold}% - the minimal required space configured. The threshold can be set using the {RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey} configuration setting."; - Logger.Warn(message); + logger.LogWarning("Audit message ingestion stopped! {PercentRemaining:P0} disk space remaining on data drive '{DataDriveInfoVolumeLabel} ({DataDriveInfoRootDirectory})' on '{EnvironmentMachineName}'. This is less than {PercentageThreshold}% - the minimal required space configured. The threshold can be set using the {RavenPersistenceConfigurationMinimumStorageLeftRequiredForIngestionKey} configuration setting.", percentRemaining, dataDriveInfo.VolumeLabel, dataDriveInfo.RootDirectory, Environment.MachineName, percentageThreshold, RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey); stateHolder.CanIngestMore = false; - return CheckResult.Failed(message); + return CheckResult.Failed($"Audit message ingestion stopped! {percentRemaining:P0} disk space remaining on data drive '{dataDriveInfo.VolumeLabel} ({dataDriveInfo.RootDirectory})' on '{Environment.MachineName}'. This is less than {percentageThreshold}% - the minimal required space configured. The threshold can be set using the {RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey} configuration setting."); } public static int Parse(IDictionary settings) @@ -61,23 +61,20 @@ public static int Parse(IDictionary settings) if (!int.TryParse(thresholdValue, out var threshold)) { - var message = $"{RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey} must be an integer."; - Logger.Fatal(message); - throw new Exception(message); + Logger.LogCritical("{RavenPersistenceConfigurationMinimumStorageLeftRequiredForIngestionKey} must be an integer.", RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey); + throw new Exception($"{RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey} must be an integer."); } if (threshold < 0) { - var message = $"{RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey} is invalid, minimum value is 0."; - Logger.Fatal(message); - throw new Exception(message); + Logger.LogCritical("{RavenPersistenceConfigurationMinimumStorageLeftRequiredForIngestionKey} is invalid, minimum value is 0.", RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey); + throw new Exception($"{RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey} is invalid, minimum value is 0."); } if (threshold > 100) { - var message = $"{RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey} is invalid, maximum value is 100."; - Logger.Fatal(message); - throw new Exception(message); + Logger.LogCritical("{RavenPersistenceConfigurationMinimumStorageLeftRequiredForIngestionKey} is invalid, maximum value is 100.", RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey); + throw new Exception($"{RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey} is invalid, maximum value is 100."); } return threshold; @@ -85,6 +82,6 @@ public static int Parse(IDictionary settings) public const int MinimumStorageLeftRequiredForIngestionDefault = 5; static readonly Task SuccessResult = Task.FromResult(CheckResult.Pass); - static readonly ILog Logger = LogManager.GetLogger(typeof(CheckMinimumStorageRequiredForIngestion)); + static readonly ILogger Logger = LoggerUtil.CreateStaticLogger(); } } \ No newline at end of file diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexLag.cs b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexLag.cs index 41f4347a71..193e384f2d 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexLag.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexLag.cs @@ -5,12 +5,13 @@ using System.Text; using System.Threading; using System.Threading.Tasks; + using Microsoft.Extensions.Logging; using NServiceBus.CustomChecks; - using NServiceBus.Logging; using Raven.Client.Documents.Operations; using ServiceControl.Audit.Persistence.RavenDB; + using ServiceControl.Infrastructure; - class CheckRavenDBIndexLag(IRavenDocumentStoreProvider documentStoreProvider) : CustomCheck("Audit Database Index Lag", "ServiceControl.Audit Health", TimeSpan.FromMinutes(5)) + class CheckRavenDBIndexLag(IRavenDocumentStoreProvider documentStoreProvider, ILogger logger) : CustomCheck("Audit Database Index Lag", "ServiceControl.Audit Health", TimeSpan.FromMinutes(5)) { public override async Task PerformCheck(CancellationToken cancellationToken = default) { @@ -20,7 +21,7 @@ public override async Task PerformCheck(CancellationToken cancellat CreateDiagnosticsLogEntry(statistics, indexes); - var indexCountWithTooMuchLag = CheckAndReportIndexesWithTooMuchIndexLag(indexes); + var indexCountWithTooMuchLag = CheckAndReportIndexesWithTooMuchIndexLag(indexes, logger); if (indexCountWithTooMuchLag > 0) { @@ -30,7 +31,7 @@ public override async Task PerformCheck(CancellationToken cancellat return CheckResult.Pass; } - static int CheckAndReportIndexesWithTooMuchIndexLag(IndexInformation[] indexes) + static int CheckAndReportIndexesWithTooMuchIndexLag(IndexInformation[] indexes, ILogger logger) { int indexCountWithTooMuchLag = 0; @@ -43,12 +44,12 @@ static int CheckAndReportIndexesWithTooMuchIndexLag(IndexInformation[] indexes) if (indexLag > IndexLagThresholdError) { indexCountWithTooMuchLag++; - Log.Error($"Index [{indexStats.Name}] IndexingLag {indexLag} is above error threshold ({IndexLagThresholdError}). Launch in maintenance mode to let indexes catch up."); + logger.LogError("Index [{IndexStatsName}] IndexingLag {IndexLag} is above error threshold ({IndexLagThresholdError}). Launch in maintenance mode to let indexes catch up.", indexStats.Name, indexLag, IndexLagThresholdError); } else if (indexLag > IndexLagThresholdWarning) { indexCountWithTooMuchLag++; - Log.Warn($"Index [{indexStats.Name}] IndexingLag {indexLag} is above warning threshold ({IndexLagThresholdWarning}). Launch in maintenance mode to let indexes catch up."); + logger.LogWarning("Index [{IndexStatsName}] IndexingLag {IndexLag} is above warning threshold ({IndexLagThresholdWarning}). Launch in maintenance mode to let indexes catch up.", indexStats.Name, indexLag, IndexLagThresholdWarning); } } } @@ -58,7 +59,7 @@ static int CheckAndReportIndexesWithTooMuchIndexLag(IndexInformation[] indexes) static void CreateDiagnosticsLogEntry(DatabaseStatistics statistics, IndexInformation[] indexes) { - if (!Log.IsDebugEnabled) + if (!Logger.IsEnabled(LogLevel.Debug)) { return; } @@ -72,11 +73,12 @@ static void CreateDiagnosticsLogEntry(DatabaseStatistics statistics, IndexInform { report.AppendLine($"- Index [{indexStats.Name,-44}] State: {indexStats.State}, Stale: {indexStats.IsStale,-5}, Priority: {indexStats.Priority,-6}, LastIndexingTime: {indexStats.LastIndexingTime:u}"); } - Log.Debug(report.ToString()); + + Logger.LogDebug(report.ToString()); } static readonly TimeSpan IndexLagThresholdWarning = TimeSpan.FromMinutes(1); static readonly TimeSpan IndexLagThresholdError = TimeSpan.FromMinutes(10); - static readonly ILog Log = LogManager.GetLogger(); + static readonly ILogger Logger = LoggerUtil.CreateStaticLogger(); } } \ No newline at end of file diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/RavenEmbeddedPersistenceLifecycle.cs b/src/ServiceControl.Audit.Persistence.RavenDB/RavenEmbeddedPersistenceLifecycle.cs index f7f1ecee16..80bf05b742 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/RavenEmbeddedPersistenceLifecycle.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/RavenEmbeddedPersistenceLifecycle.cs @@ -6,12 +6,12 @@ namespace ServiceControl.Audit.Persistence.RavenDB using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Hosting; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using Raven.Client.Documents; using Raven.Client.Exceptions.Database; using ServiceControl.RavenDB; - sealed class RavenEmbeddedPersistenceLifecycle(DatabaseConfiguration databaseConfiguration, IHostApplicationLifetime lifetime) : IRavenPersistenceLifecycle, IRavenDocumentStoreProvider, IDisposable + sealed class RavenEmbeddedPersistenceLifecycle(DatabaseConfiguration databaseConfiguration, IHostApplicationLifetime lifetime, ILogger logger) : IRavenPersistenceLifecycle, IRavenDocumentStoreProvider, IDisposable { public async ValueTask GetDocumentStore(CancellationToken cancellationToken = default) { @@ -61,7 +61,7 @@ public async Task Initialize(CancellationToken cancellationToken = default) } catch (DatabaseLoadTimeoutException e) { - Log.Warn("Connecting to the embedded RavenDB database timed out. Retrying in 500ms...", e); + logger.LogWarning(e, "Connecting to the embedded RavenDB database timed out. Retrying in 500ms..."); await Task.Delay(500, cancellationToken); } } @@ -83,7 +83,5 @@ public void Dispose() IDocumentStore? documentStore; EmbeddedDatabase? database; readonly SemaphoreSlim initializeSemaphore = new(1, 1); - - static readonly ILog Log = LogManager.GetLogger(typeof(RavenEmbeddedPersistenceLifecycle)); } } diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/RavenPersistenceConfiguration.cs b/src/ServiceControl.Audit.Persistence.RavenDB/RavenPersistenceConfiguration.cs index b22003ceae..3611a3f646 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/RavenPersistenceConfiguration.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/RavenPersistenceConfiguration.cs @@ -5,7 +5,8 @@ using System.IO; using System.Reflection; using CustomChecks; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; + using ServiceControl.Infrastructure; public class RavenPersistenceConfiguration : IPersistenceConfiguration { @@ -113,7 +114,7 @@ internal static DatabaseConfiguration GetDatabaseConfiguration(PersistenceSettin serverConfiguration = new ServerConfiguration(dbPath, serverUrl, logPath, logsMode); } - var dataSpaceRemainingThreshold = CheckFreeDiskSpace.Parse(settings.PersisterSpecificSettings); + var dataSpaceRemainingThreshold = CheckFreeDiskSpace.Parse(settings.PersisterSpecificSettings, Logger); var minimumStorageLeftRequiredForIngestion = CheckMinimumStorageRequiredForIngestion.Parse(settings.PersisterSpecificSettings); var expirationProcessTimerInSeconds = GetExpirationProcessTimerInSeconds(settings); @@ -141,15 +142,17 @@ static int GetExpirationProcessTimerInSeconds(PersistenceSettings settings) expirationProcessTimerInSeconds = int.Parse(expirationProcessTimerInSecondsString); } + var maxExpirationProcessTimerInSeconds = TimeSpan.FromHours(3).TotalSeconds; + if (expirationProcessTimerInSeconds < 0) { - Logger.Error($"ExpirationProcessTimerInSeconds cannot be negative. Defaulting to {ExpirationProcessTimerInSecondsDefault}"); + Logger.LogError("ExpirationProcessTimerInSeconds cannot be negative. Defaulting to {ExpirationProcessTimerInSecondsDefault}", ExpirationProcessTimerInSecondsDefault); return ExpirationProcessTimerInSecondsDefault; } - if (expirationProcessTimerInSeconds > TimeSpan.FromHours(3).TotalSeconds) + if (expirationProcessTimerInSeconds > maxExpirationProcessTimerInSeconds) { - Logger.Error($"ExpirationProcessTimerInSeconds cannot be larger than {TimeSpan.FromHours(3).TotalSeconds}. Defaulting to {ExpirationProcessTimerInSecondsDefault}"); + Logger.LogError("ExpirationProcessTimerInSeconds cannot be larger than {MaxExpirationProcessTimerInSeconds}. Defaulting to {ExpirationProcessTimerInSecondsDefault}", maxExpirationProcessTimerInSeconds, ExpirationProcessTimerInSecondsDefault); return ExpirationProcessTimerInSecondsDefault; } @@ -165,15 +168,17 @@ static int GetBulkInsertCommitTimeout(PersistenceSettings settings) bulkInsertCommitTimeoutInSeconds = int.Parse(bulkInsertCommitTimeoutString); } + var maxBulkInsertCommitTimeoutInSeconds = TimeSpan.FromHours(1).TotalSeconds; + if (bulkInsertCommitTimeoutInSeconds < 0) { - Logger.Error($"BulkInsertCommitTimeout cannot be negative. Defaulting to {BulkInsertCommitTimeoutInSecondsDefault}"); + Logger.LogError("BulkInsertCommitTimeout cannot be negative. Defaulting to {BulkInsertCommitTimeoutInSecondsDefault}", BulkInsertCommitTimeoutInSecondsDefault); return BulkInsertCommitTimeoutInSecondsDefault; } - if (bulkInsertCommitTimeoutInSeconds > TimeSpan.FromHours(1).TotalSeconds) + if (bulkInsertCommitTimeoutInSeconds > maxBulkInsertCommitTimeoutInSeconds) { - Logger.Error($"BulkInsertCommitTimeout cannot be larger than {TimeSpan.FromHours(1).TotalSeconds}. Defaulting to {BulkInsertCommitTimeoutInSecondsDefault}"); + Logger.LogError("BulkInsertCommitTimeout cannot be larger than {MaxBulkInsertCommitTimeoutInSeconds}. Defaulting to {BulkInsertCommitTimeoutInSecondsDefault}", maxBulkInsertCommitTimeoutInSeconds, BulkInsertCommitTimeoutInSecondsDefault); return BulkInsertCommitTimeoutInSecondsDefault; } @@ -193,9 +198,8 @@ static string GetLogPath(PersistenceSettings settings) return logPath; } - static readonly ILog Logger = LogManager.GetLogger(typeof(RavenPersistenceConfiguration)); - const int ExpirationProcessTimerInSecondsDefault = 600; const int BulkInsertCommitTimeoutInSecondsDefault = 60; + static readonly ILogger Logger = LoggerUtil.CreateStaticLogger(); } } diff --git a/src/ServiceControl.Audit.UnitTests/ApprovalFiles/APIApprovals.PlatformSampleSettings.approved.txt b/src/ServiceControl.Audit.UnitTests/ApprovalFiles/APIApprovals.PlatformSampleSettings.approved.txt index f718f461aa..7113c06339 100644 --- a/src/ServiceControl.Audit.UnitTests/ApprovalFiles/APIApprovals.PlatformSampleSettings.approved.txt +++ b/src/ServiceControl.Audit.UnitTests/ApprovalFiles/APIApprovals.PlatformSampleSettings.approved.txt @@ -1,9 +1,6 @@ { "LoggingSettings": { - "LogLevel": { - "Name": "Info", - "Ordinal": 2 - }, + "LogLevel": "Information", "LogPath": "C:\\Logs" }, "MessageFilter": null, diff --git a/src/ServiceControl.Audit/App.config b/src/ServiceControl.Audit/App.config index 00a70ad0a2..e8e4a84c26 100644 --- a/src/ServiceControl.Audit/App.config +++ b/src/ServiceControl.Audit/App.config @@ -21,6 +21,9 @@ These settings are only here so that we can debug ServiceControl while developin + + + diff --git a/src/ServiceControl.Audit/HostApplicationBuilderExtensions.cs b/src/ServiceControl.Audit/HostApplicationBuilderExtensions.cs index 6c05cac611..8f2f52f19d 100644 --- a/src/ServiceControl.Audit/HostApplicationBuilderExtensions.cs +++ b/src/ServiceControl.Audit/HostApplicationBuilderExtensions.cs @@ -39,7 +39,7 @@ public static void AddServiceControlAudit(this IHostApplicationBuilder builder, RecordStartup(settings, configuration, persistenceConfiguration); builder.Logging.ClearProviders(); - builder.Logging.BuildLogger(settings.LoggingSettings.ToHostLogLevel()); + builder.Logging.BuildLogger(settings.LoggingSettings.LogLevel); var services = builder.Services; var transportSettings = settings.ToTransportSettings(); @@ -118,7 +118,7 @@ public static void AddMetrics(this IHostApplicationBuilder builder, Settings set } }); - var logger = LoggerUtil.CreateStaticLogger(typeof(HostApplicationBuilderExtensions), settings.LoggingSettings.ToHostLogLevel()); + var logger = LoggerUtil.CreateStaticLogger(typeof(HostApplicationBuilderExtensions), settings.LoggingSettings.LogLevel); logger.LogInformation("OpenTelemetry metrics exporter enabled: {OtlpEndpointUrl}", settings.OtlpEndpointUrl); } } @@ -136,7 +136,7 @@ static void RecordStartup(Settings settings, EndpointConfiguration endpointConfi Persistence: {persistenceConfiguration.Name} -------------------------------------------------------------"; - var logger = LoggerUtil.CreateStaticLogger(typeof(HostApplicationBuilderExtensions), settings.LoggingSettings.ToHostLogLevel()); + var logger = LoggerUtil.CreateStaticLogger(typeof(HostApplicationBuilderExtensions), settings.LoggingSettings.LogLevel); logger.LogInformation(startupMessage); endpointConfiguration.GetSettings().AddStartupDiagnosticsSection("Startup", new { Settings = settings }); } diff --git a/src/ServiceControl.Audit/Infrastructure/WebApi/RootController.cs b/src/ServiceControl.Audit/Infrastructure/WebApi/RootController.cs index 42c53825d3..159e8c6d49 100644 --- a/src/ServiceControl.Audit/Infrastructure/WebApi/RootController.cs +++ b/src/ServiceControl.Audit/Infrastructure/WebApi/RootController.cs @@ -51,7 +51,7 @@ public OkObjectResult Config() Logging = new { settings.LoggingSettings.LogPath, - LoggingLevel = settings.LoggingSettings.LogLevel.Name + LoggingLevel = settings.LoggingSettings.LogLevel } }, DataRetention = new diff --git a/src/ServiceControl.Configuration/ServiceControl.Configuration.csproj b/src/ServiceControl.Configuration/ServiceControl.Configuration.csproj index 2a585451b7..302ef7cbea 100644 --- a/src/ServiceControl.Configuration/ServiceControl.Configuration.csproj +++ b/src/ServiceControl.Configuration/ServiceControl.Configuration.csproj @@ -2,6 +2,8 @@ net8.0 + true + ..\NServiceBus.snk diff --git a/src/ServiceControl.Infrastructure/LoggerUtil.cs b/src/ServiceControl.Infrastructure/LoggerUtil.cs index 039d0b4938..34fc16beb1 100644 --- a/src/ServiceControl.Infrastructure/LoggerUtil.cs +++ b/src/ServiceControl.Infrastructure/LoggerUtil.cs @@ -1,16 +1,39 @@ namespace ServiceControl.Infrastructure { using System; + using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using NLog.Extensions.Logging; + using ServiceControl.Infrastructure.TestLogger; + + [Flags] + public enum Loggers + { + None = 0, + Test = 1 << 0, + NLog = 1 << 1, + Seq = 1 << 2, + } public static class LoggerUtil { + public static Loggers ActiveLoggers { private get; set; } = Loggers.None; + public static void BuildLogger(this ILoggingBuilder loggingBuilder, LogLevel level) { - //TODO: can we get these from settings too? - loggingBuilder.AddNLog(); - loggingBuilder.AddSeq(); + if ((Loggers.Test & ActiveLoggers) == Loggers.Test) + { + loggingBuilder.Services.AddSingleton(new TestContextProvider()); + } + if ((Loggers.NLog & ActiveLoggers) == Loggers.NLog) + { + loggingBuilder.AddNLog(); + } + if ((Loggers.Seq & ActiveLoggers) == Loggers.Seq) + { + loggingBuilder.AddSeq(); + } + loggingBuilder.SetMinimumLevel(level); } diff --git a/src/ServiceControl.Infrastructure/LoggingConfigurator.cs b/src/ServiceControl.Infrastructure/LoggingConfigurator.cs index f32c84918c..4845965394 100644 --- a/src/ServiceControl.Infrastructure/LoggingConfigurator.cs +++ b/src/ServiceControl.Infrastructure/LoggingConfigurator.cs @@ -2,16 +2,17 @@ namespace ServiceControl.Infrastructure { using System; using System.IO; + using Microsoft.Extensions.Logging; using NLog; using NLog.Config; - using NLog.Extensions.Logging; using NLog.Layouts; using NLog.Targets; using NServiceBus.Extensions.Logging; using ServiceControl.Configuration; - using LogManager = NServiceBus.Logging.LogManager; + using LogLevel = NLog.LogLevel; + // TODO: Migrate from NLog to .NET logging public static class LoggingConfigurator { public static void ConfigureLogging(LoggingSettings loggingSettings) @@ -60,21 +61,27 @@ public static void ConfigureLogging(LoggingSettings loggingSettings) nlogConfig.LoggingRules.Add(aspNetCoreRule); nlogConfig.LoggingRules.Add(httpClientRule); - nlogConfig.LoggingRules.Add(new LoggingRule("*", loggingSettings.LogLevel, consoleTarget)); + // HACK: Fixed LogLevel to Info for testing purposes only. + // Migrate to .NET logging and change back to loggingSettings.LogLevel. + // nlogConfig.LoggingRules.Add(new LoggingRule("*", loggingSettings.LogLevel, consoleTarget)); + nlogConfig.LoggingRules.Add(new LoggingRule("*", LogLevel.Info, consoleTarget)); if (!AppEnvironment.RunningInContainer) { - nlogConfig.LoggingRules.Add(new LoggingRule("*", loggingSettings.LogLevel, fileTarget)); + // HACK: Fixed LogLevel to Info for testing purposes only. + // Migrate to .NET logging and change back to loggingSettings.LogLevel. + // nlogConfig.LoggingRules.Add(new LoggingRule("*", loggingSettings.LogLevel, fileTarget)); + nlogConfig.LoggingRules.Add(new LoggingRule("*", LogLevel.Info, fileTarget)); } NLog.LogManager.Configuration = nlogConfig; - LogManager.UseFactory(new ExtensionsLoggerFactory(new NLogLoggerFactory())); + LogManager.UseFactory(new ExtensionsLoggerFactory(LoggerFactory.Create(configure => configure.BuildLogger(loggingSettings.LogLevel)))); var logger = LogManager.GetLogger("LoggingConfiguration"); var logEventInfo = new LogEventInfo { TimeStamp = DateTime.UtcNow }; var loggingTo = AppEnvironment.RunningInContainer ? "console" : fileTarget.FileName.Render(logEventInfo); - logger.InfoFormat("Logging to {0} with LogLevel '{1}'", loggingTo, loggingSettings.LogLevel.Name); + logger.InfoFormat("Logging to {0} with LogLevel '{1}'", loggingTo, LogLevel.Info.Name); } const long megaByte = 1024 * 1024; diff --git a/src/ServiceControl.Infrastructure/LoggingSettings.cs b/src/ServiceControl.Infrastructure/LoggingSettings.cs index 55282759a3..1a80ccb875 100644 --- a/src/ServiceControl.Infrastructure/LoggingSettings.cs +++ b/src/ServiceControl.Infrastructure/LoggingSettings.cs @@ -1,21 +1,38 @@ namespace ServiceControl.Infrastructure; using System; +using System.Collections.Generic; using System.IO; -using NLog; -using NLog.Common; +using System.Linq; +using Microsoft.Extensions.Logging; using ServiceControl.Configuration; -public class LoggingSettings(SettingsRootNamespace rootNamespace, LogLevel defaultLevel = null, string logPath = null) +public class LoggingSettings { - public LogLevel LogLevel { get; } = InitializeLogLevel(rootNamespace, defaultLevel); + public LoggingSettings(SettingsRootNamespace rootNamespace, LogLevel defaultLevel = LogLevel.Information, string logPath = null) + { + LogLevel = InitializeLogLevel(rootNamespace, defaultLevel); + LogPath = SettingsReader.Read(rootNamespace, logPathKey, Environment.ExpandEnvironmentVariables(logPath ?? DefaultLogLocation())); + + var loggingProviders = (SettingsReader.Read(rootNamespace, loggingProvidersKey) ?? "").Split(","); + var activeLoggers = Loggers.None; + if (loggingProviders.Contains("NLog")) + { + activeLoggers |= Loggers.NLog; + } + if (loggingProviders.Contains("Seq")) + { + activeLoggers |= Loggers.Seq; + } + LoggerUtil.ActiveLoggers = activeLoggers; + } + + public LogLevel LogLevel { get; } - public string LogPath { get; } = SettingsReader.Read(rootNamespace, "LogPath", Environment.ExpandEnvironmentVariables(logPath ?? DefaultLogLocation())); + public string LogPath { get; } static LogLevel InitializeLogLevel(SettingsRootNamespace rootNamespace, LogLevel defaultLevel) { - defaultLevel ??= LogLevel.Info; - var levelText = SettingsReader.Read(rootNamespace, logLevelKey); if (string.IsNullOrWhiteSpace(levelText)) @@ -23,31 +40,41 @@ static LogLevel InitializeLogLevel(SettingsRootNamespace rootNamespace, LogLevel return defaultLevel; } - try - { - return LogLevel.FromString(levelText); - } - catch - { - InternalLogger.Warn($"Failed to parse {logLevelKey} setting. Defaulting to {defaultLevel.Name}."); - return defaultLevel; - } + return ParseLogLevel(levelText, defaultLevel); } // SC installer always populates LogPath in app.config on installation/change/upgrade so this will only be used when // debugging or if the entry is removed manually. In those circumstances default to the folder containing the exe static string DefaultLogLocation() => Path.Combine(AppContext.BaseDirectory, ".logs"); - public Microsoft.Extensions.Logging.LogLevel ToHostLogLevel() => LogLevel switch + // This is not a complete mapping of NLog levels, just the ones that are different. + static readonly Dictionary NLogAliases = + new(StringComparer.OrdinalIgnoreCase) + { + ["info"] = LogLevel.Information, + ["warn"] = LogLevel.Warning, + ["fatal"] = LogLevel.Critical, + ["off"] = LogLevel.None + }; + + static LogLevel ParseLogLevel(string value, LogLevel defaultLevel) { - _ when LogLevel == LogLevel.Trace => Microsoft.Extensions.Logging.LogLevel.Trace, - _ when LogLevel == LogLevel.Debug => Microsoft.Extensions.Logging.LogLevel.Debug, - _ when LogLevel == LogLevel.Info => Microsoft.Extensions.Logging.LogLevel.Information, - _ when LogLevel == LogLevel.Warn => Microsoft.Extensions.Logging.LogLevel.Warning, - _ when LogLevel == LogLevel.Error => Microsoft.Extensions.Logging.LogLevel.Error, - _ when LogLevel == LogLevel.Fatal => Microsoft.Extensions.Logging.LogLevel.Critical, - _ => Microsoft.Extensions.Logging.LogLevel.None - }; + if (Enum.TryParse(value, ignoreCase: true, out LogLevel parsedLevel)) + { + return parsedLevel; + } + + if (NLogAliases.TryGetValue(value.Trim(), out parsedLevel)) + { + return parsedLevel; + } + + LoggerUtil.CreateStaticLogger().LogWarning("Failed to parse {LogLevelKey} setting. Defaulting to {DefaultLevel}.", logLevelKey, defaultLevel); + + return defaultLevel; + } const string logLevelKey = "LogLevel"; + const string logPathKey = "LogPath"; + const string loggingProvidersKey = "LoggingProviders"; } \ No newline at end of file diff --git a/src/ServiceControl.Infrastructure/ServiceControl.Infrastructure.csproj b/src/ServiceControl.Infrastructure/ServiceControl.Infrastructure.csproj index 123180a850..b32d80b1fa 100644 --- a/src/ServiceControl.Infrastructure/ServiceControl.Infrastructure.csproj +++ b/src/ServiceControl.Infrastructure/ServiceControl.Infrastructure.csproj @@ -2,6 +2,8 @@ net8.0 + true + ..\NServiceBus.snk @@ -9,9 +11,11 @@ + + diff --git a/src/ServiceControl.Infrastructure/TestLogger/TestContextAppender.cs b/src/ServiceControl.Infrastructure/TestLogger/TestContextAppender.cs new file mode 100644 index 0000000000..c353a3b60a --- /dev/null +++ b/src/ServiceControl.Infrastructure/TestLogger/TestContextAppender.cs @@ -0,0 +1,29 @@ +namespace ServiceControl.Infrastructure.TestLogger +{ + using System; + using Microsoft.Extensions.Logging; + using NUnit.Framework; + + class TestContextAppender(string categoryName) : ILogger + { + public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) + { + if (IsEnabled(logLevel)) + { + TestContext.Out.WriteLine($"{categoryName}: {formatter(state, exception)}"); + } + } + public bool IsEnabled(LogLevel logLevel) => logLevel >= LogLevel.Warning; + + public IDisposable BeginScope(TState state) where TState : notnull => Disposable.Instance; + + class Disposable : IDisposable + { + public static Disposable Instance = new(); + + public void Dispose() + { + } + } + } +} \ No newline at end of file diff --git a/src/ServiceControl.Infrastructure/TestLogger/TestContextAppenderFactory.cs b/src/ServiceControl.Infrastructure/TestLogger/TestContextAppenderFactory.cs new file mode 100644 index 0000000000..98e1d683fb --- /dev/null +++ b/src/ServiceControl.Infrastructure/TestLogger/TestContextAppenderFactory.cs @@ -0,0 +1,17 @@ +namespace ServiceControl.Infrastructure.TestLogger +{ + using Microsoft.Extensions.Logging; + + public class TestContextAppenderFactory : ILoggerFactory + { + public void AddProvider(ILoggerProvider provider) + { + } + + public ILogger CreateLogger(string categoryName) => new TestContextAppender(categoryName); + + public void Dispose() + { + } + } +} \ No newline at end of file diff --git a/src/ServiceControl.Infrastructure/TestLogger/TestContextProvider.cs b/src/ServiceControl.Infrastructure/TestLogger/TestContextProvider.cs new file mode 100644 index 0000000000..e879c814a3 --- /dev/null +++ b/src/ServiceControl.Infrastructure/TestLogger/TestContextProvider.cs @@ -0,0 +1,14 @@ +namespace ServiceControl.Infrastructure.TestLogger +{ + using Microsoft.Extensions.Logging; + + public class TestContextProvider : ILoggerProvider + { + public ILogger CreateLogger(string categoryName) => new TestContextAppender(categoryName); + + public void Dispose() + { + + } + } +} diff --git a/src/ServiceControl.Monitoring.UnitTests/ApprovalFiles/SettingsTests.PlatformSampleSettings.approved.txt b/src/ServiceControl.Monitoring.UnitTests/ApprovalFiles/SettingsTests.PlatformSampleSettings.approved.txt index 5d32f42fbb..070234384e 100644 --- a/src/ServiceControl.Monitoring.UnitTests/ApprovalFiles/SettingsTests.PlatformSampleSettings.approved.txt +++ b/src/ServiceControl.Monitoring.UnitTests/ApprovalFiles/SettingsTests.PlatformSampleSettings.approved.txt @@ -1,9 +1,6 @@ { "LoggingSettings": { - "LogLevel": { - "Name": "Info", - "Ordinal": 2 - }, + "LogLevel": "Information", "LogPath": "C:\\Logs" }, "InstanceName": "Particular.Monitoring", diff --git a/src/ServiceControl.Monitoring/HostApplicationBuilderExtensions.cs b/src/ServiceControl.Monitoring/HostApplicationBuilderExtensions.cs index 90adce523d..7bda9a78ab 100644 --- a/src/ServiceControl.Monitoring/HostApplicationBuilderExtensions.cs +++ b/src/ServiceControl.Monitoring/HostApplicationBuilderExtensions.cs @@ -22,6 +22,7 @@ namespace ServiceControl.Monitoring; using NServiceBus.Features; using NServiceBus.Transport; using QueueLength; +using ServiceControl.Infrastructure; using Timings; using Transports; @@ -31,9 +32,8 @@ public static void AddServiceControlMonitoring(this IHostApplicationBuilder host Func onCriticalError, Settings settings, EndpointConfiguration endpointConfiguration) { - hostBuilder.Logging.ClearProviders(); - hostBuilder.Logging.AddNLog(); - hostBuilder.Logging.SetMinimumLevel(settings.LoggingSettings.ToHostLogLevel()); + hostBuilder.Services.AddLogging(); + hostBuilder.Logging.BuildLogger(settings.LoggingSettings.LogLevel); var services = hostBuilder.Services; diff --git a/src/ServiceControl.Monitoring/Hosting/Commands/SetupCommand.cs b/src/ServiceControl.Monitoring/Hosting/Commands/SetupCommand.cs index 3bd7830438..22a84b27f7 100644 --- a/src/ServiceControl.Monitoring/Hosting/Commands/SetupCommand.cs +++ b/src/ServiceControl.Monitoring/Hosting/Commands/SetupCommand.cs @@ -1,7 +1,8 @@ namespace ServiceControl.Monitoring { using System.Threading.Tasks; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; + using ServiceControl.Infrastructure; using Transports; class SetupCommand : AbstractCommand @@ -10,7 +11,7 @@ public override Task Execute(HostArguments args, Settings settings) { if (args.SkipQueueCreation) { - Logger.Info("Skipping queue creation"); + LoggerUtil.CreateStaticLogger().LogInformation("Skipping queue creation"); return Task.CompletedTask; } @@ -19,7 +20,5 @@ public override Task Execute(HostArguments args, Settings settings) var transportCustomization = TransportFactory.Create(transportSettings); return transportCustomization.ProvisionQueues(transportSettings, []); } - - static readonly ILog Logger = LogManager.GetLogger(); } } \ No newline at end of file diff --git a/src/ServiceControl.Monitoring/Http/Diagrams/MonitoredEndpointMessageTypeParser.cs b/src/ServiceControl.Monitoring/Http/Diagrams/MonitoredEndpointMessageTypeParser.cs index 3faa1e81c7..f089104b4f 100644 --- a/src/ServiceControl.Monitoring/Http/Diagrams/MonitoredEndpointMessageTypeParser.cs +++ b/src/ServiceControl.Monitoring/Http/Diagrams/MonitoredEndpointMessageTypeParser.cs @@ -3,7 +3,8 @@ namespace ServiceControl.Monitoring.Http.Diagrams using System; using System.Linq; using System.Reflection; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; + using ServiceControl.Infrastructure; public static class MonitoredEndpointMessageTypeParser { @@ -40,7 +41,7 @@ public static MonitoredEndpointMessageType Parse(string typeName) } catch (Exception e) { - Logger.Warn($"Error parsing message type: {typeName}.", e); + LoggerUtil.CreateStaticLogger(typeof(MonitoredEndpointMessageTypeParser)).LogWarning(e, "Error parsing message type: {typeName}.", typeName); } } @@ -50,7 +51,5 @@ public static MonitoredEndpointMessageType Parse(string typeName) TypeName = typeName }; } - - static readonly ILog Logger = LogManager.GetLogger(typeof(MonitoredEndpointMessageTypeParser)); } } \ No newline at end of file diff --git a/src/ServiceControl.Monitoring/Licensing/ActiveLicense.cs b/src/ServiceControl.Monitoring/Licensing/ActiveLicense.cs index a3a001e0ad..f5ca3be8bc 100644 --- a/src/ServiceControl.Monitoring/Licensing/ActiveLicense.cs +++ b/src/ServiceControl.Monitoring/Licensing/ActiveLicense.cs @@ -1,11 +1,15 @@ namespace ServiceControl.Monitoring.Licensing { - using global::ServiceControl.LicenseManagement; - using NServiceBus.Logging; + using ServiceControl.LicenseManagement; + using Microsoft.Extensions.Logging; public class ActiveLicense { - public ActiveLicense() => Refresh(); + public ActiveLicense(ILogger logger) + { + this.logger = logger; + Refresh(); + } public bool IsValid { get; set; } @@ -13,7 +17,7 @@ public class ActiveLicense public void Refresh() { - Logger.Debug("Refreshing ActiveLicense"); + logger.LogDebug("Refreshing ActiveLicense"); var detectedLicense = LicenseManager.FindLicense(); @@ -22,6 +26,6 @@ public void Refresh() Details = detectedLicense.Details; } - static readonly ILog Logger = LogManager.GetLogger(typeof(ActiveLicense)); + readonly ILogger logger; } } \ No newline at end of file diff --git a/src/ServiceControl.Monitoring/Licensing/LicenseCheckHostedService.cs b/src/ServiceControl.Monitoring/Licensing/LicenseCheckHostedService.cs index a5b10f73b5..b29e47fd05 100644 --- a/src/ServiceControl.Monitoring/Licensing/LicenseCheckHostedService.cs +++ b/src/ServiceControl.Monitoring/Licensing/LicenseCheckHostedService.cs @@ -4,10 +4,10 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Hosting; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using ServiceControl.Infrastructure.BackgroundTasks; - class LicenseCheckHostedService(ActiveLicense activeLicense, IAsyncTimer scheduler) : IHostedService + class LicenseCheckHostedService(ActiveLicense activeLicense, IAsyncTimer scheduler, ILogger logger) : IHostedService { public Task StartAsync(CancellationToken cancellationToken) { @@ -16,7 +16,7 @@ public Task StartAsync(CancellationToken cancellationToken) { activeLicense.Refresh(); return ScheduleNextExecutionTask; - }, due, due, ex => Logger.Error("Unhandled error while refreshing the license.", ex)); + }, due, due, ex => logger.LogError(ex, "Unhandled error while refreshing the license.")); return Task.CompletedTask; } @@ -24,7 +24,6 @@ public Task StartAsync(CancellationToken cancellationToken) TimerJob timer; - static readonly ILog Logger = LogManager.GetLogger(); static readonly Task ScheduleNextExecutionTask = Task.FromResult(TimerJobExecutionResult.ScheduleNextExecution); } } \ No newline at end of file diff --git a/src/ServiceControl.Monitoring/Program.cs b/src/ServiceControl.Monitoring/Program.cs index 8620eba3cc..7a618a381f 100644 --- a/src/ServiceControl.Monitoring/Program.cs +++ b/src/ServiceControl.Monitoring/Program.cs @@ -1,13 +1,15 @@ using System; using System.Reflection; -using NServiceBus.Logging; +using Microsoft.Extensions.Logging; using ServiceControl.Configuration; using ServiceControl.Infrastructure; using ServiceControl.Monitoring; +var logger = LoggerUtil.CreateStaticLogger(); + try { - AppDomain.CurrentDomain.UnhandledException += (s, e) => LogManager.GetLogger(typeof(Program)).Error("Unhandled exception was caught.", e.ExceptionObject as Exception); + AppDomain.CurrentDomain.UnhandledException += (s, e) => logger.LogError(e.ExceptionObject as Exception, "Unhandled exception was caught."); // Hack: See https://github.com/Particular/ServiceControl/issues/4392 var exitCode = await IntegratedSetup.Run(); @@ -32,12 +34,12 @@ } catch (Exception ex) { - NLog.LogManager.GetCurrentClassLogger().Fatal(ex, "Unrecoverable error"); + logger.LogCritical(ex, "Unrecoverable error"); throw; } finally { // The following log statement is meant to leave a trail in the logs to determine if the process was killed - NLog.LogManager.GetCurrentClassLogger().Info("Shutdown complete"); + logger.LogInformation("Shutdown complete"); NLog.LogManager.Shutdown(); -} \ No newline at end of file +} diff --git a/src/ServiceControl.Monitoring/QueueLength/LegacyQueueLengthReportHandler.cs b/src/ServiceControl.Monitoring/QueueLength/LegacyQueueLengthReportHandler.cs index 82a72e4a8b..93d905558d 100644 --- a/src/ServiceControl.Monitoring/QueueLength/LegacyQueueLengthReportHandler.cs +++ b/src/ServiceControl.Monitoring/QueueLength/LegacyQueueLengthReportHandler.cs @@ -5,33 +5,24 @@ using System.Threading; using System.Threading.Tasks; using Infrastructure; + using Microsoft.Extensions.Logging; using NServiceBus; - using NServiceBus.Logging; using NServiceBus.Metrics; - class LegacyQueueLengthReportHandler : IHandleMessages + class LegacyQueueLengthReportHandler(LegacyQueueLengthReportHandler.LegacyQueueLengthEndpoints legacyEndpoints, ILogger logger) : IHandleMessages { - public LegacyQueueLengthReportHandler(LegacyQueueLengthEndpoints legacyEndpoints) - { - this.legacyEndpoints = legacyEndpoints; - } - public Task Handle(MetricReport message, IMessageHandlerContext context) { var endpointInstanceId = EndpointInstanceId.From(context.MessageHeaders); if (legacyEndpoints.TryAdd(endpointInstanceId.InstanceId)) { - Logger.Warn($"Legacy queue length report received from {endpointInstanceId.InstanceName} instance of {endpointInstanceId.EndpointName}"); + logger.LogWarning("Legacy queue length report received from {EndpointInstanceIdInstanceName} instance of {EndpointInstanceIdEndpointName}", endpointInstanceId.InstanceName, endpointInstanceId.EndpointName); } return Task.CompletedTask; } - LegacyQueueLengthEndpoints legacyEndpoints; - - static readonly ILog Logger = LogManager.GetLogger(typeof(LegacyQueueLengthReportHandler)); - public class LegacyQueueLengthEndpoints { public bool TryAdd(string id) diff --git a/src/ServiceControl.Monitoring/ServiceControl.Monitoring.csproj b/src/ServiceControl.Monitoring/ServiceControl.Monitoring.csproj index 35246ea1b8..1a9b705469 100644 --- a/src/ServiceControl.Monitoring/ServiceControl.Monitoring.csproj +++ b/src/ServiceControl.Monitoring/ServiceControl.Monitoring.csproj @@ -24,7 +24,6 @@ - diff --git a/src/ServiceControl.Transports.ASBS/DeadLetterQueueCheck.cs b/src/ServiceControl.Transports.ASBS/DeadLetterQueueCheck.cs index abcc4fd05c..e44be27ca8 100644 --- a/src/ServiceControl.Transports.ASBS/DeadLetterQueueCheck.cs +++ b/src/ServiceControl.Transports.ASBS/DeadLetterQueueCheck.cs @@ -4,14 +4,15 @@ using System.Threading; using System.Threading.Tasks; using Azure.Messaging.ServiceBus.Administration; + using Microsoft.Extensions.Logging; using NServiceBus.CustomChecks; - using NServiceBus.Logging; + using ServiceControl.Infrastructure; public class DeadLetterQueueCheck : CustomCheck { public DeadLetterQueueCheck(TransportSettings settings) : base(id: "Dead Letter Queue", category: "Transport", repeatAfter: TimeSpan.FromHours(1)) { - Logger.Debug("Azure Service Bus Dead Letter Queue custom check starting"); + Logger.LogDebug("Azure Service Bus Dead Letter Queue custom check starting"); connectionString = settings.ConnectionString; stagingQueue = $"{settings.EndpointName}.staging"; @@ -25,7 +26,7 @@ public override async Task PerformCheck(CancellationToken cancellat return CheckResult.Pass; } - Logger.Debug("Checking Dead Letter Queue length"); + Logger.LogDebug("Checking Dead Letter Queue length"); var managementClient = new ServiceBusAdministrationClient(connectionString); var queueRuntimeInfo = await managementClient.GetQueueRuntimePropertiesAsync(stagingQueue, cancellationToken); @@ -33,13 +34,11 @@ public override async Task PerformCheck(CancellationToken cancellat if (deadLetterMessageCount > 0) { - var result = $"{deadLetterMessageCount} messages in the Dead Letter Queue '{stagingQueue}'. This could indicate a problem with ServiceControl's retries. Please submit a support ticket to Particular if you would like help from our engineers to ensure no message loss while resolving these dead letter messages."; - - Logger.Warn(result); - return CheckResult.Failed(result); + Logger.LogWarning("{DeadLetterMessageCount} messages in the Dead Letter Queue '{StagingQueue}'. This could indicate a problem with ServiceControl's retries. Please submit a support ticket to Particular if you would like help from our engineers to ensure no message loss while resolving these dead letter messages.", deadLetterMessageCount, stagingQueue); + return CheckResult.Failed($"{deadLetterMessageCount} messages in the Dead Letter Queue '{stagingQueue}'. This could indicate a problem with ServiceControl's retries. Please submit a support ticket to Particular if you would like help from our engineers to ensure no message loss while resolving these dead letter messages."); } - Logger.Debug("No messages in Dead Letter Queue"); + Logger.LogDebug("No messages in Dead Letter Queue"); return CheckResult.Pass; } @@ -49,6 +48,6 @@ public override async Task PerformCheck(CancellationToken cancellat bool runCheck; - static readonly ILog Logger = LogManager.GetLogger(typeof(DeadLetterQueueCheck)); + static readonly ILogger Logger = LoggerUtil.CreateStaticLogger(typeof(DeadLetterQueueCheck)); } } \ No newline at end of file diff --git a/src/ServiceControl.Transports.ASBS/QueueLengthProvider.cs b/src/ServiceControl.Transports.ASBS/QueueLengthProvider.cs index 24021da49a..f6fb44e593 100644 --- a/src/ServiceControl.Transports.ASBS/QueueLengthProvider.cs +++ b/src/ServiceControl.Transports.ASBS/QueueLengthProvider.cs @@ -6,17 +6,18 @@ namespace ServiceControl.Transports.ASBS using System.Threading; using System.Threading.Tasks; using Azure.Messaging.ServiceBus.Administration; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; class QueueLengthProvider : AbstractQueueLengthProvider { - public QueueLengthProvider(TransportSettings settings, Action store) : base(settings, store) + public QueueLengthProvider(TransportSettings settings, Action store, ILogger logger) : base(settings, store) { var connectionSettings = ConnectionStringParser.Parse(ConnectionString); queryDelayInterval = connectionSettings.QueryDelayInterval ?? TimeSpan.FromMilliseconds(500); managementClient = connectionSettings.AuthenticationMethod.BuildManagementClient(); + this.logger = logger; } public override void TrackEndpointInputQueue(EndpointToQueueMapping queueToTrack) => @@ -32,14 +33,14 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) { try { - Logger.Debug("Waiting for next interval"); + logger.LogDebug("Waiting for next interval"); await Task.Delay(queryDelayInterval, stoppingToken); - Logger.DebugFormat("Querying management client."); + logger.LogDebug("Querying management client."); var queueRuntimeInfos = await GetQueueList(stoppingToken); - Logger.DebugFormat("Retrieved details of {0} queues", queueRuntimeInfos.Count); + logger.LogDebug("Retrieved details of {QueueCount} queues", queueRuntimeInfos.Count); UpdateAllQueueLengths(queueRuntimeInfos); } @@ -49,7 +50,7 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) } catch (Exception e) { - Logger.Error("Error querying Azure Service Bus queue sizes.", e); + logger.LogError(e, "Error querying Azure Service Bus queue sizes."); } } } @@ -109,7 +110,6 @@ void UpdateQueueLength(KeyValuePair monitoredEndpoint, IReadOnly readonly ConcurrentDictionary endpointQueueMappings = new ConcurrentDictionary(); readonly ServiceBusAdministrationClient managementClient; readonly TimeSpan queryDelayInterval; - - static readonly ILog Logger = LogManager.GetLogger(); + readonly ILogger logger; } } \ No newline at end of file diff --git a/src/ServiceControl.Transports.ASQ/QueueLengthProvider.cs b/src/ServiceControl.Transports.ASQ/QueueLengthProvider.cs index 58a7b5783d..48ebcf6a6d 100644 --- a/src/ServiceControl.Transports.ASQ/QueueLengthProvider.cs +++ b/src/ServiceControl.Transports.ASQ/QueueLengthProvider.cs @@ -1,19 +1,22 @@ namespace ServiceControl.Transports.ASQ { using System; - using System.Linq; - using System.Threading.Tasks; using System.Collections.Concurrent; + using System.Linq; using System.Threading; - using NServiceBus.Logging; + using System.Threading.Tasks; using Azure.Storage.Queues; using Azure.Storage.Queues.Models; + using Microsoft.Extensions.Logging; class QueueLengthProvider : AbstractQueueLengthProvider { - public QueueLengthProvider(TransportSettings settings, Action store) + public QueueLengthProvider(TransportSettings settings, Action store, ILogger logger) : base(settings, store) - => connectionString = ConnectionString.RemoveCustomConnectionStringParts(out _); + { + connectionString = ConnectionString.RemoveCustomConnectionStringParts(out _); + this.logger = logger; + } public override void TrackEndpointInputQueue(EndpointToQueueMapping queueToTrack) { @@ -48,7 +51,7 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) } catch (Exception e) { - Logger.Error("Error querying sql queue sizes.", e); + logger.LogError(e, "Error querying sql queue sizes."); } } } @@ -76,7 +79,7 @@ async Task FetchLength(QueueLengthValue queueLength, CancellationToken cancellat // simple "log once" approach to do not flood logs if (problematicQueuesNames.TryAdd(queueLength.QueueName, queueLength.QueueName)) { - Logger.Error($"Obtaining Azure Storage Queue count failed for '{queueLength.QueueName}'", ex); + logger.LogError(ex, "Obtaining Azure Storage Queue count failed for '{QueueName}'", queueLength.QueueName); } } } @@ -102,7 +105,7 @@ void UpdateQueueLengthStore() readonly ConcurrentDictionary queueLengths = new ConcurrentDictionary(); readonly ConcurrentDictionary problematicQueuesNames = new ConcurrentDictionary(); - static readonly ILog Logger = LogManager.GetLogger(); + readonly ILogger logger; static readonly TimeSpan QueryDelayInterval = TimeSpan.FromMilliseconds(200); class QueueLengthValue diff --git a/src/ServiceControl.Transports.Learning/QueueLengthProvider.cs b/src/ServiceControl.Transports.Learning/QueueLengthProvider.cs index 68959ada38..93bc2fcc41 100644 --- a/src/ServiceControl.Transports.Learning/QueueLengthProvider.cs +++ b/src/ServiceControl.Transports.Learning/QueueLengthProvider.cs @@ -7,14 +7,17 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using ServiceControl.Transports.Learning; class QueueLengthProvider : AbstractQueueLengthProvider { - public QueueLengthProvider(TransportSettings settings, Action store) - : base(settings, store) => + public QueueLengthProvider(TransportSettings settings, Action store, ILogger logger) + : base(settings, store) + { rootFolder = LearningTransportCustomization.FindStoragePath(ConnectionString); + this.logger = logger; + } public override void TrackEndpointInputQueue(EndpointToQueueMapping queueToTrack) => endpointsHash.AddOrUpdate(queueToTrack, queueToTrack, (_, __) => queueToTrack); @@ -36,7 +39,7 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) } catch (Exception ex) { - Log.Warn("Problem getting learning transport queue length", ex); + logger.LogWarning(ex, "Problem getting learning transport queue length"); } } } @@ -60,7 +63,7 @@ void UpdateStore(ILookup queueLengths) } else { - Log.Warn($"Queue Length data missing for queue {instance.InputQueue} (Endpoint {instance.EndpointName})"); + logger.LogWarning("Queue Length data missing for queue {InputQueue} (Endpoint {EndpointName})", instance.InputQueue, instance.EndpointName); } } } @@ -87,7 +90,7 @@ void UpdateStore(ILookup queueLengths) readonly ConcurrentDictionary endpointsHash = new ConcurrentDictionary(); static readonly TimeSpan QueryDelayInterval = TimeSpan.FromMilliseconds(200); - static readonly ILog Log = LogManager.GetLogger(); + readonly ILogger logger; } } \ No newline at end of file diff --git a/src/ServiceControl.Transports.Msmq/DeadLetterQueueCheck.cs b/src/ServiceControl.Transports.Msmq/DeadLetterQueueCheck.cs index 7f229048f6..61c5378d4d 100644 --- a/src/ServiceControl.Transports.Msmq/DeadLetterQueueCheck.cs +++ b/src/ServiceControl.Transports.Msmq/DeadLetterQueueCheck.cs @@ -5,13 +5,13 @@ using System.Diagnostics; using System.Threading; using System.Threading.Tasks; + using Microsoft.Extensions.Logging; using NServiceBus.CustomChecks; - using NServiceBus.Logging; using Transports; public class DeadLetterQueueCheck : CustomCheck { - public DeadLetterQueueCheck(TransportSettings settings) : + public DeadLetterQueueCheck(TransportSettings settings, ILogger logger) : base("Dead Letter Queue", "Transport", TimeSpan.FromHours(1)) { runCheck = settings.RunCustomChecks; @@ -20,7 +20,7 @@ public DeadLetterQueueCheck(TransportSettings settings) : return; } - Logger.Debug("MSMQ Dead Letter Queue custom check starting"); + logger.LogDebug("MSMQ Dead Letter Queue custom check starting"); categoryName = Read("Msmq/PerformanceCounterCategoryName", "MSMQ Queue"); counterName = Read("Msmq/PerformanceCounterName", "Messages in Queue"); @@ -32,8 +32,10 @@ public DeadLetterQueueCheck(TransportSettings settings) : } catch (InvalidOperationException ex) { - Logger.Error(CounterMightBeLocalized(categoryName, counterName, counterInstanceName), ex); + logger.LogError(ex, CounterMightBeLocalized("CategoryName", "CounterName", "CounterInstanceName"), categoryName, counterName, counterInstanceName); } + + this.logger = logger; } public override Task PerformCheck(CancellationToken cancellationToken = default) @@ -43,9 +45,8 @@ public override Task PerformCheck(CancellationToken cancellationTok return CheckResult.Pass; } - Logger.Debug("Checking Dead Letter Queue length"); + logger.LogDebug("Checking Dead Letter Queue length"); float currentValue; - string result; try { if (dlqPerformanceCounter == null) @@ -57,25 +58,18 @@ public override Task PerformCheck(CancellationToken cancellationTok } catch (InvalidOperationException ex) { - result = CounterMightBeLocalized(categoryName, counterName, counterInstanceName); - Logger.Warn(result, ex); - return CheckResult.Failed(result); + logger.LogWarning(ex, CounterMightBeLocalized("CategoryName", "CounterName", "CounterInstanceName"), categoryName, counterName, counterInstanceName); + return CheckResult.Failed(CounterMightBeLocalized(categoryName, counterName, counterInstanceName)); } if (currentValue <= 0) { - Logger.Debug("No messages in Dead Letter Queue"); + logger.LogDebug("No messages in Dead Letter Queue"); return CheckResult.Pass; } - result = MessagesInDeadLetterQueue(currentValue); - Logger.Warn(result); - return CheckResult.Failed(result); - } - - static string MessagesInDeadLetterQueue(float currentValue) - { - return $"{currentValue} messages in the Dead Letter Queue on {Environment.MachineName}. This could indicate a problem with ServiceControl's retries. Please submit a support ticket to Particular if you would like help from our engineers to ensure no message loss while resolving these dead letter messages."; + logger.LogWarning("{DeadLetterMessageCount} messages in the Dead Letter Queue on {MachineName}. This could indicate a problem with ServiceControl's retries. Please submit a support ticket to Particular if you would like help from our engineers to ensure no message loss while resolving these dead letter messages.", currentValue, Environment.MachineName); + return CheckResult.Failed($"{currentValue} messages in the Dead Letter Queue on {Environment.MachineName}. This could indicate a problem with ServiceControl's retries. Please submit a support ticket to Particular if you would like help from our engineers to ensure no message loss while resolving these dead letter messages."); } static string CounterMightBeLocalized(string categoryName, string counterName, string counterInstanceName) @@ -123,6 +117,6 @@ static bool TryRead(string root, string name, out string value) string counterInstanceName; bool runCheck; - static readonly ILog Logger = LogManager.GetLogger(typeof(DeadLetterQueueCheck)); + readonly ILogger logger; } } \ No newline at end of file diff --git a/src/ServiceControl.Transports.PostgreSql/PostgreSqlTransportCustomization.cs b/src/ServiceControl.Transports.PostgreSql/PostgreSqlTransportCustomization.cs index 934bee47a1..4523792f18 100644 --- a/src/ServiceControl.Transports.PostgreSql/PostgreSqlTransportCustomization.cs +++ b/src/ServiceControl.Transports.PostgreSql/PostgreSqlTransportCustomization.cs @@ -4,11 +4,12 @@ using System.Runtime.CompilerServices; using BrokerThroughput; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using NServiceBus; -using NServiceBus.Logging; using NServiceBus.Transport.PostgreSql; +using ServiceControl.Infrastructure; -public class PostgreSqlTransportCustomization : TransportCustomization +public class PostgreSqlTransportCustomization() : TransportCustomization { protected override void CustomizeTransportForPrimaryEndpoint(EndpointConfiguration endpointConfiguration, PostgreSqlTransport transportDefinition, TransportSettings transportSettings) { @@ -66,7 +67,7 @@ protected override PostgreSqlTransport CreateTransport(TransportSettings transpo if (transportSettings.GetOrDefault("TransportSettings.EnableDtc")) { - Logger.Error("The EnableDtc setting is no longer supported natively within ServiceControl. If you require distributed transactions, you will have to use a Transport Adapter (https://docs.particular.net/servicecontrol/transport-adapter/)"); + logger.LogError("The EnableDtc setting is no longer supported natively within ServiceControl. If you require distributed transactions, you will have to use a Transport Adapter (https://docs.particular.net/servicecontrol/transport-adapter/)"); } DisableDelayedDelivery(transport) = true; @@ -94,5 +95,5 @@ protected override string ToTransportQualifiedQueueNameCore(string queueName) const string DefaultSubscriptionTableName = "SubscriptionRouting"; - static readonly ILog Logger = LogManager.GetLogger(typeof(PostgreSqlTransportCustomization)); + static readonly ILogger logger = LoggerUtil.CreateStaticLogger(); } \ No newline at end of file diff --git a/src/ServiceControl.Transports.PostgreSql/QueueLengthProvider.cs b/src/ServiceControl.Transports.PostgreSql/QueueLengthProvider.cs index d58b5c526c..79b128032d 100644 --- a/src/ServiceControl.Transports.PostgreSql/QueueLengthProvider.cs +++ b/src/ServiceControl.Transports.PostgreSql/QueueLengthProvider.cs @@ -6,17 +6,18 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; using Npgsql; -using NServiceBus.Logging; class QueueLengthProvider : AbstractQueueLengthProvider { - public QueueLengthProvider(TransportSettings settings, Action store) : base(settings, store) + public QueueLengthProvider(TransportSettings settings, Action store, ILogger logger) : base(settings, store) { connectionString = ConnectionString .RemoveCustomConnectionStringParts(out var customSchema, out _); defaultSchema = customSchema ?? "public"; + this.logger = logger; } public override void TrackEndpointInputQueue(EndpointToQueueMapping queueToTrack) { @@ -55,7 +56,7 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) } catch (Exception e) { - Logger.Error("Error querying sql queue sizes.", e); + logger.LogError(e, "Error querying SQL queue sizes."); } } } @@ -113,7 +114,7 @@ async Task UpdateChunk(NpgsqlConnection connection, KeyValuePair(); + readonly ILogger logger; static readonly TimeSpan QueryDelayInterval = TimeSpan.FromMilliseconds(200); diff --git a/src/ServiceControl.Transports.RabbitMQ/QueueLengthProvider.cs b/src/ServiceControl.Transports.RabbitMQ/QueueLengthProvider.cs index 3c60019abe..311a408aa9 100644 --- a/src/ServiceControl.Transports.RabbitMQ/QueueLengthProvider.cs +++ b/src/ServiceControl.Transports.RabbitMQ/QueueLengthProvider.cs @@ -4,12 +4,12 @@ using System.Collections.Concurrent; using System.Threading; using System.Threading.Tasks; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using NServiceBus.Transport.RabbitMQ.ManagementApi; class QueueLengthProvider : AbstractQueueLengthProvider { - public QueueLengthProvider(TransportSettings settings, Action store, ITransportCustomization transportCustomization) : base(settings, store) + public QueueLengthProvider(TransportSettings settings, Action store, ITransportCustomization transportCustomization, ILogger logger) : base(settings, store) { if (transportCustomization is IManagementClientProvider provider) { @@ -19,6 +19,8 @@ public QueueLengthProvider(TransportSettings settings, Action @@ -50,7 +52,7 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) } catch (Exception e) { - Logger.Error("Queue length query loop failure.", e); + logger.LogError(e, "Queue length query loop failure."); } } } @@ -91,7 +93,7 @@ async Task FetchQueueLengths(CancellationToken cancellationToken) } catch (Exception e) { - Logger.Warn($"Error querying queue length for {queueName}", e); + logger.LogWarning(e, "Error querying queue length for {QueueName}", queueName); } } } @@ -101,7 +103,7 @@ async Task FetchQueueLengths(CancellationToken cancellationToken) readonly ConcurrentDictionary endpointQueues = new(); readonly ConcurrentDictionary sizes = new(); - static readonly ILog Logger = LogManager.GetLogger(); + readonly ILogger logger; readonly Lazy managementClient; } diff --git a/src/ServiceControl.Transports.SQS/QueueLengthProvider.cs b/src/ServiceControl.Transports.SQS/QueueLengthProvider.cs index 431d5358ac..ea8901fca9 100644 --- a/src/ServiceControl.Transports.SQS/QueueLengthProvider.cs +++ b/src/ServiceControl.Transports.SQS/QueueLengthProvider.cs @@ -1,19 +1,19 @@ namespace ServiceControl.Transports.SQS { using System; - using System.Linq; - using System.Threading.Tasks; - using System.Data.Common; using System.Collections.Concurrent; using System.Collections.Generic; + using System.Data.Common; + using System.Linq; using System.Threading; + using System.Threading.Tasks; using Amazon.Runtime; using Amazon.SQS; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; class QueueLengthProvider : AbstractQueueLengthProvider { - public QueueLengthProvider(TransportSettings settings, Action store) : base(settings, store) + public QueueLengthProvider(TransportSettings settings, Action store, ILogger logger) : base(settings, store) { var builder = new DbConnectionStringBuilder { ConnectionString = ConnectionString }; if (builder.ContainsKey("AccessKeyId") || builder.ContainsKey("SecretAccessKey")) @@ -24,13 +24,15 @@ public QueueLengthProvider(TransportSettings settings, Action clientFactory = () => new AmazonSQSClient(); - static readonly ILog Logger = LogManager.GetLogger(); + readonly ILogger logger; } } diff --git a/src/ServiceControl.Transports.SQS/SQSTransportCustomization.cs b/src/ServiceControl.Transports.SQS/SQSTransportCustomization.cs index 8c17902b53..8aa9a0d530 100644 --- a/src/ServiceControl.Transports.SQS/SQSTransportCustomization.cs +++ b/src/ServiceControl.Transports.SQS/SQSTransportCustomization.cs @@ -2,7 +2,6 @@ { using System; using System.Linq; - using System.Runtime.CompilerServices; using Amazon; using Amazon.Runtime; using Amazon.S3; @@ -10,11 +9,12 @@ using Amazon.SQS; using BrokerThroughput; using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Logging; using NServiceBus; using NServiceBus.Configuration.AdvancedExtensibility; - using NServiceBus.Logging; + using ServiceControl.Infrastructure; - public class SQSTransportCustomization : TransportCustomization + public class SQSTransportCustomization() : TransportCustomization { protected override void CustomizeTransportForPrimaryEndpoint(EndpointConfiguration endpointConfiguration, SqsTransport transportDefinition, TransportSettings transportSettings) { @@ -65,7 +65,7 @@ protected override SqsTransport CreateTransport(TransportSettings transportSetti else { //See https://docs.aws.amazon.com/sdk-for-net/v3/developer-guide/net-dg-config-creds.html#creds-assign - log.Info( + logger.LogInformation( "BasicAWSCredentials have not been supplied in the connection string. Attempting to use existing environment or IAM role credentials for SQS Client."); sqsClient = new AmazonSQSClient(); snsClient = new AmazonSimpleNotificationServiceClient(); @@ -101,7 +101,7 @@ protected override SqsTransport CreateTransport(TransportSettings transportSetti } else { - log.Info( + logger.LogInformation( "BasicAWSCredentials have not been supplied in the connection string. Attempting to use existing environment or IAM role credentials for S3 Client."); s3Client = new AmazonS3Client(); } @@ -121,6 +121,7 @@ static void PromoteEnvironmentVariableFromConnectionString(string value, string environmentVariableName) => Environment.SetEnvironmentVariable(environmentVariableName, value, EnvironmentVariableTarget.Process); - static readonly ILog log = LogManager.GetLogger(); + static readonly ILogger logger = LoggerUtil.CreateStaticLogger(); + } } \ No newline at end of file diff --git a/src/ServiceControl.Transports.SqlServer/QueueLengthProvider.cs b/src/ServiceControl.Transports.SqlServer/QueueLengthProvider.cs index 196905a678..b9fe29a227 100644 --- a/src/ServiceControl.Transports.SqlServer/QueueLengthProvider.cs +++ b/src/ServiceControl.Transports.SqlServer/QueueLengthProvider.cs @@ -7,16 +7,17 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Data.SqlClient; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; class QueueLengthProvider : AbstractQueueLengthProvider { - public QueueLengthProvider(TransportSettings settings, Action store) : base(settings, store) + public QueueLengthProvider(TransportSettings settings, Action store, ILogger logger) : base(settings, store) { connectionString = ConnectionString .RemoveCustomConnectionStringParts(out var customSchema, out _); defaultSchema = customSchema ?? "dbo"; + this.logger = logger; } public override void TrackEndpointInputQueue(EndpointToQueueMapping queueToTrack) { @@ -53,7 +54,7 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) } catch (Exception e) { - Logger.Error("Error querying sql queue sizes.", e); + logger.LogError(e, "Error querying sql queue sizes."); } } } @@ -111,7 +112,7 @@ async Task UpdateChunk(SqlConnection connection, KeyValuePair[] c if (queueLength == -1) { - Logger.Warn($"Table {chunkPair.Key} does not exist."); + logger.LogWarning("Table {TableName} does not exist.", chunkPair.Key); } else { @@ -128,7 +129,7 @@ async Task UpdateChunk(SqlConnection connection, KeyValuePair[] c readonly string connectionString; readonly string defaultSchema; - static readonly ILog Logger = LogManager.GetLogger(); + readonly ILogger logger; static readonly TimeSpan QueryDelayInterval = TimeSpan.FromMilliseconds(200); diff --git a/src/ServiceControl.Transports.SqlServer/SqlServerTransportCustomization.cs b/src/ServiceControl.Transports.SqlServer/SqlServerTransportCustomization.cs index 24d3dec0f3..034a23dc9c 100644 --- a/src/ServiceControl.Transports.SqlServer/SqlServerTransportCustomization.cs +++ b/src/ServiceControl.Transports.SqlServer/SqlServerTransportCustomization.cs @@ -4,12 +4,13 @@ using System.Runtime.CompilerServices; using BrokerThroughput; using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Logging; using NServiceBus; using NServiceBus.Configuration.AdvancedExtensibility; - using NServiceBus.Logging; using NServiceBus.Transport.SqlServer; + using ServiceControl.Infrastructure; - public class SqlServerTransportCustomization : TransportCustomization + public class SqlServerTransportCustomization() : TransportCustomization { protected override void CustomizeTransportForPrimaryEndpoint(EndpointConfiguration endpointConfiguration, SqlServerTransport transportDefinition, TransportSettings transportSettings) { @@ -73,7 +74,7 @@ protected override SqlServerTransport CreateTransport(TransportSettings transpor if (transportSettings.GetOrDefault("TransportSettings.EnableDtc")) { - Logger.Error("The EnableDtc setting is no longer supported natively within ServiceControl. If you require distributed transactions, you will have to use a Transport Adapter (https://docs.particular.net/servicecontrol/transport-adapter/)"); + logger.LogError("The EnableDtc setting is no longer supported natively within ServiceControl. If you require distributed transactions, you will have to use a Transport Adapter (https://docs.particular.net/servicecontrol/transport-adapter/)"); } DisableDelayedDelivery(transport) = true; @@ -88,6 +89,6 @@ protected override SqlServerTransport CreateTransport(TransportSettings transpor const string defaultSubscriptionTableName = "SubscriptionRouting"; - static readonly ILog Logger = LogManager.GetLogger(typeof(SqlServerTransportCustomization)); + static readonly ILogger logger = LoggerUtil.CreateStaticLogger(); } } \ No newline at end of file diff --git a/src/ServiceControl.Transports.Tests/FullEndpointTestFixture.cs b/src/ServiceControl.Transports.Tests/FullEndpointTestFixture.cs index 55f7f24383..c1034d05f2 100644 --- a/src/ServiceControl.Transports.Tests/FullEndpointTestFixture.cs +++ b/src/ServiceControl.Transports.Tests/FullEndpointTestFixture.cs @@ -4,6 +4,7 @@ using System.Threading.Tasks; using NServiceBus.AcceptanceTesting.Customization; using NUnit.Framework; + using ServiceControl.Infrastructure; [TestFixture] class FullEndpointTestFixture @@ -11,6 +12,7 @@ class FullEndpointTestFixture [SetUp] public virtual async Task Setup() { + LoggerUtil.ActiveLoggers = Loggers.Test; configuration = new TransportTestsConfiguration(); var queueSuffix = $"-{System.IO.Path.GetRandomFileName().Replace(".", string.Empty)}"; diff --git a/src/ServiceControl.Transports.Tests/ServiceControl.Transports.Tests.csproj b/src/ServiceControl.Transports.Tests/ServiceControl.Transports.Tests.csproj index 8c7d0e9e78..aedb05ec31 100644 --- a/src/ServiceControl.Transports.Tests/ServiceControl.Transports.Tests.csproj +++ b/src/ServiceControl.Transports.Tests/ServiceControl.Transports.Tests.csproj @@ -5,6 +5,7 @@ + diff --git a/src/ServiceControl.Transports.Tests/TestContextAppender.cs b/src/ServiceControl.Transports.Tests/TestContextAppender.cs deleted file mode 100644 index 26a3a5645c..0000000000 --- a/src/ServiceControl.Transports.Tests/TestContextAppender.cs +++ /dev/null @@ -1,87 +0,0 @@ -namespace ServiceControl.Transport.Tests -{ - using System; - using NServiceBus.Logging; - using NUnit.Framework; - - class TestContextAppender : ILog - { - public bool IsDebugEnabled => false; - public bool IsInfoEnabled => false; - public bool IsWarnEnabled => true; - public bool IsErrorEnabled => true; - public bool IsFatalEnabled => true; - - public void Debug(string message) => Log(message, LogLevel.Debug); - - public void Debug(string message, Exception exception) - { - var fullMessage = $"{message} {exception}"; - Log(fullMessage, LogLevel.Debug); - } - - public void DebugFormat(string format, params object[] args) - { - var fullMessage = string.Format(format, args); - Log(fullMessage, LogLevel.Debug); - } - - public void Info(string message) => Log(message, LogLevel.Info); - - public void Info(string message, Exception exception) - { - var fullMessage = $"{message} {exception}"; - Log(fullMessage, LogLevel.Info); - } - - public void InfoFormat(string format, params object[] args) - { - var fullMessage = string.Format(format, args); - Log(fullMessage, LogLevel.Info); - } - - public void Warn(string message) => Log(message, LogLevel.Warn); - - public void Warn(string message, Exception exception) - { - var fullMessage = $"{message} {exception}"; - Log(fullMessage, LogLevel.Warn); - } - - public void WarnFormat(string format, params object[] args) - { - var fullMessage = string.Format(format, args); - Log(fullMessage, LogLevel.Warn); - } - - public void Error(string message) => Log(message, LogLevel.Error); - - public void Error(string message, Exception exception) - { - var fullMessage = $"{message} {exception}"; - Log(fullMessage, LogLevel.Error); - } - - public void ErrorFormat(string format, params object[] args) - { - var fullMessage = string.Format(format, args); - Log(fullMessage, LogLevel.Error); - } - - public void Fatal(string message) => Log(message, LogLevel.Fatal); - - public void Fatal(string message, Exception exception) - { - var fullMessage = $"{message} {exception}"; - Log(fullMessage, LogLevel.Fatal); - } - - public void FatalFormat(string format, params object[] args) - { - var fullMessage = string.Format(format, args); - Log(fullMessage, LogLevel.Fatal); - } - - static void Log(string message, LogLevel _) => TestContext.Out.WriteLine(message); - } -} \ No newline at end of file diff --git a/src/ServiceControl.Transports.Tests/TestContextAppenderFactory.cs b/src/ServiceControl.Transports.Tests/TestContextAppenderFactory.cs deleted file mode 100644 index 75d8dbfcef..0000000000 --- a/src/ServiceControl.Transports.Tests/TestContextAppenderFactory.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace ServiceControl.Transport.Tests -{ - using System; - using NServiceBus.Logging; - - class TestContextAppenderFactory : ILoggerFactory - { - public ILog GetLogger(Type type) => GetLogger(type.FullName); - - public ILog GetLogger(string name) => new TestContextAppender(); - } -} \ No newline at end of file diff --git a/src/ServiceControl.Transports.Tests/TransportManifestLibraryTests.cs b/src/ServiceControl.Transports.Tests/TransportManifestLibraryTests.cs index aa678c8b01..6345f0e618 100644 --- a/src/ServiceControl.Transports.Tests/TransportManifestLibraryTests.cs +++ b/src/ServiceControl.Transports.Tests/TransportManifestLibraryTests.cs @@ -7,6 +7,7 @@ using System.Runtime.InteropServices; using NUnit.Framework; using Particular.Approvals; + using ServiceControl.Infrastructure; using ServiceControl.Transports; [TestFixture] @@ -16,6 +17,12 @@ public class TransportManifestLibraryTests const string transportType = "ServiceControl.Transports.ASBS.ASBSTransportCustomization, ServiceControl.Transports.ASBS"; const string transportAlias = "ServiceControl.Transports.AzureServiceBus.AzureServiceBusTransport, ServiceControl.Transports.AzureServiceBus"; + [SetUp] + public void SetUp() + { + LoggerUtil.ActiveLoggers = Loggers.Test; + } + [Test] public void Should_find_transport_manifest_by_name() { diff --git a/src/ServiceControl.Transports.Tests/TransportTestFixture.cs b/src/ServiceControl.Transports.Tests/TransportTestFixture.cs index 0f6d9027e1..ac1501232b 100644 --- a/src/ServiceControl.Transports.Tests/TransportTestFixture.cs +++ b/src/ServiceControl.Transports.Tests/TransportTestFixture.cs @@ -9,9 +9,12 @@ using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using NServiceBus; + using NServiceBus.Extensions.Logging; using NServiceBus.Logging; using NServiceBus.Transport; using NUnit.Framework; + using ServiceControl.Infrastructure; + using ServiceControl.Infrastructure.TestLogger; using Transports; [TestFixture] @@ -20,7 +23,9 @@ class TransportTestFixture [SetUp] public virtual async Task Setup() { - LogManager.UseFactory(new TestContextAppenderFactory()); + //TODO remove LogManager usage + LogManager.UseFactory(new ExtensionsLoggerFactory(new TestContextAppenderFactory())); + LoggerUtil.ActiveLoggers = Loggers.Test; configuration = new TransportTestsConfiguration(); testCancellationTokenSource = Debugger.IsAttached ? new CancellationTokenSource() : new CancellationTokenSource(TestTimeout); registrations = []; @@ -102,6 +107,7 @@ protected async Task StartQueueLengthProvider(string queueName configuration.TransportCustomization.CustomizeMonitoringEndpoint(new EndpointConfiguration("queueName"), transportSettings); serviceCollection.AddSingleton>((qlt, _) => onQueueLengthReported(qlt.First())); + serviceCollection.AddLogging(); var serviceProvider = serviceCollection.BuildServiceProvider(); queueLengthProvider = serviceProvider.GetRequiredService(); diff --git a/src/ServiceControl.Transports/ServiceControl.Transports.csproj b/src/ServiceControl.Transports/ServiceControl.Transports.csproj index 435491c160..263429e5d4 100644 --- a/src/ServiceControl.Transports/ServiceControl.Transports.csproj +++ b/src/ServiceControl.Transports/ServiceControl.Transports.csproj @@ -9,6 +9,7 @@ + diff --git a/src/ServiceControl.Transports/TransportManifest.cs b/src/ServiceControl.Transports/TransportManifest.cs index c37538867a..429d80db9b 100644 --- a/src/ServiceControl.Transports/TransportManifest.cs +++ b/src/ServiceControl.Transports/TransportManifest.cs @@ -5,7 +5,8 @@ using System.IO; using System.Linq; using System.Text.Json; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; + using ServiceControl.Infrastructure; public class TransportManifest { @@ -60,7 +61,7 @@ static TransportManifestLibrary() } catch (Exception ex) { - logger.Warn($"Failed to load transport manifests from {assemblyDirectory}", ex); + logger.LogWarning(ex, "Failed to load transport manifests from {AssemblyDirectory}", assemblyDirectory); } try @@ -79,10 +80,10 @@ static TransportManifestLibrary() } catch (Exception ex) { - logger.Warn($"Failed to load transport manifests from development locations", ex); + logger.LogWarning(ex, "Failed to load transport manifests from development locations"); } - TransportManifests.SelectMany(t => t.Definitions).ToList().ForEach(m => logger.Info($"Found transport manifest for {m.DisplayName}")); + TransportManifests.SelectMany(t => t.Definitions).ToList().ForEach(m => logger.LogInformation("Found transport manifest for {TransportManifestDisplayName}", m.DisplayName)); } static string GetAssemblyDirectory() @@ -105,7 +106,7 @@ public static TransportManifestDefinition Find(string transportType) return transportManifestDefinition; } - static readonly ILog logger = LogManager.GetLogger(typeof(TransportManifestLibrary)); + static readonly ILogger logger = LoggerUtil.CreateStaticLogger(typeof(TransportManifestLibrary)); } } diff --git a/src/ServiceControl.UnitTests/ApprovalFiles/APIApprovals.PlatformSampleSettings.approved.txt b/src/ServiceControl.UnitTests/ApprovalFiles/APIApprovals.PlatformSampleSettings.approved.txt index a23480af26..246f3e5678 100644 --- a/src/ServiceControl.UnitTests/ApprovalFiles/APIApprovals.PlatformSampleSettings.approved.txt +++ b/src/ServiceControl.UnitTests/ApprovalFiles/APIApprovals.PlatformSampleSettings.approved.txt @@ -1,9 +1,6 @@ { "LoggingSettings": { - "LogLevel": { - "Name": "Info", - "Ordinal": 2 - }, + "LogLevel": "Information", "LogPath": "C:\\Logs" }, "NotificationsFilter": null, diff --git a/src/ServiceControl/HostApplicationBuilderExtensions.cs b/src/ServiceControl/HostApplicationBuilderExtensions.cs index 39d550f3e6..25685e7623 100644 --- a/src/ServiceControl/HostApplicationBuilderExtensions.cs +++ b/src/ServiceControl/HostApplicationBuilderExtensions.cs @@ -46,7 +46,7 @@ public static void AddServiceControl(this IHostApplicationBuilder hostBuilder, S logging.ClearProviders(); //HINT: configuration used by NLog comes from LoggingConfigurator.cs logging.AddNLog(); - logging.SetMinimumLevel(settings.LoggingSettings.ToHostLogLevel()); + logging.SetMinimumLevel(settings.LoggingSettings.LogLevel); var services = hostBuilder.Services; var transportSettings = settings.ToTransportSettings(); @@ -127,7 +127,7 @@ Audit Retention Period (optional): {settings.AuditRetentionPeriod} Selected Transport Customization: {settings.TransportType} -------------------------------------------------------------"; - var logger = LoggerUtil.CreateStaticLogger(typeof(HostApplicationBuilderExtensions), settings.LoggingSettings.ToHostLogLevel()); + var logger = LoggerUtil.CreateStaticLogger(typeof(HostApplicationBuilderExtensions), settings.LoggingSettings.LogLevel); logger.LogInformation(startupMessage); endpointConfiguration.GetSettings().AddStartupDiagnosticsSection("Startup", new { diff --git a/src/ServiceControl/Infrastructure/Api/ConfigurationApi.cs b/src/ServiceControl/Infrastructure/Api/ConfigurationApi.cs index fa06e80bc9..f8af272eb4 100644 --- a/src/ServiceControl/Infrastructure/Api/ConfigurationApi.cs +++ b/src/ServiceControl/Infrastructure/Api/ConfigurationApi.cs @@ -60,7 +60,7 @@ public Task GetConfig(CancellationToken cancellationToken) Logging = new { settings.LoggingSettings.LogPath, - LoggingLevel = settings.LoggingSettings.LogLevel.Name + LoggingLevel = settings.LoggingSettings.LogLevel } }, DataRetention = new From 479d40936103f9a8bec6b5b537ff00edda6daf6a Mon Sep 17 00:00:00 2001 From: Phil Bastian Date: Thu, 19 Jun 2025 08:43:16 +0800 Subject: [PATCH 31/56] set default to nlog and pass loglevel to test context --- src/ServiceControl.Infrastructure/LoggerUtil.cs | 2 +- src/ServiceControl.Infrastructure/LoggingSettings.cs | 3 ++- .../TestLogger/TestContextAppender.cs | 4 ++-- .../TestLogger/TestContextAppenderFactory.cs | 4 ++-- .../TestLogger/TestContextProvider.cs | 9 ++++++++- .../ServiceControl.Persistence.Tests.InMemory.csproj | 1 + .../ServiceControl.Persistence.Tests.RavenDB.csproj | 1 + .../PersistenceTestBase.cs | 6 ++++++ src/ServiceControl.RavenDB/ServiceControl.RavenDB.csproj | 4 ++++ .../TransportTestFixture.cs | 2 +- 10 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/ServiceControl.Infrastructure/LoggerUtil.cs b/src/ServiceControl.Infrastructure/LoggerUtil.cs index 34fc16beb1..f85bd6776a 100644 --- a/src/ServiceControl.Infrastructure/LoggerUtil.cs +++ b/src/ServiceControl.Infrastructure/LoggerUtil.cs @@ -23,7 +23,7 @@ public static void BuildLogger(this ILoggingBuilder loggingBuilder, LogLevel lev { if ((Loggers.Test & ActiveLoggers) == Loggers.Test) { - loggingBuilder.Services.AddSingleton(new TestContextProvider()); + loggingBuilder.Services.AddSingleton(new TestContextProvider(level)); } if ((Loggers.NLog & ActiveLoggers) == Loggers.NLog) { diff --git a/src/ServiceControl.Infrastructure/LoggingSettings.cs b/src/ServiceControl.Infrastructure/LoggingSettings.cs index 1a80ccb875..c48b27d889 100644 --- a/src/ServiceControl.Infrastructure/LoggingSettings.cs +++ b/src/ServiceControl.Infrastructure/LoggingSettings.cs @@ -24,7 +24,8 @@ public LoggingSettings(SettingsRootNamespace rootNamespace, LogLevel defaultLeve { activeLoggers |= Loggers.Seq; } - LoggerUtil.ActiveLoggers = activeLoggers; + //this defaults to NLog because historically that was the default, and we don't want to break existing installs that don't have the config key to define loggingProviders + LoggerUtil.ActiveLoggers = activeLoggers == Loggers.None ? Loggers.NLog : activeLoggers; } public LogLevel LogLevel { get; } diff --git a/src/ServiceControl.Infrastructure/TestLogger/TestContextAppender.cs b/src/ServiceControl.Infrastructure/TestLogger/TestContextAppender.cs index c353a3b60a..ed37368e16 100644 --- a/src/ServiceControl.Infrastructure/TestLogger/TestContextAppender.cs +++ b/src/ServiceControl.Infrastructure/TestLogger/TestContextAppender.cs @@ -4,7 +4,7 @@ using Microsoft.Extensions.Logging; using NUnit.Framework; - class TestContextAppender(string categoryName) : ILogger + class TestContextAppender(string categoryName, LogLevel level) : ILogger { public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) { @@ -13,7 +13,7 @@ public void Log(LogLevel logLevel, EventId eventId, TState state, Except TestContext.Out.WriteLine($"{categoryName}: {formatter(state, exception)}"); } } - public bool IsEnabled(LogLevel logLevel) => logLevel >= LogLevel.Warning; + public bool IsEnabled(LogLevel logLevel) => logLevel >= level; public IDisposable BeginScope(TState state) where TState : notnull => Disposable.Instance; diff --git a/src/ServiceControl.Infrastructure/TestLogger/TestContextAppenderFactory.cs b/src/ServiceControl.Infrastructure/TestLogger/TestContextAppenderFactory.cs index 98e1d683fb..3cac38fce7 100644 --- a/src/ServiceControl.Infrastructure/TestLogger/TestContextAppenderFactory.cs +++ b/src/ServiceControl.Infrastructure/TestLogger/TestContextAppenderFactory.cs @@ -2,13 +2,13 @@ { using Microsoft.Extensions.Logging; - public class TestContextAppenderFactory : ILoggerFactory + public class TestContextAppenderFactory(LogLevel logLevel) : ILoggerFactory { public void AddProvider(ILoggerProvider provider) { } - public ILogger CreateLogger(string categoryName) => new TestContextAppender(categoryName); + public ILogger CreateLogger(string categoryName) => new TestContextAppender(categoryName, logLevel); public void Dispose() { diff --git a/src/ServiceControl.Infrastructure/TestLogger/TestContextProvider.cs b/src/ServiceControl.Infrastructure/TestLogger/TestContextProvider.cs index e879c814a3..90e2dae5d8 100644 --- a/src/ServiceControl.Infrastructure/TestLogger/TestContextProvider.cs +++ b/src/ServiceControl.Infrastructure/TestLogger/TestContextProvider.cs @@ -4,7 +4,14 @@ public class TestContextProvider : ILoggerProvider { - public ILogger CreateLogger(string categoryName) => new TestContextAppender(categoryName); + readonly LogLevel level; + + public TestContextProvider(LogLevel level) + { + this.level = level; + } + + public ILogger CreateLogger(string categoryName) => new TestContextAppender(categoryName, level); public void Dispose() { diff --git a/src/ServiceControl.Persistence.Tests.InMemory/ServiceControl.Persistence.Tests.InMemory.csproj b/src/ServiceControl.Persistence.Tests.InMemory/ServiceControl.Persistence.Tests.InMemory.csproj index 4e0fac1da4..14f8701c33 100644 --- a/src/ServiceControl.Persistence.Tests.InMemory/ServiceControl.Persistence.Tests.InMemory.csproj +++ b/src/ServiceControl.Persistence.Tests.InMemory/ServiceControl.Persistence.Tests.InMemory.csproj @@ -6,6 +6,7 @@ + diff --git a/src/ServiceControl.Persistence.Tests.RavenDB/ServiceControl.Persistence.Tests.RavenDB.csproj b/src/ServiceControl.Persistence.Tests.RavenDB/ServiceControl.Persistence.Tests.RavenDB.csproj index bb4f028ee1..f3ed716dde 100644 --- a/src/ServiceControl.Persistence.Tests.RavenDB/ServiceControl.Persistence.Tests.RavenDB.csproj +++ b/src/ServiceControl.Persistence.Tests.RavenDB/ServiceControl.Persistence.Tests.RavenDB.csproj @@ -5,6 +5,7 @@ + diff --git a/src/ServiceControl.Persistence.Tests/PersistenceTestBase.cs b/src/ServiceControl.Persistence.Tests/PersistenceTestBase.cs index c6d0de3aa2..7cc5f39cca 100644 --- a/src/ServiceControl.Persistence.Tests/PersistenceTestBase.cs +++ b/src/ServiceControl.Persistence.Tests/PersistenceTestBase.cs @@ -4,10 +4,12 @@ using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; using NServiceBus; using NServiceBus.Settings; using NUnit.Framework; using Particular.LicensingComponent.Persistence; +using ServiceControl.Infrastructure; using ServiceControl.Infrastructure.DomainEvents; using ServiceControl.Operations.BodyStorage; using ServiceControl.Persistence; @@ -30,6 +32,10 @@ public async Task SetUp() } var hostBuilder = Host.CreateApplicationBuilder(); + + LoggerUtil.ActiveLoggers = Loggers.Test; + hostBuilder.Logging.BuildLogger(LogLevel.Information); + await PersistenceTestsContext.Setup(hostBuilder); // This is not cool. We have things that are registered as part of "the persistence" that then require parts diff --git a/src/ServiceControl.RavenDB/ServiceControl.RavenDB.csproj b/src/ServiceControl.RavenDB/ServiceControl.RavenDB.csproj index 46705a80e7..0479c4ff74 100644 --- a/src/ServiceControl.RavenDB/ServiceControl.RavenDB.csproj +++ b/src/ServiceControl.RavenDB/ServiceControl.RavenDB.csproj @@ -12,6 +12,10 @@ + + + + diff --git a/src/ServiceControl.Transports.Tests/TransportTestFixture.cs b/src/ServiceControl.Transports.Tests/TransportTestFixture.cs index ac1501232b..9ecf8f1725 100644 --- a/src/ServiceControl.Transports.Tests/TransportTestFixture.cs +++ b/src/ServiceControl.Transports.Tests/TransportTestFixture.cs @@ -24,7 +24,7 @@ class TransportTestFixture public virtual async Task Setup() { //TODO remove LogManager usage - LogManager.UseFactory(new ExtensionsLoggerFactory(new TestContextAppenderFactory())); + LogManager.UseFactory(new ExtensionsLoggerFactory(new TestContextAppenderFactory(Microsoft.Extensions.Logging.LogLevel.Warning))); LoggerUtil.ActiveLoggers = Loggers.Test; configuration = new TransportTestsConfiguration(); testCancellationTokenSource = Debugger.IsAttached ? new CancellationTokenSource() : new CancellationTokenSource(TestTimeout); From c3c3de47ad29b909f3ec1711846dc91f114afdfe Mon Sep 17 00:00:00 2001 From: Phil Bastian Date: Thu, 19 Jun 2025 09:26:19 +0800 Subject: [PATCH 32/56] default to nLog --- src/ServiceControl.Infrastructure/LoggingSettings.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ServiceControl.Infrastructure/LoggingSettings.cs b/src/ServiceControl.Infrastructure/LoggingSettings.cs index 1a80ccb875..c48b27d889 100644 --- a/src/ServiceControl.Infrastructure/LoggingSettings.cs +++ b/src/ServiceControl.Infrastructure/LoggingSettings.cs @@ -24,7 +24,8 @@ public LoggingSettings(SettingsRootNamespace rootNamespace, LogLevel defaultLeve { activeLoggers |= Loggers.Seq; } - LoggerUtil.ActiveLoggers = activeLoggers; + //this defaults to NLog because historically that was the default, and we don't want to break existing installs that don't have the config key to define loggingProviders + LoggerUtil.ActiveLoggers = activeLoggers == Loggers.None ? Loggers.NLog : activeLoggers; } public LogLevel LogLevel { get; } From 316516e521b5053c08c575ff51a7889968180f7e Mon Sep 17 00:00:00 2001 From: Phil Bastian Date: Thu, 19 Jun 2025 12:04:24 +0800 Subject: [PATCH 33/56] replace logmanager usage in persistence --- .../CustomChecks/CheckDirtyMemory.cs | 13 ++--- .../CustomChecks/CheckFreeDiskSpace.cs | 29 ++++------- ...CheckMinimumStorageRequiredForIngestion.cs | 38 +++++++------- .../CustomChecks/CheckRavenDBIndexErrors.cs | 8 ++- .../CustomChecks/CheckRavenDBIndexLag.cs | 17 +++---- .../ErrorMessagesDataStore.cs | 13 +++-- .../FailedErrorImportDataStore.cs | 19 +++---- .../FailedMessageViewIndexNotifications.cs | 8 ++- .../Subscriptions/RavenSubscriptionStorage.cs | 18 +++---- .../RavenEmbeddedPersistenceLifecycle.cs | 8 ++- .../Archiving/ArchiveDocumentManager.cs | 7 ++- .../Archiving/MessageArchiver.cs | 51 ++++++++++--------- .../RetryBatchesDataStore.cs | 14 +++-- .../RetryDocumentDataStore.cs | 8 ++- .../SubscriptionPersisterTests.cs | 5 +- .../PersistenceManifest.cs | 10 ++-- .../EmbeddedDatabase.cs | 33 ++++++------ 17 files changed, 135 insertions(+), 164 deletions(-) diff --git a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckDirtyMemory.cs b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckDirtyMemory.cs index 8eee53911a..c90bbc4a8e 100644 --- a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckDirtyMemory.cs +++ b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckDirtyMemory.cs @@ -3,26 +3,23 @@ namespace ServiceControl.Persistence.RavenDB.CustomChecks; using System; using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; using NServiceBus.CustomChecks; -using NServiceBus.Logging; -class CheckDirtyMemory(MemoryInformationRetriever memoryInformationRetriever) : CustomCheck("RavenDB dirty memory", "ServiceControl Health", TimeSpan.FromMinutes(5)) +class CheckDirtyMemory(MemoryInformationRetriever memoryInformationRetriever, ILogger logger) : CustomCheck("RavenDB dirty memory", "ServiceControl Health", TimeSpan.FromMinutes(5)) { public override async Task PerformCheck(CancellationToken cancellationToken = default) { var (isHighDirty, dirtyMemory) = await memoryInformationRetriever.GetMemoryInformation(cancellationToken); - Log.Debug($"RavenDB dirty memory value: {dirtyMemory}."); + logger.LogDebug("RavenDB dirty memory value: {DirtyMemory}.", dirtyMemory); if (isHighDirty) { - var message = $"There is a high level of RavenDB dirty memory ({dirtyMemory}). See https://docs.particular.net/servicecontrol/troubleshooting#ravendb-dirty-memory for guidance on how to mitigate the issue."; - Log.Warn(message); - return CheckResult.Failed(message); + logger.LogWarning("There is a high level of RavenDB dirty memory ({DirtyMemory}). See https://docs.particular.net/servicecontrol/troubleshooting#ravendb-dirty-memory for guidance on how to mitigate the issue.", dirtyMemory); + return CheckResult.Failed($"There is a high level of RavenDB dirty memory ({dirtyMemory}). See https://docs.particular.net/servicecontrol/troubleshooting#ravendb-dirty-memory for guidance on how to mitigate the issue."); } return CheckResult.Pass; } - - static readonly ILog Log = LogManager.GetLogger(); } \ No newline at end of file diff --git a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs index c90bce9807..22029f309c 100644 --- a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs +++ b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs @@ -4,18 +4,16 @@ using System.IO; using System.Threading; using System.Threading.Tasks; + using Microsoft.Extensions.Logging; using NServiceBus.CustomChecks; - using NServiceBus.Logging; + using ServiceControl.Infrastructure; using ServiceControl.Persistence.RavenDB; - class CheckFreeDiskSpace(RavenPersisterSettings settings) : CustomCheck("ServiceControl database", "Storage space", TimeSpan.FromMinutes(5)) + class CheckFreeDiskSpace(RavenPersisterSettings settings, ILogger logger) : CustomCheck("ServiceControl database", "Storage space", TimeSpan.FromMinutes(5)) { public override Task PerformCheck(CancellationToken cancellationToken = default) { - if (Logger.IsDebugEnabled) - { - Logger.Debug($"Check ServiceControl data drive space remaining custom check starting. Threshold {percentageThreshold:P0}"); - } + logger.LogDebug("Check ServiceControl data drive space remaining custom check starting. Threshold {PercentageThreshold:P0}", percentageThreshold); if (!settings.UseEmbeddedServer) { @@ -33,10 +31,7 @@ public override Task PerformCheck(CancellationToken cancellationTok var percentRemaining = (decimal)dataDriveInfo.AvailableFreeSpace / dataDriveInfo.TotalSize; - if (Logger.IsDebugEnabled) - { - Logger.Debug($"Free space: {availableFreeSpace:N0}B | Total: {totalSpace:N0}B | Percent remaining {percentRemaining:P1}"); - } + logger.LogDebug("Free space: {AvailableFreeSpace:N0}B | Total: {TotalSpace:N0}B | Percent remaining {PercentRemaining:P1}", availableFreeSpace, totalSpace, percentRemaining); return percentRemaining > percentageThreshold ? CheckResult.Pass @@ -45,22 +40,19 @@ public override Task PerformCheck(CancellationToken cancellationTok public static void Validate(RavenPersisterSettings settings) { + var logger = LoggerUtil.CreateStaticLogger(); var threshold = settings.DataSpaceRemainingThreshold; - string message; - if (threshold < 0) { - message = $"{RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey} is invalid, minimum value is 0."; - Logger.Fatal(message); - throw new Exception(message); + logger.LogCritical("{RavenPersistenceConfigurationDataSpaceRemainingThresholdKey} is invalid, minimum value is 0.", RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey); + throw new Exception($"{RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey} is invalid, minimum value is 0."); } if (threshold > 100) { - message = $"{RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey} is invalid, maximum value is 100."; - Logger.Fatal(message); - throw new Exception(message); + logger.LogCritical("{RavenPersistenceConfigurationDataSpaceRemainingThresholdKey} is invalid, maximum value is 100.", RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey); + throw new Exception($"{RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey} is invalid, maximum value is 100."); } } @@ -68,6 +60,5 @@ public static void Validate(RavenPersisterSettings settings) readonly decimal percentageThreshold = settings.DataSpaceRemainingThreshold / 100m; public const int DataSpaceRemainingThresholdDefault = 20; - static readonly ILog Logger = LogManager.GetLogger(typeof(CheckFreeDiskSpace)); } } \ No newline at end of file diff --git a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs index 053a41cff7..0c04857571 100644 --- a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs +++ b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs @@ -4,21 +4,19 @@ using System.IO; using System.Threading; using System.Threading.Tasks; + using Microsoft.Extensions.Logging; using NServiceBus.CustomChecks; - using NServiceBus.Logging; + using ServiceControl.Infrastructure; using ServiceControl.Persistence; using ServiceControl.Persistence.RavenDB; - class CheckMinimumStorageRequiredForIngestion(MinimumRequiredStorageState stateHolder, RavenPersisterSettings settings) : CustomCheck("Message Ingestion Process", "ServiceControl Health", TimeSpan.FromSeconds(5)) + class CheckMinimumStorageRequiredForIngestion(MinimumRequiredStorageState stateHolder, RavenPersisterSettings settings, ILogger logger) : CustomCheck("Message Ingestion Process", "ServiceControl Health", TimeSpan.FromSeconds(5)) { public override Task PerformCheck(CancellationToken cancellationToken = default) { var percentageThreshold = settings.MinimumStorageLeftRequiredForIngestion / 100m; - if (Logger.IsDebugEnabled) - { - Logger.Debug($"Check ServiceControl data drive space starting. Threshold {percentageThreshold:P0}"); - } + logger.LogDebug("Check ServiceControl data drive space starting. Threshold {PercentageThreshold:P0}", percentageThreshold); // Should be checking UseEmbeddedServer but need to check DatabasePath instead for the ATT hack to work if (string.IsNullOrEmpty(settings.DatabasePath)) @@ -35,10 +33,7 @@ public override Task PerformCheck(CancellationToken cancellationTok var percentRemaining = (decimal)dataDriveInfo.AvailableFreeSpace / dataDriveInfo.TotalSize; - if (Logger.IsDebugEnabled) - { - Logger.Debug($"Free space: {availableFreeSpace:N0}B | Total: {totalSpace:N0}B | Percent remaining {percentRemaining:P1}"); - } + logger.LogDebug("Free space: {AvailableFreeSpace:N0}B | Total: {TotalSpace:N0}B | Percent remaining {PercentRemaining:P1}", availableFreeSpace, totalSpace, percentRemaining); if (percentRemaining > percentageThreshold) { @@ -46,33 +41,36 @@ public override Task PerformCheck(CancellationToken cancellationTok return SuccessResult; } - var message = $"Error message ingestion stopped! {percentRemaining:P0} disk space remaining on data drive '{dataDriveInfo.VolumeLabel} ({dataDriveInfo.RootDirectory})' on '{Environment.MachineName}'. This is less than {percentageThreshold}% - the minimal required space configured. The threshold can be set using the {RavenBootstrapper.MinimumStorageLeftRequiredForIngestionKey} configuration setting."; - Logger.Warn(message); + logger.LogWarning("Error message ingestion stopped! {PercentRemaining:P0} disk space remaining on data drive '{DataDriveInfoVolumeLabel} ({DataDriveInfoRootDirectory})' on '{MachineName}'. This is less than {PercentageThreshold}% - the minimal required space configured. The threshold can be set using the {RavenBootstrapperMinimumStorageLeftRequiredForIngestionKey} configuration setting.", + percentRemaining, + dataDriveInfo.VolumeLabel, + dataDriveInfo.RootDirectory, + Environment.MachineName, + percentageThreshold, + RavenBootstrapper.MinimumStorageLeftRequiredForIngestionKey); stateHolder.CanIngestMore = false; - return CheckResult.Failed(message); + return CheckResult.Failed($"Error message ingestion stopped! {percentRemaining:P0} disk space remaining on data drive '{dataDriveInfo.VolumeLabel} ({dataDriveInfo.RootDirectory})' on '{Environment.MachineName}'. This is less than {percentageThreshold}% - the minimal required space configured. The threshold can be set using the {RavenBootstrapper.MinimumStorageLeftRequiredForIngestionKey} configuration setting."); } public static void Validate(RavenPersisterSettings settings) { + var logger = LoggerUtil.CreateStaticLogger(); var threshold = settings.MinimumStorageLeftRequiredForIngestion; if (threshold < 0) { - var message = $"{RavenBootstrapper.MinimumStorageLeftRequiredForIngestionKey} is invalid, minimum value is 0."; - Logger.Fatal(message); - throw new Exception(message); + logger.LogCritical("{RavenBootstrapperMinimumStorageLeftRequiredForIngestionKey} is invalid, minimum value is 0.", RavenBootstrapper.MinimumStorageLeftRequiredForIngestionKey); + throw new Exception($"{RavenBootstrapper.MinimumStorageLeftRequiredForIngestionKey} is invalid, minimum value is 0."); } if (threshold > 100) { - var message = $"{RavenBootstrapper.MinimumStorageLeftRequiredForIngestionKey} is invalid, maximum value is 100."; - Logger.Fatal(message); - throw new Exception(message); + logger.LogCritical("{RavenBootstrapperMinimumStorageLeftRequiredForIngestionKey} is invalid, maximum value is 100.", RavenBootstrapper.MinimumStorageLeftRequiredForIngestionKey); + throw new Exception($"{RavenBootstrapper.MinimumStorageLeftRequiredForIngestionKey} is invalid, maximum value is 100."); } } public const int MinimumStorageLeftRequiredForIngestionDefault = 5; static readonly Task SuccessResult = Task.FromResult(CheckResult.Pass); - static readonly ILog Logger = LogManager.GetLogger(typeof(CheckMinimumStorageRequiredForIngestion)); } } \ No newline at end of file diff --git a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexErrors.cs b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexErrors.cs index 5567aa7507..89ea567a80 100644 --- a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexErrors.cs +++ b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexErrors.cs @@ -5,12 +5,12 @@ using System.Text; using System.Threading; using System.Threading.Tasks; + using Microsoft.Extensions.Logging; using NServiceBus.CustomChecks; - using NServiceBus.Logging; using Raven.Client.Documents.Operations.Indexes; using ServiceControl.Persistence.RavenDB; - class CheckRavenDBIndexErrors(IRavenDocumentStoreProvider documentStoreProvider) : CustomCheck("Error Database Index Errors", "ServiceControl Health", TimeSpan.FromMinutes(5)) + class CheckRavenDBIndexErrors(IRavenDocumentStoreProvider documentStoreProvider, ILogger logger) : CustomCheck("Error Database Index Errors", "ServiceControl Health", TimeSpan.FromMinutes(5)) { public override async Task PerformCheck(CancellationToken cancellationToken = default) { @@ -41,10 +41,8 @@ public override async Task PerformCheck(CancellationToken cancellat text.AppendLine().AppendLine("See: https://docs.particular.net/search?q=servicecontrol+troubleshooting"); var message = text.ToString(); - Logger.Error(message); + logger.LogError(message); return CheckResult.Failed(message); } - - static readonly ILog Logger = LogManager.GetLogger(); } } diff --git a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexLag.cs b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexLag.cs index 7084d78e34..d0fd05de1c 100644 --- a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexLag.cs +++ b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexLag.cs @@ -5,13 +5,13 @@ using System.Text; using System.Threading; using System.Threading.Tasks; + using Microsoft.Extensions.Logging; using NServiceBus.CustomChecks; - using NServiceBus.Logging; using Raven.Client.Documents.Operations; using ServiceControl.Persistence.RavenDB; using CustomCheck = NServiceBus.CustomChecks.CustomCheck; - class CheckRavenDBIndexLag(IRavenDocumentStoreProvider documentStoreProvider) : CustomCheck("Error Database Index Lag", "ServiceControl Health", TimeSpan.FromMinutes(5)) + class CheckRavenDBIndexLag(IRavenDocumentStoreProvider documentStoreProvider, ILogger logger) : CustomCheck("Error Database Index Lag", "ServiceControl Health", TimeSpan.FromMinutes(5)) { public override async Task PerformCheck(CancellationToken cancellationToken = default) { @@ -31,7 +31,7 @@ public override async Task PerformCheck(CancellationToken cancellat return CheckResult.Pass; } - static int CheckAndReportIndexesWithTooMuchIndexLag(IndexInformation[] indexes) + int CheckAndReportIndexesWithTooMuchIndexLag(IndexInformation[] indexes) { int indexCountWithTooMuchLag = 0; @@ -44,12 +44,12 @@ static int CheckAndReportIndexesWithTooMuchIndexLag(IndexInformation[] indexes) if (indexLag > IndexLagThresholdError) { indexCountWithTooMuchLag++; - Log.Error($"Index [{indexStats.Name}] IndexingLag {indexLag} is above error threshold ({IndexLagThresholdError}). Launch in maintenance mode to let indexes catch up."); + logger.LogError("Index [{IndexName}] IndexingLag {IndexLag} is above error threshold ({IndexLagThresholdError}). Launch in maintenance mode to let indexes catch up.", indexStats.Name, indexLag, IndexLagThresholdError); } else if (indexLag > IndexLagThresholdWarning) { indexCountWithTooMuchLag++; - Log.Warn($"Index [{indexStats.Name}] IndexingLag {indexLag} is above warning threshold ({IndexLagThresholdWarning}). Launch in maintenance mode to let indexes catch up."); + logger.LogWarning("Index [{IndexName}] IndexingLag {IndexLag} is above warning threshold ({IndexLagThresholdWarning}). Launch in maintenance mode to let indexes catch up.", indexStats.Name, indexLag, IndexLagThresholdWarning); } } } @@ -57,9 +57,9 @@ static int CheckAndReportIndexesWithTooMuchIndexLag(IndexInformation[] indexes) return indexCountWithTooMuchLag; } - static void CreateDiagnosticsLogEntry(DatabaseStatistics statistics, IndexInformation[] indexes) + void CreateDiagnosticsLogEntry(DatabaseStatistics statistics, IndexInformation[] indexes) { - if (!Log.IsDebugEnabled) + if (!logger.IsEnabled(LogLevel.Debug)) { return; } @@ -73,11 +73,10 @@ static void CreateDiagnosticsLogEntry(DatabaseStatistics statistics, IndexInform { report.AppendLine($"- Index [{indexStats.Name,-44}] State: {indexStats.State}, Stale: {indexStats.IsStale,-5}, Priority: {indexStats.Priority,-6}, LastIndexingTime: {indexStats.LastIndexingTime:u}"); } - Log.Debug(report.ToString()); + logger.LogDebug(report.ToString()); } static readonly TimeSpan IndexLagThresholdWarning = TimeSpan.FromMinutes(1); static readonly TimeSpan IndexLagThresholdError = TimeSpan.FromMinutes(10); - static readonly ILog Log = LogManager.GetLogger(); } } \ No newline at end of file diff --git a/src/ServiceControl.Persistence.RavenDB/ErrorMessagesDataStore.cs b/src/ServiceControl.Persistence.RavenDB/ErrorMessagesDataStore.cs index 4c3f77bf6d..4940807646 100644 --- a/src/ServiceControl.Persistence.RavenDB/ErrorMessagesDataStore.cs +++ b/src/ServiceControl.Persistence.RavenDB/ErrorMessagesDataStore.cs @@ -6,7 +6,7 @@ using System.Linq; using System.Threading.Tasks; using Editing; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using Raven.Client; using Raven.Client.Documents; using Raven.Client.Documents.Commands; @@ -28,7 +28,8 @@ class ErrorMessagesDataStore( IRavenSessionProvider sessionProvider, IRavenDocumentStoreProvider documentStoreProvider, IBodyStorage bodyStorage, - ExpirationManager expirationManager) + ExpirationManager expirationManager, + ILogger logger) : IErrorMessageDataStore { public async Task>> GetAllMessages( @@ -338,7 +339,7 @@ public async Task ErrorLastBy(string failedMessageId) return result; } - static FailedMessageView Map(FailedMessage message, IAsyncDocumentSession session) + FailedMessageView Map(FailedMessage message, IAsyncDocumentSession session) { var processingAttempt = message.ProcessingAttempts.Last(); @@ -369,7 +370,7 @@ static FailedMessageView Map(FailedMessage message, IAsyncDocumentSession sessio } catch (Exception ex) { - Logger.Warn($"Unable to parse SendingEndpoint from metadata for messageId {message.UniqueMessageId}", ex); + logger.LogWarning(ex, "Unable to parse SendingEndpoint from metadata for messageId {UniqueMessageId}", message.UniqueMessageId); failedMsgView.SendingEndpoint = EndpointDetailsParser.SendingEndpoint(processingAttempt.Headers); } @@ -379,7 +380,7 @@ static FailedMessageView Map(FailedMessage message, IAsyncDocumentSession sessio } catch (Exception ex) { - Logger.Warn($"Unable to parse ReceivingEndpoint from metadata for messageId {message.UniqueMessageId}", ex); + logger.LogWarning(ex, "Unable to parse ReceivingEndpoint from metadata for messageId {UniqueMessageId}", message.UniqueMessageId); failedMsgView.ReceivingEndpoint = EndpointDetailsParser.ReceivingEndpoint(processingAttempt.Headers); } @@ -676,7 +677,5 @@ public async Task StoreFailedMessagesForTestsOnly(params FailedMessage[] failedM await session.SaveChangesAsync(); } - - static readonly ILog Logger = LogManager.GetLogger(); } } diff --git a/src/ServiceControl.Persistence.RavenDB/FailedErrorImportDataStore.cs b/src/ServiceControl.Persistence.RavenDB/FailedErrorImportDataStore.cs index 440468a790..730413af0b 100644 --- a/src/ServiceControl.Persistence.RavenDB/FailedErrorImportDataStore.cs +++ b/src/ServiceControl.Persistence.RavenDB/FailedErrorImportDataStore.cs @@ -3,14 +3,12 @@ using System; using System.Threading; using System.Threading.Tasks; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using Raven.Client.Documents.Commands; using ServiceControl.Operations; - class FailedErrorImportDataStore(IRavenSessionProvider sessionProvider) : IFailedErrorImportDataStore + class FailedErrorImportDataStore(IRavenSessionProvider sessionProvider, ILogger logger) : IFailedErrorImportDataStore { - static readonly ILog Logger = LogManager.GetLogger(typeof(FailedErrorImportDataStore)); - public async Task ProcessFailedErrorImports(Func processMessage, CancellationToken cancellationToken) { var succeeded = 0; @@ -30,28 +28,25 @@ public async Task ProcessFailedErrorImports(Func p succeeded++; - if (Logger.IsDebugEnabled) - { - Logger.Debug($"Successfully re-imported failed error message {transportMessage.Id}."); - } + logger.LogDebug("Successfully re-imported failed error message {MessageId}", transportMessage.Id); } catch (OperationCanceledException e) when (cancellationToken.IsCancellationRequested) { - Logger.Info("Cancelled", e); + logger.LogInformation(e, "Cancelled"); } catch (Exception e) { - Logger.Error($"Error while attempting to re-import failed error message {transportMessage.Id}.", e); + logger.LogError(e, "Error while attempting to re-import failed error message {MessageId}.", transportMessage.Id); failed++; } } } - Logger.Info($"Done re-importing failed errors. Successfully re-imported {succeeded} messages. Failed re-importing {failed} messages."); + logger.LogInformation("Done re-importing failed errors. Successfully re-imported {SucceededCount} messages. Failed re-importing {FailedCount} messages.", succeeded, failed); if (failed > 0) { - Logger.Warn($"{failed} messages could not be re-imported. This could indicate a problem with the data. Contact Particular support if you need help with recovering the messages."); + logger.LogWarning("{FailedCount} messages could not be re-imported. This could indicate a problem with the data. Contact Particular support if you need help with recovering the messages.", failed); } } diff --git a/src/ServiceControl.Persistence.RavenDB/FailedMessageViewIndexNotifications.cs b/src/ServiceControl.Persistence.RavenDB/FailedMessageViewIndexNotifications.cs index 690bc056bb..83b2370b36 100644 --- a/src/ServiceControl.Persistence.RavenDB/FailedMessageViewIndexNotifications.cs +++ b/src/ServiceControl.Persistence.RavenDB/FailedMessageViewIndexNotifications.cs @@ -5,12 +5,12 @@ using System.Threading.Tasks; using Api; using Microsoft.Extensions.Hosting; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using Persistence; using Persistence.RavenDB; using Raven.Client.Documents; - class FailedMessageViewIndexNotifications(IRavenSessionProvider sessionProvider, IRavenDocumentStoreProvider documentStoreProvider) : IFailedMessageViewIndexNotifications + class FailedMessageViewIndexNotifications(IRavenSessionProvider sessionProvider, IRavenDocumentStoreProvider documentStoreProvider, ILogger logger) : IFailedMessageViewIndexNotifications , IDisposable , IHostedService { @@ -22,7 +22,7 @@ void OnNext() } catch (Exception ex) { - Logger.WarnFormat("Failed to emit MessageFailuresUpdated - {0}", ex); + logger.LogWarning(ex, "Failed to emit MessageFailuresUpdated"); } } @@ -87,8 +87,6 @@ public Task StopAsync(CancellationToken cancellationToken) return Task.CompletedTask; } - static readonly ILog Logger = LogManager.GetLogger(typeof(FailedMessageViewIndexNotifications)); - Func subscriber; IDisposable subscription; int lastUnresolvedCount; diff --git a/src/ServiceControl.Persistence.RavenDB/Infrastructure/Subscriptions/RavenSubscriptionStorage.cs b/src/ServiceControl.Persistence.RavenDB/Infrastructure/Subscriptions/RavenSubscriptionStorage.cs index fdf1520dd6..6b8218b753 100644 --- a/src/ServiceControl.Persistence.RavenDB/Infrastructure/Subscriptions/RavenSubscriptionStorage.cs +++ b/src/ServiceControl.Persistence.RavenDB/Infrastructure/Subscriptions/RavenSubscriptionStorage.cs @@ -7,9 +7,9 @@ using System.Text; using System.Threading; using System.Threading.Tasks; + using Microsoft.Extensions.Logging; using NServiceBus; using NServiceBus.Extensibility; - using NServiceBus.Logging; using NServiceBus.Settings; using NServiceBus.Unicast.Subscriptions; using NServiceBus.Unicast.Subscriptions.MessageDrivenSubscriptions; @@ -21,12 +21,12 @@ class RavenSubscriptionStorage : IServiceControlSubscriptionStorage { - public RavenSubscriptionStorage(IRavenSessionProvider sessionProvider, IReadOnlySettings settings, ReceiveAddresses receiveAddresses) : - this(sessionProvider, settings.EndpointName(), receiveAddresses.MainReceiveAddress, settings.GetAvailableTypes().Implementing().Select(e => new MessageType(e)).ToArray()) + public RavenSubscriptionStorage(IRavenSessionProvider sessionProvider, IReadOnlySettings settings, ReceiveAddresses receiveAddresses, ILogger logger) : + this(sessionProvider, settings.EndpointName(), receiveAddresses.MainReceiveAddress, settings.GetAvailableTypes().Implementing().Select(e => new MessageType(e)).ToArray(), logger) { } - public RavenSubscriptionStorage(IRavenSessionProvider sessionProvider, string endpointName, string localAddress, MessageType[] locallyHandledEventTypes) + public RavenSubscriptionStorage(IRavenSessionProvider sessionProvider, string endpointName, string localAddress, MessageType[] locallyHandledEventTypes, ILogger logger) { this.sessionProvider = sessionProvider; localClient = new SubscriptionClient @@ -36,7 +36,7 @@ public RavenSubscriptionStorage(IRavenSessionProvider sessionProvider, string en }; this.locallyHandledEventTypes = locallyHandledEventTypes; - + this.logger = logger; subscriptions = new Subscriptions(); UpdateLookup(); } @@ -198,9 +198,9 @@ async Task SetSubscriptions(Subscriptions newSubscriptions) static Task LoadSubscriptions(IAsyncDocumentSession session) => session.LoadAsync(Subscriptions.SingleDocumentId); - static async Task MigrateSubscriptions(IAsyncDocumentSession session, SubscriptionClient localClient) + async Task MigrateSubscriptions(IAsyncDocumentSession session, SubscriptionClient localClient) { - Logger.Info("Migrating subscriptions to new format"); + logger.LogInformation("Migrating subscriptions to new format"); var subscriptions = new Subscriptions(); @@ -224,10 +224,8 @@ static async Task MigrateSubscriptions(IAsyncDocumentSession sess Subscriptions subscriptions; ILookup subscriptionsLookup; MessageType[] locallyHandledEventTypes; - + readonly ILogger logger; SemaphoreSlim subscriptionsLock = new SemaphoreSlim(1); - - static readonly ILog Logger = LogManager.GetLogger(); } class Subscriptions diff --git a/src/ServiceControl.Persistence.RavenDB/RavenEmbeddedPersistenceLifecycle.cs b/src/ServiceControl.Persistence.RavenDB/RavenEmbeddedPersistenceLifecycle.cs index f1971af65c..f0172acff7 100644 --- a/src/ServiceControl.Persistence.RavenDB/RavenEmbeddedPersistenceLifecycle.cs +++ b/src/ServiceControl.Persistence.RavenDB/RavenEmbeddedPersistenceLifecycle.cs @@ -6,12 +6,12 @@ namespace ServiceControl.Persistence.RavenDB using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Hosting; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using Raven.Client.Documents; using Raven.Client.Exceptions.Database; using ServiceControl.RavenDB; - sealed class RavenEmbeddedPersistenceLifecycle(RavenPersisterSettings databaseConfiguration, IHostApplicationLifetime lifetime) + sealed class RavenEmbeddedPersistenceLifecycle(RavenPersisterSettings databaseConfiguration, IHostApplicationLifetime lifetime, ILogger logger) : IRavenPersistenceLifecycle, IRavenDocumentStoreProvider, IDisposable { public async ValueTask GetDocumentStore(CancellationToken cancellationToken = default) @@ -58,7 +58,7 @@ public async Task Initialize(CancellationToken cancellationToken) } catch (DatabaseLoadTimeoutException e) { - Log.Warn("Could not connect to database. Retrying in 500ms...", e); + logger.LogWarning(e, "Could not connect to database. Retrying in 500ms..."); await Task.Delay(500, cancellationToken); } } @@ -86,7 +86,5 @@ public void Dispose() IDocumentStore? documentStore; EmbeddedDatabase? database; readonly SemaphoreSlim initializeSemaphore = new(1, 1); - - static readonly ILog Log = LogManager.GetLogger(typeof(RavenEmbeddedPersistenceLifecycle)); } } \ No newline at end of file diff --git a/src/ServiceControl.Persistence.RavenDB/Recoverability/Archiving/ArchiveDocumentManager.cs b/src/ServiceControl.Persistence.RavenDB/Recoverability/Archiving/ArchiveDocumentManager.cs index 46589133a4..c83e693141 100644 --- a/src/ServiceControl.Persistence.RavenDB/Recoverability/Archiving/ArchiveDocumentManager.cs +++ b/src/ServiceControl.Persistence.RavenDB/Recoverability/Archiving/ArchiveDocumentManager.cs @@ -5,14 +5,14 @@ using System.Linq; using System.Threading.Tasks; using MessageFailures; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using Persistence.RavenDB; using Raven.Client.Documents; using Raven.Client.Documents.Commands.Batches; using Raven.Client.Documents.Operations; using Raven.Client.Documents.Session; - class ArchiveDocumentManager(ExpirationManager expirationManager) + class ArchiveDocumentManager(ExpirationManager expirationManager, ILogger logger) { public Task LoadArchiveOperation(IAsyncDocumentSession session, string groupId, ArchiveType archiveType) => session.LoadAsync(ArchiveOperation.MakeId(groupId, archiveType)); @@ -138,7 +138,7 @@ public async Task RemoveArchiveOperation(IRavenSessionProvider sessionProvider, session.Advanced.Defer(new DeleteCommandData(archiveOperation.Id, null)); await session.SaveChangesAsync(); - Logger.Info($"Removing ArchiveOperation {archiveOperation.Id} completed"); + logger.LogInformation("Removing ArchiveOperation {ArchiveOperationId} completed", archiveOperation.Id); } public class GroupDetails @@ -147,6 +147,5 @@ public class GroupDetails public int NumberOfMessagesInGroup { get; set; } } - static readonly ILog Logger = LogManager.GetLogger(); } } \ No newline at end of file diff --git a/src/ServiceControl.Persistence.RavenDB/Recoverability/Archiving/MessageArchiver.cs b/src/ServiceControl.Persistence.RavenDB/Recoverability/Archiving/MessageArchiver.cs index caf8715282..64f722bbe2 100644 --- a/src/ServiceControl.Persistence.RavenDB/Recoverability/Archiving/MessageArchiver.cs +++ b/src/ServiceControl.Persistence.RavenDB/Recoverability/Archiving/MessageArchiver.cs @@ -4,8 +4,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; - using NServiceBus.Logging; - using Raven.Client.Documents; + using Microsoft.Extensions.Logging; using RavenDB; using ServiceControl.Infrastructure.DomainEvents; using ServiceControl.Persistence.Recoverability; @@ -17,15 +16,17 @@ public MessageArchiver( IRavenSessionProvider sessionProvider, OperationsManager operationsManager, IDomainEvents domainEvents, - ExpirationManager expirationManager + ExpirationManager expirationManager, + ILogger logger ) { this.sessionProvider = sessionProvider; this.domainEvents = domainEvents; this.expirationManager = expirationManager; + this.logger = logger; this.operationsManager = operationsManager; - archiveDocumentManager = new ArchiveDocumentManager(expirationManager); + archiveDocumentManager = new ArchiveDocumentManager(expirationManager, logger); archivingManager = new ArchivingManager(domainEvents, operationsManager); unarchiveDocumentManager = new UnarchiveDocumentManager(); @@ -34,7 +35,7 @@ ExpirationManager expirationManager public async Task ArchiveAllInGroup(string groupId) { - logger.Info($"Archiving of {groupId} started"); + logger.LogInformation("Archiving of {GroupId} started", groupId); ArchiveOperation archiveOperation; using (var session = await sessionProvider.OpenSession()) @@ -48,15 +49,15 @@ public async Task ArchiveAllInGroup(string groupId) var groupDetails = await archiveDocumentManager.GetGroupDetails(session, groupId); if (groupDetails.NumberOfMessagesInGroup == 0) { - logger.Warn($"No messages to archive in group {groupId}"); + logger.LogWarning("No messages to archive in group {GroupId}", groupId); return; } - logger.Info($"Splitting group {groupId} into batches"); + logger.LogInformation("Splitting group {GroupId} into batches", groupId); archiveOperation = await archiveDocumentManager.CreateArchiveOperation(session, groupId, ArchiveType.FailureGroup, groupDetails.NumberOfMessagesInGroup, groupDetails.GroupName, batchSize); await session.SaveChangesAsync(); - logger.Info($"Group {groupId} has been split into {archiveOperation.NumberOfBatches} batches"); + logger.LogInformation("Group {GroupId} has been split into {NumberOfBatches} batches", groupId, archiveOperation.NumberOfBatches); } } @@ -70,11 +71,11 @@ public async Task ArchiveAllInGroup(string groupId) if (nextBatch == null) { // We're only here in the case where Raven indexes are stale - logger.Warn($"Attempting to archive a batch ({archiveOperation.Id}/{archiveOperation.CurrentBatch}) which appears to already have been archived."); + logger.LogWarning("Attempting to archive a batch ({ArchiveOperationId}/{ArchiveOperationCurrentBatch}) which appears to already have been archived.", archiveOperation.Id, archiveOperation.CurrentBatch); } else { - logger.Info($"Archiving {nextBatch.DocumentIds.Count} messages from group {groupId} starting"); + logger.LogInformation("Archiving {MessageCount} messages from group {GroupId} starting", nextBatch.DocumentIds.Count, groupId); } archiveDocumentManager.ArchiveMessageGroupBatch(batchSession, nextBatch); @@ -98,17 +99,17 @@ await domainEvents.Raise(new FailedMessageGroupBatchArchived if (nextBatch != null) { - logger.Info($"Archiving of {nextBatch.DocumentIds.Count} messages from group {groupId} completed"); + logger.LogInformation("Archiving of {MessageCount} messages from group {GroupId} completed", nextBatch.DocumentIds.Count, groupId); } } } - logger.Info($"Archiving of group {groupId} is complete. Waiting for index updates."); + logger.LogInformation("Archiving of group {GroupId} is complete. Waiting for index updates.", groupId); await archivingManager.ArchiveOperationFinalizing(archiveOperation.RequestId, archiveOperation.ArchiveType); if (!await archiveDocumentManager.WaitForIndexUpdateOfArchiveOperation(sessionProvider, archiveOperation.RequestId, TimeSpan.FromMinutes(5)) ) { - logger.Warn($"Archiving group {groupId} completed but index not updated."); + logger.LogWarning("Archiving group {GroupId} completed but index not updated.", groupId); } await archivingManager.ArchiveOperationCompleted(archiveOperation.RequestId, archiveOperation.ArchiveType); @@ -121,12 +122,12 @@ await domainEvents.Raise(new FailedMessageGroupArchived MessagesCount = archiveOperation.TotalNumberOfMessages, }); - logger.Info($"Archiving of group {groupId} completed"); + logger.LogInformation("Archiving of group {GroupId} completed", groupId); } public async Task UnarchiveAllInGroup(string groupId) { - logger.Info($"Unarchiving of {groupId} started"); + logger.LogInformation("Unarchiving of {GroupId} started", groupId); UnarchiveOperation unarchiveOperation; using (var session = await sessionProvider.OpenSession()) @@ -140,16 +141,16 @@ public async Task UnarchiveAllInGroup(string groupId) var groupDetails = await unarchiveDocumentManager.GetGroupDetails(session, groupId); if (groupDetails.NumberOfMessagesInGroup == 0) { - logger.Warn($"No messages to unarchive in group {groupId}"); + logger.LogWarning("No messages to unarchive in group {GroupId}", groupId); return; } - logger.Info($"Splitting group {groupId} into batches"); + logger.LogInformation("Splitting group {GroupId} into batches", groupId); unarchiveOperation = await unarchiveDocumentManager.CreateUnarchiveOperation(session, groupId, ArchiveType.FailureGroup, groupDetails.NumberOfMessagesInGroup, groupDetails.GroupName, batchSize); await session.SaveChangesAsync(); - logger.Info($"Group {groupId} has been split into {unarchiveOperation.NumberOfBatches} batches"); + logger.LogInformation("Group {GroupId} has been split into {NumberOfBatches} batches", groupId, unarchiveOperation.NumberOfBatches); } } @@ -162,11 +163,11 @@ public async Task UnarchiveAllInGroup(string groupId) if (nextBatch == null) { // We're only here in the case where Raven indexes are stale - logger.Warn($"Attempting to unarchive a batch ({unarchiveOperation.Id}/{unarchiveOperation.CurrentBatch}) which appears to already have been archived."); + logger.LogWarning("Attempting to unarchive a batch ({UnarchiveOperationId}/{UnarchiveOperationCurrentBatch}) which appears to already have been archived.", unarchiveOperation.Id, unarchiveOperation.CurrentBatch); } else { - logger.Info($"Unarchiving {nextBatch.DocumentIds.Count} messages from group {groupId} starting"); + logger.LogInformation("Unarchiving {MessageCount} messages from group {GroupId} starting", nextBatch.DocumentIds.Count, groupId); } unarchiveDocumentManager.UnarchiveMessageGroupBatch(batchSession, nextBatch, expirationManager); @@ -190,19 +191,19 @@ await domainEvents.Raise(new FailedMessageGroupBatchUnarchived if (nextBatch != null) { - logger.Info($"Unarchiving of {nextBatch.DocumentIds.Count} messages from group {groupId} completed"); + logger.LogInformation("Unarchiving of {MessageCount} messages from group {GroupId} completed", nextBatch.DocumentIds.Count, groupId); } } - logger.Info($"Unarchiving of group {groupId} is complete. Waiting for index updates."); + logger.LogInformation("Unarchiving of group {GroupId} is complete. Waiting for index updates.", groupId); await unarchivingManager.UnarchiveOperationFinalizing(unarchiveOperation.RequestId, unarchiveOperation.ArchiveType); if (!await unarchiveDocumentManager.WaitForIndexUpdateOfUnarchiveOperation(sessionProvider, unarchiveOperation.RequestId, TimeSpan.FromMinutes(5)) ) { - logger.Warn($"Unarchiving group {groupId} completed but index not updated."); + logger.LogWarning("Unarchiving group {GroupId} completed but index not updated.", groupId); } - logger.Info($"Unarchiving of group {groupId} completed"); + logger.LogInformation("Unarchiving of group {GroupId} completed", groupId); await unarchivingManager.UnarchiveOperationCompleted(unarchiveOperation.RequestId, unarchiveOperation.ArchiveType); await unarchiveDocumentManager.RemoveUnarchiveOperation(sessionProvider, unarchiveOperation); @@ -239,7 +240,7 @@ public IEnumerable GetArchivalOperations() readonly ArchivingManager archivingManager; readonly UnarchiveDocumentManager unarchiveDocumentManager; readonly UnarchivingManager unarchivingManager; - static readonly ILog logger = LogManager.GetLogger(); + readonly ILogger logger; const int batchSize = 1000; } } diff --git a/src/ServiceControl.Persistence.RavenDB/RetryBatchesDataStore.cs b/src/ServiceControl.Persistence.RavenDB/RetryBatchesDataStore.cs index 3138d9b893..4d951b9354 100644 --- a/src/ServiceControl.Persistence.RavenDB/RetryBatchesDataStore.cs +++ b/src/ServiceControl.Persistence.RavenDB/RetryBatchesDataStore.cs @@ -4,18 +4,16 @@ using System.Collections.Generic; using System.Threading.Tasks; using MessageFailures; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using Raven.Client.Documents.Commands; using Raven.Client.Documents.Commands.Batches; using Raven.Client.Documents.Operations; using Raven.Client.Exceptions; using ServiceControl.Recoverability; - class RetryBatchesDataStore(IRavenSessionProvider sessionProvider, IRavenDocumentStoreProvider documentStoreProvider, ExpirationManager expirationManager) + class RetryBatchesDataStore(IRavenSessionProvider sessionProvider, IRavenDocumentStoreProvider documentStoreProvider, ExpirationManager expirationManager, ILogger logger) : IRetryBatchesDataStore { - static readonly ILog Log = LogManager.GetLogger(typeof(RetryBatchesDataStore)); - public async Task CreateRetryBatchesManager() { var session = await sessionProvider.OpenSession(); @@ -32,7 +30,7 @@ public async Task RecordFailedStagingAttempt(IReadOnlyCollection { var failedMessageRetry = failedMessageRetriesById[failedMessage.Id]; - Log.Warn($"Attempt {1} of {maxStagingAttempts} to stage a retry message {failedMessage.UniqueMessageId} failed", e); + logger.LogWarning(e, "Attempt 1 of {MaxStagingAttempts} to stage a retry message {UniqueMessageId} failed", maxStagingAttempts, failedMessage.UniqueMessageId); commands[commandIndex] = new PatchCommandData(failedMessageRetry.Id, null, new PatchRequest { @@ -57,8 +55,8 @@ public async Task RecordFailedStagingAttempt(IReadOnlyCollection } catch (ConcurrencyException) { - Log.DebugFormat( - "Ignoring concurrency exception while incrementing staging attempt count for {0}", + logger.LogDebug( + "Ignoring concurrency exception while incrementing staging attempt count for {StagingId}", stagingId); } } @@ -75,7 +73,7 @@ public async Task IncrementAttemptCounter(FailedMessageRetry message) } catch (ConcurrencyException) { - Log.DebugFormat("Ignoring concurrency exception while incrementing staging attempt count for {0}", message.FailedMessageId); + logger.LogDebug("Ignoring concurrency exception while incrementing staging attempt count for {MessageId}", message.FailedMessageId); } } diff --git a/src/ServiceControl.Persistence.RavenDB/RetryDocumentDataStore.cs b/src/ServiceControl.Persistence.RavenDB/RetryDocumentDataStore.cs index 5d5270cc14..686b77df9f 100644 --- a/src/ServiceControl.Persistence.RavenDB/RetryDocumentDataStore.cs +++ b/src/ServiceControl.Persistence.RavenDB/RetryDocumentDataStore.cs @@ -5,7 +5,7 @@ using System.Linq; using System.Threading.Tasks; using MessageFailures; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using Persistence.Infrastructure; using Raven.Client.Documents; using Raven.Client.Documents.Commands.Batches; @@ -15,7 +15,7 @@ using ServiceControl.MessageFailures.Api; using ServiceControl.Recoverability; - class RetryDocumentDataStore(IRavenSessionProvider sessionProvider, IRavenDocumentStoreProvider documentStoreProvider) : IRetryDocumentDataStore + class RetryDocumentDataStore(IRavenSessionProvider sessionProvider, IRavenDocumentStoreProvider documentStoreProvider, ILogger logger) : IRetryDocumentDataStore { public async Task StageRetryByUniqueMessageIds(string batchDocumentId, string[] messageIds) { @@ -48,7 +48,7 @@ public async Task MoveBatchToStaging(string batchDocumentId) } catch (ConcurrencyException) { - Logger.DebugFormat("Ignoring concurrency exception while moving batch to staging {0}", batchDocumentId); + logger.LogDebug("Ignoring concurrency exception while moving batch to staging {BatchDocumentId}", batchDocumentId); } } @@ -202,7 +202,5 @@ public async Task QueryFailureGroupViewOnGroupId(string groupI .FirstOrDefaultAsync(x => x.Id == groupId); return group; } - - static readonly ILog Logger = LogManager.GetLogger(typeof(RetryDocumentDataStore)); } } \ No newline at end of file diff --git a/src/ServiceControl.Persistence.Tests.RavenDB/SubscriptionPersisterTests.cs b/src/ServiceControl.Persistence.Tests.RavenDB/SubscriptionPersisterTests.cs index bf60c59a17..1a5b35664c 100644 --- a/src/ServiceControl.Persistence.Tests.RavenDB/SubscriptionPersisterTests.cs +++ b/src/ServiceControl.Persistence.Tests.RavenDB/SubscriptionPersisterTests.cs @@ -8,6 +8,7 @@ using NServiceBus.Unicast.Subscriptions; using NServiceBus.Unicast.Subscriptions.MessageDrivenSubscriptions; using NUnit.Framework; + using ServiceControl.Infrastructure; using ServiceControl.Infrastructure.RavenDB.Subscriptions; [TestFixture] @@ -16,7 +17,7 @@ class SubscriptionPersisterTests : RavenPersistenceTestBase [Test] public async Task ShouldReturnSubscriptionsForOlderVersionsOfSameMessageType() { - var subscriptionPersister = new RavenSubscriptionStorage(SessionProvider, "NServiceBus.Routing.EndpointName", "TestEndpoint", []); + var subscriptionPersister = new RavenSubscriptionStorage(SessionProvider, "NServiceBus.Routing.EndpointName", "TestEndpoint", [], LoggerUtil.CreateStaticLogger()); var v1MessageType = new MessageType(typeof(SampleMessageType).FullName, new Version(1, 0, 0)); var v2MessageType = new MessageType(typeof(SampleMessageType).FullName, new Version(2, 0, 0)); @@ -37,7 +38,7 @@ public async Task ShouldReturnSubscriptionsForOlderVersionsOfSameMessageType() [Test] public async Task ShouldReturnSubscriptionsForNewerVersionsOfSameMessageType() { - var subscriptionPersister = new RavenSubscriptionStorage(SessionProvider, "NServiceBus.Routing.EndpointName", "TestEndpoint", []); + var subscriptionPersister = new RavenSubscriptionStorage(SessionProvider, "NServiceBus.Routing.EndpointName", "TestEndpoint", [], LoggerUtil.CreateStaticLogger()); var v1MessageType = new MessageType(typeof(SampleMessageType).FullName, new Version(1, 0, 0)); var v2MessageType = new MessageType(typeof(SampleMessageType).FullName, new Version(2, 0, 0)); diff --git a/src/ServiceControl.Persistence/PersistenceManifest.cs b/src/ServiceControl.Persistence/PersistenceManifest.cs index 0be97cafb6..df6f0941f6 100644 --- a/src/ServiceControl.Persistence/PersistenceManifest.cs +++ b/src/ServiceControl.Persistence/PersistenceManifest.cs @@ -5,7 +5,9 @@ using System.IO; using System.Linq; using System.Text.Json; + using Microsoft.Extensions.Logging; using NServiceBus.Logging; + using ServiceControl.Infrastructure; public class PersistenceManifest { @@ -68,7 +70,7 @@ static PersistenceManifestLibrary() } catch (Exception ex) { - logger.Warn($"Failed to load persistence manifests from {assemblyDirectory}", ex); + logger.LogWarning(ex, "Failed to load persistence manifests from {AssemblyDirectory}", assemblyDirectory); } try @@ -83,10 +85,10 @@ static PersistenceManifestLibrary() } catch (Exception ex) { - logger.Warn($"Failed to load persistence manifests from development locations", ex); + logger.LogWarning(ex, "Failed to load persistence manifests from development locations"); } - PersistenceManifests.ForEach(m => logger.Info($"Found persistence manifest for {m.DisplayName}")); + PersistenceManifests.ForEach(m => logger.LogInformation("Found persistence manifest for {ManifestDisplayName}", m.DisplayName)); } static string GetAssemblyDirectory() @@ -107,7 +109,7 @@ public static PersistenceManifest Find(string persistenceType) return persistenceManifest; } - static readonly ILog logger = LogManager.GetLogger(typeof(PersistenceManifestLibrary)); + static readonly ILogger logger = LoggerUtil.CreateStaticLogger(typeof(PersistenceManifestLibrary)); } } diff --git a/src/ServiceControl.RavenDB/EmbeddedDatabase.cs b/src/ServiceControl.RavenDB/EmbeddedDatabase.cs index 590792fe20..e9fa10ea44 100644 --- a/src/ServiceControl.RavenDB/EmbeddedDatabase.cs +++ b/src/ServiceControl.RavenDB/EmbeddedDatabase.cs @@ -10,11 +10,12 @@ namespace ServiceControl.RavenDB using System.Threading.Tasks; using ByteSizeLib; using Microsoft.Extensions.Hosting; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using Raven.Client.Documents; using Raven.Client.Documents.Conventions; using Raven.Client.ServerWide.Operations; using Raven.Embedded; + using ServiceControl.Infrastructure; using Sparrow.Logging; public sealed class EmbeddedDatabase : IDisposable @@ -67,7 +68,7 @@ public static EmbeddedDatabase Start(EmbeddedDatabaseConfiguration databaseConfi ); } - Logger.InfoFormat("Loading RavenDB license from {0}", licenseFileNameAndServerDirectory.LicenseFileName); + logger.LogInformation("Loading RavenDB license from {LicenseFileName}", licenseFileNameAndServerDirectory.LicenseFileName); var serverOptions = new ServerOptions { CommandLineArgs = @@ -119,12 +120,12 @@ void Start(ServerOptions serverOptions) shutdownCancellationToken.ThrowIfCancellationRequested(); - Logger.Info("Restarting RavenDB server process"); + logger.LogInformation("Restarting RavenDB server process"); await EmbeddedServer.Instance.RestartServerAsync(); restartRequired = false; - Logger.Info("RavenDB server process restarted successfully."); + logger.LogInformation("RavenDB server process restarted successfully."); } catch (OperationCanceledException) when (shutdownCancellationToken.IsCancellationRequested) { @@ -132,7 +133,7 @@ void Start(ServerOptions serverOptions) } catch (Exception e) { - Logger.Fatal($"RavenDB server restart failed. Restart will be retried in {delayBetweenRestarts}.", e); + logger.LogCritical(e, "RavenDB server restart failed. Restart will be retried in {RavenDelayBetweenRestarts}.", delayBetweenRestarts); } } }, CancellationToken.None); @@ -148,11 +149,11 @@ void OnServerProcessExited(object? sender, ServerProcessExitedEventArgs _) restartRequired = true; if (sender is Process process) { - Logger.Warn($"RavenDB server process exited unexpectedly with exitCode: {process.ExitCode}. Process will be restarted."); + logger.LogWarning("RavenDB server process exited unexpectedly with exitCode: {RavenExitCode}. Process will be restarted.", process.ExitCode); } else { - Logger.Warn($"RavenDB server process exited unexpectedly. Process will be restarted."); + logger.LogWarning("RavenDB server process exited unexpectedly. Process will be restarted."); } } @@ -187,7 +188,7 @@ public async Task DeleteDatabase(string dbName) public async Task Stop(CancellationToken cancellationToken) { - Logger.Debug("Stopping RavenDB server"); + logger.LogDebug("Stopping RavenDB server"); EmbeddedServer.Instance.ServerProcessExited -= OnServerProcessExited; await shutdownTokenSource.CancelAsync(); @@ -224,23 +225,23 @@ public async Task Stop(CancellationToken cancellationToken) { // We always want to try and kill the process, even when already cancelled processId = await EmbeddedServer.Instance.GetServerProcessIdAsync(CancellationToken.None); - Logger.WarnFormat("Killing RavenDB server PID {0} because host cancelled", processId); + logger.LogWarning("Killing RavenDB server PID {PID} because host cancelled", processId); using var ravenChildProcess = Process.GetProcessById(processId); ravenChildProcess.Kill(entireProcessTree: true); // Kill only signals - Logger.WarnFormat("Waiting for RavenDB server PID {0} to exit... ", processId); + logger.LogWarning("Waiting for RavenDB server PID {PID} to exit... ", processId); // When WaitForExitAsync returns, the process could still exist but in a frozen state to flush // memory mapped pages to storage. await ravenChildProcess.WaitForExitAsync(CancellationToken.None); } catch (Exception e) { - Logger.ErrorFormat("Failed to kill RavenDB server PID {0} shutdown\n{1}", processId, e); + logger.LogError(e, "Failed to kill RavenDB server PID {PID} shutdown", processId); } } serverOptions = null!; - Logger.Debug("Stopped RavenDB server"); + logger.LogDebug("Stopped RavenDB server"); } public void Dispose() @@ -262,9 +263,9 @@ public void Dispose() // Set GracefulShutdownTimeout to Zero and exit ASAP, under normal operation instance would already // have been allowed to gracefully stop during "Stop" method. serverOptions!.GracefulShutdownTimeout = TimeSpan.Zero; - Logger.Debug("Disposing RavenDB server"); + logger.LogDebug("Disposing RavenDB server"); EmbeddedServer.Instance.Dispose(); - Logger.Debug("Disposed RavenDB server"); + logger.LogDebug("Disposed RavenDB server"); } shutdownTokenSource.Dispose(); @@ -287,7 +288,7 @@ static void RecordStartup(EmbeddedDatabaseConfiguration configuration) RavenDB Logging Level: {configuration.LogsMode} -------------------------------------------------------------"; - Logger.Info(startupMessage); + logger.LogInformation(startupMessage); } static long DataSize(EmbeddedDatabaseConfiguration configuration) @@ -354,6 +355,6 @@ static long DirSize(DirectoryInfo d) ServerOptions? serverOptions; static TimeSpan delayBetweenRestarts = TimeSpan.FromSeconds(60); - static readonly ILog Logger = LogManager.GetLogger(); + static readonly ILogger logger = LoggerUtil.CreateStaticLogger(); } } From 6df6fd2aed397c3acea595fea38550e901daf36b Mon Sep 17 00:00:00 2001 From: Phil Bastian Date: Thu, 19 Jun 2025 13:05:53 +0800 Subject: [PATCH 34/56] cleanup remaining references to LogManager --- .../TestSupport/ServiceControlComponentRunner.cs | 7 ++++--- .../TestSupport/ServiceControlComponentRunner.cs | 7 ++++--- .../LoggingConfigurator.cs | 10 ++++++---- .../RavenDbLogLevelToLogsModeMapper.cs | 5 +---- .../TestSupport/ServiceControlComponentRunner.cs | 15 ++++++++++----- .../ServiceControl.Persistence.csproj | 1 + .../HostApplicationBuilderExtensions.cs | 8 ++------ 7 files changed, 28 insertions(+), 25 deletions(-) diff --git a/src/ServiceControl.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs b/src/ServiceControl.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs index f1b3e58a01..8ac0a4454a 100644 --- a/src/ServiceControl.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs +++ b/src/ServiceControl.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs @@ -50,6 +50,7 @@ async Task InitializeServiceControl(ScenarioContext context) var logPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); Directory.CreateDirectory(logPath); var loggingSettings = new LoggingSettings(Settings.SettingsRootNamespace, defaultLevel: LogLevel.Debug, logPath: logPath); + LoggerUtil.ActiveLoggers = Loggers.Test; var settings = new Settings(transportToUse.TypeName, persistenceToUse.PersistenceType, loggingSettings, forwardErrorMessages: false, errorRetentionPeriod: TimeSpan.FromDays(10)) { @@ -65,9 +66,9 @@ async Task InitializeServiceControl(ScenarioContext context) { var headers = messageContext.Headers; var id = messageContext.NativeMessageId; - var log = NServiceBus.Logging.LogManager.GetLogger(); + var logger = LoggerUtil.CreateStaticLogger(loggingSettings.LogLevel); headers.TryGetValue(Headers.MessageId, out var originalMessageId); - log.Debug($"OnMessage for message '{id}'({originalMessageId ?? string.Empty})."); + logger.LogDebug("OnMessage for message '{MessageId}'({OriginalMessageId})", id, originalMessageId ?? string.Empty); //Do not filter out CC, SA and HB messages as they can't be stamped if (headers.TryGetValue(Headers.EnclosedMessageTypes, out var messageTypes) @@ -86,7 +87,7 @@ async Task InitializeServiceControl(ScenarioContext context) var currentSession = context.TestRunId.ToString(); if (!headers.TryGetValue("SC.SessionID", out var session) || session != currentSession) { - log.Debug($"Discarding message '{id}'({originalMessageId ?? string.Empty}) because it's session id is '{session}' instead of '{currentSession}'."); + logger.LogDebug("Discarding message '{MessageId}'({OriginalMessageId}) because it's session id is '{SessionId}' instead of '{CurrentSessionId}'", id, originalMessageId ?? string.Empty, session, currentSession); return true; } diff --git a/src/ServiceControl.Audit.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs b/src/ServiceControl.Audit.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs index 65e1b4752f..27ed1bfade 100644 --- a/src/ServiceControl.Audit.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs +++ b/src/ServiceControl.Audit.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs @@ -45,6 +45,7 @@ async Task InitializeServiceControl(ScenarioContext context) Directory.CreateDirectory(logPath); var loggingSettings = new LoggingSettings(Settings.SettingsRootNamespace, defaultLevel: LogLevel.Debug, logPath: logPath); + LoggerUtil.ActiveLoggers = Loggers.Test; settings = new Settings(transportToUse.TypeName, persistenceToUse.PersistenceType, loggingSettings) { @@ -56,9 +57,9 @@ async Task InitializeServiceControl(ScenarioContext context) { var id = messageContext.NativeMessageId; var headers = messageContext.Headers; - var log = LoggerUtil.CreateStaticLogger(); + var logger = LoggerUtil.CreateStaticLogger(loggingSettings.LogLevel); headers.TryGetValue(Headers.MessageId, out var originalMessageId); - log.LogDebug("OnMessage for message '{MessageId}'({OriginalMessageId}).", id, originalMessageId ?? string.Empty); + logger.LogDebug("OnMessage for message '{MessageId}'({OriginalMessageId}).", id, originalMessageId ?? string.Empty); //Do not filter out CC, SA and HB messages as they can't be stamped if (headers.TryGetValue(Headers.EnclosedMessageTypes, out var messageTypes) @@ -77,7 +78,7 @@ async Task InitializeServiceControl(ScenarioContext context) var currentSession = context.TestRunId.ToString(); if (!headers.TryGetValue("SC.SessionID", out var session) || session != currentSession) { - log.LogDebug("Discarding message '{MessageId}'({OriginalMessageId}) because it's session id is '{SessionId}' instead of '{CurrentSessionId}'.", id, originalMessageId ?? string.Empty, session, currentSession); + logger.LogDebug("Discarding message '{MessageId}'({OriginalMessageId}) because it's session id is '{SessionId}' instead of '{CurrentSessionId}'.", id, originalMessageId ?? string.Empty, session, currentSession); return true; } diff --git a/src/ServiceControl.Infrastructure/LoggingConfigurator.cs b/src/ServiceControl.Infrastructure/LoggingConfigurator.cs index 4845965394..848c6a3cf3 100644 --- a/src/ServiceControl.Infrastructure/LoggingConfigurator.cs +++ b/src/ServiceControl.Infrastructure/LoggingConfigurator.cs @@ -12,16 +12,19 @@ namespace ServiceControl.Infrastructure using LogManager = NServiceBus.Logging.LogManager; using LogLevel = NLog.LogLevel; - // TODO: Migrate from NLog to .NET logging public static class LoggingConfigurator { public static void ConfigureLogging(LoggingSettings loggingSettings) { - if (NLog.LogManager.Configuration != null) + //used for loggers outside of ServiceControl (i.e. transports and core) to use the logger factory defined here + LogManager.UseFactory(new ExtensionsLoggerFactory(LoggerFactory.Create(configure => configure.BuildLogger(loggingSettings.LogLevel)))); + + if (!LoggerUtil.IsLoggingTo(Loggers.NLog) || NLog.LogManager.Configuration != null) { return; } + //configure NLog var nlogConfig = new LoggingConfiguration(); var simpleLayout = new SimpleLayout("${longdate}|${processtime}|${threadid}|${level}|${logger}|${message}${onexception:|${exception:format=tostring}}"); @@ -76,8 +79,7 @@ public static void ConfigureLogging(LoggingSettings loggingSettings) NLog.LogManager.Configuration = nlogConfig; - LogManager.UseFactory(new ExtensionsLoggerFactory(LoggerFactory.Create(configure => configure.BuildLogger(loggingSettings.LogLevel)))); - + //using LogManager here rather than LoggerUtil.CreateStaticLogger since this is exclusive to NLog var logger = LogManager.GetLogger("LoggingConfiguration"); var logEventInfo = new LogEventInfo { TimeStamp = DateTime.UtcNow }; var loggingTo = AppEnvironment.RunningInContainer ? "console" : fileTarget.FileName.Render(logEventInfo); diff --git a/src/ServiceControl.Infrastructure/RavenDbLogLevelToLogsModeMapper.cs b/src/ServiceControl.Infrastructure/RavenDbLogLevelToLogsModeMapper.cs index 16a99ab8f3..d3316ba830 100644 --- a/src/ServiceControl.Infrastructure/RavenDbLogLevelToLogsModeMapper.cs +++ b/src/ServiceControl.Infrastructure/RavenDbLogLevelToLogsModeMapper.cs @@ -1,12 +1,9 @@ namespace ServiceControl { using Microsoft.Extensions.Logging; - using NServiceBus.Logging; public class RavenDbLogLevelToLogsModeMapper { - static readonly ILog Logger = LogManager.GetLogger(typeof(RavenDbLogLevelToLogsModeMapper)); - public static string Map(string ravenDbLogLevel, ILogger logger) { switch (ravenDbLogLevel.ToLower()) @@ -25,7 +22,7 @@ public static string Map(string ravenDbLogLevel, ILogger logger) case "operations": return "Operations"; default: - Logger.WarnFormat("Unknown log level '{0}', mapped to 'Operations'", ravenDbLogLevel); + logger.LogWarning("Unknown log level '{RavenDbLogLevel}', mapped to 'Operations'", ravenDbLogLevel); return "Operations"; } } diff --git a/src/ServiceControl.Monitoring.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs b/src/ServiceControl.Monitoring.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs index debc3ed629..63635fa2cf 100644 --- a/src/ServiceControl.Monitoring.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs +++ b/src/ServiceControl.Monitoring.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs @@ -13,11 +13,12 @@ namespace ServiceControl.Monitoring.AcceptanceTests.TestSupport using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; + using Microsoft.Extensions.Logging; using Monitoring; using NServiceBus; using NServiceBus.AcceptanceTesting; using NServiceBus.AcceptanceTesting.Support; - using NServiceBus.Logging; + using ServiceControl.Infrastructure; class ServiceControlComponentRunner( ITransportIntegration transportToUse, @@ -33,15 +34,16 @@ class ServiceControlComponentRunner( async Task InitializeServiceControl(ScenarioContext context) { + LoggerUtil.ActiveLoggers = Loggers.Test; settings = new Settings(transportType: transportToUse.TypeName) { ConnectionString = transportToUse.ConnectionString, HttpHostName = "localhost", OnMessage = (id, headers, body, @continue) => { - var log = LogManager.GetLogger(); + var logger = LoggerUtil.CreateStaticLogger(); headers.TryGetValue(Headers.MessageId, out var originalMessageId); - log.Debug($"OnMessage for message '{id}'({originalMessageId ?? string.Empty})."); + logger.LogDebug("OnMessage for message '{MessageId}'({OriginalMessageId})", id, originalMessageId ?? string.Empty); //Do not filter out CC, SA and HB messages as they can't be stamped if (headers.TryGetValue(Headers.EnclosedMessageTypes, out var messageTypes) @@ -60,7 +62,7 @@ async Task InitializeServiceControl(ScenarioContext context) var currentSession = context.TestRunId.ToString(); if (!headers.TryGetValue("SC.SessionID", out var session) || session != currentSession) { - log.Debug($"Discarding message '{id}'({originalMessageId ?? string.Empty}) because it's session id is '{session}' instead of '{currentSession}'."); + logger.LogDebug("Discarding message '{MessageId}'({OriginalMessageId}) because it's session id is '{SessionId}' instead of '{CurrentSessionId}'", id, originalMessageId ?? string.Empty, session, currentSession); return Task.CompletedTask; } @@ -91,12 +93,15 @@ async Task InitializeServiceControl(ScenarioContext context) // Force the DI container to run the dependency resolution check to verify all dependencies can be resolved EnvironmentName = Environments.Development }); + hostBuilder.Logging.ClearProviders(); + hostBuilder.Logging.BuildLogger(LogLevel.Information); + hostBuilder.AddServiceControlMonitoring((criticalErrorContext, cancellationToken) => { var logitem = new ScenarioContext.LogItem { Endpoint = settings.InstanceName, - Level = LogLevel.Fatal, + Level = NServiceBus.Logging.LogLevel.Fatal, LoggerName = $"{settings.InstanceName}.CriticalError", Message = $"{criticalErrorContext.Error}{Environment.NewLine}{criticalErrorContext.Exception}" }; diff --git a/src/ServiceControl.Persistence/ServiceControl.Persistence.csproj b/src/ServiceControl.Persistence/ServiceControl.Persistence.csproj index 050bcbec4b..1806eaf133 100644 --- a/src/ServiceControl.Persistence/ServiceControl.Persistence.csproj +++ b/src/ServiceControl.Persistence/ServiceControl.Persistence.csproj @@ -7,6 +7,7 @@ + diff --git a/src/ServiceControl/HostApplicationBuilderExtensions.cs b/src/ServiceControl/HostApplicationBuilderExtensions.cs index 25685e7623..14ee26a003 100644 --- a/src/ServiceControl/HostApplicationBuilderExtensions.cs +++ b/src/ServiceControl/HostApplicationBuilderExtensions.cs @@ -21,7 +21,6 @@ namespace Particular.ServiceControl using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting.WindowsServices; using Microsoft.Extensions.Logging; - using NLog.Extensions.Logging; using NServiceBus; using NServiceBus.Configuration.AdvancedExtensibility; using NServiceBus.Transport; @@ -42,11 +41,8 @@ public static void AddServiceControl(this IHostApplicationBuilder hostBuilder, S EventSourceCreator.Create(); } - var logging = hostBuilder.Logging; - logging.ClearProviders(); - //HINT: configuration used by NLog comes from LoggingConfigurator.cs - logging.AddNLog(); - logging.SetMinimumLevel(settings.LoggingSettings.LogLevel); + hostBuilder.Logging.ClearProviders(); + hostBuilder.Logging.BuildLogger(settings.LoggingSettings.LogLevel); var services = hostBuilder.Services; var transportSettings = settings.ToTransportSettings(); From e37e28256aaa93f20ac67398ec3e34aa6dddf979 Mon Sep 17 00:00:00 2001 From: Phil Bastian Date: Thu, 19 Jun 2025 15:53:19 +0800 Subject: [PATCH 35/56] missing files from last checkin --- src/ServiceControl.Infrastructure/LoggerUtil.cs | 11 ++++++++--- .../TransportTestFixture.cs | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/ServiceControl.Infrastructure/LoggerUtil.cs b/src/ServiceControl.Infrastructure/LoggerUtil.cs index f85bd6776a..c18a54afc1 100644 --- a/src/ServiceControl.Infrastructure/LoggerUtil.cs +++ b/src/ServiceControl.Infrastructure/LoggerUtil.cs @@ -19,17 +19,22 @@ public static class LoggerUtil { public static Loggers ActiveLoggers { private get; set; } = Loggers.None; + public static bool IsLoggingTo(Loggers logger) + { + return (logger & ActiveLoggers) == logger; + } + public static void BuildLogger(this ILoggingBuilder loggingBuilder, LogLevel level) { - if ((Loggers.Test & ActiveLoggers) == Loggers.Test) + if (IsLoggingTo(Loggers.Test)) { loggingBuilder.Services.AddSingleton(new TestContextProvider(level)); } - if ((Loggers.NLog & ActiveLoggers) == Loggers.NLog) + if (IsLoggingTo(Loggers.NLog)) { loggingBuilder.AddNLog(); } - if ((Loggers.Seq & ActiveLoggers) == Loggers.Seq) + if (IsLoggingTo(Loggers.Seq)) { loggingBuilder.AddSeq(); } diff --git a/src/ServiceControl.Transports.Tests/TransportTestFixture.cs b/src/ServiceControl.Transports.Tests/TransportTestFixture.cs index 9ecf8f1725..7dd9d6ef5d 100644 --- a/src/ServiceControl.Transports.Tests/TransportTestFixture.cs +++ b/src/ServiceControl.Transports.Tests/TransportTestFixture.cs @@ -23,7 +23,7 @@ class TransportTestFixture [SetUp] public virtual async Task Setup() { - //TODO remove LogManager usage + //used for loggers outside of ServiceControl (i.e. transports and core) to use the logger factory defined here LogManager.UseFactory(new ExtensionsLoggerFactory(new TestContextAppenderFactory(Microsoft.Extensions.Logging.LogLevel.Warning))); LoggerUtil.ActiveLoggers = Loggers.Test; configuration = new TransportTestsConfiguration(); From 4485d7b1bb4b8d63efd3e0219a0e8b644b6fa97c Mon Sep 17 00:00:00 2001 From: Phil Bastian Date: Fri, 20 Jun 2025 10:13:02 +0800 Subject: [PATCH 36/56] fix different dependency version test failure --- src/Directory.Packages.props | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index dfd35a5f78..fd7e86d45d 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -24,6 +24,7 @@ + From 4b80ba321070de38e67b4ffdb8c19865cae393af Mon Sep 17 00:00:00 2001 From: Phil Bastian Date: Fri, 20 Jun 2025 10:13:36 +0800 Subject: [PATCH 37/56] move loggerutil setup before first static logger usage --- src/ServiceControl.Infrastructure/LoggingSettings.cs | 6 +++--- src/ServiceControl.Persistence/PersistenceManifest.cs | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/ServiceControl.Infrastructure/LoggingSettings.cs b/src/ServiceControl.Infrastructure/LoggingSettings.cs index c48b27d889..ea8967bb00 100644 --- a/src/ServiceControl.Infrastructure/LoggingSettings.cs +++ b/src/ServiceControl.Infrastructure/LoggingSettings.cs @@ -11,9 +11,6 @@ public class LoggingSettings { public LoggingSettings(SettingsRootNamespace rootNamespace, LogLevel defaultLevel = LogLevel.Information, string logPath = null) { - LogLevel = InitializeLogLevel(rootNamespace, defaultLevel); - LogPath = SettingsReader.Read(rootNamespace, logPathKey, Environment.ExpandEnvironmentVariables(logPath ?? DefaultLogLocation())); - var loggingProviders = (SettingsReader.Read(rootNamespace, loggingProvidersKey) ?? "").Split(","); var activeLoggers = Loggers.None; if (loggingProviders.Contains("NLog")) @@ -26,6 +23,9 @@ public LoggingSettings(SettingsRootNamespace rootNamespace, LogLevel defaultLeve } //this defaults to NLog because historically that was the default, and we don't want to break existing installs that don't have the config key to define loggingProviders LoggerUtil.ActiveLoggers = activeLoggers == Loggers.None ? Loggers.NLog : activeLoggers; + + LogLevel = InitializeLogLevel(rootNamespace, defaultLevel); + LogPath = SettingsReader.Read(rootNamespace, logPathKey, Environment.ExpandEnvironmentVariables(logPath ?? DefaultLogLocation())); } public LogLevel LogLevel { get; } diff --git a/src/ServiceControl.Persistence/PersistenceManifest.cs b/src/ServiceControl.Persistence/PersistenceManifest.cs index df6f0941f6..9279f6cdc6 100644 --- a/src/ServiceControl.Persistence/PersistenceManifest.cs +++ b/src/ServiceControl.Persistence/PersistenceManifest.cs @@ -6,7 +6,6 @@ using System.Linq; using System.Text.Json; using Microsoft.Extensions.Logging; - using NServiceBus.Logging; using ServiceControl.Infrastructure; public class PersistenceManifest From 92b99b069de550516157c978556cf53f14cf3911 Mon Sep 17 00:00:00 2001 From: Phil Bastian Date: Fri, 20 Jun 2025 10:52:07 +0800 Subject: [PATCH 38/56] fix different dependency version test failure --- src/Directory.Packages.props | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index fd7e86d45d..16035eade5 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -25,6 +25,7 @@ + From 9ab9af67f42b1cc7e56f9600698869e677c1aa2a Mon Sep 17 00:00:00 2001 From: Phil Bastian <155411597+PhilBastian@users.noreply.github.com> Date: Fri, 20 Jun 2025 16:40:31 +0800 Subject: [PATCH 39/56] remove/refactor remaining references to LogManager (#5023) * convert SC transports from NServiceBus.Logging to Microsoft.Extensions.Logging * remove signedassembly requirement so that infrastructure can be imported * revert previous change and instead propogate signing back to servicecontrol.infrastructure * fix signature of customisation classes that are dynamically created * add ilogger to test services and remove direct construction with logger * get tests to use ilogger * Switch to .NET logging * Work in progress * Remove test code * Improve logging format for storage space details * Properly shutdown NLog in Program.cs * Remove Seq logging and prepare for .NET logging migration * Update LogLevel format * Update LogLevel format in logging settings * enable adding test logging provider as part of loggerutils and create framework for settings driven logger selection * add ability to select logging provider from config * handle setting not existing * change logmanager logger factory to the standard one now used by the rest of SC * ensure logger for transport tests * domain events and persister loggers * set default to nlog and pass loglevel to test context * replace logmanager usage in persistence * cleanup remaining references to LogManager * missing files from last checkin * fix different dependency version test failure * move loggerutil setup before first static logger usage * fix different dependency version test failure --------- Co-authored-by: JasonTaylorDev --- src/Directory.Packages.props | 2 + .../DiscardMessagesBehavior.cs | 12 +++-- .../ServiceControlComponentRunner.cs | 7 +-- .../ServiceControlComponentRunner.cs | 7 +-- .../RavenPersistenceConfiguration.cs | 2 +- .../DomainEvents.cs | 13 ++--- .../ServiceControl.DomainEvents.csproj | 1 + .../LoggerUtil.cs | 13 +++-- .../LoggingConfigurator.cs | 10 ++-- .../LoggingSettings.cs | 6 +-- .../RavenDbLogLevelToLogsModeMapper.cs | 8 ++- .../RepeatedFailuresOverTimeCircuitBreaker.cs | 23 ++++----- .../TestLogger/TestContextAppender.cs | 4 +- .../TestLogger/TestContextAppenderFactory.cs | 4 +- .../TestLogger/TestContextProvider.cs | 9 +++- .../ServiceControlComponentRunner.cs | 15 ++++-- .../CustomChecks/CheckDirtyMemory.cs | 13 ++--- .../CustomChecks/CheckFreeDiskSpace.cs | 29 ++++------- ...CheckMinimumStorageRequiredForIngestion.cs | 38 +++++++------- .../CustomChecks/CheckRavenDBIndexErrors.cs | 8 ++- .../CustomChecks/CheckRavenDBIndexLag.cs | 17 +++---- .../ErrorMessagesDataStore.cs | 13 +++-- .../ExternalIntegrationRequestsDataStore.cs | 21 ++++---- .../FailedErrorImportDataStore.cs | 19 +++---- .../FailedMessageViewIndexNotifications.cs | 8 ++- .../Subscriptions/RavenSubscriptionStorage.cs | 18 +++---- .../RavenEmbeddedPersistenceLifecycle.cs | 8 ++- .../RavenPersistenceConfiguration.cs | 3 +- .../Archiving/ArchiveDocumentManager.cs | 7 ++- .../Archiving/MessageArchiver.cs | 51 ++++++++++--------- .../RetryBatchesDataStore.cs | 14 +++-- .../RetryDocumentDataStore.cs | 8 ++- ...eControl.Persistence.Tests.InMemory.csproj | 1 + ...ceControl.Persistence.Tests.RavenDB.csproj | 1 + .../SubscriptionPersisterTests.cs | 5 +- .../PersistenceTestBase.cs | 6 +++ .../PersistenceManifest.cs | 11 ++-- .../ServiceControl.Persistence.csproj | 1 + .../EmbeddedDatabase.cs | 33 ++++++------ .../ServiceControl.RavenDB.csproj | 4 ++ .../TransportTestFixture.cs | 4 +- ...atedFailuresOverTimeCircuitBreakerTests.cs | 13 +++++ .../HostApplicationBuilderExtensions.cs | 8 +-- 43 files changed, 258 insertions(+), 240 deletions(-) diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index dfd35a5f78..16035eade5 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -24,6 +24,8 @@ + + diff --git a/src/ServiceControl.AcceptanceTesting/DiscardMessagesBehavior.cs b/src/ServiceControl.AcceptanceTesting/DiscardMessagesBehavior.cs index ed2fd50768..134db9bdec 100644 --- a/src/ServiceControl.AcceptanceTesting/DiscardMessagesBehavior.cs +++ b/src/ServiceControl.AcceptanceTesting/DiscardMessagesBehavior.cs @@ -3,10 +3,11 @@ namespace ServiceControl.AcceptanceTesting using System; using System.Linq; using System.Threading.Tasks; + using Microsoft.Extensions.Logging; using NServiceBus; using NServiceBus.AcceptanceTesting; - using NServiceBus.Logging; using NServiceBus.Pipeline; + using ServiceControl.Infrastructure; public class DiscardMessagesBehavior : IBehavior { @@ -44,7 +45,13 @@ public Task Invoke(ITransportReceiveContext context, Func(); + logger.LogDebug("Discarding message '{MessageId}'({OriginalMessageId}) because it's session id is '{MessageSessionId}' instead of '{CurrentSessionId}' Message Types: {EnclosedMessageTypes}.", + context.Message.MessageId, + originalMessageId ?? string.Empty, + session, + currentSession, + enclosedMessageTypes); return Task.CompletedTask; } @@ -52,7 +59,6 @@ public Task Invoke(ITransportReceiveContext context, Func(); static string[] pluginMessages = { diff --git a/src/ServiceControl.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs b/src/ServiceControl.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs index f1b3e58a01..8ac0a4454a 100644 --- a/src/ServiceControl.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs +++ b/src/ServiceControl.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs @@ -50,6 +50,7 @@ async Task InitializeServiceControl(ScenarioContext context) var logPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); Directory.CreateDirectory(logPath); var loggingSettings = new LoggingSettings(Settings.SettingsRootNamespace, defaultLevel: LogLevel.Debug, logPath: logPath); + LoggerUtil.ActiveLoggers = Loggers.Test; var settings = new Settings(transportToUse.TypeName, persistenceToUse.PersistenceType, loggingSettings, forwardErrorMessages: false, errorRetentionPeriod: TimeSpan.FromDays(10)) { @@ -65,9 +66,9 @@ async Task InitializeServiceControl(ScenarioContext context) { var headers = messageContext.Headers; var id = messageContext.NativeMessageId; - var log = NServiceBus.Logging.LogManager.GetLogger(); + var logger = LoggerUtil.CreateStaticLogger(loggingSettings.LogLevel); headers.TryGetValue(Headers.MessageId, out var originalMessageId); - log.Debug($"OnMessage for message '{id}'({originalMessageId ?? string.Empty})."); + logger.LogDebug("OnMessage for message '{MessageId}'({OriginalMessageId})", id, originalMessageId ?? string.Empty); //Do not filter out CC, SA and HB messages as they can't be stamped if (headers.TryGetValue(Headers.EnclosedMessageTypes, out var messageTypes) @@ -86,7 +87,7 @@ async Task InitializeServiceControl(ScenarioContext context) var currentSession = context.TestRunId.ToString(); if (!headers.TryGetValue("SC.SessionID", out var session) || session != currentSession) { - log.Debug($"Discarding message '{id}'({originalMessageId ?? string.Empty}) because it's session id is '{session}' instead of '{currentSession}'."); + logger.LogDebug("Discarding message '{MessageId}'({OriginalMessageId}) because it's session id is '{SessionId}' instead of '{CurrentSessionId}'", id, originalMessageId ?? string.Empty, session, currentSession); return true; } diff --git a/src/ServiceControl.Audit.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs b/src/ServiceControl.Audit.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs index 65e1b4752f..27ed1bfade 100644 --- a/src/ServiceControl.Audit.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs +++ b/src/ServiceControl.Audit.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs @@ -45,6 +45,7 @@ async Task InitializeServiceControl(ScenarioContext context) Directory.CreateDirectory(logPath); var loggingSettings = new LoggingSettings(Settings.SettingsRootNamespace, defaultLevel: LogLevel.Debug, logPath: logPath); + LoggerUtil.ActiveLoggers = Loggers.Test; settings = new Settings(transportToUse.TypeName, persistenceToUse.PersistenceType, loggingSettings) { @@ -56,9 +57,9 @@ async Task InitializeServiceControl(ScenarioContext context) { var id = messageContext.NativeMessageId; var headers = messageContext.Headers; - var log = LoggerUtil.CreateStaticLogger(); + var logger = LoggerUtil.CreateStaticLogger(loggingSettings.LogLevel); headers.TryGetValue(Headers.MessageId, out var originalMessageId); - log.LogDebug("OnMessage for message '{MessageId}'({OriginalMessageId}).", id, originalMessageId ?? string.Empty); + logger.LogDebug("OnMessage for message '{MessageId}'({OriginalMessageId}).", id, originalMessageId ?? string.Empty); //Do not filter out CC, SA and HB messages as they can't be stamped if (headers.TryGetValue(Headers.EnclosedMessageTypes, out var messageTypes) @@ -77,7 +78,7 @@ async Task InitializeServiceControl(ScenarioContext context) var currentSession = context.TestRunId.ToString(); if (!headers.TryGetValue("SC.SessionID", out var session) || session != currentSession) { - log.LogDebug("Discarding message '{MessageId}'({OriginalMessageId}) because it's session id is '{SessionId}' instead of '{CurrentSessionId}'.", id, originalMessageId ?? string.Empty, session, currentSession); + logger.LogDebug("Discarding message '{MessageId}'({OriginalMessageId}) because it's session id is '{SessionId}' instead of '{CurrentSessionId}'.", id, originalMessageId ?? string.Empty, session, currentSession); return true; } diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/RavenPersistenceConfiguration.cs b/src/ServiceControl.Audit.Persistence.RavenDB/RavenPersistenceConfiguration.cs index 3611a3f646..eced9e35b2 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/RavenPersistenceConfiguration.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/RavenPersistenceConfiguration.cs @@ -108,7 +108,7 @@ internal static DatabaseConfiguration GetDatabaseConfiguration(PersistenceSettin if (settings.PersisterSpecificSettings.TryGetValue(RavenDbLogLevelKey, out var ravenDbLogLevel)) { - logsMode = RavenDbLogLevelToLogsModeMapper.Map(ravenDbLogLevel); + logsMode = RavenDbLogLevelToLogsModeMapper.Map(ravenDbLogLevel, Logger); } serverConfiguration = new ServerConfiguration(dbPath, serverUrl, logPath, logsMode); diff --git a/src/ServiceControl.DomainEvents/DomainEvents.cs b/src/ServiceControl.DomainEvents/DomainEvents.cs index 5443c784d7..0367f199fb 100644 --- a/src/ServiceControl.DomainEvents/DomainEvents.cs +++ b/src/ServiceControl.DomainEvents/DomainEvents.cs @@ -4,15 +4,10 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; - public class DomainEvents : IDomainEvents + public class DomainEvents(IServiceProvider serviceProvider, ILogger logger) : IDomainEvents { - static readonly ILog Log = LogManager.GetLogger(); - - readonly IServiceProvider serviceProvider; - public DomainEvents(IServiceProvider serviceProvider) => this.serviceProvider = serviceProvider; - public async Task Raise(T domainEvent, CancellationToken cancellationToken) where T : IDomainEvent { var handlers = serviceProvider.GetServices>(); @@ -25,7 +20,7 @@ await handler.Handle(domainEvent, cancellationToken) } catch (Exception e) { - Log.Error($"Unexpected error publishing domain event {typeof(T)}", e); + logger.LogError(e, "Unexpected error publishing domain event {EventType}", typeof(T)); throw; } } @@ -40,7 +35,7 @@ await handler.Handle(domainEvent, cancellationToken) } catch (Exception e) { - Log.Error($"Unexpected error publishing domain event {typeof(T)}", e); + logger.LogError(e, "Unexpected error publishing domain event {EventType}", typeof(T)); throw; } } diff --git a/src/ServiceControl.DomainEvents/ServiceControl.DomainEvents.csproj b/src/ServiceControl.DomainEvents/ServiceControl.DomainEvents.csproj index 8b8037bc48..bb654606ec 100644 --- a/src/ServiceControl.DomainEvents/ServiceControl.DomainEvents.csproj +++ b/src/ServiceControl.DomainEvents/ServiceControl.DomainEvents.csproj @@ -6,6 +6,7 @@ + diff --git a/src/ServiceControl.Infrastructure/LoggerUtil.cs b/src/ServiceControl.Infrastructure/LoggerUtil.cs index 34fc16beb1..c18a54afc1 100644 --- a/src/ServiceControl.Infrastructure/LoggerUtil.cs +++ b/src/ServiceControl.Infrastructure/LoggerUtil.cs @@ -19,17 +19,22 @@ public static class LoggerUtil { public static Loggers ActiveLoggers { private get; set; } = Loggers.None; + public static bool IsLoggingTo(Loggers logger) + { + return (logger & ActiveLoggers) == logger; + } + public static void BuildLogger(this ILoggingBuilder loggingBuilder, LogLevel level) { - if ((Loggers.Test & ActiveLoggers) == Loggers.Test) + if (IsLoggingTo(Loggers.Test)) { - loggingBuilder.Services.AddSingleton(new TestContextProvider()); + loggingBuilder.Services.AddSingleton(new TestContextProvider(level)); } - if ((Loggers.NLog & ActiveLoggers) == Loggers.NLog) + if (IsLoggingTo(Loggers.NLog)) { loggingBuilder.AddNLog(); } - if ((Loggers.Seq & ActiveLoggers) == Loggers.Seq) + if (IsLoggingTo(Loggers.Seq)) { loggingBuilder.AddSeq(); } diff --git a/src/ServiceControl.Infrastructure/LoggingConfigurator.cs b/src/ServiceControl.Infrastructure/LoggingConfigurator.cs index 4845965394..848c6a3cf3 100644 --- a/src/ServiceControl.Infrastructure/LoggingConfigurator.cs +++ b/src/ServiceControl.Infrastructure/LoggingConfigurator.cs @@ -12,16 +12,19 @@ namespace ServiceControl.Infrastructure using LogManager = NServiceBus.Logging.LogManager; using LogLevel = NLog.LogLevel; - // TODO: Migrate from NLog to .NET logging public static class LoggingConfigurator { public static void ConfigureLogging(LoggingSettings loggingSettings) { - if (NLog.LogManager.Configuration != null) + //used for loggers outside of ServiceControl (i.e. transports and core) to use the logger factory defined here + LogManager.UseFactory(new ExtensionsLoggerFactory(LoggerFactory.Create(configure => configure.BuildLogger(loggingSettings.LogLevel)))); + + if (!LoggerUtil.IsLoggingTo(Loggers.NLog) || NLog.LogManager.Configuration != null) { return; } + //configure NLog var nlogConfig = new LoggingConfiguration(); var simpleLayout = new SimpleLayout("${longdate}|${processtime}|${threadid}|${level}|${logger}|${message}${onexception:|${exception:format=tostring}}"); @@ -76,8 +79,7 @@ public static void ConfigureLogging(LoggingSettings loggingSettings) NLog.LogManager.Configuration = nlogConfig; - LogManager.UseFactory(new ExtensionsLoggerFactory(LoggerFactory.Create(configure => configure.BuildLogger(loggingSettings.LogLevel)))); - + //using LogManager here rather than LoggerUtil.CreateStaticLogger since this is exclusive to NLog var logger = LogManager.GetLogger("LoggingConfiguration"); var logEventInfo = new LogEventInfo { TimeStamp = DateTime.UtcNow }; var loggingTo = AppEnvironment.RunningInContainer ? "console" : fileTarget.FileName.Render(logEventInfo); diff --git a/src/ServiceControl.Infrastructure/LoggingSettings.cs b/src/ServiceControl.Infrastructure/LoggingSettings.cs index c48b27d889..ea8967bb00 100644 --- a/src/ServiceControl.Infrastructure/LoggingSettings.cs +++ b/src/ServiceControl.Infrastructure/LoggingSettings.cs @@ -11,9 +11,6 @@ public class LoggingSettings { public LoggingSettings(SettingsRootNamespace rootNamespace, LogLevel defaultLevel = LogLevel.Information, string logPath = null) { - LogLevel = InitializeLogLevel(rootNamespace, defaultLevel); - LogPath = SettingsReader.Read(rootNamespace, logPathKey, Environment.ExpandEnvironmentVariables(logPath ?? DefaultLogLocation())); - var loggingProviders = (SettingsReader.Read(rootNamespace, loggingProvidersKey) ?? "").Split(","); var activeLoggers = Loggers.None; if (loggingProviders.Contains("NLog")) @@ -26,6 +23,9 @@ public LoggingSettings(SettingsRootNamespace rootNamespace, LogLevel defaultLeve } //this defaults to NLog because historically that was the default, and we don't want to break existing installs that don't have the config key to define loggingProviders LoggerUtil.ActiveLoggers = activeLoggers == Loggers.None ? Loggers.NLog : activeLoggers; + + LogLevel = InitializeLogLevel(rootNamespace, defaultLevel); + LogPath = SettingsReader.Read(rootNamespace, logPathKey, Environment.ExpandEnvironmentVariables(logPath ?? DefaultLogLocation())); } public LogLevel LogLevel { get; } diff --git a/src/ServiceControl.Infrastructure/RavenDbLogLevelToLogsModeMapper.cs b/src/ServiceControl.Infrastructure/RavenDbLogLevelToLogsModeMapper.cs index 8711bc9854..d3316ba830 100644 --- a/src/ServiceControl.Infrastructure/RavenDbLogLevelToLogsModeMapper.cs +++ b/src/ServiceControl.Infrastructure/RavenDbLogLevelToLogsModeMapper.cs @@ -1,12 +1,10 @@ namespace ServiceControl { - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; public class RavenDbLogLevelToLogsModeMapper { - static readonly ILog Logger = LogManager.GetLogger(typeof(RavenDbLogLevelToLogsModeMapper)); - - public static string Map(string ravenDbLogLevel) + public static string Map(string ravenDbLogLevel, ILogger logger) { switch (ravenDbLogLevel.ToLower()) { @@ -24,7 +22,7 @@ public static string Map(string ravenDbLogLevel) case "operations": return "Operations"; default: - Logger.WarnFormat("Unknown log level '{0}', mapped to 'Operations'", ravenDbLogLevel); + logger.LogWarning("Unknown log level '{RavenDbLogLevel}', mapped to 'Operations'", ravenDbLogLevel); return "Operations"; } } diff --git a/src/ServiceControl.Infrastructure/RepeatedFailuresOverTimeCircuitBreaker.cs b/src/ServiceControl.Infrastructure/RepeatedFailuresOverTimeCircuitBreaker.cs index abd6c9a354..3ae3d1c879 100644 --- a/src/ServiceControl.Infrastructure/RepeatedFailuresOverTimeCircuitBreaker.cs +++ b/src/ServiceControl.Infrastructure/RepeatedFailuresOverTimeCircuitBreaker.cs @@ -5,7 +5,7 @@ namespace NServiceBus; using System; using System.Threading; using System.Threading.Tasks; -using Logging; +using Microsoft.Extensions.Logging; /// /// A circuit breaker that is armed on a failure and disarmed on success. After in the @@ -44,6 +44,7 @@ public RepeatedFailuresOverTimeCircuitBreaker( string name, TimeSpan timeToWaitBeforeTriggering, Action triggerAction, + ILogger logger, Action? armedAction = null, Action? disarmedAction = null, TimeSpan? timeToWaitWhenTriggered = default, @@ -51,6 +52,7 @@ public RepeatedFailuresOverTimeCircuitBreaker( { this.name = name; this.triggerAction = triggerAction; + this.logger = logger; this.armedAction = armedAction ?? (static () => { }); this.disarmedAction = disarmedAction ?? (static () => { }); this.timeToWaitBeforeTriggering = timeToWaitBeforeTriggering; @@ -82,14 +84,14 @@ public void Success() circuitBreakerState = Disarmed; _ = timer.Change(Timeout.Infinite, Timeout.Infinite); - Logger.InfoFormat("The circuit breaker for '{0}' is now disarmed.", name); + logger.LogInformation("The circuit breaker for '{BreakerName}' is now disarmed.", name); try { disarmedAction(); } catch (Exception ex) { - Logger.Error($"The circuit breaker for '{name}' was unable to execute the disarm action.", ex); + logger.LogError(ex, "The circuit breaker for '{BreakerName}' was unable to execute the disarm action.", name); throw; } } @@ -130,12 +132,12 @@ public Task Failure(Exception exception, CancellationToken cancellationToken = d } catch (Exception ex) { - Logger.Error($"The circuit breaker for '{name}' was unable to execute the arm action.", new AggregateException(ex, exception)); + logger.LogError(new AggregateException(ex, exception), "The circuit breaker for '{BreakerName}' was unable to execute the arm action.", name); throw; } _ = timer.Change(timeToWaitBeforeTriggering, NoPeriodicTriggering); - Logger.WarnFormat("The circuit breaker for '{0}' is now in the armed state due to '{1}' and might trigger in '{2}' when not disarmed.", name, exception, timeToWaitBeforeTriggering); + logger.LogWarning("The circuit breaker for '{BreakerName}' is now in the armed state due to '{BreakerCause}' and might trigger in '{BreakerTriggerTime}' when not disarmed.", name, exception, timeToWaitBeforeTriggering); } return Delay(); @@ -143,10 +145,7 @@ public Task Failure(Exception exception, CancellationToken cancellationToken = d Task Delay() { var timeToWait = previousState == Triggered ? timeToWaitWhenTriggered : timeToWaitWhenArmed; - if (Logger.IsDebugEnabled) - { - Logger.DebugFormat("The circuit breaker for '{0}' is delaying the operation by '{1}'.", name, timeToWait); - } + logger.LogDebug("The circuit breaker for '{BreakerName}' is delaying the operation by '{BreakerTriggerTime}'.", name, timeToWait); return Task.Delay(timeToWait, cancellationToken); } } @@ -173,7 +172,7 @@ void CircuitBreakerTriggered(object? state) } circuitBreakerState = Triggered; - Logger.WarnFormat("The circuit breaker for '{0}' will now be triggered with exception '{1}'.", name, lastException); + logger.LogWarning("The circuit breaker for '{BreakerName}' will now be triggered with exception '{BreakerCause}'.", name, lastException); try { @@ -181,7 +180,7 @@ void CircuitBreakerTriggered(object? state) } catch (Exception ex) { - Logger.Fatal($"The circuit breaker for '{name}' was unable to execute the trigger action.", new AggregateException(ex, lastException!)); + logger.LogCritical(new AggregateException(ex, lastException!), "The circuit breaker for '{BreakerName}' was unable to execute the trigger action.", name); } } } @@ -204,5 +203,5 @@ void CircuitBreakerTriggered(object? state) const int Triggered = 2; static readonly TimeSpan NoPeriodicTriggering = TimeSpan.FromMilliseconds(-1); - static readonly ILog Logger = LogManager.GetLogger(); + readonly ILogger logger; } \ No newline at end of file diff --git a/src/ServiceControl.Infrastructure/TestLogger/TestContextAppender.cs b/src/ServiceControl.Infrastructure/TestLogger/TestContextAppender.cs index c353a3b60a..ed37368e16 100644 --- a/src/ServiceControl.Infrastructure/TestLogger/TestContextAppender.cs +++ b/src/ServiceControl.Infrastructure/TestLogger/TestContextAppender.cs @@ -4,7 +4,7 @@ using Microsoft.Extensions.Logging; using NUnit.Framework; - class TestContextAppender(string categoryName) : ILogger + class TestContextAppender(string categoryName, LogLevel level) : ILogger { public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) { @@ -13,7 +13,7 @@ public void Log(LogLevel logLevel, EventId eventId, TState state, Except TestContext.Out.WriteLine($"{categoryName}: {formatter(state, exception)}"); } } - public bool IsEnabled(LogLevel logLevel) => logLevel >= LogLevel.Warning; + public bool IsEnabled(LogLevel logLevel) => logLevel >= level; public IDisposable BeginScope(TState state) where TState : notnull => Disposable.Instance; diff --git a/src/ServiceControl.Infrastructure/TestLogger/TestContextAppenderFactory.cs b/src/ServiceControl.Infrastructure/TestLogger/TestContextAppenderFactory.cs index 98e1d683fb..3cac38fce7 100644 --- a/src/ServiceControl.Infrastructure/TestLogger/TestContextAppenderFactory.cs +++ b/src/ServiceControl.Infrastructure/TestLogger/TestContextAppenderFactory.cs @@ -2,13 +2,13 @@ { using Microsoft.Extensions.Logging; - public class TestContextAppenderFactory : ILoggerFactory + public class TestContextAppenderFactory(LogLevel logLevel) : ILoggerFactory { public void AddProvider(ILoggerProvider provider) { } - public ILogger CreateLogger(string categoryName) => new TestContextAppender(categoryName); + public ILogger CreateLogger(string categoryName) => new TestContextAppender(categoryName, logLevel); public void Dispose() { diff --git a/src/ServiceControl.Infrastructure/TestLogger/TestContextProvider.cs b/src/ServiceControl.Infrastructure/TestLogger/TestContextProvider.cs index e879c814a3..90e2dae5d8 100644 --- a/src/ServiceControl.Infrastructure/TestLogger/TestContextProvider.cs +++ b/src/ServiceControl.Infrastructure/TestLogger/TestContextProvider.cs @@ -4,7 +4,14 @@ public class TestContextProvider : ILoggerProvider { - public ILogger CreateLogger(string categoryName) => new TestContextAppender(categoryName); + readonly LogLevel level; + + public TestContextProvider(LogLevel level) + { + this.level = level; + } + + public ILogger CreateLogger(string categoryName) => new TestContextAppender(categoryName, level); public void Dispose() { diff --git a/src/ServiceControl.Monitoring.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs b/src/ServiceControl.Monitoring.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs index debc3ed629..63635fa2cf 100644 --- a/src/ServiceControl.Monitoring.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs +++ b/src/ServiceControl.Monitoring.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs @@ -13,11 +13,12 @@ namespace ServiceControl.Monitoring.AcceptanceTests.TestSupport using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; + using Microsoft.Extensions.Logging; using Monitoring; using NServiceBus; using NServiceBus.AcceptanceTesting; using NServiceBus.AcceptanceTesting.Support; - using NServiceBus.Logging; + using ServiceControl.Infrastructure; class ServiceControlComponentRunner( ITransportIntegration transportToUse, @@ -33,15 +34,16 @@ class ServiceControlComponentRunner( async Task InitializeServiceControl(ScenarioContext context) { + LoggerUtil.ActiveLoggers = Loggers.Test; settings = new Settings(transportType: transportToUse.TypeName) { ConnectionString = transportToUse.ConnectionString, HttpHostName = "localhost", OnMessage = (id, headers, body, @continue) => { - var log = LogManager.GetLogger(); + var logger = LoggerUtil.CreateStaticLogger(); headers.TryGetValue(Headers.MessageId, out var originalMessageId); - log.Debug($"OnMessage for message '{id}'({originalMessageId ?? string.Empty})."); + logger.LogDebug("OnMessage for message '{MessageId}'({OriginalMessageId})", id, originalMessageId ?? string.Empty); //Do not filter out CC, SA and HB messages as they can't be stamped if (headers.TryGetValue(Headers.EnclosedMessageTypes, out var messageTypes) @@ -60,7 +62,7 @@ async Task InitializeServiceControl(ScenarioContext context) var currentSession = context.TestRunId.ToString(); if (!headers.TryGetValue("SC.SessionID", out var session) || session != currentSession) { - log.Debug($"Discarding message '{id}'({originalMessageId ?? string.Empty}) because it's session id is '{session}' instead of '{currentSession}'."); + logger.LogDebug("Discarding message '{MessageId}'({OriginalMessageId}) because it's session id is '{SessionId}' instead of '{CurrentSessionId}'", id, originalMessageId ?? string.Empty, session, currentSession); return Task.CompletedTask; } @@ -91,12 +93,15 @@ async Task InitializeServiceControl(ScenarioContext context) // Force the DI container to run the dependency resolution check to verify all dependencies can be resolved EnvironmentName = Environments.Development }); + hostBuilder.Logging.ClearProviders(); + hostBuilder.Logging.BuildLogger(LogLevel.Information); + hostBuilder.AddServiceControlMonitoring((criticalErrorContext, cancellationToken) => { var logitem = new ScenarioContext.LogItem { Endpoint = settings.InstanceName, - Level = LogLevel.Fatal, + Level = NServiceBus.Logging.LogLevel.Fatal, LoggerName = $"{settings.InstanceName}.CriticalError", Message = $"{criticalErrorContext.Error}{Environment.NewLine}{criticalErrorContext.Exception}" }; diff --git a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckDirtyMemory.cs b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckDirtyMemory.cs index 8eee53911a..c90bbc4a8e 100644 --- a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckDirtyMemory.cs +++ b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckDirtyMemory.cs @@ -3,26 +3,23 @@ namespace ServiceControl.Persistence.RavenDB.CustomChecks; using System; using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; using NServiceBus.CustomChecks; -using NServiceBus.Logging; -class CheckDirtyMemory(MemoryInformationRetriever memoryInformationRetriever) : CustomCheck("RavenDB dirty memory", "ServiceControl Health", TimeSpan.FromMinutes(5)) +class CheckDirtyMemory(MemoryInformationRetriever memoryInformationRetriever, ILogger logger) : CustomCheck("RavenDB dirty memory", "ServiceControl Health", TimeSpan.FromMinutes(5)) { public override async Task PerformCheck(CancellationToken cancellationToken = default) { var (isHighDirty, dirtyMemory) = await memoryInformationRetriever.GetMemoryInformation(cancellationToken); - Log.Debug($"RavenDB dirty memory value: {dirtyMemory}."); + logger.LogDebug("RavenDB dirty memory value: {DirtyMemory}.", dirtyMemory); if (isHighDirty) { - var message = $"There is a high level of RavenDB dirty memory ({dirtyMemory}). See https://docs.particular.net/servicecontrol/troubleshooting#ravendb-dirty-memory for guidance on how to mitigate the issue."; - Log.Warn(message); - return CheckResult.Failed(message); + logger.LogWarning("There is a high level of RavenDB dirty memory ({DirtyMemory}). See https://docs.particular.net/servicecontrol/troubleshooting#ravendb-dirty-memory for guidance on how to mitigate the issue.", dirtyMemory); + return CheckResult.Failed($"There is a high level of RavenDB dirty memory ({dirtyMemory}). See https://docs.particular.net/servicecontrol/troubleshooting#ravendb-dirty-memory for guidance on how to mitigate the issue."); } return CheckResult.Pass; } - - static readonly ILog Log = LogManager.GetLogger(); } \ No newline at end of file diff --git a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs index c90bce9807..22029f309c 100644 --- a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs +++ b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs @@ -4,18 +4,16 @@ using System.IO; using System.Threading; using System.Threading.Tasks; + using Microsoft.Extensions.Logging; using NServiceBus.CustomChecks; - using NServiceBus.Logging; + using ServiceControl.Infrastructure; using ServiceControl.Persistence.RavenDB; - class CheckFreeDiskSpace(RavenPersisterSettings settings) : CustomCheck("ServiceControl database", "Storage space", TimeSpan.FromMinutes(5)) + class CheckFreeDiskSpace(RavenPersisterSettings settings, ILogger logger) : CustomCheck("ServiceControl database", "Storage space", TimeSpan.FromMinutes(5)) { public override Task PerformCheck(CancellationToken cancellationToken = default) { - if (Logger.IsDebugEnabled) - { - Logger.Debug($"Check ServiceControl data drive space remaining custom check starting. Threshold {percentageThreshold:P0}"); - } + logger.LogDebug("Check ServiceControl data drive space remaining custom check starting. Threshold {PercentageThreshold:P0}", percentageThreshold); if (!settings.UseEmbeddedServer) { @@ -33,10 +31,7 @@ public override Task PerformCheck(CancellationToken cancellationTok var percentRemaining = (decimal)dataDriveInfo.AvailableFreeSpace / dataDriveInfo.TotalSize; - if (Logger.IsDebugEnabled) - { - Logger.Debug($"Free space: {availableFreeSpace:N0}B | Total: {totalSpace:N0}B | Percent remaining {percentRemaining:P1}"); - } + logger.LogDebug("Free space: {AvailableFreeSpace:N0}B | Total: {TotalSpace:N0}B | Percent remaining {PercentRemaining:P1}", availableFreeSpace, totalSpace, percentRemaining); return percentRemaining > percentageThreshold ? CheckResult.Pass @@ -45,22 +40,19 @@ public override Task PerformCheck(CancellationToken cancellationTok public static void Validate(RavenPersisterSettings settings) { + var logger = LoggerUtil.CreateStaticLogger(); var threshold = settings.DataSpaceRemainingThreshold; - string message; - if (threshold < 0) { - message = $"{RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey} is invalid, minimum value is 0."; - Logger.Fatal(message); - throw new Exception(message); + logger.LogCritical("{RavenPersistenceConfigurationDataSpaceRemainingThresholdKey} is invalid, minimum value is 0.", RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey); + throw new Exception($"{RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey} is invalid, minimum value is 0."); } if (threshold > 100) { - message = $"{RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey} is invalid, maximum value is 100."; - Logger.Fatal(message); - throw new Exception(message); + logger.LogCritical("{RavenPersistenceConfigurationDataSpaceRemainingThresholdKey} is invalid, maximum value is 100.", RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey); + throw new Exception($"{RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey} is invalid, maximum value is 100."); } } @@ -68,6 +60,5 @@ public static void Validate(RavenPersisterSettings settings) readonly decimal percentageThreshold = settings.DataSpaceRemainingThreshold / 100m; public const int DataSpaceRemainingThresholdDefault = 20; - static readonly ILog Logger = LogManager.GetLogger(typeof(CheckFreeDiskSpace)); } } \ No newline at end of file diff --git a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs index 053a41cff7..0c04857571 100644 --- a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs +++ b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs @@ -4,21 +4,19 @@ using System.IO; using System.Threading; using System.Threading.Tasks; + using Microsoft.Extensions.Logging; using NServiceBus.CustomChecks; - using NServiceBus.Logging; + using ServiceControl.Infrastructure; using ServiceControl.Persistence; using ServiceControl.Persistence.RavenDB; - class CheckMinimumStorageRequiredForIngestion(MinimumRequiredStorageState stateHolder, RavenPersisterSettings settings) : CustomCheck("Message Ingestion Process", "ServiceControl Health", TimeSpan.FromSeconds(5)) + class CheckMinimumStorageRequiredForIngestion(MinimumRequiredStorageState stateHolder, RavenPersisterSettings settings, ILogger logger) : CustomCheck("Message Ingestion Process", "ServiceControl Health", TimeSpan.FromSeconds(5)) { public override Task PerformCheck(CancellationToken cancellationToken = default) { var percentageThreshold = settings.MinimumStorageLeftRequiredForIngestion / 100m; - if (Logger.IsDebugEnabled) - { - Logger.Debug($"Check ServiceControl data drive space starting. Threshold {percentageThreshold:P0}"); - } + logger.LogDebug("Check ServiceControl data drive space starting. Threshold {PercentageThreshold:P0}", percentageThreshold); // Should be checking UseEmbeddedServer but need to check DatabasePath instead for the ATT hack to work if (string.IsNullOrEmpty(settings.DatabasePath)) @@ -35,10 +33,7 @@ public override Task PerformCheck(CancellationToken cancellationTok var percentRemaining = (decimal)dataDriveInfo.AvailableFreeSpace / dataDriveInfo.TotalSize; - if (Logger.IsDebugEnabled) - { - Logger.Debug($"Free space: {availableFreeSpace:N0}B | Total: {totalSpace:N0}B | Percent remaining {percentRemaining:P1}"); - } + logger.LogDebug("Free space: {AvailableFreeSpace:N0}B | Total: {TotalSpace:N0}B | Percent remaining {PercentRemaining:P1}", availableFreeSpace, totalSpace, percentRemaining); if (percentRemaining > percentageThreshold) { @@ -46,33 +41,36 @@ public override Task PerformCheck(CancellationToken cancellationTok return SuccessResult; } - var message = $"Error message ingestion stopped! {percentRemaining:P0} disk space remaining on data drive '{dataDriveInfo.VolumeLabel} ({dataDriveInfo.RootDirectory})' on '{Environment.MachineName}'. This is less than {percentageThreshold}% - the minimal required space configured. The threshold can be set using the {RavenBootstrapper.MinimumStorageLeftRequiredForIngestionKey} configuration setting."; - Logger.Warn(message); + logger.LogWarning("Error message ingestion stopped! {PercentRemaining:P0} disk space remaining on data drive '{DataDriveInfoVolumeLabel} ({DataDriveInfoRootDirectory})' on '{MachineName}'. This is less than {PercentageThreshold}% - the minimal required space configured. The threshold can be set using the {RavenBootstrapperMinimumStorageLeftRequiredForIngestionKey} configuration setting.", + percentRemaining, + dataDriveInfo.VolumeLabel, + dataDriveInfo.RootDirectory, + Environment.MachineName, + percentageThreshold, + RavenBootstrapper.MinimumStorageLeftRequiredForIngestionKey); stateHolder.CanIngestMore = false; - return CheckResult.Failed(message); + return CheckResult.Failed($"Error message ingestion stopped! {percentRemaining:P0} disk space remaining on data drive '{dataDriveInfo.VolumeLabel} ({dataDriveInfo.RootDirectory})' on '{Environment.MachineName}'. This is less than {percentageThreshold}% - the minimal required space configured. The threshold can be set using the {RavenBootstrapper.MinimumStorageLeftRequiredForIngestionKey} configuration setting."); } public static void Validate(RavenPersisterSettings settings) { + var logger = LoggerUtil.CreateStaticLogger(); var threshold = settings.MinimumStorageLeftRequiredForIngestion; if (threshold < 0) { - var message = $"{RavenBootstrapper.MinimumStorageLeftRequiredForIngestionKey} is invalid, minimum value is 0."; - Logger.Fatal(message); - throw new Exception(message); + logger.LogCritical("{RavenBootstrapperMinimumStorageLeftRequiredForIngestionKey} is invalid, minimum value is 0.", RavenBootstrapper.MinimumStorageLeftRequiredForIngestionKey); + throw new Exception($"{RavenBootstrapper.MinimumStorageLeftRequiredForIngestionKey} is invalid, minimum value is 0."); } if (threshold > 100) { - var message = $"{RavenBootstrapper.MinimumStorageLeftRequiredForIngestionKey} is invalid, maximum value is 100."; - Logger.Fatal(message); - throw new Exception(message); + logger.LogCritical("{RavenBootstrapperMinimumStorageLeftRequiredForIngestionKey} is invalid, maximum value is 100.", RavenBootstrapper.MinimumStorageLeftRequiredForIngestionKey); + throw new Exception($"{RavenBootstrapper.MinimumStorageLeftRequiredForIngestionKey} is invalid, maximum value is 100."); } } public const int MinimumStorageLeftRequiredForIngestionDefault = 5; static readonly Task SuccessResult = Task.FromResult(CheckResult.Pass); - static readonly ILog Logger = LogManager.GetLogger(typeof(CheckMinimumStorageRequiredForIngestion)); } } \ No newline at end of file diff --git a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexErrors.cs b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexErrors.cs index 5567aa7507..89ea567a80 100644 --- a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexErrors.cs +++ b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexErrors.cs @@ -5,12 +5,12 @@ using System.Text; using System.Threading; using System.Threading.Tasks; + using Microsoft.Extensions.Logging; using NServiceBus.CustomChecks; - using NServiceBus.Logging; using Raven.Client.Documents.Operations.Indexes; using ServiceControl.Persistence.RavenDB; - class CheckRavenDBIndexErrors(IRavenDocumentStoreProvider documentStoreProvider) : CustomCheck("Error Database Index Errors", "ServiceControl Health", TimeSpan.FromMinutes(5)) + class CheckRavenDBIndexErrors(IRavenDocumentStoreProvider documentStoreProvider, ILogger logger) : CustomCheck("Error Database Index Errors", "ServiceControl Health", TimeSpan.FromMinutes(5)) { public override async Task PerformCheck(CancellationToken cancellationToken = default) { @@ -41,10 +41,8 @@ public override async Task PerformCheck(CancellationToken cancellat text.AppendLine().AppendLine("See: https://docs.particular.net/search?q=servicecontrol+troubleshooting"); var message = text.ToString(); - Logger.Error(message); + logger.LogError(message); return CheckResult.Failed(message); } - - static readonly ILog Logger = LogManager.GetLogger(); } } diff --git a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexLag.cs b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexLag.cs index 7084d78e34..d0fd05de1c 100644 --- a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexLag.cs +++ b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexLag.cs @@ -5,13 +5,13 @@ using System.Text; using System.Threading; using System.Threading.Tasks; + using Microsoft.Extensions.Logging; using NServiceBus.CustomChecks; - using NServiceBus.Logging; using Raven.Client.Documents.Operations; using ServiceControl.Persistence.RavenDB; using CustomCheck = NServiceBus.CustomChecks.CustomCheck; - class CheckRavenDBIndexLag(IRavenDocumentStoreProvider documentStoreProvider) : CustomCheck("Error Database Index Lag", "ServiceControl Health", TimeSpan.FromMinutes(5)) + class CheckRavenDBIndexLag(IRavenDocumentStoreProvider documentStoreProvider, ILogger logger) : CustomCheck("Error Database Index Lag", "ServiceControl Health", TimeSpan.FromMinutes(5)) { public override async Task PerformCheck(CancellationToken cancellationToken = default) { @@ -31,7 +31,7 @@ public override async Task PerformCheck(CancellationToken cancellat return CheckResult.Pass; } - static int CheckAndReportIndexesWithTooMuchIndexLag(IndexInformation[] indexes) + int CheckAndReportIndexesWithTooMuchIndexLag(IndexInformation[] indexes) { int indexCountWithTooMuchLag = 0; @@ -44,12 +44,12 @@ static int CheckAndReportIndexesWithTooMuchIndexLag(IndexInformation[] indexes) if (indexLag > IndexLagThresholdError) { indexCountWithTooMuchLag++; - Log.Error($"Index [{indexStats.Name}] IndexingLag {indexLag} is above error threshold ({IndexLagThresholdError}). Launch in maintenance mode to let indexes catch up."); + logger.LogError("Index [{IndexName}] IndexingLag {IndexLag} is above error threshold ({IndexLagThresholdError}). Launch in maintenance mode to let indexes catch up.", indexStats.Name, indexLag, IndexLagThresholdError); } else if (indexLag > IndexLagThresholdWarning) { indexCountWithTooMuchLag++; - Log.Warn($"Index [{indexStats.Name}] IndexingLag {indexLag} is above warning threshold ({IndexLagThresholdWarning}). Launch in maintenance mode to let indexes catch up."); + logger.LogWarning("Index [{IndexName}] IndexingLag {IndexLag} is above warning threshold ({IndexLagThresholdWarning}). Launch in maintenance mode to let indexes catch up.", indexStats.Name, indexLag, IndexLagThresholdWarning); } } } @@ -57,9 +57,9 @@ static int CheckAndReportIndexesWithTooMuchIndexLag(IndexInformation[] indexes) return indexCountWithTooMuchLag; } - static void CreateDiagnosticsLogEntry(DatabaseStatistics statistics, IndexInformation[] indexes) + void CreateDiagnosticsLogEntry(DatabaseStatistics statistics, IndexInformation[] indexes) { - if (!Log.IsDebugEnabled) + if (!logger.IsEnabled(LogLevel.Debug)) { return; } @@ -73,11 +73,10 @@ static void CreateDiagnosticsLogEntry(DatabaseStatistics statistics, IndexInform { report.AppendLine($"- Index [{indexStats.Name,-44}] State: {indexStats.State}, Stale: {indexStats.IsStale,-5}, Priority: {indexStats.Priority,-6}, LastIndexingTime: {indexStats.LastIndexingTime:u}"); } - Log.Debug(report.ToString()); + logger.LogDebug(report.ToString()); } static readonly TimeSpan IndexLagThresholdWarning = TimeSpan.FromMinutes(1); static readonly TimeSpan IndexLagThresholdError = TimeSpan.FromMinutes(10); - static readonly ILog Log = LogManager.GetLogger(); } } \ No newline at end of file diff --git a/src/ServiceControl.Persistence.RavenDB/ErrorMessagesDataStore.cs b/src/ServiceControl.Persistence.RavenDB/ErrorMessagesDataStore.cs index 4c3f77bf6d..4940807646 100644 --- a/src/ServiceControl.Persistence.RavenDB/ErrorMessagesDataStore.cs +++ b/src/ServiceControl.Persistence.RavenDB/ErrorMessagesDataStore.cs @@ -6,7 +6,7 @@ using System.Linq; using System.Threading.Tasks; using Editing; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using Raven.Client; using Raven.Client.Documents; using Raven.Client.Documents.Commands; @@ -28,7 +28,8 @@ class ErrorMessagesDataStore( IRavenSessionProvider sessionProvider, IRavenDocumentStoreProvider documentStoreProvider, IBodyStorage bodyStorage, - ExpirationManager expirationManager) + ExpirationManager expirationManager, + ILogger logger) : IErrorMessageDataStore { public async Task>> GetAllMessages( @@ -338,7 +339,7 @@ public async Task ErrorLastBy(string failedMessageId) return result; } - static FailedMessageView Map(FailedMessage message, IAsyncDocumentSession session) + FailedMessageView Map(FailedMessage message, IAsyncDocumentSession session) { var processingAttempt = message.ProcessingAttempts.Last(); @@ -369,7 +370,7 @@ static FailedMessageView Map(FailedMessage message, IAsyncDocumentSession sessio } catch (Exception ex) { - Logger.Warn($"Unable to parse SendingEndpoint from metadata for messageId {message.UniqueMessageId}", ex); + logger.LogWarning(ex, "Unable to parse SendingEndpoint from metadata for messageId {UniqueMessageId}", message.UniqueMessageId); failedMsgView.SendingEndpoint = EndpointDetailsParser.SendingEndpoint(processingAttempt.Headers); } @@ -379,7 +380,7 @@ static FailedMessageView Map(FailedMessage message, IAsyncDocumentSession sessio } catch (Exception ex) { - Logger.Warn($"Unable to parse ReceivingEndpoint from metadata for messageId {message.UniqueMessageId}", ex); + logger.LogWarning(ex, "Unable to parse ReceivingEndpoint from metadata for messageId {UniqueMessageId}", message.UniqueMessageId); failedMsgView.ReceivingEndpoint = EndpointDetailsParser.ReceivingEndpoint(processingAttempt.Headers); } @@ -676,7 +677,5 @@ public async Task StoreFailedMessagesForTestsOnly(params FailedMessage[] failedM await session.SaveChangesAsync(); } - - static readonly ILog Logger = LogManager.GetLogger(); } } diff --git a/src/ServiceControl.Persistence.RavenDB/ExternalIntegrationRequestsDataStore.cs b/src/ServiceControl.Persistence.RavenDB/ExternalIntegrationRequestsDataStore.cs index 27762fc546..6f68141edc 100644 --- a/src/ServiceControl.Persistence.RavenDB/ExternalIntegrationRequestsDataStore.cs +++ b/src/ServiceControl.Persistence.RavenDB/ExternalIntegrationRequestsDataStore.cs @@ -8,8 +8,8 @@ using System.Threading.Tasks; using ExternalIntegrations; using Microsoft.Extensions.Hosting; + using Microsoft.Extensions.Logging; using NServiceBus; - using NServiceBus.Logging; using Raven.Client.Documents; using Raven.Client.Documents.Changes; using ServiceControl.Infrastructure; @@ -20,12 +20,17 @@ class ExternalIntegrationRequestsDataStore , IAsyncDisposable { - public ExternalIntegrationRequestsDataStore(RavenPersisterSettings settings, IRavenSessionProvider sessionProvider, IRavenDocumentStoreProvider documentStoreProvider, CriticalError criticalError) + public ExternalIntegrationRequestsDataStore( + RavenPersisterSettings settings, + IRavenSessionProvider sessionProvider, + IRavenDocumentStoreProvider documentStoreProvider, + CriticalError criticalError, + ILogger logger) { this.settings = settings; this.sessionProvider = sessionProvider; this.documentStoreProvider = documentStoreProvider; - + this.logger = logger; var timeToWait = TimeSpan.FromMinutes(5); var delayAfterFailure = TimeSpan.FromSeconds(20); @@ -33,6 +38,7 @@ public ExternalIntegrationRequestsDataStore(RavenPersisterSettings settings, IRa "EventDispatcher", timeToWait, ex => criticalError.Raise("Repeated failures when dispatching external integration events.", ex), + logger, timeToWaitWhenArmed: delayAfterFailure ); } @@ -97,7 +103,7 @@ async Task StartDispatcherTask(CancellationToken cancellationToken) } catch (Exception ex) { - Logger.Error("An exception occurred when dispatching external integration events", ex); + logger.LogError(ex, "An exception occurred when dispatching external integration events"); await circuitBreaker.Failure(ex, cancellationToken); if (!tokenSource.IsCancellationRequested) @@ -143,10 +149,7 @@ async Task TryDispatchEventBatch() } var allContexts = awaitingDispatching.Select(r => r.DispatchContext).ToArray(); - if (Logger.IsDebugEnabled) - { - Logger.Debug($"Dispatching {allContexts.Length} events."); - } + logger.LogDebug("Dispatching {EventCount} events.", allContexts.Length); await callback(allContexts); @@ -206,6 +209,6 @@ public async ValueTask DisposeAsync() Func callback; bool isDisposed; - static ILog Logger = LogManager.GetLogger(typeof(ExternalIntegrationRequestsDataStore)); + readonly ILogger logger; } } \ No newline at end of file diff --git a/src/ServiceControl.Persistence.RavenDB/FailedErrorImportDataStore.cs b/src/ServiceControl.Persistence.RavenDB/FailedErrorImportDataStore.cs index 440468a790..730413af0b 100644 --- a/src/ServiceControl.Persistence.RavenDB/FailedErrorImportDataStore.cs +++ b/src/ServiceControl.Persistence.RavenDB/FailedErrorImportDataStore.cs @@ -3,14 +3,12 @@ using System; using System.Threading; using System.Threading.Tasks; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using Raven.Client.Documents.Commands; using ServiceControl.Operations; - class FailedErrorImportDataStore(IRavenSessionProvider sessionProvider) : IFailedErrorImportDataStore + class FailedErrorImportDataStore(IRavenSessionProvider sessionProvider, ILogger logger) : IFailedErrorImportDataStore { - static readonly ILog Logger = LogManager.GetLogger(typeof(FailedErrorImportDataStore)); - public async Task ProcessFailedErrorImports(Func processMessage, CancellationToken cancellationToken) { var succeeded = 0; @@ -30,28 +28,25 @@ public async Task ProcessFailedErrorImports(Func p succeeded++; - if (Logger.IsDebugEnabled) - { - Logger.Debug($"Successfully re-imported failed error message {transportMessage.Id}."); - } + logger.LogDebug("Successfully re-imported failed error message {MessageId}", transportMessage.Id); } catch (OperationCanceledException e) when (cancellationToken.IsCancellationRequested) { - Logger.Info("Cancelled", e); + logger.LogInformation(e, "Cancelled"); } catch (Exception e) { - Logger.Error($"Error while attempting to re-import failed error message {transportMessage.Id}.", e); + logger.LogError(e, "Error while attempting to re-import failed error message {MessageId}.", transportMessage.Id); failed++; } } } - Logger.Info($"Done re-importing failed errors. Successfully re-imported {succeeded} messages. Failed re-importing {failed} messages."); + logger.LogInformation("Done re-importing failed errors. Successfully re-imported {SucceededCount} messages. Failed re-importing {FailedCount} messages.", succeeded, failed); if (failed > 0) { - Logger.Warn($"{failed} messages could not be re-imported. This could indicate a problem with the data. Contact Particular support if you need help with recovering the messages."); + logger.LogWarning("{FailedCount} messages could not be re-imported. This could indicate a problem with the data. Contact Particular support if you need help with recovering the messages.", failed); } } diff --git a/src/ServiceControl.Persistence.RavenDB/FailedMessageViewIndexNotifications.cs b/src/ServiceControl.Persistence.RavenDB/FailedMessageViewIndexNotifications.cs index 690bc056bb..83b2370b36 100644 --- a/src/ServiceControl.Persistence.RavenDB/FailedMessageViewIndexNotifications.cs +++ b/src/ServiceControl.Persistence.RavenDB/FailedMessageViewIndexNotifications.cs @@ -5,12 +5,12 @@ using System.Threading.Tasks; using Api; using Microsoft.Extensions.Hosting; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using Persistence; using Persistence.RavenDB; using Raven.Client.Documents; - class FailedMessageViewIndexNotifications(IRavenSessionProvider sessionProvider, IRavenDocumentStoreProvider documentStoreProvider) : IFailedMessageViewIndexNotifications + class FailedMessageViewIndexNotifications(IRavenSessionProvider sessionProvider, IRavenDocumentStoreProvider documentStoreProvider, ILogger logger) : IFailedMessageViewIndexNotifications , IDisposable , IHostedService { @@ -22,7 +22,7 @@ void OnNext() } catch (Exception ex) { - Logger.WarnFormat("Failed to emit MessageFailuresUpdated - {0}", ex); + logger.LogWarning(ex, "Failed to emit MessageFailuresUpdated"); } } @@ -87,8 +87,6 @@ public Task StopAsync(CancellationToken cancellationToken) return Task.CompletedTask; } - static readonly ILog Logger = LogManager.GetLogger(typeof(FailedMessageViewIndexNotifications)); - Func subscriber; IDisposable subscription; int lastUnresolvedCount; diff --git a/src/ServiceControl.Persistence.RavenDB/Infrastructure/Subscriptions/RavenSubscriptionStorage.cs b/src/ServiceControl.Persistence.RavenDB/Infrastructure/Subscriptions/RavenSubscriptionStorage.cs index fdf1520dd6..6b8218b753 100644 --- a/src/ServiceControl.Persistence.RavenDB/Infrastructure/Subscriptions/RavenSubscriptionStorage.cs +++ b/src/ServiceControl.Persistence.RavenDB/Infrastructure/Subscriptions/RavenSubscriptionStorage.cs @@ -7,9 +7,9 @@ using System.Text; using System.Threading; using System.Threading.Tasks; + using Microsoft.Extensions.Logging; using NServiceBus; using NServiceBus.Extensibility; - using NServiceBus.Logging; using NServiceBus.Settings; using NServiceBus.Unicast.Subscriptions; using NServiceBus.Unicast.Subscriptions.MessageDrivenSubscriptions; @@ -21,12 +21,12 @@ class RavenSubscriptionStorage : IServiceControlSubscriptionStorage { - public RavenSubscriptionStorage(IRavenSessionProvider sessionProvider, IReadOnlySettings settings, ReceiveAddresses receiveAddresses) : - this(sessionProvider, settings.EndpointName(), receiveAddresses.MainReceiveAddress, settings.GetAvailableTypes().Implementing().Select(e => new MessageType(e)).ToArray()) + public RavenSubscriptionStorage(IRavenSessionProvider sessionProvider, IReadOnlySettings settings, ReceiveAddresses receiveAddresses, ILogger logger) : + this(sessionProvider, settings.EndpointName(), receiveAddresses.MainReceiveAddress, settings.GetAvailableTypes().Implementing().Select(e => new MessageType(e)).ToArray(), logger) { } - public RavenSubscriptionStorage(IRavenSessionProvider sessionProvider, string endpointName, string localAddress, MessageType[] locallyHandledEventTypes) + public RavenSubscriptionStorage(IRavenSessionProvider sessionProvider, string endpointName, string localAddress, MessageType[] locallyHandledEventTypes, ILogger logger) { this.sessionProvider = sessionProvider; localClient = new SubscriptionClient @@ -36,7 +36,7 @@ public RavenSubscriptionStorage(IRavenSessionProvider sessionProvider, string en }; this.locallyHandledEventTypes = locallyHandledEventTypes; - + this.logger = logger; subscriptions = new Subscriptions(); UpdateLookup(); } @@ -198,9 +198,9 @@ async Task SetSubscriptions(Subscriptions newSubscriptions) static Task LoadSubscriptions(IAsyncDocumentSession session) => session.LoadAsync(Subscriptions.SingleDocumentId); - static async Task MigrateSubscriptions(IAsyncDocumentSession session, SubscriptionClient localClient) + async Task MigrateSubscriptions(IAsyncDocumentSession session, SubscriptionClient localClient) { - Logger.Info("Migrating subscriptions to new format"); + logger.LogInformation("Migrating subscriptions to new format"); var subscriptions = new Subscriptions(); @@ -224,10 +224,8 @@ static async Task MigrateSubscriptions(IAsyncDocumentSession sess Subscriptions subscriptions; ILookup subscriptionsLookup; MessageType[] locallyHandledEventTypes; - + readonly ILogger logger; SemaphoreSlim subscriptionsLock = new SemaphoreSlim(1); - - static readonly ILog Logger = LogManager.GetLogger(); } class Subscriptions diff --git a/src/ServiceControl.Persistence.RavenDB/RavenEmbeddedPersistenceLifecycle.cs b/src/ServiceControl.Persistence.RavenDB/RavenEmbeddedPersistenceLifecycle.cs index f1971af65c..f0172acff7 100644 --- a/src/ServiceControl.Persistence.RavenDB/RavenEmbeddedPersistenceLifecycle.cs +++ b/src/ServiceControl.Persistence.RavenDB/RavenEmbeddedPersistenceLifecycle.cs @@ -6,12 +6,12 @@ namespace ServiceControl.Persistence.RavenDB using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Hosting; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using Raven.Client.Documents; using Raven.Client.Exceptions.Database; using ServiceControl.RavenDB; - sealed class RavenEmbeddedPersistenceLifecycle(RavenPersisterSettings databaseConfiguration, IHostApplicationLifetime lifetime) + sealed class RavenEmbeddedPersistenceLifecycle(RavenPersisterSettings databaseConfiguration, IHostApplicationLifetime lifetime, ILogger logger) : IRavenPersistenceLifecycle, IRavenDocumentStoreProvider, IDisposable { public async ValueTask GetDocumentStore(CancellationToken cancellationToken = default) @@ -58,7 +58,7 @@ public async Task Initialize(CancellationToken cancellationToken) } catch (DatabaseLoadTimeoutException e) { - Log.Warn("Could not connect to database. Retrying in 500ms...", e); + logger.LogWarning(e, "Could not connect to database. Retrying in 500ms..."); await Task.Delay(500, cancellationToken); } } @@ -86,7 +86,5 @@ public void Dispose() IDocumentStore? documentStore; EmbeddedDatabase? database; readonly SemaphoreSlim initializeSemaphore = new(1, 1); - - static readonly ILog Log = LogManager.GetLogger(typeof(RavenEmbeddedPersistenceLifecycle)); } } \ No newline at end of file diff --git a/src/ServiceControl.Persistence.RavenDB/RavenPersistenceConfiguration.cs b/src/ServiceControl.Persistence.RavenDB/RavenPersistenceConfiguration.cs index f9f66aa6ca..c9d03685e7 100644 --- a/src/ServiceControl.Persistence.RavenDB/RavenPersistenceConfiguration.cs +++ b/src/ServiceControl.Persistence.RavenDB/RavenPersistenceConfiguration.cs @@ -6,6 +6,7 @@ using Configuration; using CustomChecks; using Particular.LicensingComponent.Contracts; + using ServiceControl.Infrastructure; class RavenPersistenceConfiguration : IPersistenceConfiguration { @@ -29,7 +30,7 @@ static T GetRequiredSetting(SettingsRootNamespace settingsRootNamespace, stri } var ravenDbLogLevel = SettingsReader.Read(settingsRootNamespace, RavenBootstrapper.RavenDbLogLevelKey, "Warn"); - var logsMode = RavenDbLogLevelToLogsModeMapper.Map(ravenDbLogLevel); + var logsMode = RavenDbLogLevelToLogsModeMapper.Map(ravenDbLogLevel, LoggerUtil.CreateStaticLogger()); var settings = new RavenPersisterSettings { diff --git a/src/ServiceControl.Persistence.RavenDB/Recoverability/Archiving/ArchiveDocumentManager.cs b/src/ServiceControl.Persistence.RavenDB/Recoverability/Archiving/ArchiveDocumentManager.cs index 46589133a4..c83e693141 100644 --- a/src/ServiceControl.Persistence.RavenDB/Recoverability/Archiving/ArchiveDocumentManager.cs +++ b/src/ServiceControl.Persistence.RavenDB/Recoverability/Archiving/ArchiveDocumentManager.cs @@ -5,14 +5,14 @@ using System.Linq; using System.Threading.Tasks; using MessageFailures; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using Persistence.RavenDB; using Raven.Client.Documents; using Raven.Client.Documents.Commands.Batches; using Raven.Client.Documents.Operations; using Raven.Client.Documents.Session; - class ArchiveDocumentManager(ExpirationManager expirationManager) + class ArchiveDocumentManager(ExpirationManager expirationManager, ILogger logger) { public Task LoadArchiveOperation(IAsyncDocumentSession session, string groupId, ArchiveType archiveType) => session.LoadAsync(ArchiveOperation.MakeId(groupId, archiveType)); @@ -138,7 +138,7 @@ public async Task RemoveArchiveOperation(IRavenSessionProvider sessionProvider, session.Advanced.Defer(new DeleteCommandData(archiveOperation.Id, null)); await session.SaveChangesAsync(); - Logger.Info($"Removing ArchiveOperation {archiveOperation.Id} completed"); + logger.LogInformation("Removing ArchiveOperation {ArchiveOperationId} completed", archiveOperation.Id); } public class GroupDetails @@ -147,6 +147,5 @@ public class GroupDetails public int NumberOfMessagesInGroup { get; set; } } - static readonly ILog Logger = LogManager.GetLogger(); } } \ No newline at end of file diff --git a/src/ServiceControl.Persistence.RavenDB/Recoverability/Archiving/MessageArchiver.cs b/src/ServiceControl.Persistence.RavenDB/Recoverability/Archiving/MessageArchiver.cs index caf8715282..64f722bbe2 100644 --- a/src/ServiceControl.Persistence.RavenDB/Recoverability/Archiving/MessageArchiver.cs +++ b/src/ServiceControl.Persistence.RavenDB/Recoverability/Archiving/MessageArchiver.cs @@ -4,8 +4,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; - using NServiceBus.Logging; - using Raven.Client.Documents; + using Microsoft.Extensions.Logging; using RavenDB; using ServiceControl.Infrastructure.DomainEvents; using ServiceControl.Persistence.Recoverability; @@ -17,15 +16,17 @@ public MessageArchiver( IRavenSessionProvider sessionProvider, OperationsManager operationsManager, IDomainEvents domainEvents, - ExpirationManager expirationManager + ExpirationManager expirationManager, + ILogger logger ) { this.sessionProvider = sessionProvider; this.domainEvents = domainEvents; this.expirationManager = expirationManager; + this.logger = logger; this.operationsManager = operationsManager; - archiveDocumentManager = new ArchiveDocumentManager(expirationManager); + archiveDocumentManager = new ArchiveDocumentManager(expirationManager, logger); archivingManager = new ArchivingManager(domainEvents, operationsManager); unarchiveDocumentManager = new UnarchiveDocumentManager(); @@ -34,7 +35,7 @@ ExpirationManager expirationManager public async Task ArchiveAllInGroup(string groupId) { - logger.Info($"Archiving of {groupId} started"); + logger.LogInformation("Archiving of {GroupId} started", groupId); ArchiveOperation archiveOperation; using (var session = await sessionProvider.OpenSession()) @@ -48,15 +49,15 @@ public async Task ArchiveAllInGroup(string groupId) var groupDetails = await archiveDocumentManager.GetGroupDetails(session, groupId); if (groupDetails.NumberOfMessagesInGroup == 0) { - logger.Warn($"No messages to archive in group {groupId}"); + logger.LogWarning("No messages to archive in group {GroupId}", groupId); return; } - logger.Info($"Splitting group {groupId} into batches"); + logger.LogInformation("Splitting group {GroupId} into batches", groupId); archiveOperation = await archiveDocumentManager.CreateArchiveOperation(session, groupId, ArchiveType.FailureGroup, groupDetails.NumberOfMessagesInGroup, groupDetails.GroupName, batchSize); await session.SaveChangesAsync(); - logger.Info($"Group {groupId} has been split into {archiveOperation.NumberOfBatches} batches"); + logger.LogInformation("Group {GroupId} has been split into {NumberOfBatches} batches", groupId, archiveOperation.NumberOfBatches); } } @@ -70,11 +71,11 @@ public async Task ArchiveAllInGroup(string groupId) if (nextBatch == null) { // We're only here in the case where Raven indexes are stale - logger.Warn($"Attempting to archive a batch ({archiveOperation.Id}/{archiveOperation.CurrentBatch}) which appears to already have been archived."); + logger.LogWarning("Attempting to archive a batch ({ArchiveOperationId}/{ArchiveOperationCurrentBatch}) which appears to already have been archived.", archiveOperation.Id, archiveOperation.CurrentBatch); } else { - logger.Info($"Archiving {nextBatch.DocumentIds.Count} messages from group {groupId} starting"); + logger.LogInformation("Archiving {MessageCount} messages from group {GroupId} starting", nextBatch.DocumentIds.Count, groupId); } archiveDocumentManager.ArchiveMessageGroupBatch(batchSession, nextBatch); @@ -98,17 +99,17 @@ await domainEvents.Raise(new FailedMessageGroupBatchArchived if (nextBatch != null) { - logger.Info($"Archiving of {nextBatch.DocumentIds.Count} messages from group {groupId} completed"); + logger.LogInformation("Archiving of {MessageCount} messages from group {GroupId} completed", nextBatch.DocumentIds.Count, groupId); } } } - logger.Info($"Archiving of group {groupId} is complete. Waiting for index updates."); + logger.LogInformation("Archiving of group {GroupId} is complete. Waiting for index updates.", groupId); await archivingManager.ArchiveOperationFinalizing(archiveOperation.RequestId, archiveOperation.ArchiveType); if (!await archiveDocumentManager.WaitForIndexUpdateOfArchiveOperation(sessionProvider, archiveOperation.RequestId, TimeSpan.FromMinutes(5)) ) { - logger.Warn($"Archiving group {groupId} completed but index not updated."); + logger.LogWarning("Archiving group {GroupId} completed but index not updated.", groupId); } await archivingManager.ArchiveOperationCompleted(archiveOperation.RequestId, archiveOperation.ArchiveType); @@ -121,12 +122,12 @@ await domainEvents.Raise(new FailedMessageGroupArchived MessagesCount = archiveOperation.TotalNumberOfMessages, }); - logger.Info($"Archiving of group {groupId} completed"); + logger.LogInformation("Archiving of group {GroupId} completed", groupId); } public async Task UnarchiveAllInGroup(string groupId) { - logger.Info($"Unarchiving of {groupId} started"); + logger.LogInformation("Unarchiving of {GroupId} started", groupId); UnarchiveOperation unarchiveOperation; using (var session = await sessionProvider.OpenSession()) @@ -140,16 +141,16 @@ public async Task UnarchiveAllInGroup(string groupId) var groupDetails = await unarchiveDocumentManager.GetGroupDetails(session, groupId); if (groupDetails.NumberOfMessagesInGroup == 0) { - logger.Warn($"No messages to unarchive in group {groupId}"); + logger.LogWarning("No messages to unarchive in group {GroupId}", groupId); return; } - logger.Info($"Splitting group {groupId} into batches"); + logger.LogInformation("Splitting group {GroupId} into batches", groupId); unarchiveOperation = await unarchiveDocumentManager.CreateUnarchiveOperation(session, groupId, ArchiveType.FailureGroup, groupDetails.NumberOfMessagesInGroup, groupDetails.GroupName, batchSize); await session.SaveChangesAsync(); - logger.Info($"Group {groupId} has been split into {unarchiveOperation.NumberOfBatches} batches"); + logger.LogInformation("Group {GroupId} has been split into {NumberOfBatches} batches", groupId, unarchiveOperation.NumberOfBatches); } } @@ -162,11 +163,11 @@ public async Task UnarchiveAllInGroup(string groupId) if (nextBatch == null) { // We're only here in the case where Raven indexes are stale - logger.Warn($"Attempting to unarchive a batch ({unarchiveOperation.Id}/{unarchiveOperation.CurrentBatch}) which appears to already have been archived."); + logger.LogWarning("Attempting to unarchive a batch ({UnarchiveOperationId}/{UnarchiveOperationCurrentBatch}) which appears to already have been archived.", unarchiveOperation.Id, unarchiveOperation.CurrentBatch); } else { - logger.Info($"Unarchiving {nextBatch.DocumentIds.Count} messages from group {groupId} starting"); + logger.LogInformation("Unarchiving {MessageCount} messages from group {GroupId} starting", nextBatch.DocumentIds.Count, groupId); } unarchiveDocumentManager.UnarchiveMessageGroupBatch(batchSession, nextBatch, expirationManager); @@ -190,19 +191,19 @@ await domainEvents.Raise(new FailedMessageGroupBatchUnarchived if (nextBatch != null) { - logger.Info($"Unarchiving of {nextBatch.DocumentIds.Count} messages from group {groupId} completed"); + logger.LogInformation("Unarchiving of {MessageCount} messages from group {GroupId} completed", nextBatch.DocumentIds.Count, groupId); } } - logger.Info($"Unarchiving of group {groupId} is complete. Waiting for index updates."); + logger.LogInformation("Unarchiving of group {GroupId} is complete. Waiting for index updates.", groupId); await unarchivingManager.UnarchiveOperationFinalizing(unarchiveOperation.RequestId, unarchiveOperation.ArchiveType); if (!await unarchiveDocumentManager.WaitForIndexUpdateOfUnarchiveOperation(sessionProvider, unarchiveOperation.RequestId, TimeSpan.FromMinutes(5)) ) { - logger.Warn($"Unarchiving group {groupId} completed but index not updated."); + logger.LogWarning("Unarchiving group {GroupId} completed but index not updated.", groupId); } - logger.Info($"Unarchiving of group {groupId} completed"); + logger.LogInformation("Unarchiving of group {GroupId} completed", groupId); await unarchivingManager.UnarchiveOperationCompleted(unarchiveOperation.RequestId, unarchiveOperation.ArchiveType); await unarchiveDocumentManager.RemoveUnarchiveOperation(sessionProvider, unarchiveOperation); @@ -239,7 +240,7 @@ public IEnumerable GetArchivalOperations() readonly ArchivingManager archivingManager; readonly UnarchiveDocumentManager unarchiveDocumentManager; readonly UnarchivingManager unarchivingManager; - static readonly ILog logger = LogManager.GetLogger(); + readonly ILogger logger; const int batchSize = 1000; } } diff --git a/src/ServiceControl.Persistence.RavenDB/RetryBatchesDataStore.cs b/src/ServiceControl.Persistence.RavenDB/RetryBatchesDataStore.cs index 3138d9b893..4d951b9354 100644 --- a/src/ServiceControl.Persistence.RavenDB/RetryBatchesDataStore.cs +++ b/src/ServiceControl.Persistence.RavenDB/RetryBatchesDataStore.cs @@ -4,18 +4,16 @@ using System.Collections.Generic; using System.Threading.Tasks; using MessageFailures; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using Raven.Client.Documents.Commands; using Raven.Client.Documents.Commands.Batches; using Raven.Client.Documents.Operations; using Raven.Client.Exceptions; using ServiceControl.Recoverability; - class RetryBatchesDataStore(IRavenSessionProvider sessionProvider, IRavenDocumentStoreProvider documentStoreProvider, ExpirationManager expirationManager) + class RetryBatchesDataStore(IRavenSessionProvider sessionProvider, IRavenDocumentStoreProvider documentStoreProvider, ExpirationManager expirationManager, ILogger logger) : IRetryBatchesDataStore { - static readonly ILog Log = LogManager.GetLogger(typeof(RetryBatchesDataStore)); - public async Task CreateRetryBatchesManager() { var session = await sessionProvider.OpenSession(); @@ -32,7 +30,7 @@ public async Task RecordFailedStagingAttempt(IReadOnlyCollection { var failedMessageRetry = failedMessageRetriesById[failedMessage.Id]; - Log.Warn($"Attempt {1} of {maxStagingAttempts} to stage a retry message {failedMessage.UniqueMessageId} failed", e); + logger.LogWarning(e, "Attempt 1 of {MaxStagingAttempts} to stage a retry message {UniqueMessageId} failed", maxStagingAttempts, failedMessage.UniqueMessageId); commands[commandIndex] = new PatchCommandData(failedMessageRetry.Id, null, new PatchRequest { @@ -57,8 +55,8 @@ public async Task RecordFailedStagingAttempt(IReadOnlyCollection } catch (ConcurrencyException) { - Log.DebugFormat( - "Ignoring concurrency exception while incrementing staging attempt count for {0}", + logger.LogDebug( + "Ignoring concurrency exception while incrementing staging attempt count for {StagingId}", stagingId); } } @@ -75,7 +73,7 @@ public async Task IncrementAttemptCounter(FailedMessageRetry message) } catch (ConcurrencyException) { - Log.DebugFormat("Ignoring concurrency exception while incrementing staging attempt count for {0}", message.FailedMessageId); + logger.LogDebug("Ignoring concurrency exception while incrementing staging attempt count for {MessageId}", message.FailedMessageId); } } diff --git a/src/ServiceControl.Persistence.RavenDB/RetryDocumentDataStore.cs b/src/ServiceControl.Persistence.RavenDB/RetryDocumentDataStore.cs index 5d5270cc14..686b77df9f 100644 --- a/src/ServiceControl.Persistence.RavenDB/RetryDocumentDataStore.cs +++ b/src/ServiceControl.Persistence.RavenDB/RetryDocumentDataStore.cs @@ -5,7 +5,7 @@ using System.Linq; using System.Threading.Tasks; using MessageFailures; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using Persistence.Infrastructure; using Raven.Client.Documents; using Raven.Client.Documents.Commands.Batches; @@ -15,7 +15,7 @@ using ServiceControl.MessageFailures.Api; using ServiceControl.Recoverability; - class RetryDocumentDataStore(IRavenSessionProvider sessionProvider, IRavenDocumentStoreProvider documentStoreProvider) : IRetryDocumentDataStore + class RetryDocumentDataStore(IRavenSessionProvider sessionProvider, IRavenDocumentStoreProvider documentStoreProvider, ILogger logger) : IRetryDocumentDataStore { public async Task StageRetryByUniqueMessageIds(string batchDocumentId, string[] messageIds) { @@ -48,7 +48,7 @@ public async Task MoveBatchToStaging(string batchDocumentId) } catch (ConcurrencyException) { - Logger.DebugFormat("Ignoring concurrency exception while moving batch to staging {0}", batchDocumentId); + logger.LogDebug("Ignoring concurrency exception while moving batch to staging {BatchDocumentId}", batchDocumentId); } } @@ -202,7 +202,5 @@ public async Task QueryFailureGroupViewOnGroupId(string groupI .FirstOrDefaultAsync(x => x.Id == groupId); return group; } - - static readonly ILog Logger = LogManager.GetLogger(typeof(RetryDocumentDataStore)); } } \ No newline at end of file diff --git a/src/ServiceControl.Persistence.Tests.InMemory/ServiceControl.Persistence.Tests.InMemory.csproj b/src/ServiceControl.Persistence.Tests.InMemory/ServiceControl.Persistence.Tests.InMemory.csproj index 4e0fac1da4..14f8701c33 100644 --- a/src/ServiceControl.Persistence.Tests.InMemory/ServiceControl.Persistence.Tests.InMemory.csproj +++ b/src/ServiceControl.Persistence.Tests.InMemory/ServiceControl.Persistence.Tests.InMemory.csproj @@ -6,6 +6,7 @@ + diff --git a/src/ServiceControl.Persistence.Tests.RavenDB/ServiceControl.Persistence.Tests.RavenDB.csproj b/src/ServiceControl.Persistence.Tests.RavenDB/ServiceControl.Persistence.Tests.RavenDB.csproj index bb4f028ee1..f3ed716dde 100644 --- a/src/ServiceControl.Persistence.Tests.RavenDB/ServiceControl.Persistence.Tests.RavenDB.csproj +++ b/src/ServiceControl.Persistence.Tests.RavenDB/ServiceControl.Persistence.Tests.RavenDB.csproj @@ -5,6 +5,7 @@ + diff --git a/src/ServiceControl.Persistence.Tests.RavenDB/SubscriptionPersisterTests.cs b/src/ServiceControl.Persistence.Tests.RavenDB/SubscriptionPersisterTests.cs index bf60c59a17..1a5b35664c 100644 --- a/src/ServiceControl.Persistence.Tests.RavenDB/SubscriptionPersisterTests.cs +++ b/src/ServiceControl.Persistence.Tests.RavenDB/SubscriptionPersisterTests.cs @@ -8,6 +8,7 @@ using NServiceBus.Unicast.Subscriptions; using NServiceBus.Unicast.Subscriptions.MessageDrivenSubscriptions; using NUnit.Framework; + using ServiceControl.Infrastructure; using ServiceControl.Infrastructure.RavenDB.Subscriptions; [TestFixture] @@ -16,7 +17,7 @@ class SubscriptionPersisterTests : RavenPersistenceTestBase [Test] public async Task ShouldReturnSubscriptionsForOlderVersionsOfSameMessageType() { - var subscriptionPersister = new RavenSubscriptionStorage(SessionProvider, "NServiceBus.Routing.EndpointName", "TestEndpoint", []); + var subscriptionPersister = new RavenSubscriptionStorage(SessionProvider, "NServiceBus.Routing.EndpointName", "TestEndpoint", [], LoggerUtil.CreateStaticLogger()); var v1MessageType = new MessageType(typeof(SampleMessageType).FullName, new Version(1, 0, 0)); var v2MessageType = new MessageType(typeof(SampleMessageType).FullName, new Version(2, 0, 0)); @@ -37,7 +38,7 @@ public async Task ShouldReturnSubscriptionsForOlderVersionsOfSameMessageType() [Test] public async Task ShouldReturnSubscriptionsForNewerVersionsOfSameMessageType() { - var subscriptionPersister = new RavenSubscriptionStorage(SessionProvider, "NServiceBus.Routing.EndpointName", "TestEndpoint", []); + var subscriptionPersister = new RavenSubscriptionStorage(SessionProvider, "NServiceBus.Routing.EndpointName", "TestEndpoint", [], LoggerUtil.CreateStaticLogger()); var v1MessageType = new MessageType(typeof(SampleMessageType).FullName, new Version(1, 0, 0)); var v2MessageType = new MessageType(typeof(SampleMessageType).FullName, new Version(2, 0, 0)); diff --git a/src/ServiceControl.Persistence.Tests/PersistenceTestBase.cs b/src/ServiceControl.Persistence.Tests/PersistenceTestBase.cs index c6d0de3aa2..7cc5f39cca 100644 --- a/src/ServiceControl.Persistence.Tests/PersistenceTestBase.cs +++ b/src/ServiceControl.Persistence.Tests/PersistenceTestBase.cs @@ -4,10 +4,12 @@ using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; using NServiceBus; using NServiceBus.Settings; using NUnit.Framework; using Particular.LicensingComponent.Persistence; +using ServiceControl.Infrastructure; using ServiceControl.Infrastructure.DomainEvents; using ServiceControl.Operations.BodyStorage; using ServiceControl.Persistence; @@ -30,6 +32,10 @@ public async Task SetUp() } var hostBuilder = Host.CreateApplicationBuilder(); + + LoggerUtil.ActiveLoggers = Loggers.Test; + hostBuilder.Logging.BuildLogger(LogLevel.Information); + await PersistenceTestsContext.Setup(hostBuilder); // This is not cool. We have things that are registered as part of "the persistence" that then require parts diff --git a/src/ServiceControl.Persistence/PersistenceManifest.cs b/src/ServiceControl.Persistence/PersistenceManifest.cs index 0be97cafb6..9279f6cdc6 100644 --- a/src/ServiceControl.Persistence/PersistenceManifest.cs +++ b/src/ServiceControl.Persistence/PersistenceManifest.cs @@ -5,7 +5,8 @@ using System.IO; using System.Linq; using System.Text.Json; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; + using ServiceControl.Infrastructure; public class PersistenceManifest { @@ -68,7 +69,7 @@ static PersistenceManifestLibrary() } catch (Exception ex) { - logger.Warn($"Failed to load persistence manifests from {assemblyDirectory}", ex); + logger.LogWarning(ex, "Failed to load persistence manifests from {AssemblyDirectory}", assemblyDirectory); } try @@ -83,10 +84,10 @@ static PersistenceManifestLibrary() } catch (Exception ex) { - logger.Warn($"Failed to load persistence manifests from development locations", ex); + logger.LogWarning(ex, "Failed to load persistence manifests from development locations"); } - PersistenceManifests.ForEach(m => logger.Info($"Found persistence manifest for {m.DisplayName}")); + PersistenceManifests.ForEach(m => logger.LogInformation("Found persistence manifest for {ManifestDisplayName}", m.DisplayName)); } static string GetAssemblyDirectory() @@ -107,7 +108,7 @@ public static PersistenceManifest Find(string persistenceType) return persistenceManifest; } - static readonly ILog logger = LogManager.GetLogger(typeof(PersistenceManifestLibrary)); + static readonly ILogger logger = LoggerUtil.CreateStaticLogger(typeof(PersistenceManifestLibrary)); } } diff --git a/src/ServiceControl.Persistence/ServiceControl.Persistence.csproj b/src/ServiceControl.Persistence/ServiceControl.Persistence.csproj index 050bcbec4b..1806eaf133 100644 --- a/src/ServiceControl.Persistence/ServiceControl.Persistence.csproj +++ b/src/ServiceControl.Persistence/ServiceControl.Persistence.csproj @@ -7,6 +7,7 @@ + diff --git a/src/ServiceControl.RavenDB/EmbeddedDatabase.cs b/src/ServiceControl.RavenDB/EmbeddedDatabase.cs index 590792fe20..e9fa10ea44 100644 --- a/src/ServiceControl.RavenDB/EmbeddedDatabase.cs +++ b/src/ServiceControl.RavenDB/EmbeddedDatabase.cs @@ -10,11 +10,12 @@ namespace ServiceControl.RavenDB using System.Threading.Tasks; using ByteSizeLib; using Microsoft.Extensions.Hosting; - using NServiceBus.Logging; + using Microsoft.Extensions.Logging; using Raven.Client.Documents; using Raven.Client.Documents.Conventions; using Raven.Client.ServerWide.Operations; using Raven.Embedded; + using ServiceControl.Infrastructure; using Sparrow.Logging; public sealed class EmbeddedDatabase : IDisposable @@ -67,7 +68,7 @@ public static EmbeddedDatabase Start(EmbeddedDatabaseConfiguration databaseConfi ); } - Logger.InfoFormat("Loading RavenDB license from {0}", licenseFileNameAndServerDirectory.LicenseFileName); + logger.LogInformation("Loading RavenDB license from {LicenseFileName}", licenseFileNameAndServerDirectory.LicenseFileName); var serverOptions = new ServerOptions { CommandLineArgs = @@ -119,12 +120,12 @@ void Start(ServerOptions serverOptions) shutdownCancellationToken.ThrowIfCancellationRequested(); - Logger.Info("Restarting RavenDB server process"); + logger.LogInformation("Restarting RavenDB server process"); await EmbeddedServer.Instance.RestartServerAsync(); restartRequired = false; - Logger.Info("RavenDB server process restarted successfully."); + logger.LogInformation("RavenDB server process restarted successfully."); } catch (OperationCanceledException) when (shutdownCancellationToken.IsCancellationRequested) { @@ -132,7 +133,7 @@ void Start(ServerOptions serverOptions) } catch (Exception e) { - Logger.Fatal($"RavenDB server restart failed. Restart will be retried in {delayBetweenRestarts}.", e); + logger.LogCritical(e, "RavenDB server restart failed. Restart will be retried in {RavenDelayBetweenRestarts}.", delayBetweenRestarts); } } }, CancellationToken.None); @@ -148,11 +149,11 @@ void OnServerProcessExited(object? sender, ServerProcessExitedEventArgs _) restartRequired = true; if (sender is Process process) { - Logger.Warn($"RavenDB server process exited unexpectedly with exitCode: {process.ExitCode}. Process will be restarted."); + logger.LogWarning("RavenDB server process exited unexpectedly with exitCode: {RavenExitCode}. Process will be restarted.", process.ExitCode); } else { - Logger.Warn($"RavenDB server process exited unexpectedly. Process will be restarted."); + logger.LogWarning("RavenDB server process exited unexpectedly. Process will be restarted."); } } @@ -187,7 +188,7 @@ public async Task DeleteDatabase(string dbName) public async Task Stop(CancellationToken cancellationToken) { - Logger.Debug("Stopping RavenDB server"); + logger.LogDebug("Stopping RavenDB server"); EmbeddedServer.Instance.ServerProcessExited -= OnServerProcessExited; await shutdownTokenSource.CancelAsync(); @@ -224,23 +225,23 @@ public async Task Stop(CancellationToken cancellationToken) { // We always want to try and kill the process, even when already cancelled processId = await EmbeddedServer.Instance.GetServerProcessIdAsync(CancellationToken.None); - Logger.WarnFormat("Killing RavenDB server PID {0} because host cancelled", processId); + logger.LogWarning("Killing RavenDB server PID {PID} because host cancelled", processId); using var ravenChildProcess = Process.GetProcessById(processId); ravenChildProcess.Kill(entireProcessTree: true); // Kill only signals - Logger.WarnFormat("Waiting for RavenDB server PID {0} to exit... ", processId); + logger.LogWarning("Waiting for RavenDB server PID {PID} to exit... ", processId); // When WaitForExitAsync returns, the process could still exist but in a frozen state to flush // memory mapped pages to storage. await ravenChildProcess.WaitForExitAsync(CancellationToken.None); } catch (Exception e) { - Logger.ErrorFormat("Failed to kill RavenDB server PID {0} shutdown\n{1}", processId, e); + logger.LogError(e, "Failed to kill RavenDB server PID {PID} shutdown", processId); } } serverOptions = null!; - Logger.Debug("Stopped RavenDB server"); + logger.LogDebug("Stopped RavenDB server"); } public void Dispose() @@ -262,9 +263,9 @@ public void Dispose() // Set GracefulShutdownTimeout to Zero and exit ASAP, under normal operation instance would already // have been allowed to gracefully stop during "Stop" method. serverOptions!.GracefulShutdownTimeout = TimeSpan.Zero; - Logger.Debug("Disposing RavenDB server"); + logger.LogDebug("Disposing RavenDB server"); EmbeddedServer.Instance.Dispose(); - Logger.Debug("Disposed RavenDB server"); + logger.LogDebug("Disposed RavenDB server"); } shutdownTokenSource.Dispose(); @@ -287,7 +288,7 @@ static void RecordStartup(EmbeddedDatabaseConfiguration configuration) RavenDB Logging Level: {configuration.LogsMode} -------------------------------------------------------------"; - Logger.Info(startupMessage); + logger.LogInformation(startupMessage); } static long DataSize(EmbeddedDatabaseConfiguration configuration) @@ -354,6 +355,6 @@ static long DirSize(DirectoryInfo d) ServerOptions? serverOptions; static TimeSpan delayBetweenRestarts = TimeSpan.FromSeconds(60); - static readonly ILog Logger = LogManager.GetLogger(); + static readonly ILogger logger = LoggerUtil.CreateStaticLogger(); } } diff --git a/src/ServiceControl.RavenDB/ServiceControl.RavenDB.csproj b/src/ServiceControl.RavenDB/ServiceControl.RavenDB.csproj index 46705a80e7..0479c4ff74 100644 --- a/src/ServiceControl.RavenDB/ServiceControl.RavenDB.csproj +++ b/src/ServiceControl.RavenDB/ServiceControl.RavenDB.csproj @@ -12,6 +12,10 @@ + + + + diff --git a/src/ServiceControl.Transports.Tests/TransportTestFixture.cs b/src/ServiceControl.Transports.Tests/TransportTestFixture.cs index ac1501232b..7dd9d6ef5d 100644 --- a/src/ServiceControl.Transports.Tests/TransportTestFixture.cs +++ b/src/ServiceControl.Transports.Tests/TransportTestFixture.cs @@ -23,8 +23,8 @@ class TransportTestFixture [SetUp] public virtual async Task Setup() { - //TODO remove LogManager usage - LogManager.UseFactory(new ExtensionsLoggerFactory(new TestContextAppenderFactory())); + //used for loggers outside of ServiceControl (i.e. transports and core) to use the logger factory defined here + LogManager.UseFactory(new ExtensionsLoggerFactory(new TestContextAppenderFactory(Microsoft.Extensions.Logging.LogLevel.Warning))); LoggerUtil.ActiveLoggers = Loggers.Test; configuration = new TransportTestsConfiguration(); testCancellationTokenSource = Debugger.IsAttached ? new CancellationTokenSource() : new CancellationTokenSource(TestTimeout); diff --git a/src/ServiceControl.UnitTests/RepeatedFailuresOverTimeCircuitBreakerTests.cs b/src/ServiceControl.UnitTests/RepeatedFailuresOverTimeCircuitBreakerTests.cs index 67e71198cc..e955646a88 100644 --- a/src/ServiceControl.UnitTests/RepeatedFailuresOverTimeCircuitBreakerTests.cs +++ b/src/ServiceControl.UnitTests/RepeatedFailuresOverTimeCircuitBreakerTests.cs @@ -6,12 +6,16 @@ using System.Threading; using System.Threading.Tasks; using NUnit.Framework; + using ServiceControl.Infrastructure; // Ideally the circuit breaker would use a time provider to allow for easier testing but that would require a significant refactor // and we want keep the changes to a minimum for now to allow backporting to older versions. [TestFixture] public class RepeatedFailuresOverTimeCircuitBreakerTests { + [SetUp] + public void Setup() => LoggerUtil.ActiveLoggers = Loggers.Test; + [Test] public async Task Should_disarm_on_success() { @@ -22,6 +26,7 @@ public async Task Should_disarm_on_success() "TestCircuitBreaker", TimeSpan.FromMilliseconds(100), ex => { }, + LoggerUtil.CreateStaticLogger(), () => armedActionCalled = true, () => disarmedActionCalled = true, TimeSpan.Zero, @@ -42,6 +47,7 @@ public async Task Should_rethrow_exception_on_success() "TestCircuitBreaker", TimeSpan.FromMilliseconds(100), ex => { }, + LoggerUtil.CreateStaticLogger(), () => { }, () => throw new Exception("Exception from disarmed action"), timeToWaitWhenTriggered: TimeSpan.Zero, @@ -64,6 +70,7 @@ public async Task Should_trigger_after_failure_timeout() "TestCircuitBreaker", TimeSpan.Zero, ex => { triggerActionCalled = true; lastTriggerException = ex; }, + LoggerUtil.CreateStaticLogger(), timeToWaitWhenTriggered: TimeSpan.Zero, timeToWaitWhenArmed: TimeSpan.FromMilliseconds(100) ); @@ -81,6 +88,7 @@ public void Should_rethrow_exception_on_failure() "TestCircuitBreaker", TimeSpan.FromMilliseconds(100), ex => { }, + LoggerUtil.CreateStaticLogger(), () => throw new Exception("Exception from armed action"), () => { }, timeToWaitWhenTriggered: TimeSpan.Zero, @@ -101,6 +109,7 @@ public async Task Should_delay_after_trigger_failure() "TestCircuitBreaker", TimeSpan.Zero, _ => { }, + LoggerUtil.CreateStaticLogger(), timeToWaitWhenTriggered: timeToWaitWhenTriggered, timeToWaitWhenArmed: timeToWaitWhenArmed ); @@ -124,6 +133,7 @@ public async Task Should_not_trigger_if_disarmed_before_timeout() "TestCircuitBreaker", TimeSpan.FromMilliseconds(100), ex => triggerActionCalled = true, + LoggerUtil.CreateStaticLogger(), timeToWaitWhenTriggered: TimeSpan.Zero, timeToWaitWhenArmed: TimeSpan.Zero ); @@ -145,6 +155,7 @@ public async Task Should_handle_concurrent_failure_and_success() "TestCircuitBreaker", TimeSpan.FromMilliseconds(100), ex => triggerActionCalled = true, + LoggerUtil.CreateStaticLogger(), () => armedActionCalled = true, () => disarmedActionCalled = true, TimeSpan.Zero, @@ -176,6 +187,7 @@ public async Task Should_handle_high_concurrent_failure_and_success() "TestCircuitBreaker", TimeSpan.FromSeconds(5), ex => Interlocked.Increment(ref triggerActionCalled), + LoggerUtil.CreateStaticLogger(), () => Interlocked.Increment(ref armedActionCalled), () => Interlocked.Increment(ref disarmedActionCalled), TimeSpan.Zero, @@ -209,6 +221,7 @@ public async Task Should_trigger_after_multiple_failures_and_timeout() "TestCircuitBreaker", TimeSpan.FromMilliseconds(50), ex => triggerActionCalled = true, + LoggerUtil.CreateStaticLogger(), timeToWaitWhenTriggered: TimeSpan.FromMilliseconds(50), timeToWaitWhenArmed: TimeSpan.FromMilliseconds(50) ); diff --git a/src/ServiceControl/HostApplicationBuilderExtensions.cs b/src/ServiceControl/HostApplicationBuilderExtensions.cs index 25685e7623..14ee26a003 100644 --- a/src/ServiceControl/HostApplicationBuilderExtensions.cs +++ b/src/ServiceControl/HostApplicationBuilderExtensions.cs @@ -21,7 +21,6 @@ namespace Particular.ServiceControl using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting.WindowsServices; using Microsoft.Extensions.Logging; - using NLog.Extensions.Logging; using NServiceBus; using NServiceBus.Configuration.AdvancedExtensibility; using NServiceBus.Transport; @@ -42,11 +41,8 @@ public static void AddServiceControl(this IHostApplicationBuilder hostBuilder, S EventSourceCreator.Create(); } - var logging = hostBuilder.Logging; - logging.ClearProviders(); - //HINT: configuration used by NLog comes from LoggingConfigurator.cs - logging.AddNLog(); - logging.SetMinimumLevel(settings.LoggingSettings.LogLevel); + hostBuilder.Logging.ClearProviders(); + hostBuilder.Logging.BuildLogger(settings.LoggingSettings.LogLevel); var services = hostBuilder.Services; var transportSettings = settings.ToTransportSettings(); From 39039ed85f4a6a21f97e928c362baa09eb37293a Mon Sep 17 00:00:00 2001 From: Phil Bastian Date: Tue, 24 Jun 2025 07:32:54 +0800 Subject: [PATCH 40/56] add logging config to all services --- src/ServiceControl.Audit/App.config | 4 ++-- src/ServiceControl.Monitoring/App.config | 2 ++ src/ServiceControl/App.config | 3 +++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/ServiceControl.Audit/App.config b/src/ServiceControl.Audit/App.config index e8e4a84c26..821af51fb6 100644 --- a/src/ServiceControl.Audit/App.config +++ b/src/ServiceControl.Audit/App.config @@ -22,8 +22,8 @@ These settings are only here so that we can debug ServiceControl while developin - - + + diff --git a/src/ServiceControl.Monitoring/App.config b/src/ServiceControl.Monitoring/App.config index 8ce3bdf576..6dc4b1feab 100644 --- a/src/ServiceControl.Monitoring/App.config +++ b/src/ServiceControl.Monitoring/App.config @@ -19,6 +19,8 @@ These settings are only here so that we can debug ServiceControl while developin + + diff --git a/src/ServiceControl/App.config b/src/ServiceControl/App.config index a99b7b9afe..b08610faf9 100644 --- a/src/ServiceControl/App.config +++ b/src/ServiceControl/App.config @@ -23,6 +23,9 @@ These settings are only here so that we can debug ServiceControl while developin + + + From 56a4635477d040fbe3409f0eb7244af40e7a9852 Mon Sep 17 00:00:00 2001 From: Phil Bastian Date: Tue, 24 Jun 2025 08:10:54 +0800 Subject: [PATCH 41/56] enable seq url to be configured --- src/ServiceControl.Audit/App.config | 1 + src/ServiceControl.Infrastructure/LoggerUtil.cs | 11 ++++++++++- src/ServiceControl.Infrastructure/LoggingSettings.cs | 6 ++++++ src/ServiceControl.Monitoring/App.config | 3 ++- src/ServiceControl/App.config | 10 ++++++---- 5 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/ServiceControl.Audit/App.config b/src/ServiceControl.Audit/App.config index 821af51fb6..2d276941f4 100644 --- a/src/ServiceControl.Audit/App.config +++ b/src/ServiceControl.Audit/App.config @@ -24,6 +24,7 @@ These settings are only here so that we can debug ServiceControl while developin + diff --git a/src/ServiceControl.Infrastructure/LoggerUtil.cs b/src/ServiceControl.Infrastructure/LoggerUtil.cs index c18a54afc1..973c2b3cd2 100644 --- a/src/ServiceControl.Infrastructure/LoggerUtil.cs +++ b/src/ServiceControl.Infrastructure/LoggerUtil.cs @@ -19,6 +19,8 @@ public static class LoggerUtil { public static Loggers ActiveLoggers { private get; set; } = Loggers.None; + public static string SeqAddress { private get; set; } + public static bool IsLoggingTo(Loggers logger) { return (logger & ActiveLoggers) == logger; @@ -36,7 +38,14 @@ public static void BuildLogger(this ILoggingBuilder loggingBuilder, LogLevel lev } if (IsLoggingTo(Loggers.Seq)) { - loggingBuilder.AddSeq(); + if (!string.IsNullOrWhiteSpace(SeqAddress)) + { + loggingBuilder.AddSeq(SeqAddress); + } + else + { + loggingBuilder.AddSeq(); + } } loggingBuilder.SetMinimumLevel(level); diff --git a/src/ServiceControl.Infrastructure/LoggingSettings.cs b/src/ServiceControl.Infrastructure/LoggingSettings.cs index ea8967bb00..23b172c353 100644 --- a/src/ServiceControl.Infrastructure/LoggingSettings.cs +++ b/src/ServiceControl.Infrastructure/LoggingSettings.cs @@ -20,6 +20,11 @@ public LoggingSettings(SettingsRootNamespace rootNamespace, LogLevel defaultLeve if (loggingProviders.Contains("Seq")) { activeLoggers |= Loggers.Seq; + var seqAddress = SettingsReader.Read(rootNamespace, seqAddressKey); + if (!string.IsNullOrWhiteSpace(seqAddress)) + { + LoggerUtil.SeqAddress = seqAddress; + } } //this defaults to NLog because historically that was the default, and we don't want to break existing installs that don't have the config key to define loggingProviders LoggerUtil.ActiveLoggers = activeLoggers == Loggers.None ? Loggers.NLog : activeLoggers; @@ -78,4 +83,5 @@ static LogLevel ParseLogLevel(string value, LogLevel defaultLevel) const string logLevelKey = "LogLevel"; const string logPathKey = "LogPath"; const string loggingProvidersKey = "LoggingProviders"; + const string seqAddressKey = "SeqAddress"; } \ No newline at end of file diff --git a/src/ServiceControl.Monitoring/App.config b/src/ServiceControl.Monitoring/App.config index 6dc4b1feab..5ea2193cbc 100644 --- a/src/ServiceControl.Monitoring/App.config +++ b/src/ServiceControl.Monitoring/App.config @@ -20,7 +20,8 @@ These settings are only here so that we can debug ServiceControl while developin - + + diff --git a/src/ServiceControl/App.config b/src/ServiceControl/App.config index b08610faf9..c1fbabd7a0 100644 --- a/src/ServiceControl/App.config +++ b/src/ServiceControl/App.config @@ -13,26 +13,27 @@ These settings are only here so that we can debug ServiceControl while developin - + - + - + + - + @@ -51,6 +52,7 @@ These settings are only here so that we can debug ServiceControl while developin + From b825edc89c55ec26cde35b013741fa81a3b157a3 Mon Sep 17 00:00:00 2001 From: Phil Bastian Date: Tue, 24 Jun 2025 09:05:13 +0800 Subject: [PATCH 42/56] fix logger not being available in program.cs --- src/ServiceControl.Audit/Program.cs | 6 +++--- src/ServiceControl.Monitoring/Program.cs | 5 ++--- src/ServiceControl/Program.cs | 5 ++--- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/ServiceControl.Audit/Program.cs b/src/ServiceControl.Audit/Program.cs index 19e1989234..89026d33fa 100644 --- a/src/ServiceControl.Audit/Program.cs +++ b/src/ServiceControl.Audit/Program.cs @@ -7,7 +7,10 @@ using ServiceControl.Configuration; using ServiceControl.Infrastructure; +var loggingSettings = new LoggingSettings(Settings.SettingsRootNamespace); +LoggingConfigurator.ConfigureLogging(loggingSettings); var logger = LoggerUtil.CreateStaticLogger(typeof(Program)); + try { AppDomain.CurrentDomain.UnhandledException += (s, e) => logger.LogError(e.ExceptionObject as Exception, "Unhandled exception was caught."); @@ -30,9 +33,6 @@ return 0; } - var loggingSettings = new LoggingSettings(Settings.SettingsRootNamespace); - LoggingConfigurator.ConfigureLogging(loggingSettings); - var settings = new Settings(loggingSettings: loggingSettings); await new CommandRunner(arguments.Command).Execute(arguments, settings); diff --git a/src/ServiceControl.Monitoring/Program.cs b/src/ServiceControl.Monitoring/Program.cs index 7a618a381f..b77e339894 100644 --- a/src/ServiceControl.Monitoring/Program.cs +++ b/src/ServiceControl.Monitoring/Program.cs @@ -5,6 +5,8 @@ using ServiceControl.Infrastructure; using ServiceControl.Monitoring; +var loggingSettings = new LoggingSettings(Settings.SettingsRootNamespace); +LoggingConfigurator.ConfigureLogging(loggingSettings); var logger = LoggerUtil.CreateStaticLogger(); try @@ -23,9 +25,6 @@ var arguments = new HostArguments(args); - var loggingSettings = new LoggingSettings(Settings.SettingsRootNamespace); - LoggingConfigurator.ConfigureLogging(loggingSettings); - var settings = new Settings(loggingSettings: loggingSettings); await new CommandRunner(arguments.Command).Execute(arguments, settings); diff --git a/src/ServiceControl/Program.cs b/src/ServiceControl/Program.cs index 1c8778490f..7177c7822b 100644 --- a/src/ServiceControl/Program.cs +++ b/src/ServiceControl/Program.cs @@ -7,6 +7,8 @@ using ServiceControl.Hosting.Commands; using ServiceControl.Infrastructure; +var loggingSettings = new LoggingSettings(Settings.SettingsRootNamespace); +LoggingConfigurator.ConfigureLogging(loggingSettings); var logger = LoggerUtil.CreateStaticLogger(typeof(Program)); try @@ -31,9 +33,6 @@ return 0; } - var loggingSettings = new LoggingSettings(Settings.SettingsRootNamespace); - LoggingConfigurator.ConfigureLogging(loggingSettings); - var settings = new Settings(loggingSettings: loggingSettings); await new CommandRunner(arguments.Command).Execute(arguments, settings); From 7edf38faf7095852652e4f979d5b4035922460f0 Mon Sep 17 00:00:00 2001 From: Phil Bastian Date: Tue, 24 Jun 2025 10:54:41 +0800 Subject: [PATCH 43/56] make nlog level based on configuration again --- .../LoggingConfigurator.cs | 29 +++++++++++++------ 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/ServiceControl.Infrastructure/LoggingConfigurator.cs b/src/ServiceControl.Infrastructure/LoggingConfigurator.cs index 848c6a3cf3..141f69df7a 100644 --- a/src/ServiceControl.Infrastructure/LoggingConfigurator.cs +++ b/src/ServiceControl.Infrastructure/LoggingConfigurator.cs @@ -64,17 +64,12 @@ public static void ConfigureLogging(LoggingSettings loggingSettings) nlogConfig.LoggingRules.Add(aspNetCoreRule); nlogConfig.LoggingRules.Add(httpClientRule); - // HACK: Fixed LogLevel to Info for testing purposes only. - // Migrate to .NET logging and change back to loggingSettings.LogLevel. - // nlogConfig.LoggingRules.Add(new LoggingRule("*", loggingSettings.LogLevel, consoleTarget)); - nlogConfig.LoggingRules.Add(new LoggingRule("*", LogLevel.Info, consoleTarget)); + var logLevel = loggingSettings.LogLevel.ToNLogLevel(); + nlogConfig.LoggingRules.Add(new LoggingRule("*", logLevel, consoleTarget)); if (!AppEnvironment.RunningInContainer) { - // HACK: Fixed LogLevel to Info for testing purposes only. - // Migrate to .NET logging and change back to loggingSettings.LogLevel. - // nlogConfig.LoggingRules.Add(new LoggingRule("*", loggingSettings.LogLevel, fileTarget)); - nlogConfig.LoggingRules.Add(new LoggingRule("*", LogLevel.Info, fileTarget)); + nlogConfig.LoggingRules.Add(new LoggingRule("*", logLevel, fileTarget)); } NLog.LogManager.Configuration = nlogConfig; @@ -83,9 +78,25 @@ public static void ConfigureLogging(LoggingSettings loggingSettings) var logger = LogManager.GetLogger("LoggingConfiguration"); var logEventInfo = new LogEventInfo { TimeStamp = DateTime.UtcNow }; var loggingTo = AppEnvironment.RunningInContainer ? "console" : fileTarget.FileName.Render(logEventInfo); - logger.InfoFormat("Logging to {0} with LogLevel '{1}'", loggingTo, LogLevel.Info.Name); + logger.InfoFormat("Logging to {0} with LogLevel '{1}'", loggingTo, logLevel.Name); + } + + static LogLevel ToNLogLevel(this Microsoft.Extensions.Logging.LogLevel level) + { + return level switch + { + Microsoft.Extensions.Logging.LogLevel.Trace => LogLevel.Trace, + Microsoft.Extensions.Logging.LogLevel.Debug => LogLevel.Debug, + Microsoft.Extensions.Logging.LogLevel.Information => LogLevel.Info, + Microsoft.Extensions.Logging.LogLevel.Warning => LogLevel.Warn, + Microsoft.Extensions.Logging.LogLevel.Error => LogLevel.Error, + Microsoft.Extensions.Logging.LogLevel.Critical => LogLevel.Fatal, + Microsoft.Extensions.Logging.LogLevel.None => LogLevel.Off, + _ => LogLevel.Off, + }; } const long megaByte = 1024 * 1024; + } } \ No newline at end of file From ec9c21f2ef1285b5899df08ff5144d234fe4e439 Mon Sep 17 00:00:00 2001 From: Phil Bastian Date: Wed, 25 Jun 2025 12:52:25 +0800 Subject: [PATCH 44/56] fix logging not being available during logging setup --- src/ServiceControl.Audit/Program.cs | 20 ++++++++++++++----- .../LoggingConfigurator.cs | 20 ++++++++++++------- src/ServiceControl.Monitoring/Program.cs | 18 +++++++++++++---- src/ServiceControl/Program.cs | 20 ++++++++++++++----- 4 files changed, 57 insertions(+), 21 deletions(-) diff --git a/src/ServiceControl.Audit/Program.cs b/src/ServiceControl.Audit/Program.cs index 89026d33fa..582bff42ea 100644 --- a/src/ServiceControl.Audit/Program.cs +++ b/src/ServiceControl.Audit/Program.cs @@ -7,12 +7,14 @@ using ServiceControl.Configuration; using ServiceControl.Infrastructure; -var loggingSettings = new LoggingSettings(Settings.SettingsRootNamespace); -LoggingConfigurator.ConfigureLogging(loggingSettings); -var logger = LoggerUtil.CreateStaticLogger(typeof(Program)); +ILogger logger = null; try { + var loggingSettings = new LoggingSettings(Settings.SettingsRootNamespace); + LoggingConfigurator.ConfigureLogging(loggingSettings); + logger = LoggerUtil.CreateStaticLogger(typeof(Program)); + AppDomain.CurrentDomain.UnhandledException += (s, e) => logger.LogError(e.ExceptionObject as Exception, "Unhandled exception was caught."); // Hack: See https://github.com/Particular/ServiceControl/issues/4392 @@ -41,12 +43,20 @@ } catch (Exception ex) { - logger.LogCritical(ex, "Unrecoverable error"); + if (logger != null) + { + logger.LogCritical(ex, "Unrecoverable error"); + } + else + { + LoggingConfigurator.ConfigureNLog("bootstrap.${shortdate}.txt", "./", NLog.LogLevel.Fatal); + NLog.LogManager.GetCurrentClassLogger().Fatal(ex, "Unrecoverable error"); + } throw; } finally { // The following log statement is meant to leave a trail in the logs to determine if the process was killed - logger.LogInformation("Shutdown complete"); + logger?.LogInformation("Shutdown complete"); NLog.LogManager.Shutdown(); } \ No newline at end of file diff --git a/src/ServiceControl.Infrastructure/LoggingConfigurator.cs b/src/ServiceControl.Infrastructure/LoggingConfigurator.cs index 141f69df7a..e35aa23194 100644 --- a/src/ServiceControl.Infrastructure/LoggingConfigurator.cs +++ b/src/ServiceControl.Infrastructure/LoggingConfigurator.cs @@ -24,6 +24,16 @@ public static void ConfigureLogging(LoggingSettings loggingSettings) return; } + var logLevel = loggingSettings.LogLevel.ToNLogLevel(); + var loggingTo = ConfigureNLog("logfile.${shortdate}.txt", loggingSettings.LogPath, loggingSettings.LogLevel.ToNLogLevel()); + + //using LogManager here rather than LoggerUtil.CreateStaticLogger since this is exclusive to NLog + var logger = LogManager.GetLogger("LoggingConfiguration"); + logger.InfoFormat("Logging to {0} with LogLevel '{1}'", loggingTo, logLevel.Name); + } + + public static string ConfigureNLog(string logFileName, string logPath, LogLevel logLevel) + { //configure NLog var nlogConfig = new LoggingConfiguration(); var simpleLayout = new SimpleLayout("${longdate}|${processtime}|${threadid}|${level}|${logger}|${message}${onexception:|${exception:format=tostring}}"); @@ -32,8 +42,8 @@ public static void ConfigureLogging(LoggingSettings loggingSettings) { Name = "file", ArchiveEvery = FileArchivePeriod.Day, - FileName = Path.Combine(loggingSettings.LogPath, "logfile.${shortdate}.txt"), - ArchiveFileName = Path.Combine(loggingSettings.LogPath, "logfile.{#}.txt"), + FileName = Path.Combine(logPath, logFileName), + ArchiveFileName = Path.Combine(logPath, "logfile.{#}.txt"), ArchiveNumbering = ArchiveNumberingMode.DateAndSequence, Layout = simpleLayout, MaxArchiveFiles = 14, @@ -64,7 +74,6 @@ public static void ConfigureLogging(LoggingSettings loggingSettings) nlogConfig.LoggingRules.Add(aspNetCoreRule); nlogConfig.LoggingRules.Add(httpClientRule); - var logLevel = loggingSettings.LogLevel.ToNLogLevel(); nlogConfig.LoggingRules.Add(new LoggingRule("*", logLevel, consoleTarget)); if (!AppEnvironment.RunningInContainer) @@ -74,11 +83,8 @@ public static void ConfigureLogging(LoggingSettings loggingSettings) NLog.LogManager.Configuration = nlogConfig; - //using LogManager here rather than LoggerUtil.CreateStaticLogger since this is exclusive to NLog - var logger = LogManager.GetLogger("LoggingConfiguration"); var logEventInfo = new LogEventInfo { TimeStamp = DateTime.UtcNow }; - var loggingTo = AppEnvironment.RunningInContainer ? "console" : fileTarget.FileName.Render(logEventInfo); - logger.InfoFormat("Logging to {0} with LogLevel '{1}'", loggingTo, logLevel.Name); + return AppEnvironment.RunningInContainer ? "console" : fileTarget.FileName.Render(logEventInfo); } static LogLevel ToNLogLevel(this Microsoft.Extensions.Logging.LogLevel level) diff --git a/src/ServiceControl.Monitoring/Program.cs b/src/ServiceControl.Monitoring/Program.cs index b77e339894..3ff815616b 100644 --- a/src/ServiceControl.Monitoring/Program.cs +++ b/src/ServiceControl.Monitoring/Program.cs @@ -5,12 +5,14 @@ using ServiceControl.Infrastructure; using ServiceControl.Monitoring; -var loggingSettings = new LoggingSettings(Settings.SettingsRootNamespace); -LoggingConfigurator.ConfigureLogging(loggingSettings); -var logger = LoggerUtil.CreateStaticLogger(); +ILogger logger = null; try { + var loggingSettings = new LoggingSettings(Settings.SettingsRootNamespace); + LoggingConfigurator.ConfigureLogging(loggingSettings); + logger = LoggerUtil.CreateStaticLogger(typeof(Program)); + AppDomain.CurrentDomain.UnhandledException += (s, e) => logger.LogError(e.ExceptionObject as Exception, "Unhandled exception was caught."); // Hack: See https://github.com/Particular/ServiceControl/issues/4392 @@ -33,7 +35,15 @@ } catch (Exception ex) { - logger.LogCritical(ex, "Unrecoverable error"); + if (logger != null) + { + logger.LogCritical(ex, "Unrecoverable error"); + } + else + { + LoggingConfigurator.ConfigureNLog("bootstrap.${shortdate}.txt", "./", NLog.LogLevel.Fatal); + NLog.LogManager.GetCurrentClassLogger().Fatal(ex, "Unrecoverable error"); + } throw; } finally diff --git a/src/ServiceControl/Program.cs b/src/ServiceControl/Program.cs index 7177c7822b..bf2023306f 100644 --- a/src/ServiceControl/Program.cs +++ b/src/ServiceControl/Program.cs @@ -7,12 +7,14 @@ using ServiceControl.Hosting.Commands; using ServiceControl.Infrastructure; -var loggingSettings = new LoggingSettings(Settings.SettingsRootNamespace); -LoggingConfigurator.ConfigureLogging(loggingSettings); -var logger = LoggerUtil.CreateStaticLogger(typeof(Program)); +ILogger logger = null; try { + var loggingSettings = new LoggingSettings(Settings.SettingsRootNamespace); + LoggingConfigurator.ConfigureLogging(loggingSettings); + logger = LoggerUtil.CreateStaticLogger(typeof(Program)); + AppDomain.CurrentDomain.UnhandledException += (s, e) => logger.LogError(e.ExceptionObject as Exception, "Unhandled exception was caught"); // Hack: See https://github.com/Particular/ServiceControl/issues/4392 @@ -41,12 +43,20 @@ } catch (Exception ex) { - logger.LogCritical(ex, "Unrecoverable error"); + if (logger != null) + { + logger.LogCritical(ex, "Unrecoverable error"); + } + else + { + LoggingConfigurator.ConfigureNLog("bootstrap.${shortdate}.txt", "./", NLog.LogLevel.Fatal); + NLog.LogManager.GetCurrentClassLogger().Fatal(ex, "Unrecoverable error"); + } throw; } finally { // The following log statement is meant to leave a trail in the logs to determine if the process was killed - logger.LogInformation("Shutdown complete"); + logger?.LogInformation("Shutdown complete"); NLog.LogManager.Shutdown(); } \ No newline at end of file From 912ef81d93da52847de6f2c13e44f89dc4134771 Mon Sep 17 00:00:00 2001 From: Phil Bastian Date: Thu, 26 Jun 2025 13:34:58 +0800 Subject: [PATCH 45/56] remove '.' from the end of log messages --- .../AuditThroughputCollectorHostedService.cs | 6 +++--- .../DiscardMessagesBehavior.cs | 2 +- .../TestSupport/ServiceControlComponentRunner.cs | 4 ++-- .../CustomChecks/CheckDirtyMemory.cs | 4 ++-- .../CustomChecks/CheckFreeDiskSpace.cs | 6 +++--- .../CheckMinimumStorageRequiredForIngestion.cs | 8 ++++---- .../CustomChecks/CheckRavenDBIndexLag.cs | 4 ++-- .../Auditing/AuditPersister.cs | 8 ++++---- .../Auditing/ImportFailedAudits.cs | 8 ++++---- .../Infrastructure/Settings/Settings.cs | 2 +- src/ServiceControl.Audit/Program.cs | 2 +- .../LoggingSettings.cs | 2 +- .../RepeatedFailuresOverTimeCircuitBreaker.cs | 14 +++++++------- src/ServiceControl.Infrastructure/Watchdog.cs | 4 ++-- .../Diagrams/MonitoredEndpointMessageTypeParser.cs | 2 +- .../RemoveExpiredEndpointInstances.cs | 2 +- .../ReportThroughputHostedService.cs | 2 +- .../Licensing/LicenseCheckHostedService.cs | 2 +- src/ServiceControl.Monitoring/Program.cs | 2 +- .../CustomChecks/CheckDirtyMemory.cs | 4 ++-- .../CustomChecks/CheckFreeDiskSpace.cs | 4 ++-- .../CheckMinimumStorageRequiredForIngestion.cs | 6 +++--- .../CustomChecks/CheckRavenDBIndexLag.cs | 4 ++-- .../ExternalIntegrationRequestsDataStore.cs | 2 +- .../FailedErrorImportDataStore.cs | 6 +++--- .../Recoverability/Archiving/MessageArchiver.cs | 12 ++++++------ src/ServiceControl.RavenDB/EmbeddedDatabase.cs | 8 ++++---- .../DeadLetterQueueCheck.cs | 2 +- .../QueueLengthProvider.cs | 4 ++-- .../QueueLengthProvider.cs | 2 +- .../DeadLetterQueueCheck.cs | 2 +- .../QueueLengthProvider.cs | 4 ++-- .../QueueLengthProvider.cs | 2 +- .../QueueLengthProvider.cs | 4 ++-- .../QueueLengthProvider.cs | 4 ++-- .../EventDispatcherHostedService.cs | 4 ++-- src/ServiceControl/SagaAudit/SagaUpdatedHandler.cs | 2 +- 37 files changed, 80 insertions(+), 80 deletions(-) diff --git a/src/Particular.LicensingComponent/AuditThroughput/AuditThroughputCollectorHostedService.cs b/src/Particular.LicensingComponent/AuditThroughput/AuditThroughputCollectorHostedService.cs index fed7540ac6..91c90dbb95 100644 --- a/src/Particular.LicensingComponent/AuditThroughput/AuditThroughputCollectorHostedService.cs +++ b/src/Particular.LicensingComponent/AuditThroughput/AuditThroughputCollectorHostedService.cs @@ -59,7 +59,7 @@ async Task GatherThroughput(CancellationToken cancellationToken) if (!knownEndpoints.Any()) { - logger.LogWarning("No known endpoints could be found."); + logger.LogWarning("No known endpoints could be found"); } foreach (var tuple in await dataStore.GetEndpoints([.. knownEndpointsLookup.Keys], cancellationToken)) @@ -119,14 +119,14 @@ async Task VerifyAuditInstances(CancellationToken cancellationToken) } else { - logger.LogWarning("Unable to determine the version of one or more ServiceControl Audit instances. For the instance with URI {RemoteApiUri}, the status was '{RemoteStatus}' and the version string returned was '{RemoteVersionString}'.", remote.ApiUri, remote.Status, remote.VersionString); + logger.LogWarning("Unable to determine the version of one or more ServiceControl Audit instances. For the instance with URI {RemoteApiUri}, the status was '{RemoteStatus}' and the version string returned was '{RemoteVersionString}'", remote.ApiUri, remote.Status, remote.VersionString); } } var allHaveAuditCounts = remotesInfo.All(auditQuery.ValidRemoteInstances); if (!allHaveAuditCounts) { - logger.LogWarning("At least one ServiceControl Audit instance is either not running the required version ({RequiredAuditVersion}) or is not configured for at least 2 days of retention. Audit throughput will not be available.", auditQuery.MinAuditCountsVersion); + logger.LogWarning("At least one ServiceControl Audit instance is either not running the required version ({RequiredAuditVersion}) or is not configured for at least 2 days of retention. Audit throughput will not be available", auditQuery.MinAuditCountsVersion); } } diff --git a/src/ServiceControl.AcceptanceTesting/DiscardMessagesBehavior.cs b/src/ServiceControl.AcceptanceTesting/DiscardMessagesBehavior.cs index 134db9bdec..109c545e22 100644 --- a/src/ServiceControl.AcceptanceTesting/DiscardMessagesBehavior.cs +++ b/src/ServiceControl.AcceptanceTesting/DiscardMessagesBehavior.cs @@ -46,7 +46,7 @@ public Task Invoke(ITransportReceiveContext context, Func(); - logger.LogDebug("Discarding message '{MessageId}'({OriginalMessageId}) because it's session id is '{MessageSessionId}' instead of '{CurrentSessionId}' Message Types: {EnclosedMessageTypes}.", + logger.LogDebug("Discarding message '{MessageId}'({OriginalMessageId}) because it's session id is '{MessageSessionId}' instead of '{CurrentSessionId}' Message Types: {EnclosedMessageTypes}", context.Message.MessageId, originalMessageId ?? string.Empty, session, diff --git a/src/ServiceControl.Audit.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs b/src/ServiceControl.Audit.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs index 27ed1bfade..e0b41effe6 100644 --- a/src/ServiceControl.Audit.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs +++ b/src/ServiceControl.Audit.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs @@ -59,7 +59,7 @@ async Task InitializeServiceControl(ScenarioContext context) var headers = messageContext.Headers; var logger = LoggerUtil.CreateStaticLogger(loggingSettings.LogLevel); headers.TryGetValue(Headers.MessageId, out var originalMessageId); - logger.LogDebug("OnMessage for message '{MessageId}'({OriginalMessageId}).", id, originalMessageId ?? string.Empty); + logger.LogDebug("OnMessage for message '{MessageId}'({OriginalMessageId})", id, originalMessageId ?? string.Empty); //Do not filter out CC, SA and HB messages as they can't be stamped if (headers.TryGetValue(Headers.EnclosedMessageTypes, out var messageTypes) @@ -78,7 +78,7 @@ async Task InitializeServiceControl(ScenarioContext context) var currentSession = context.TestRunId.ToString(); if (!headers.TryGetValue("SC.SessionID", out var session) || session != currentSession) { - logger.LogDebug("Discarding message '{MessageId}'({OriginalMessageId}) because it's session id is '{SessionId}' instead of '{CurrentSessionId}'.", id, originalMessageId ?? string.Empty, session, currentSession); + logger.LogDebug("Discarding message '{MessageId}'({OriginalMessageId}) because it's session id is '{SessionId}' instead of '{CurrentSessionId}'", id, originalMessageId ?? string.Empty, session, currentSession); return true; } diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckDirtyMemory.cs b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckDirtyMemory.cs index 409b3d6df1..85b02e55c5 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckDirtyMemory.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckDirtyMemory.cs @@ -13,11 +13,11 @@ public override async Task PerformCheck(CancellationToken cancellat { var (isHighDirty, dirtyMemory) = await memoryInformationRetriever.GetMemoryInformation(cancellationToken); - logger.LogDebug("RavenDB dirty memory value: {DirtyMemory}.", dirtyMemory); + logger.LogDebug("RavenDB dirty memory value: {DirtyMemory}", dirtyMemory); if (isHighDirty) { - logger.LogWarning("There is a high level of RavenDB dirty memory ({DirtyMemory}). See https://docs.particular.net/servicecontrol/troubleshooting#ravendb-dirty-memory for guidance on how to mitigate the issue.", dirtyMemory); + logger.LogWarning("There is a high level of RavenDB dirty memory ({DirtyMemory}). See https://docs.particular.net/servicecontrol/troubleshooting#ravendb-dirty-memory for guidance on how to mitigate the issue", dirtyMemory); return CheckResult.Failed($"There is a high level of RavenDB dirty memory ({dirtyMemory}). See https://docs.particular.net/servicecontrol/troubleshooting#ravendb-dirty-memory for guidance on how to mitigate the issue."); } diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs index 45efbac8e0..834655eb5a 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs @@ -53,19 +53,19 @@ public static int Parse(IDictionary settings, ILogger logger) if (!int.TryParse(thresholdValue, out var threshold)) { - logger.LogCritical("{RavenPersistenceConfigurationDataSpaceRemainingThresholdKey} must be an integer.", RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey); + logger.LogCritical("{RavenPersistenceConfigurationDataSpaceRemainingThresholdKey} must be an integer", RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey); throw new Exception($"{RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey} must be an integer."); } if (threshold < 0) { - logger.LogCritical("{RavenPersistenceConfigurationDataSpaceRemainingThresholdKey} is invalid, minimum value is 0.", RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey); + logger.LogCritical("{RavenPersistenceConfigurationDataSpaceRemainingThresholdKey} is invalid, minimum value is 0", RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey); throw new Exception($"{RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey} is invalid, minimum value is 0."); } if (threshold > 100) { - logger.LogCritical("{RavenPersistenceConfigurationDataSpaceRemainingThresholdKey} is invalid, maximum value is 100.", RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey); + logger.LogCritical("{RavenPersistenceConfigurationDataSpaceRemainingThresholdKey} is invalid, maximum value is 100", RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey); throw new Exception($"{RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey} is invalid, maximum value is 100."); } diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs index 033a99fbbe..7bfad30a84 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs @@ -47,7 +47,7 @@ public override Task PerformCheck(CancellationToken cancellationTok return SuccessResult; } - logger.LogWarning("Audit message ingestion stopped! {PercentRemaining:P0} disk space remaining on data drive '{DataDriveInfoVolumeLabel} ({DataDriveInfoRootDirectory})' on '{EnvironmentMachineName}'. This is less than {PercentageThreshold}% - the minimal required space configured. The threshold can be set using the {RavenPersistenceConfigurationMinimumStorageLeftRequiredForIngestionKey} configuration setting.", percentRemaining, dataDriveInfo.VolumeLabel, dataDriveInfo.RootDirectory, Environment.MachineName, percentageThreshold, RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey); + logger.LogWarning("Audit message ingestion stopped! {PercentRemaining:P0} disk space remaining on data drive '{DataDriveInfoVolumeLabel} ({DataDriveInfoRootDirectory})' on '{EnvironmentMachineName}'. This is less than {PercentageThreshold}% - the minimal required space configured. The threshold can be set using the {RavenPersistenceConfigurationMinimumStorageLeftRequiredForIngestionKey} configuration setting", percentRemaining, dataDriveInfo.VolumeLabel, dataDriveInfo.RootDirectory, Environment.MachineName, percentageThreshold, RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey); stateHolder.CanIngestMore = false; return CheckResult.Failed($"Audit message ingestion stopped! {percentRemaining:P0} disk space remaining on data drive '{dataDriveInfo.VolumeLabel} ({dataDriveInfo.RootDirectory})' on '{Environment.MachineName}'. This is less than {percentageThreshold}% - the minimal required space configured. The threshold can be set using the {RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey} configuration setting."); } @@ -61,19 +61,19 @@ public static int Parse(IDictionary settings) if (!int.TryParse(thresholdValue, out var threshold)) { - Logger.LogCritical("{RavenPersistenceConfigurationMinimumStorageLeftRequiredForIngestionKey} must be an integer.", RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey); + Logger.LogCritical("{RavenPersistenceConfigurationMinimumStorageLeftRequiredForIngestionKey} must be an integer", RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey); throw new Exception($"{RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey} must be an integer."); } if (threshold < 0) { - Logger.LogCritical("{RavenPersistenceConfigurationMinimumStorageLeftRequiredForIngestionKey} is invalid, minimum value is 0.", RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey); + Logger.LogCritical("{RavenPersistenceConfigurationMinimumStorageLeftRequiredForIngestionKey} is invalid, minimum value is 0", RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey); throw new Exception($"{RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey} is invalid, minimum value is 0."); } if (threshold > 100) { - Logger.LogCritical("{RavenPersistenceConfigurationMinimumStorageLeftRequiredForIngestionKey} is invalid, maximum value is 100.", RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey); + Logger.LogCritical("{RavenPersistenceConfigurationMinimumStorageLeftRequiredForIngestionKey} is invalid, maximum value is 100", RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey); throw new Exception($"{RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey} is invalid, maximum value is 100."); } diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexLag.cs b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexLag.cs index 193e384f2d..78c8ddebc5 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexLag.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexLag.cs @@ -44,12 +44,12 @@ static int CheckAndReportIndexesWithTooMuchIndexLag(IndexInformation[] indexes, if (indexLag > IndexLagThresholdError) { indexCountWithTooMuchLag++; - logger.LogError("Index [{IndexStatsName}] IndexingLag {IndexLag} is above error threshold ({IndexLagThresholdError}). Launch in maintenance mode to let indexes catch up.", indexStats.Name, indexLag, IndexLagThresholdError); + logger.LogError("Index [{IndexStatsName}] IndexingLag {IndexLag} is above error threshold ({IndexLagThresholdError}). Launch in maintenance mode to let indexes catch up", indexStats.Name, indexLag, IndexLagThresholdError); } else if (indexLag > IndexLagThresholdWarning) { indexCountWithTooMuchLag++; - logger.LogWarning("Index [{IndexStatsName}] IndexingLag {IndexLag} is above warning threshold ({IndexLagThresholdWarning}). Launch in maintenance mode to let indexes catch up.", indexStats.Name, indexLag, IndexLagThresholdWarning); + logger.LogWarning("Index [{IndexStatsName}] IndexingLag {IndexLag} is above warning threshold ({IndexLagThresholdWarning}). Launch in maintenance mode to let indexes catch up", indexStats.Name, indexLag, IndexLagThresholdWarning); } } } diff --git a/src/ServiceControl.Audit/Auditing/AuditPersister.cs b/src/ServiceControl.Audit/Auditing/AuditPersister.cs index a37e5a4f56..136688919e 100644 --- a/src/ServiceControl.Audit/Auditing/AuditPersister.cs +++ b/src/ServiceControl.Audit/Auditing/AuditPersister.cs @@ -155,7 +155,7 @@ void ProcessSagaAuditMessage(MessageContext context) } catch (Exception e) { - logger.LogWarning(e, "Processing of saga audit message '{NativeMessageId}' failed.", context.NativeMessageId); + logger.LogWarning(e, "Processing of saga audit message '{NativeMessageId}' failed", context.NativeMessageId); // releasing the failed message context early so that they can be retried outside the current batch context.GetTaskCompletionSource().TrySetException(e); @@ -188,7 +188,7 @@ async Task ProcessAuditMessage(MessageContext context) var auditMessage = new ProcessedMessage(context.Headers, new Dictionary(metadata)); - logger.LogDebug("Emitting {CommandsToEmitCount} commands and {MessagesToEmitCount} control messages.", commandsToEmit.Count, messagesToEmit.Count); + logger.LogDebug("Emitting {CommandsToEmitCount} commands and {MessagesToEmitCount} control messages", commandsToEmit.Count, messagesToEmit.Count); foreach (var commandToEmit in commandsToEmit) { @@ -198,7 +198,7 @@ async Task ProcessAuditMessage(MessageContext context) await messageDispatcher.Value.Dispatch(new TransportOperations(messagesToEmit.ToArray()), new TransportTransaction()); //Do not hook into the incoming transaction - logger.LogDebug("{CommandsToEmitCount} commands and {MessagesToEmitCount} control messages emitted.", commandsToEmit.Count, messagesToEmit.Count); + logger.LogDebug("{CommandsToEmitCount} commands and {MessagesToEmitCount} control messages emitted", commandsToEmit.Count, messagesToEmit.Count); if (metadata.TryGetValue("SendingEndpoint", out var sendingEndpoint)) { @@ -215,7 +215,7 @@ await messageDispatcher.Value.Dispatch(new TransportOperations(messagesToEmit.To } catch (Exception e) { - logger.LogWarning(e, "Processing of message '{MessageId}' failed.", messageId); + logger.LogWarning(e, "Processing of message '{MessageId}' failed", messageId); // releasing the failed message context early so that they can be retried outside the current batch context.GetTaskCompletionSource().TrySetException(e); diff --git a/src/ServiceControl.Audit/Auditing/ImportFailedAudits.cs b/src/ServiceControl.Audit/Auditing/ImportFailedAudits.cs index 99321dc69f..07cbdebc9b 100644 --- a/src/ServiceControl.Audit/Auditing/ImportFailedAudits.cs +++ b/src/ServiceControl.Audit/Auditing/ImportFailedAudits.cs @@ -52,7 +52,7 @@ await failedAuditStore.ProcessFailedMessages( await markComplete(token); succeeded++; - logger.LogDebug("Successfully re-imported failed audit message {MessageId}.", transportMessage.Id); + logger.LogDebug("Successfully re-imported failed audit message {MessageId}", transportMessage.Id); } catch (OperationCanceledException e) when (token.IsCancellationRequested) { @@ -60,17 +60,17 @@ await failedAuditStore.ProcessFailedMessages( } catch (Exception e) { - logger.LogError(e, "Error while attempting to re-import failed audit message {MessageId}.", transportMessage.Id); + logger.LogError(e, "Error while attempting to re-import failed audit message {MessageId}", transportMessage.Id); failed++; } }, cancellationToken); - logger.LogInformation("Done re-importing failed audits. Successfully re-imported {SuccessCount} messages. Failed re-importing {FailureCount} messages.", succeeded, failed); + logger.LogInformation("Done re-importing failed audits. Successfully re-imported {SuccessCount} messages. Failed re-importing {FailureCount} messages", succeeded, failed); if (failed > 0) { - logger.LogWarning("{FailureCount} messages could not be re-imported. This could indicate a problem with the data. Contact Particular support if you need help with recovering the messages.", failed); + logger.LogWarning("{FailureCount} messages could not be re-imported. This could indicate a problem with the data. Contact Particular support if you need help with recovering the messages", failed); } } diff --git a/src/ServiceControl.Audit/Infrastructure/Settings/Settings.cs b/src/ServiceControl.Audit/Infrastructure/Settings/Settings.cs index 4bd0352edb..dd409f0334 100644 --- a/src/ServiceControl.Audit/Infrastructure/Settings/Settings.cs +++ b/src/ServiceControl.Audit/Infrastructure/Settings/Settings.cs @@ -75,7 +75,7 @@ void LoadAuditQueueInformation() if (IngestAuditMessages == false) { - logger.LogInformation("Audit ingestion disabled."); + logger.LogInformation("Audit ingestion disabled"); } AuditLogQueue = SettingsReader.Read(serviceBusRootNamespace, "AuditLogQueue", null); diff --git a/src/ServiceControl.Audit/Program.cs b/src/ServiceControl.Audit/Program.cs index 582bff42ea..8c4bf1ea67 100644 --- a/src/ServiceControl.Audit/Program.cs +++ b/src/ServiceControl.Audit/Program.cs @@ -15,7 +15,7 @@ LoggingConfigurator.ConfigureLogging(loggingSettings); logger = LoggerUtil.CreateStaticLogger(typeof(Program)); - AppDomain.CurrentDomain.UnhandledException += (s, e) => logger.LogError(e.ExceptionObject as Exception, "Unhandled exception was caught."); + AppDomain.CurrentDomain.UnhandledException += (s, e) => logger.LogError(e.ExceptionObject as Exception, "Unhandled exception was caught"); // Hack: See https://github.com/Particular/ServiceControl/issues/4392 var exitCode = await IntegratedSetup.Run(); diff --git a/src/ServiceControl.Infrastructure/LoggingSettings.cs b/src/ServiceControl.Infrastructure/LoggingSettings.cs index 23b172c353..d99200fba0 100644 --- a/src/ServiceControl.Infrastructure/LoggingSettings.cs +++ b/src/ServiceControl.Infrastructure/LoggingSettings.cs @@ -75,7 +75,7 @@ static LogLevel ParseLogLevel(string value, LogLevel defaultLevel) return parsedLevel; } - LoggerUtil.CreateStaticLogger().LogWarning("Failed to parse {LogLevelKey} setting. Defaulting to {DefaultLevel}.", logLevelKey, defaultLevel); + LoggerUtil.CreateStaticLogger().LogWarning("Failed to parse {LogLevelKey} setting. Defaulting to {DefaultLevel}", logLevelKey, defaultLevel); return defaultLevel; } diff --git a/src/ServiceControl.Infrastructure/RepeatedFailuresOverTimeCircuitBreaker.cs b/src/ServiceControl.Infrastructure/RepeatedFailuresOverTimeCircuitBreaker.cs index 3ae3d1c879..12e77ab01b 100644 --- a/src/ServiceControl.Infrastructure/RepeatedFailuresOverTimeCircuitBreaker.cs +++ b/src/ServiceControl.Infrastructure/RepeatedFailuresOverTimeCircuitBreaker.cs @@ -84,14 +84,14 @@ public void Success() circuitBreakerState = Disarmed; _ = timer.Change(Timeout.Infinite, Timeout.Infinite); - logger.LogInformation("The circuit breaker for '{BreakerName}' is now disarmed.", name); + logger.LogInformation("The circuit breaker for '{BreakerName}' is now disarmed", name); try { disarmedAction(); } catch (Exception ex) { - logger.LogError(ex, "The circuit breaker for '{BreakerName}' was unable to execute the disarm action.", name); + logger.LogError(ex, "The circuit breaker for '{BreakerName}' was unable to execute the disarm action", name); throw; } } @@ -132,12 +132,12 @@ public Task Failure(Exception exception, CancellationToken cancellationToken = d } catch (Exception ex) { - logger.LogError(new AggregateException(ex, exception), "The circuit breaker for '{BreakerName}' was unable to execute the arm action.", name); + logger.LogError(new AggregateException(ex, exception), "The circuit breaker for '{BreakerName}' was unable to execute the arm action", name); throw; } _ = timer.Change(timeToWaitBeforeTriggering, NoPeriodicTriggering); - logger.LogWarning("The circuit breaker for '{BreakerName}' is now in the armed state due to '{BreakerCause}' and might trigger in '{BreakerTriggerTime}' when not disarmed.", name, exception, timeToWaitBeforeTriggering); + logger.LogWarning("The circuit breaker for '{BreakerName}' is now in the armed state due to '{BreakerCause}' and might trigger in '{BreakerTriggerTime}' when not disarmed", name, exception, timeToWaitBeforeTriggering); } return Delay(); @@ -145,7 +145,7 @@ public Task Failure(Exception exception, CancellationToken cancellationToken = d Task Delay() { var timeToWait = previousState == Triggered ? timeToWaitWhenTriggered : timeToWaitWhenArmed; - logger.LogDebug("The circuit breaker for '{BreakerName}' is delaying the operation by '{BreakerTriggerTime}'.", name, timeToWait); + logger.LogDebug("The circuit breaker for '{BreakerName}' is delaying the operation by '{BreakerTriggerTime}'", name, timeToWait); return Task.Delay(timeToWait, cancellationToken); } } @@ -172,7 +172,7 @@ void CircuitBreakerTriggered(object? state) } circuitBreakerState = Triggered; - logger.LogWarning("The circuit breaker for '{BreakerName}' will now be triggered with exception '{BreakerCause}'.", name, lastException); + logger.LogWarning("The circuit breaker for '{BreakerName}' will now be triggered with exception '{BreakerCause}'", name, lastException); try { @@ -180,7 +180,7 @@ void CircuitBreakerTriggered(object? state) } catch (Exception ex) { - logger.LogCritical(new AggregateException(ex, lastException!), "The circuit breaker for '{BreakerName}' was unable to execute the trigger action.", name); + logger.LogCritical(new AggregateException(ex, lastException!), "The circuit breaker for '{BreakerName}' was unable to execute the trigger action", name); } } } diff --git a/src/ServiceControl.Infrastructure/Watchdog.cs b/src/ServiceControl.Infrastructure/Watchdog.cs index efdb739f8c..443abe3b5d 100644 --- a/src/ServiceControl.Infrastructure/Watchdog.cs +++ b/src/ServiceControl.Infrastructure/Watchdog.cs @@ -76,12 +76,12 @@ public Task Start(Action onFailedOnStartup, CancellationToken cancellationToken) if (startup) { - log.LogError(e, "Error during initial startup attempt for {TaskName}.", taskName); + log.LogError(e, "Error during initial startup attempt for {TaskName}", taskName); onFailedOnStartup(); return; } - log.LogError(e, "Error while trying to start {TaskName}. Starting will be retried in {TimeToWaitBetweenStartupAttempts}.", taskName, timeToWaitBetweenStartupAttempts); + log.LogError(e, "Error while trying to start {TaskName}. Starting will be retried in {TimeToWaitBetweenStartupAttempts}", taskName, timeToWaitBetweenStartupAttempts); } try { diff --git a/src/ServiceControl.Monitoring/Http/Diagrams/MonitoredEndpointMessageTypeParser.cs b/src/ServiceControl.Monitoring/Http/Diagrams/MonitoredEndpointMessageTypeParser.cs index f089104b4f..903013183a 100644 --- a/src/ServiceControl.Monitoring/Http/Diagrams/MonitoredEndpointMessageTypeParser.cs +++ b/src/ServiceControl.Monitoring/Http/Diagrams/MonitoredEndpointMessageTypeParser.cs @@ -41,7 +41,7 @@ public static MonitoredEndpointMessageType Parse(string typeName) } catch (Exception e) { - LoggerUtil.CreateStaticLogger(typeof(MonitoredEndpointMessageTypeParser)).LogWarning(e, "Error parsing message type: {typeName}.", typeName); + LoggerUtil.CreateStaticLogger(typeof(MonitoredEndpointMessageTypeParser)).LogWarning(e, "Error parsing message type: {typeName}", typeName); } } diff --git a/src/ServiceControl.Monitoring/Infrastructure/RemoveExpiredEndpointInstances.cs b/src/ServiceControl.Monitoring/Infrastructure/RemoveExpiredEndpointInstances.cs index 991cf534e3..c563aa45b0 100644 --- a/src/ServiceControl.Monitoring/Infrastructure/RemoveExpiredEndpointInstances.cs +++ b/src/ServiceControl.Monitoring/Infrastructure/RemoveExpiredEndpointInstances.cs @@ -44,7 +44,7 @@ protected override async Task ExecuteAsync(CancellationToken cancellationToken) catch (Exception ex) when (ex is not OperationCanceledException) { logger.LogError(ex, - $"Error deleting expired endpoint instances, trying again in {IntervalInMinutes} minutes."); + $"Error deleting expired endpoint instances, trying again in {IntervalInMinutes} minutes"); } } while (await timer.WaitForNextTickAsync(cancellationToken)); } diff --git a/src/ServiceControl.Monitoring/Infrastructure/ReportThroughputHostedService.cs b/src/ServiceControl.Monitoring/Infrastructure/ReportThroughputHostedService.cs index fb26a708c3..5789593d4e 100644 --- a/src/ServiceControl.Monitoring/Infrastructure/ReportThroughputHostedService.cs +++ b/src/ServiceControl.Monitoring/Infrastructure/ReportThroughputHostedService.cs @@ -37,7 +37,7 @@ protected override async Task ExecuteAsync(CancellationToken cancellationToken) } else { - logger.LogError(ex, $"Error obtaining throughput from Monitoring for {ReportSendingIntervalInMinutes} minutes interval."); + logger.LogError(ex, $"Error obtaining throughput from Monitoring for {ReportSendingIntervalInMinutes} minutes interval"); } } } while (await timer.WaitForNextTickAsync(cancellationToken)); diff --git a/src/ServiceControl.Monitoring/Licensing/LicenseCheckHostedService.cs b/src/ServiceControl.Monitoring/Licensing/LicenseCheckHostedService.cs index b29e47fd05..3bc9d0ec21 100644 --- a/src/ServiceControl.Monitoring/Licensing/LicenseCheckHostedService.cs +++ b/src/ServiceControl.Monitoring/Licensing/LicenseCheckHostedService.cs @@ -16,7 +16,7 @@ public Task StartAsync(CancellationToken cancellationToken) { activeLicense.Refresh(); return ScheduleNextExecutionTask; - }, due, due, ex => logger.LogError(ex, "Unhandled error while refreshing the license.")); + }, due, due, ex => logger.LogError(ex, "Unhandled error while refreshing the license")); return Task.CompletedTask; } diff --git a/src/ServiceControl.Monitoring/Program.cs b/src/ServiceControl.Monitoring/Program.cs index 3ff815616b..987953763d 100644 --- a/src/ServiceControl.Monitoring/Program.cs +++ b/src/ServiceControl.Monitoring/Program.cs @@ -13,7 +13,7 @@ LoggingConfigurator.ConfigureLogging(loggingSettings); logger = LoggerUtil.CreateStaticLogger(typeof(Program)); - AppDomain.CurrentDomain.UnhandledException += (s, e) => logger.LogError(e.ExceptionObject as Exception, "Unhandled exception was caught."); + AppDomain.CurrentDomain.UnhandledException += (s, e) => logger.LogError(e.ExceptionObject as Exception, "Unhandled exception was caught"); // Hack: See https://github.com/Particular/ServiceControl/issues/4392 var exitCode = await IntegratedSetup.Run(); diff --git a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckDirtyMemory.cs b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckDirtyMemory.cs index c90bbc4a8e..2654acff11 100644 --- a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckDirtyMemory.cs +++ b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckDirtyMemory.cs @@ -12,11 +12,11 @@ public override async Task PerformCheck(CancellationToken cancellat { var (isHighDirty, dirtyMemory) = await memoryInformationRetriever.GetMemoryInformation(cancellationToken); - logger.LogDebug("RavenDB dirty memory value: {DirtyMemory}.", dirtyMemory); + logger.LogDebug("RavenDB dirty memory value: {DirtyMemory}", dirtyMemory); if (isHighDirty) { - logger.LogWarning("There is a high level of RavenDB dirty memory ({DirtyMemory}). See https://docs.particular.net/servicecontrol/troubleshooting#ravendb-dirty-memory for guidance on how to mitigate the issue.", dirtyMemory); + logger.LogWarning("There is a high level of RavenDB dirty memory ({DirtyMemory}). See https://docs.particular.net/servicecontrol/troubleshooting#ravendb-dirty-memory for guidance on how to mitigate the issue", dirtyMemory); return CheckResult.Failed($"There is a high level of RavenDB dirty memory ({dirtyMemory}). See https://docs.particular.net/servicecontrol/troubleshooting#ravendb-dirty-memory for guidance on how to mitigate the issue."); } diff --git a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs index 22029f309c..a72f42b026 100644 --- a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs +++ b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs @@ -45,13 +45,13 @@ public static void Validate(RavenPersisterSettings settings) if (threshold < 0) { - logger.LogCritical("{RavenPersistenceConfigurationDataSpaceRemainingThresholdKey} is invalid, minimum value is 0.", RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey); + logger.LogCritical("{RavenPersistenceConfigurationDataSpaceRemainingThresholdKey} is invalid, minimum value is 0", RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey); throw new Exception($"{RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey} is invalid, minimum value is 0."); } if (threshold > 100) { - logger.LogCritical("{RavenPersistenceConfigurationDataSpaceRemainingThresholdKey} is invalid, maximum value is 100.", RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey); + logger.LogCritical("{RavenPersistenceConfigurationDataSpaceRemainingThresholdKey} is invalid, maximum value is 100", RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey); throw new Exception($"{RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey} is invalid, maximum value is 100."); } } diff --git a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs index 0c04857571..865c1d1c59 100644 --- a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs +++ b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs @@ -41,7 +41,7 @@ public override Task PerformCheck(CancellationToken cancellationTok return SuccessResult; } - logger.LogWarning("Error message ingestion stopped! {PercentRemaining:P0} disk space remaining on data drive '{DataDriveInfoVolumeLabel} ({DataDriveInfoRootDirectory})' on '{MachineName}'. This is less than {PercentageThreshold}% - the minimal required space configured. The threshold can be set using the {RavenBootstrapperMinimumStorageLeftRequiredForIngestionKey} configuration setting.", + logger.LogWarning("Error message ingestion stopped! {PercentRemaining:P0} disk space remaining on data drive '{DataDriveInfoVolumeLabel} ({DataDriveInfoRootDirectory})' on '{MachineName}'. This is less than {PercentageThreshold}% - the minimal required space configured. The threshold can be set using the {RavenBootstrapperMinimumStorageLeftRequiredForIngestionKey} configuration setting", percentRemaining, dataDriveInfo.VolumeLabel, dataDriveInfo.RootDirectory, @@ -59,13 +59,13 @@ public static void Validate(RavenPersisterSettings settings) if (threshold < 0) { - logger.LogCritical("{RavenBootstrapperMinimumStorageLeftRequiredForIngestionKey} is invalid, minimum value is 0.", RavenBootstrapper.MinimumStorageLeftRequiredForIngestionKey); + logger.LogCritical("{RavenBootstrapperMinimumStorageLeftRequiredForIngestionKey} is invalid, minimum value is 0", RavenBootstrapper.MinimumStorageLeftRequiredForIngestionKey); throw new Exception($"{RavenBootstrapper.MinimumStorageLeftRequiredForIngestionKey} is invalid, minimum value is 0."); } if (threshold > 100) { - logger.LogCritical("{RavenBootstrapperMinimumStorageLeftRequiredForIngestionKey} is invalid, maximum value is 100.", RavenBootstrapper.MinimumStorageLeftRequiredForIngestionKey); + logger.LogCritical("{RavenBootstrapperMinimumStorageLeftRequiredForIngestionKey} is invalid, maximum value is 100", RavenBootstrapper.MinimumStorageLeftRequiredForIngestionKey); throw new Exception($"{RavenBootstrapper.MinimumStorageLeftRequiredForIngestionKey} is invalid, maximum value is 100."); } } diff --git a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexLag.cs b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexLag.cs index d0fd05de1c..57c191756b 100644 --- a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexLag.cs +++ b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexLag.cs @@ -44,12 +44,12 @@ int CheckAndReportIndexesWithTooMuchIndexLag(IndexInformation[] indexes) if (indexLag > IndexLagThresholdError) { indexCountWithTooMuchLag++; - logger.LogError("Index [{IndexName}] IndexingLag {IndexLag} is above error threshold ({IndexLagThresholdError}). Launch in maintenance mode to let indexes catch up.", indexStats.Name, indexLag, IndexLagThresholdError); + logger.LogError("Index [{IndexName}] IndexingLag {IndexLag} is above error threshold ({IndexLagThresholdError}). Launch in maintenance mode to let indexes catch up", indexStats.Name, indexLag, IndexLagThresholdError); } else if (indexLag > IndexLagThresholdWarning) { indexCountWithTooMuchLag++; - logger.LogWarning("Index [{IndexName}] IndexingLag {IndexLag} is above warning threshold ({IndexLagThresholdWarning}). Launch in maintenance mode to let indexes catch up.", indexStats.Name, indexLag, IndexLagThresholdWarning); + logger.LogWarning("Index [{IndexName}] IndexingLag {IndexLag} is above warning threshold ({IndexLagThresholdWarning}). Launch in maintenance mode to let indexes catch up", indexStats.Name, indexLag, IndexLagThresholdWarning); } } } diff --git a/src/ServiceControl.Persistence.RavenDB/ExternalIntegrationRequestsDataStore.cs b/src/ServiceControl.Persistence.RavenDB/ExternalIntegrationRequestsDataStore.cs index 6f68141edc..7b339732ad 100644 --- a/src/ServiceControl.Persistence.RavenDB/ExternalIntegrationRequestsDataStore.cs +++ b/src/ServiceControl.Persistence.RavenDB/ExternalIntegrationRequestsDataStore.cs @@ -149,7 +149,7 @@ async Task TryDispatchEventBatch() } var allContexts = awaitingDispatching.Select(r => r.DispatchContext).ToArray(); - logger.LogDebug("Dispatching {EventCount} events.", allContexts.Length); + logger.LogDebug("Dispatching {EventCount} events", allContexts.Length); await callback(allContexts); diff --git a/src/ServiceControl.Persistence.RavenDB/FailedErrorImportDataStore.cs b/src/ServiceControl.Persistence.RavenDB/FailedErrorImportDataStore.cs index 730413af0b..10d63a5a1c 100644 --- a/src/ServiceControl.Persistence.RavenDB/FailedErrorImportDataStore.cs +++ b/src/ServiceControl.Persistence.RavenDB/FailedErrorImportDataStore.cs @@ -36,17 +36,17 @@ public async Task ProcessFailedErrorImports(Func p } catch (Exception e) { - logger.LogError(e, "Error while attempting to re-import failed error message {MessageId}.", transportMessage.Id); + logger.LogError(e, "Error while attempting to re-import failed error message {MessageId}", transportMessage.Id); failed++; } } } - logger.LogInformation("Done re-importing failed errors. Successfully re-imported {SucceededCount} messages. Failed re-importing {FailedCount} messages.", succeeded, failed); + logger.LogInformation("Done re-importing failed errors. Successfully re-imported {SucceededCount} messages. Failed re-importing {FailedCount} messages", succeeded, failed); if (failed > 0) { - logger.LogWarning("{FailedCount} messages could not be re-imported. This could indicate a problem with the data. Contact Particular support if you need help with recovering the messages.", failed); + logger.LogWarning("{FailedCount} messages could not be re-imported. This could indicate a problem with the data. Contact Particular support if you need help with recovering the messages", failed); } } diff --git a/src/ServiceControl.Persistence.RavenDB/Recoverability/Archiving/MessageArchiver.cs b/src/ServiceControl.Persistence.RavenDB/Recoverability/Archiving/MessageArchiver.cs index 64f722bbe2..b2957ba9a8 100644 --- a/src/ServiceControl.Persistence.RavenDB/Recoverability/Archiving/MessageArchiver.cs +++ b/src/ServiceControl.Persistence.RavenDB/Recoverability/Archiving/MessageArchiver.cs @@ -71,7 +71,7 @@ public async Task ArchiveAllInGroup(string groupId) if (nextBatch == null) { // We're only here in the case where Raven indexes are stale - logger.LogWarning("Attempting to archive a batch ({ArchiveOperationId}/{ArchiveOperationCurrentBatch}) which appears to already have been archived.", archiveOperation.Id, archiveOperation.CurrentBatch); + logger.LogWarning("Attempting to archive a batch ({ArchiveOperationId}/{ArchiveOperationCurrentBatch}) which appears to already have been archived", archiveOperation.Id, archiveOperation.CurrentBatch); } else { @@ -104,12 +104,12 @@ await domainEvents.Raise(new FailedMessageGroupBatchArchived } } - logger.LogInformation("Archiving of group {GroupId} is complete. Waiting for index updates.", groupId); + logger.LogInformation("Archiving of group {GroupId} is complete. Waiting for index updates", groupId); await archivingManager.ArchiveOperationFinalizing(archiveOperation.RequestId, archiveOperation.ArchiveType); if (!await archiveDocumentManager.WaitForIndexUpdateOfArchiveOperation(sessionProvider, archiveOperation.RequestId, TimeSpan.FromMinutes(5)) ) { - logger.LogWarning("Archiving group {GroupId} completed but index not updated.", groupId); + logger.LogWarning("Archiving group {GroupId} completed but index not updated", groupId); } await archivingManager.ArchiveOperationCompleted(archiveOperation.RequestId, archiveOperation.ArchiveType); @@ -163,7 +163,7 @@ public async Task UnarchiveAllInGroup(string groupId) if (nextBatch == null) { // We're only here in the case where Raven indexes are stale - logger.LogWarning("Attempting to unarchive a batch ({UnarchiveOperationId}/{UnarchiveOperationCurrentBatch}) which appears to already have been archived.", unarchiveOperation.Id, unarchiveOperation.CurrentBatch); + logger.LogWarning("Attempting to unarchive a batch ({UnarchiveOperationId}/{UnarchiveOperationCurrentBatch}) which appears to already have been archived", unarchiveOperation.Id, unarchiveOperation.CurrentBatch); } else { @@ -195,12 +195,12 @@ await domainEvents.Raise(new FailedMessageGroupBatchUnarchived } } - logger.LogInformation("Unarchiving of group {GroupId} is complete. Waiting for index updates.", groupId); + logger.LogInformation("Unarchiving of group {GroupId} is complete. Waiting for index updates", groupId); await unarchivingManager.UnarchiveOperationFinalizing(unarchiveOperation.RequestId, unarchiveOperation.ArchiveType); if (!await unarchiveDocumentManager.WaitForIndexUpdateOfUnarchiveOperation(sessionProvider, unarchiveOperation.RequestId, TimeSpan.FromMinutes(5)) ) { - logger.LogWarning("Unarchiving group {GroupId} completed but index not updated.", groupId); + logger.LogWarning("Unarchiving group {GroupId} completed but index not updated", groupId); } logger.LogInformation("Unarchiving of group {GroupId} completed", groupId); diff --git a/src/ServiceControl.RavenDB/EmbeddedDatabase.cs b/src/ServiceControl.RavenDB/EmbeddedDatabase.cs index e9fa10ea44..08fb28eb88 100644 --- a/src/ServiceControl.RavenDB/EmbeddedDatabase.cs +++ b/src/ServiceControl.RavenDB/EmbeddedDatabase.cs @@ -125,7 +125,7 @@ void Start(ServerOptions serverOptions) await EmbeddedServer.Instance.RestartServerAsync(); restartRequired = false; - logger.LogInformation("RavenDB server process restarted successfully."); + logger.LogInformation("RavenDB server process restarted successfully"); } catch (OperationCanceledException) when (shutdownCancellationToken.IsCancellationRequested) { @@ -133,7 +133,7 @@ void Start(ServerOptions serverOptions) } catch (Exception e) { - logger.LogCritical(e, "RavenDB server restart failed. Restart will be retried in {RavenDelayBetweenRestarts}.", delayBetweenRestarts); + logger.LogCritical(e, "RavenDB server restart failed. Restart will be retried in {RavenDelayBetweenRestarts}", delayBetweenRestarts); } } }, CancellationToken.None); @@ -149,11 +149,11 @@ void OnServerProcessExited(object? sender, ServerProcessExitedEventArgs _) restartRequired = true; if (sender is Process process) { - logger.LogWarning("RavenDB server process exited unexpectedly with exitCode: {RavenExitCode}. Process will be restarted.", process.ExitCode); + logger.LogWarning("RavenDB server process exited unexpectedly with exitCode: {RavenExitCode}. Process will be restarted", process.ExitCode); } else { - logger.LogWarning("RavenDB server process exited unexpectedly. Process will be restarted."); + logger.LogWarning("RavenDB server process exited unexpectedly. Process will be restarted"); } } diff --git a/src/ServiceControl.Transports.ASBS/DeadLetterQueueCheck.cs b/src/ServiceControl.Transports.ASBS/DeadLetterQueueCheck.cs index e44be27ca8..afdfe34b7a 100644 --- a/src/ServiceControl.Transports.ASBS/DeadLetterQueueCheck.cs +++ b/src/ServiceControl.Transports.ASBS/DeadLetterQueueCheck.cs @@ -34,7 +34,7 @@ public override async Task PerformCheck(CancellationToken cancellat if (deadLetterMessageCount > 0) { - Logger.LogWarning("{DeadLetterMessageCount} messages in the Dead Letter Queue '{StagingQueue}'. This could indicate a problem with ServiceControl's retries. Please submit a support ticket to Particular if you would like help from our engineers to ensure no message loss while resolving these dead letter messages.", deadLetterMessageCount, stagingQueue); + Logger.LogWarning("{DeadLetterMessageCount} messages in the Dead Letter Queue '{StagingQueue}'. This could indicate a problem with ServiceControl's retries. Please submit a support ticket to Particular if you would like help from our engineers to ensure no message loss while resolving these dead letter messages", deadLetterMessageCount, stagingQueue); return CheckResult.Failed($"{deadLetterMessageCount} messages in the Dead Letter Queue '{stagingQueue}'. This could indicate a problem with ServiceControl's retries. Please submit a support ticket to Particular if you would like help from our engineers to ensure no message loss while resolving these dead letter messages."); } diff --git a/src/ServiceControl.Transports.ASBS/QueueLengthProvider.cs b/src/ServiceControl.Transports.ASBS/QueueLengthProvider.cs index f6fb44e593..8978c03fed 100644 --- a/src/ServiceControl.Transports.ASBS/QueueLengthProvider.cs +++ b/src/ServiceControl.Transports.ASBS/QueueLengthProvider.cs @@ -36,7 +36,7 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) logger.LogDebug("Waiting for next interval"); await Task.Delay(queryDelayInterval, stoppingToken); - logger.LogDebug("Querying management client."); + logger.LogDebug("Querying management client"); var queueRuntimeInfos = await GetQueueList(stoppingToken); @@ -50,7 +50,7 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) } catch (Exception e) { - logger.LogError(e, "Error querying Azure Service Bus queue sizes."); + logger.LogError(e, "Error querying Azure Service Bus queue sizes"); } } } diff --git a/src/ServiceControl.Transports.ASQ/QueueLengthProvider.cs b/src/ServiceControl.Transports.ASQ/QueueLengthProvider.cs index 48ebcf6a6d..01b29e98fd 100644 --- a/src/ServiceControl.Transports.ASQ/QueueLengthProvider.cs +++ b/src/ServiceControl.Transports.ASQ/QueueLengthProvider.cs @@ -51,7 +51,7 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) } catch (Exception e) { - logger.LogError(e, "Error querying sql queue sizes."); + logger.LogError(e, "Error querying sql queue sizes"); } } } diff --git a/src/ServiceControl.Transports.Msmq/DeadLetterQueueCheck.cs b/src/ServiceControl.Transports.Msmq/DeadLetterQueueCheck.cs index 61c5378d4d..06594b0e2b 100644 --- a/src/ServiceControl.Transports.Msmq/DeadLetterQueueCheck.cs +++ b/src/ServiceControl.Transports.Msmq/DeadLetterQueueCheck.cs @@ -68,7 +68,7 @@ public override Task PerformCheck(CancellationToken cancellationTok return CheckResult.Pass; } - logger.LogWarning("{DeadLetterMessageCount} messages in the Dead Letter Queue on {MachineName}. This could indicate a problem with ServiceControl's retries. Please submit a support ticket to Particular if you would like help from our engineers to ensure no message loss while resolving these dead letter messages.", currentValue, Environment.MachineName); + logger.LogWarning("{DeadLetterMessageCount} messages in the Dead Letter Queue on {MachineName}. This could indicate a problem with ServiceControl's retries. Please submit a support ticket to Particular if you would like help from our engineers to ensure no message loss while resolving these dead letter messages", currentValue, Environment.MachineName); return CheckResult.Failed($"{currentValue} messages in the Dead Letter Queue on {Environment.MachineName}. This could indicate a problem with ServiceControl's retries. Please submit a support ticket to Particular if you would like help from our engineers to ensure no message loss while resolving these dead letter messages."); } diff --git a/src/ServiceControl.Transports.PostgreSql/QueueLengthProvider.cs b/src/ServiceControl.Transports.PostgreSql/QueueLengthProvider.cs index 79b128032d..e6067e131e 100644 --- a/src/ServiceControl.Transports.PostgreSql/QueueLengthProvider.cs +++ b/src/ServiceControl.Transports.PostgreSql/QueueLengthProvider.cs @@ -56,7 +56,7 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) } catch (Exception e) { - logger.LogError(e, "Error querying SQL queue sizes."); + logger.LogError(e, "Error querying SQL queue sizes"); } } } @@ -114,7 +114,7 @@ async Task UpdateChunk(NpgsqlConnection connection, KeyValuePair[] c if (queueLength == -1) { - logger.LogWarning("Table {TableName} does not exist.", chunkPair.Key); + logger.LogWarning("Table {TableName} does not exist", chunkPair.Key); } else { diff --git a/src/ServiceControl/ExternalIntegrations/EventDispatcherHostedService.cs b/src/ServiceControl/ExternalIntegrations/EventDispatcherHostedService.cs index ad6b91141c..91c9eb56f5 100644 --- a/src/ServiceControl/ExternalIntegrations/EventDispatcherHostedService.cs +++ b/src/ServiceControl/ExternalIntegrations/EventDispatcherHostedService.cs @@ -44,7 +44,7 @@ async Task TryDispatchEventBatch(object[] allContexts) foreach (var eventToBePublished in eventsToBePublished) { - logger.LogDebug("Publishing external event on the bus."); + logger.LogDebug("Publishing external event on the bus"); try { @@ -52,7 +52,7 @@ async Task TryDispatchEventBatch(object[] allContexts) } catch (Exception e) { - logger.LogError(e, "Failed dispatching external integration event."); + logger.LogError(e, "Failed dispatching external integration event"); var m = new ExternalIntegrationEventFailedToBePublished { diff --git a/src/ServiceControl/SagaAudit/SagaUpdatedHandler.cs b/src/ServiceControl/SagaAudit/SagaUpdatedHandler.cs index 47a7ba3b8e..48c1b97536 100644 --- a/src/ServiceControl/SagaAudit/SagaUpdatedHandler.cs +++ b/src/ServiceControl/SagaAudit/SagaUpdatedHandler.cs @@ -57,7 +57,7 @@ async Task RefreshAuditQueue() // Pick any audit queue, assume all instance are based on competing consumer auditQueueName = sagaAudit.GetProperty("SagaAuditQueue").GetString(); nextAuditQueueNameRefresh = DateTime.UtcNow.AddMinutes(5); - logger.LogInformation("Refreshed audit queue name '{AuditQueueName}' from ServiceControl Audit instance. Will continue to use this value for forwarding saga update messages for the next 5 minutes.", auditQueueName); + logger.LogInformation("Refreshed audit queue name '{AuditQueueName}' from ServiceControl Audit instance. Will continue to use this value for forwarding saga update messages for the next 5 minutes", auditQueueName); } } catch (Exception x) From e7bf499c4b9313ebc8573b350c39416d8ae159d5 Mon Sep 17 00:00:00 2001 From: Phil Bastian Date: Thu, 26 Jun 2025 13:36:29 +0800 Subject: [PATCH 46/56] remove unnecessary static logger --- .../CustomChecks/CheckRavenDBIndexLag.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexLag.cs b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexLag.cs index 78c8ddebc5..7cd6d76321 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexLag.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexLag.cs @@ -9,7 +9,6 @@ using NServiceBus.CustomChecks; using Raven.Client.Documents.Operations; using ServiceControl.Audit.Persistence.RavenDB; - using ServiceControl.Infrastructure; class CheckRavenDBIndexLag(IRavenDocumentStoreProvider documentStoreProvider, ILogger logger) : CustomCheck("Audit Database Index Lag", "ServiceControl.Audit Health", TimeSpan.FromMinutes(5)) { @@ -21,7 +20,7 @@ public override async Task PerformCheck(CancellationToken cancellat CreateDiagnosticsLogEntry(statistics, indexes); - var indexCountWithTooMuchLag = CheckAndReportIndexesWithTooMuchIndexLag(indexes, logger); + var indexCountWithTooMuchLag = CheckAndReportIndexesWithTooMuchIndexLag(indexes); if (indexCountWithTooMuchLag > 0) { @@ -31,7 +30,7 @@ public override async Task PerformCheck(CancellationToken cancellat return CheckResult.Pass; } - static int CheckAndReportIndexesWithTooMuchIndexLag(IndexInformation[] indexes, ILogger logger) + int CheckAndReportIndexesWithTooMuchIndexLag(IndexInformation[] indexes) { int indexCountWithTooMuchLag = 0; @@ -57,9 +56,9 @@ static int CheckAndReportIndexesWithTooMuchIndexLag(IndexInformation[] indexes, return indexCountWithTooMuchLag; } - static void CreateDiagnosticsLogEntry(DatabaseStatistics statistics, IndexInformation[] indexes) + void CreateDiagnosticsLogEntry(DatabaseStatistics statistics, IndexInformation[] indexes) { - if (!Logger.IsEnabled(LogLevel.Debug)) + if (!logger.IsEnabled(LogLevel.Debug)) { return; } @@ -74,11 +73,10 @@ static void CreateDiagnosticsLogEntry(DatabaseStatistics statistics, IndexInform report.AppendLine($"- Index [{indexStats.Name,-44}] State: {indexStats.State}, Stale: {indexStats.IsStale,-5}, Priority: {indexStats.Priority,-6}, LastIndexingTime: {indexStats.LastIndexingTime:u}"); } - Logger.LogDebug(report.ToString()); + logger.LogDebug(report.ToString()); } static readonly TimeSpan IndexLagThresholdWarning = TimeSpan.FromMinutes(1); static readonly TimeSpan IndexLagThresholdError = TimeSpan.FromMinutes(10); - static readonly ILogger Logger = LoggerUtil.CreateStaticLogger(); } } \ No newline at end of file From f0be16f235e70e14d4f64b2ce01f77dadf56e1af Mon Sep 17 00:00:00 2001 From: Phil Bastian Date: Thu, 26 Jun 2025 14:54:14 +0800 Subject: [PATCH 47/56] remove unnecessary checks since it's not around intensive log conversions --- .../CheckMinimumStorageRequiredForIngestion.cs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs index 7bfad30a84..830e97d95f 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs @@ -15,11 +15,7 @@ class CheckMinimumStorageRequiredForIngestion(MinimumRequiredStorageState stateH public override Task PerformCheck(CancellationToken cancellationToken = default) { var percentageThreshold = databaseConfiguration.MinimumStorageLeftRequiredForIngestion / 100m; - - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug("Check ServiceControl data drive space starting. Threshold {PercentageThreshold:P0}", percentageThreshold); - } + logger.LogDebug("Check ServiceControl data drive space starting. Threshold {PercentageThreshold:P0}", percentageThreshold); // Should be checking UseEmbeddedServer but need to check DbPath instead for the ATT hack to work if (string.IsNullOrEmpty(databaseConfiguration.ServerConfiguration.DbPath)) @@ -35,11 +31,7 @@ public override Task PerformCheck(CancellationToken cancellationTok var totalSpace = (decimal)dataDriveInfo.TotalSize; var percentRemaining = (decimal)dataDriveInfo.AvailableFreeSpace / dataDriveInfo.TotalSize; - - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug("Free space: {AvailableFreeSpace:N0}B | Total: {TotalSpace:N0}B | Percent remaining {PercentRemaining:P0}", availableFreeSpace, totalSpace, percentRemaining); - } + logger.LogDebug("Free space: {AvailableFreeSpace:N0}B | Total: {TotalSpace:N0}B | Percent remaining {PercentRemaining:P0}", availableFreeSpace, totalSpace, percentRemaining); if (percentRemaining > percentageThreshold) { From 061ba554b9d1c365be18de9e7024beb9f8124d0a Mon Sep 17 00:00:00 2001 From: Phil Bastian Date: Fri, 27 Jun 2025 08:43:03 +0800 Subject: [PATCH 48/56] remove unnecessary checks --- .../CustomChecks/CheckFreeDiskSpace.cs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs index 834655eb5a..9e4f74054b 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs @@ -13,10 +13,7 @@ class CheckFreeDiskSpace(DatabaseConfiguration databaseConfiguration, ILogger PerformCheck(CancellationToken cancellationToken = default) { - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug("Check ServiceControl data drive space remaining custom check starting. Threshold {PercentageThreshold:P0}", percentageThreshold); - } + logger.LogDebug("Check ServiceControl data drive space remaining custom check starting. Threshold {PercentageThreshold:P0}", percentageThreshold); if (!databaseConfiguration.ServerConfiguration.UseEmbeddedServer) { @@ -33,11 +30,7 @@ public override Task PerformCheck(CancellationToken cancellationTok var totalSpace = (decimal)dataDriveInfo.TotalSize; var percentRemaining = (decimal)dataDriveInfo.AvailableFreeSpace / dataDriveInfo.TotalSize; - - if (logger.IsEnabled(LogLevel.Debug)) - { - logger.LogDebug("Free space: {AvailableFreeSpace:N0}B | Total: {TotalSpace:N0}B | Percent remaining {PercentRemaining:P1}", availableFreeSpace, totalSpace, percentRemaining); - } + logger.LogDebug("Free space: {AvailableFreeSpace:N0}B | Total: {TotalSpace:N0}B | Percent remaining {PercentRemaining:P1}", availableFreeSpace, totalSpace, percentRemaining); return percentRemaining > percentageThreshold ? CheckResult.Pass From 22bcf4b586263f212b8f4f1cefd584b18691c019 Mon Sep 17 00:00:00 2001 From: Phil Bastian Date: Fri, 27 Jun 2025 08:49:26 +0800 Subject: [PATCH 49/56] add opentelemetry as a logging provider option --- src/ServiceControl.Audit/App.config | 2 +- src/ServiceControl.Infrastructure/LoggerUtil.cs | 6 ++++++ src/ServiceControl.Infrastructure/LoggingSettings.cs | 4 ++++ src/ServiceControl.Monitoring/App.config | 2 +- src/ServiceControl/App.config | 2 +- 5 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/ServiceControl.Audit/App.config b/src/ServiceControl.Audit/App.config index 2d276941f4..9452cd7e00 100644 --- a/src/ServiceControl.Audit/App.config +++ b/src/ServiceControl.Audit/App.config @@ -22,7 +22,7 @@ These settings are only here so that we can debug ServiceControl while developin - + diff --git a/src/ServiceControl.Infrastructure/LoggerUtil.cs b/src/ServiceControl.Infrastructure/LoggerUtil.cs index 973c2b3cd2..873f35a365 100644 --- a/src/ServiceControl.Infrastructure/LoggerUtil.cs +++ b/src/ServiceControl.Infrastructure/LoggerUtil.cs @@ -4,6 +4,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using NLog.Extensions.Logging; + using OpenTelemetry.Logs; using ServiceControl.Infrastructure.TestLogger; [Flags] @@ -13,6 +14,7 @@ public enum Loggers Test = 1 << 0, NLog = 1 << 1, Seq = 1 << 2, + Otlp = 1 << 3, } public static class LoggerUtil @@ -47,6 +49,10 @@ public static void BuildLogger(this ILoggingBuilder loggingBuilder, LogLevel lev loggingBuilder.AddSeq(); } } + if (IsLoggingTo(Loggers.Otlp)) + { + loggingBuilder.AddOpenTelemetry(configure => configure.AddOtlpExporter()); + } loggingBuilder.SetMinimumLevel(level); } diff --git a/src/ServiceControl.Infrastructure/LoggingSettings.cs b/src/ServiceControl.Infrastructure/LoggingSettings.cs index d99200fba0..e92e29e7e5 100644 --- a/src/ServiceControl.Infrastructure/LoggingSettings.cs +++ b/src/ServiceControl.Infrastructure/LoggingSettings.cs @@ -26,6 +26,10 @@ public LoggingSettings(SettingsRootNamespace rootNamespace, LogLevel defaultLeve LoggerUtil.SeqAddress = seqAddress; } } + if (loggingProviders.Contains("Otlp")) + { + activeLoggers |= Loggers.Otlp; + } //this defaults to NLog because historically that was the default, and we don't want to break existing installs that don't have the config key to define loggingProviders LoggerUtil.ActiveLoggers = activeLoggers == Loggers.None ? Loggers.NLog : activeLoggers; diff --git a/src/ServiceControl.Monitoring/App.config b/src/ServiceControl.Monitoring/App.config index 5ea2193cbc..0a2fa4d478 100644 --- a/src/ServiceControl.Monitoring/App.config +++ b/src/ServiceControl.Monitoring/App.config @@ -19,7 +19,7 @@ These settings are only here so that we can debug ServiceControl while developin - + diff --git a/src/ServiceControl/App.config b/src/ServiceControl/App.config index c5803553e0..953b727cc8 100644 --- a/src/ServiceControl/App.config +++ b/src/ServiceControl/App.config @@ -24,7 +24,7 @@ These settings are only here so that we can debug ServiceControl while developin - + From ca52fa15ce887a0f92987809a6b4fe2138c481e1 Mon Sep 17 00:00:00 2001 From: Phil Bastian Date: Fri, 27 Jun 2025 09:33:26 +0800 Subject: [PATCH 50/56] missing package reference --- .../ServiceControl.Infrastructure.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ServiceControl.Infrastructure/ServiceControl.Infrastructure.csproj b/src/ServiceControl.Infrastructure/ServiceControl.Infrastructure.csproj index b32d80b1fa..225a545bd9 100644 --- a/src/ServiceControl.Infrastructure/ServiceControl.Infrastructure.csproj +++ b/src/ServiceControl.Infrastructure/ServiceControl.Infrastructure.csproj @@ -16,6 +16,7 @@ + From 8b55728ead643b30ca9ddea36a72ed6a82863775 Mon Sep 17 00:00:00 2001 From: Phil Bastian <155411597+PhilBastian@users.noreply.github.com> Date: Fri, 27 Jun 2025 10:00:00 +0800 Subject: [PATCH 51/56] Update src/ServiceControl/Monitoring/HeartbeatEndpointSettingsSyncHostedService.cs Co-authored-by: Ramon Smits --- .../Monitoring/HeartbeatEndpointSettingsSyncHostedService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ServiceControl/Monitoring/HeartbeatEndpointSettingsSyncHostedService.cs b/src/ServiceControl/Monitoring/HeartbeatEndpointSettingsSyncHostedService.cs index 5f75cf5885..8e74516613 100644 --- a/src/ServiceControl/Monitoring/HeartbeatEndpointSettingsSyncHostedService.cs +++ b/src/ServiceControl/Monitoring/HeartbeatEndpointSettingsSyncHostedService.cs @@ -121,7 +121,7 @@ await endpointSettingsStore.UpdateEndpointSettings( new EndpointSettings { Name = string.Empty, TrackInstances = userSetTrackInstances }, cancellationToken); logger.LogInformation( - "Initialized default value of EndpointTracking to {TrackInstances}", userSetTrackInstances ? "tracking" : "not tracking"); + "Initialized default value of EndpointTracking to {TrackInstancesEnabled}", userSetTrackInstances); } // Initialise settings for any missing endpoint From 43cc46ccbe73373c85727d39cf2e6e05e0162c9f Mon Sep 17 00:00:00 2001 From: Phil Bastian <155411597+PhilBastian@users.noreply.github.com> Date: Fri, 27 Jun 2025 10:02:27 +0800 Subject: [PATCH 52/56] Update src/ServiceControl/Monitoring/HeartbeatEndpointSettingsSyncHostedService.cs Co-authored-by: Ramon Smits --- .../Monitoring/HeartbeatEndpointSettingsSyncHostedService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ServiceControl/Monitoring/HeartbeatEndpointSettingsSyncHostedService.cs b/src/ServiceControl/Monitoring/HeartbeatEndpointSettingsSyncHostedService.cs index 8e74516613..ec5158a4f9 100644 --- a/src/ServiceControl/Monitoring/HeartbeatEndpointSettingsSyncHostedService.cs +++ b/src/ServiceControl/Monitoring/HeartbeatEndpointSettingsSyncHostedService.cs @@ -131,7 +131,7 @@ await endpointSettingsStore.UpdateEndpointSettings( new EndpointSettings { Name = name, TrackInstances = userSetTrackInstances }, cancellationToken); logger.LogInformation( - "Initialized '{Setting}' value of EndpointTracking to {TrackInstances}", name, userSetTrackInstances ? "tracking" : "not tracking"); + "Initialized '{SettingKey}' value of EndpointTracking to {TrackInstancesEnabled}", name, userSetTrackInstances); } } } \ No newline at end of file From ff857496b7546bdb1ff5486d6600f47b00d5b6d7 Mon Sep 17 00:00:00 2001 From: Phil Bastian Date: Fri, 27 Jun 2025 10:18:39 +0800 Subject: [PATCH 53/56] log text changes suggested in review --- .../CustomChecks/CheckFreeDiskSpace.cs | 2 +- .../CustomChecks/CheckMinimumStorageRequiredForIngestion.cs | 2 +- .../CustomChecks/CheckFreeDiskSpace.cs | 2 +- .../CustomChecks/CheckMinimumStorageRequiredForIngestion.cs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs index 9e4f74054b..e7757101a2 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs @@ -30,7 +30,7 @@ public override Task PerformCheck(CancellationToken cancellationTok var totalSpace = (decimal)dataDriveInfo.TotalSize; var percentRemaining = (decimal)dataDriveInfo.AvailableFreeSpace / dataDriveInfo.TotalSize; - logger.LogDebug("Free space: {AvailableFreeSpace:N0}B | Total: {TotalSpace:N0}B | Percent remaining {PercentRemaining:P1}", availableFreeSpace, totalSpace, percentRemaining); + logger.LogDebug("Free space: {FreeSpaceTotalBytesFree:N0}B | Total: {FreeSpaceTotalBytesAvailable:N0}B | Remaining {PercentRemaining:P1}%", availableFreeSpace, totalSpace, percentRemaining); return percentRemaining > percentageThreshold ? CheckResult.Pass diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs index 830e97d95f..58fb1ed984 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs @@ -31,7 +31,7 @@ public override Task PerformCheck(CancellationToken cancellationTok var totalSpace = (decimal)dataDriveInfo.TotalSize; var percentRemaining = (decimal)dataDriveInfo.AvailableFreeSpace / dataDriveInfo.TotalSize; - logger.LogDebug("Free space: {AvailableFreeSpace:N0}B | Total: {TotalSpace:N0}B | Percent remaining {PercentRemaining:P0}", availableFreeSpace, totalSpace, percentRemaining); + logger.LogDebug("Free space: {FreeSpaceTotalBytesFree:N0}B | Total: {FreeSpaceTotalBytesAvailable:N0}B | Remaining {PercentRemaining:P0}%", availableFreeSpace, totalSpace, percentRemaining); if (percentRemaining > percentageThreshold) { diff --git a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs index a72f42b026..cbfcfbcf8f 100644 --- a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs +++ b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs @@ -31,7 +31,7 @@ public override Task PerformCheck(CancellationToken cancellationTok var percentRemaining = (decimal)dataDriveInfo.AvailableFreeSpace / dataDriveInfo.TotalSize; - logger.LogDebug("Free space: {AvailableFreeSpace:N0}B | Total: {TotalSpace:N0}B | Percent remaining {PercentRemaining:P1}", availableFreeSpace, totalSpace, percentRemaining); + logger.LogDebug("Free space: {FreeSpaceTotalBytesFree:N0}B | Total: {FreeSpaceTotalBytesAvailable:N0}B | Remaining {PercentRemaining:P1}%", availableFreeSpace, totalSpace, percentRemaining); return percentRemaining > percentageThreshold ? CheckResult.Pass diff --git a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs index 865c1d1c59..dad26352d7 100644 --- a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs +++ b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs @@ -33,7 +33,7 @@ public override Task PerformCheck(CancellationToken cancellationTok var percentRemaining = (decimal)dataDriveInfo.AvailableFreeSpace / dataDriveInfo.TotalSize; - logger.LogDebug("Free space: {AvailableFreeSpace:N0}B | Total: {TotalSpace:N0}B | Percent remaining {PercentRemaining:P1}", availableFreeSpace, totalSpace, percentRemaining); + logger.LogDebug("Free space: {FreeSpaceTotalBytesFree:N0}B | Total: {FreeSpaceTotalBytesAvailable:N0}B | Remaining {PercentRemaining:P1}%", availableFreeSpace, totalSpace, percentRemaining); if (percentRemaining > percentageThreshold) { From e7a28a27979cbd5831bf0a7e3cd8f08902b68d0b Mon Sep 17 00:00:00 2001 From: Phil Bastian <155411597+PhilBastian@users.noreply.github.com> Date: Tue, 1 Jul 2025 15:44:32 +0800 Subject: [PATCH 54/56] Update src/ServiceControl.Infrastructure/LoggerUtil.cs Co-authored-by: Ramon Smits --- src/ServiceControl.Infrastructure/LoggerUtil.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ServiceControl.Infrastructure/LoggerUtil.cs b/src/ServiceControl.Infrastructure/LoggerUtil.cs index 873f35a365..463c3dffb1 100644 --- a/src/ServiceControl.Infrastructure/LoggerUtil.cs +++ b/src/ServiceControl.Infrastructure/LoggerUtil.cs @@ -28,7 +28,7 @@ public static bool IsLoggingTo(Loggers logger) return (logger & ActiveLoggers) == logger; } - public static void BuildLogger(this ILoggingBuilder loggingBuilder, LogLevel level) + public static void BuildServiceControlLogging(this ILoggingBuilder loggingBuilder, LogLevel level) { if (IsLoggingTo(Loggers.Test)) { From 0533c6e63228739d1349b0c315ac1099ff423863 Mon Sep 17 00:00:00 2001 From: Phil Bastian Date: Tue, 1 Jul 2025 15:54:06 +0800 Subject: [PATCH 55/56] update method calls to match new name --- src/ServiceControl.Audit/HostApplicationBuilderExtensions.cs | 2 +- src/ServiceControl.Infrastructure/LoggerUtil.cs | 4 ++-- src/ServiceControl.Infrastructure/LoggingConfigurator.cs | 2 +- .../TestSupport/ServiceControlComponentRunner.cs | 2 +- .../HostApplicationBuilderExtensions.cs | 4 +--- src/ServiceControl.Persistence.Tests/PersistenceTestBase.cs | 2 +- src/ServiceControl/HostApplicationBuilderExtensions.cs | 2 +- 7 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/ServiceControl.Audit/HostApplicationBuilderExtensions.cs b/src/ServiceControl.Audit/HostApplicationBuilderExtensions.cs index 8f2f52f19d..5221152387 100644 --- a/src/ServiceControl.Audit/HostApplicationBuilderExtensions.cs +++ b/src/ServiceControl.Audit/HostApplicationBuilderExtensions.cs @@ -39,7 +39,7 @@ public static void AddServiceControlAudit(this IHostApplicationBuilder builder, RecordStartup(settings, configuration, persistenceConfiguration); builder.Logging.ClearProviders(); - builder.Logging.BuildLogger(settings.LoggingSettings.LogLevel); + builder.Logging.BuildServiceControlLogging(settings.LoggingSettings.LogLevel); var services = builder.Services; var transportSettings = settings.ToTransportSettings(); diff --git a/src/ServiceControl.Infrastructure/LoggerUtil.cs b/src/ServiceControl.Infrastructure/LoggerUtil.cs index 463c3dffb1..5aec1b7673 100644 --- a/src/ServiceControl.Infrastructure/LoggerUtil.cs +++ b/src/ServiceControl.Infrastructure/LoggerUtil.cs @@ -59,13 +59,13 @@ public static void BuildServiceControlLogging(this ILoggingBuilder loggingBuilde public static ILogger CreateStaticLogger(LogLevel level = LogLevel.Information) { - var factory = LoggerFactory.Create(configure => configure.BuildLogger(level)); + var factory = LoggerFactory.Create(configure => configure.BuildServiceControlLogging(level)); return factory.CreateLogger(); } public static ILogger CreateStaticLogger(Type type, LogLevel level = LogLevel.Information) { - var factory = LoggerFactory.Create(configure => configure.BuildLogger(level)); + var factory = LoggerFactory.Create(configure => configure.BuildServiceControlLogging(level)); return factory.CreateLogger(type); } } diff --git a/src/ServiceControl.Infrastructure/LoggingConfigurator.cs b/src/ServiceControl.Infrastructure/LoggingConfigurator.cs index e35aa23194..b6d183a90f 100644 --- a/src/ServiceControl.Infrastructure/LoggingConfigurator.cs +++ b/src/ServiceControl.Infrastructure/LoggingConfigurator.cs @@ -17,7 +17,7 @@ public static class LoggingConfigurator public static void ConfigureLogging(LoggingSettings loggingSettings) { //used for loggers outside of ServiceControl (i.e. transports and core) to use the logger factory defined here - LogManager.UseFactory(new ExtensionsLoggerFactory(LoggerFactory.Create(configure => configure.BuildLogger(loggingSettings.LogLevel)))); + LogManager.UseFactory(new ExtensionsLoggerFactory(LoggerFactory.Create(configure => configure.BuildServiceControlLogging(loggingSettings.LogLevel)))); if (!LoggerUtil.IsLoggingTo(Loggers.NLog) || NLog.LogManager.Configuration != null) { diff --git a/src/ServiceControl.Monitoring.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs b/src/ServiceControl.Monitoring.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs index 63635fa2cf..d51eb01de4 100644 --- a/src/ServiceControl.Monitoring.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs +++ b/src/ServiceControl.Monitoring.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs @@ -94,7 +94,7 @@ async Task InitializeServiceControl(ScenarioContext context) EnvironmentName = Environments.Development }); hostBuilder.Logging.ClearProviders(); - hostBuilder.Logging.BuildLogger(LogLevel.Information); + hostBuilder.Logging.BuildServiceControlLogging(LogLevel.Information); hostBuilder.AddServiceControlMonitoring((criticalErrorContext, cancellationToken) => { diff --git a/src/ServiceControl.Monitoring/HostApplicationBuilderExtensions.cs b/src/ServiceControl.Monitoring/HostApplicationBuilderExtensions.cs index 7bda9a78ab..d35d87bced 100644 --- a/src/ServiceControl.Monitoring/HostApplicationBuilderExtensions.cs +++ b/src/ServiceControl.Monitoring/HostApplicationBuilderExtensions.cs @@ -15,8 +15,6 @@ namespace ServiceControl.Monitoring; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting.WindowsServices; -using Microsoft.Extensions.Logging; -using NLog.Extensions.Logging; using NServiceBus; using NServiceBus.Configuration.AdvancedExtensibility; using NServiceBus.Features; @@ -33,7 +31,7 @@ public static void AddServiceControlMonitoring(this IHostApplicationBuilder host EndpointConfiguration endpointConfiguration) { hostBuilder.Services.AddLogging(); - hostBuilder.Logging.BuildLogger(settings.LoggingSettings.LogLevel); + hostBuilder.Logging.BuildServiceControlLogging(settings.LoggingSettings.LogLevel); var services = hostBuilder.Services; diff --git a/src/ServiceControl.Persistence.Tests/PersistenceTestBase.cs b/src/ServiceControl.Persistence.Tests/PersistenceTestBase.cs index 7cc5f39cca..0d73396675 100644 --- a/src/ServiceControl.Persistence.Tests/PersistenceTestBase.cs +++ b/src/ServiceControl.Persistence.Tests/PersistenceTestBase.cs @@ -34,7 +34,7 @@ public async Task SetUp() var hostBuilder = Host.CreateApplicationBuilder(); LoggerUtil.ActiveLoggers = Loggers.Test; - hostBuilder.Logging.BuildLogger(LogLevel.Information); + hostBuilder.Logging.BuildServiceControlLogging(LogLevel.Information); await PersistenceTestsContext.Setup(hostBuilder); diff --git a/src/ServiceControl/HostApplicationBuilderExtensions.cs b/src/ServiceControl/HostApplicationBuilderExtensions.cs index 14ee26a003..6724d3834b 100644 --- a/src/ServiceControl/HostApplicationBuilderExtensions.cs +++ b/src/ServiceControl/HostApplicationBuilderExtensions.cs @@ -42,7 +42,7 @@ public static void AddServiceControl(this IHostApplicationBuilder hostBuilder, S } hostBuilder.Logging.ClearProviders(); - hostBuilder.Logging.BuildLogger(settings.LoggingSettings.LogLevel); + hostBuilder.Logging.BuildServiceControlLogging(settings.LoggingSettings.LogLevel); var services = hostBuilder.Services; var transportSettings = settings.ToTransportSettings(); From 2f1d97eb086b2d53f0fd5b07efb7fe4c40fbeacb Mon Sep 17 00:00:00 2001 From: Jason Taylor Date: Wed, 2 Jul 2025 09:57:47 +1000 Subject: [PATCH 56/56] Enhanced `LoggerUtil` to include `DisposeLoggerFactories` for better resource management during shutdown. --- .../HostApplicationBuilderExtensions.cs | 2 +- src/ServiceControl.Audit/Program.cs | 2 +- .../LoggerUtil.cs | 32 ++++++++++++++++--- .../LoggingConfigurator.cs | 2 +- .../ServiceControlComponentRunner.cs | 2 +- .../HostApplicationBuilderExtensions.cs | 2 +- src/ServiceControl.Monitoring/Program.cs | 4 +-- .../PersistenceTestBase.cs | 2 +- .../HostApplicationBuilderExtensions.cs | 2 +- src/ServiceControl/Program.cs | 2 +- 10 files changed, 38 insertions(+), 14 deletions(-) diff --git a/src/ServiceControl.Audit/HostApplicationBuilderExtensions.cs b/src/ServiceControl.Audit/HostApplicationBuilderExtensions.cs index 5221152387..d65a66697f 100644 --- a/src/ServiceControl.Audit/HostApplicationBuilderExtensions.cs +++ b/src/ServiceControl.Audit/HostApplicationBuilderExtensions.cs @@ -39,7 +39,7 @@ public static void AddServiceControlAudit(this IHostApplicationBuilder builder, RecordStartup(settings, configuration, persistenceConfiguration); builder.Logging.ClearProviders(); - builder.Logging.BuildServiceControlLogging(settings.LoggingSettings.LogLevel); + builder.Logging.ConfigureLogging(settings.LoggingSettings.LogLevel); var services = builder.Services; var transportSettings = settings.ToTransportSettings(); diff --git a/src/ServiceControl.Audit/Program.cs b/src/ServiceControl.Audit/Program.cs index 8c4bf1ea67..dbe5268e93 100644 --- a/src/ServiceControl.Audit/Program.cs +++ b/src/ServiceControl.Audit/Program.cs @@ -58,5 +58,5 @@ { // The following log statement is meant to leave a trail in the logs to determine if the process was killed logger?.LogInformation("Shutdown complete"); - NLog.LogManager.Shutdown(); + LoggerUtil.DisposeLoggerFactories(); } \ No newline at end of file diff --git a/src/ServiceControl.Infrastructure/LoggerUtil.cs b/src/ServiceControl.Infrastructure/LoggerUtil.cs index 5aec1b7673..b00617fbe0 100644 --- a/src/ServiceControl.Infrastructure/LoggerUtil.cs +++ b/src/ServiceControl.Infrastructure/LoggerUtil.cs @@ -1,6 +1,7 @@ namespace ServiceControl.Infrastructure { using System; + using System.Collections.Concurrent; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using NLog.Extensions.Logging; @@ -28,8 +29,10 @@ public static bool IsLoggingTo(Loggers logger) return (logger & ActiveLoggers) == logger; } - public static void BuildServiceControlLogging(this ILoggingBuilder loggingBuilder, LogLevel level) + public static void ConfigureLogging(this ILoggingBuilder loggingBuilder, LogLevel level) { + loggingBuilder.SetMinimumLevel(level); + if (IsLoggingTo(Loggers.Test)) { loggingBuilder.Services.AddSingleton(new TestContextProvider(level)); @@ -53,20 +56,41 @@ public static void BuildServiceControlLogging(this ILoggingBuilder loggingBuilde { loggingBuilder.AddOpenTelemetry(configure => configure.AddOtlpExporter()); } + } - loggingBuilder.SetMinimumLevel(level); + static readonly ConcurrentDictionary _factories = new(); + + static ILoggerFactory GetOrCreateLoggerFactory(LogLevel level) + { + if (!_factories.TryGetValue(level, out var factory)) + { + factory = LoggerFactory.Create(configure => configure.ConfigureLogging(level)); + _factories[level] = factory; + } + + return factory; } public static ILogger CreateStaticLogger(LogLevel level = LogLevel.Information) { - var factory = LoggerFactory.Create(configure => configure.BuildServiceControlLogging(level)); + var factory = GetOrCreateLoggerFactory(level); return factory.CreateLogger(); } public static ILogger CreateStaticLogger(Type type, LogLevel level = LogLevel.Information) { - var factory = LoggerFactory.Create(configure => configure.BuildServiceControlLogging(level)); + var factory = GetOrCreateLoggerFactory(level); return factory.CreateLogger(type); } + + public static void DisposeLoggerFactories() + { + foreach (var factory in _factories.Values) + { + factory.Dispose(); + } + + _factories.Clear(); + } } } \ No newline at end of file diff --git a/src/ServiceControl.Infrastructure/LoggingConfigurator.cs b/src/ServiceControl.Infrastructure/LoggingConfigurator.cs index b6d183a90f..f86f776bac 100644 --- a/src/ServiceControl.Infrastructure/LoggingConfigurator.cs +++ b/src/ServiceControl.Infrastructure/LoggingConfigurator.cs @@ -17,7 +17,7 @@ public static class LoggingConfigurator public static void ConfigureLogging(LoggingSettings loggingSettings) { //used for loggers outside of ServiceControl (i.e. transports and core) to use the logger factory defined here - LogManager.UseFactory(new ExtensionsLoggerFactory(LoggerFactory.Create(configure => configure.BuildServiceControlLogging(loggingSettings.LogLevel)))); + LogManager.UseFactory(new ExtensionsLoggerFactory(LoggerFactory.Create(configure => configure.ConfigureLogging(loggingSettings.LogLevel)))); if (!LoggerUtil.IsLoggingTo(Loggers.NLog) || NLog.LogManager.Configuration != null) { diff --git a/src/ServiceControl.Monitoring.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs b/src/ServiceControl.Monitoring.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs index d51eb01de4..00c545bd97 100644 --- a/src/ServiceControl.Monitoring.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs +++ b/src/ServiceControl.Monitoring.AcceptanceTests/TestSupport/ServiceControlComponentRunner.cs @@ -94,7 +94,7 @@ async Task InitializeServiceControl(ScenarioContext context) EnvironmentName = Environments.Development }); hostBuilder.Logging.ClearProviders(); - hostBuilder.Logging.BuildServiceControlLogging(LogLevel.Information); + hostBuilder.Logging.ConfigureLogging(LogLevel.Information); hostBuilder.AddServiceControlMonitoring((criticalErrorContext, cancellationToken) => { diff --git a/src/ServiceControl.Monitoring/HostApplicationBuilderExtensions.cs b/src/ServiceControl.Monitoring/HostApplicationBuilderExtensions.cs index d35d87bced..b55672e51d 100644 --- a/src/ServiceControl.Monitoring/HostApplicationBuilderExtensions.cs +++ b/src/ServiceControl.Monitoring/HostApplicationBuilderExtensions.cs @@ -31,7 +31,7 @@ public static void AddServiceControlMonitoring(this IHostApplicationBuilder host EndpointConfiguration endpointConfiguration) { hostBuilder.Services.AddLogging(); - hostBuilder.Logging.BuildServiceControlLogging(settings.LoggingSettings.LogLevel); + hostBuilder.Logging.ConfigureLogging(settings.LoggingSettings.LogLevel); var services = hostBuilder.Services; diff --git a/src/ServiceControl.Monitoring/Program.cs b/src/ServiceControl.Monitoring/Program.cs index 987953763d..e8dce81512 100644 --- a/src/ServiceControl.Monitoring/Program.cs +++ b/src/ServiceControl.Monitoring/Program.cs @@ -49,6 +49,6 @@ finally { // The following log statement is meant to leave a trail in the logs to determine if the process was killed - logger.LogInformation("Shutdown complete"); - NLog.LogManager.Shutdown(); + logger?.LogInformation("Shutdown complete"); + LoggerUtil.DisposeLoggerFactories(); } diff --git a/src/ServiceControl.Persistence.Tests/PersistenceTestBase.cs b/src/ServiceControl.Persistence.Tests/PersistenceTestBase.cs index 0d73396675..fdd41695c7 100644 --- a/src/ServiceControl.Persistence.Tests/PersistenceTestBase.cs +++ b/src/ServiceControl.Persistence.Tests/PersistenceTestBase.cs @@ -34,7 +34,7 @@ public async Task SetUp() var hostBuilder = Host.CreateApplicationBuilder(); LoggerUtil.ActiveLoggers = Loggers.Test; - hostBuilder.Logging.BuildServiceControlLogging(LogLevel.Information); + hostBuilder.Logging.ConfigureLogging(LogLevel.Information); await PersistenceTestsContext.Setup(hostBuilder); diff --git a/src/ServiceControl/HostApplicationBuilderExtensions.cs b/src/ServiceControl/HostApplicationBuilderExtensions.cs index 6724d3834b..fbe99dada5 100644 --- a/src/ServiceControl/HostApplicationBuilderExtensions.cs +++ b/src/ServiceControl/HostApplicationBuilderExtensions.cs @@ -42,7 +42,7 @@ public static void AddServiceControl(this IHostApplicationBuilder hostBuilder, S } hostBuilder.Logging.ClearProviders(); - hostBuilder.Logging.BuildServiceControlLogging(settings.LoggingSettings.LogLevel); + hostBuilder.Logging.ConfigureLogging(settings.LoggingSettings.LogLevel); var services = hostBuilder.Services; var transportSettings = settings.ToTransportSettings(); diff --git a/src/ServiceControl/Program.cs b/src/ServiceControl/Program.cs index bf2023306f..ec4a0bc70d 100644 --- a/src/ServiceControl/Program.cs +++ b/src/ServiceControl/Program.cs @@ -58,5 +58,5 @@ { // The following log statement is meant to leave a trail in the logs to determine if the process was killed logger?.LogInformation("Shutdown complete"); - NLog.LogManager.Shutdown(); + LoggerUtil.DisposeLoggerFactories(); } \ No newline at end of file