Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
a8c746f
convert SC transports from NServiceBus.Logging to Microsoft.Extension…
PhilBastian Jun 12, 2025
42d01e7
remove signedassembly requirement so that infrastructure can be imported
PhilBastian Jun 15, 2025
96ec124
revert previous change and instead propogate signing back to servicec…
PhilBastian Jun 15, 2025
5aaabe6
fix signature of customisation classes that are dynamically created
PhilBastian Jun 16, 2025
67920ff
add ilogger to test services and remove direct construction with logger
PhilBastian Jun 16, 2025
b3c690a
get tests to use ilogger
PhilBastian Jun 16, 2025
66aaa02
Switch to .NET logging
jasontaylordev Jun 10, 2025
e2196e6
Work in progress
jasontaylordev Jun 12, 2025
e9f287e
Remove test code
jasontaylordev Jun 13, 2025
9b97c92
Improve logging format for storage space details
jasontaylordev Jun 17, 2025
005968d
Properly shutdown NLog in Program.cs
jasontaylordev Jun 17, 2025
49ba86c
Remove Seq logging and prepare for .NET logging migration
jasontaylordev Jun 17, 2025
938c963
Update LogLevel format
jasontaylordev Jun 17, 2025
fb7f77e
Update LogLevel format in logging settings
jasontaylordev Jun 17, 2025
6c713bb
Merge branch 'master' into extensions.logging_transports
PhilBastian Jun 17, 2025
40eef99
Merge branch 'logging-spike-jt' into extensions.logging_transports
PhilBastian Jun 17, 2025
07d5606
enable adding test logging provider as part of loggerutils and create…
PhilBastian Jun 17, 2025
a843701
add ability to select logging provider from config
PhilBastian Jun 17, 2025
3e59886
handle setting not existing
PhilBastian Jun 17, 2025
ab580f6
change logmanager logger factory to the standard one now used by the …
PhilBastian Jun 17, 2025
3e16970
ensure logger for transport tests
PhilBastian Jun 18, 2025
2f1f578
Merge branch 'extensions.logging_spike' into extensions.logging_trans…
PhilBastian Jun 18, 2025
18604ca
Merge branch 'extensions.logging_spike' into extensions.logging_trans…
PhilBastian Jun 18, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="8.0.1" />
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.1" />
<PackageVersion Include="Microsoft.Extensions.Hosting.WindowsServices" Version="8.0.1" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.3" />
<PackageVersion Include="Microsoft.Extensions.TimeProvider.Testing" Version="8.10.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
<PackageVersion Include="Microsoft-WindowsAPICodePack-Shell" Version="1.1.5" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<CheckDirtyMemory> logger) : CustomCheck("RavenDB dirty memory", "ServiceControl.Audit Health", TimeSpan.FromMinutes(5))
{

public override async Task<CheckResult> 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<CheckDirtyMemory>();
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<CheckFreeDiskSpace> logger) : CustomCheck("ServiceControl.Audit database", "Storage space", TimeSpan.FromMinutes(5))
{
public override Task<CheckResult> 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)
Expand All @@ -34,52 +34,46 @@ public override Task<CheckResult> 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
? CheckResult.Pass
: CheckResult.Failed($"{percentRemaining:P0} disk space remaining on data drive '{dataDriveInfo.VolumeLabel} ({dataDriveInfo.RootDirectory})' on '{Environment.MachineName}'.");
}

public static int Parse(IDictionary<string, string> settings)
public static int Parse(IDictionary<string, string> 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;
}

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));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<CheckMinimumStorageRequiredForIngestion> logger) : CustomCheck("Audit Message Ingestion Process", "ServiceControl.Audit Health", TimeSpan.FromSeconds(5))
{
public override Task<CheckResult> 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
Expand All @@ -35,9 +36,9 @@ public override Task<CheckResult> 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)
Expand All @@ -46,10 +47,9 @@ public override Task<CheckResult> 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<string, string> settings)
Expand All @@ -61,30 +61,27 @@ public static int Parse(IDictionary<string, string> 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;
}

public const int MinimumStorageLeftRequiredForIngestionDefault = 5;
static readonly Task<CheckResult> SuccessResult = Task.FromResult(CheckResult.Pass);
static readonly ILog Logger = LogManager.GetLogger(typeof(CheckMinimumStorageRequiredForIngestion));
static readonly ILogger<CheckMinimumStorageRequiredForIngestion> Logger = LoggerUtil.CreateStaticLogger<CheckMinimumStorageRequiredForIngestion>();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<CheckRavenDBIndexLag> logger) : CustomCheck("Audit Database Index Lag", "ServiceControl.Audit Health", TimeSpan.FromMinutes(5))
{
public override async Task<CheckResult> PerformCheck(CancellationToken cancellationToken = default)
{
Expand All @@ -20,7 +21,7 @@ public override async Task<CheckResult> PerformCheck(CancellationToken cancellat

CreateDiagnosticsLogEntry(statistics, indexes);

var indexCountWithTooMuchLag = CheckAndReportIndexesWithTooMuchIndexLag(indexes);
var indexCountWithTooMuchLag = CheckAndReportIndexesWithTooMuchIndexLag(indexes, logger);

if (indexCountWithTooMuchLag > 0)
{
Expand All @@ -30,7 +31,7 @@ public override async Task<CheckResult> PerformCheck(CancellationToken cancellat
return CheckResult.Pass;
}

static int CheckAndReportIndexesWithTooMuchIndexLag(IndexInformation[] indexes)
static int CheckAndReportIndexesWithTooMuchIndexLag(IndexInformation[] indexes, ILogger logger)
{
int indexCountWithTooMuchLag = 0;

Expand All @@ -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);
}
}
}
Expand All @@ -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;
}
Expand All @@ -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<CheckRavenDBIndexLag>();
static readonly ILogger<CheckRavenDBIndexLag> Logger = LoggerUtil.CreateStaticLogger<CheckRavenDBIndexLag>();
}
}
Loading