From b625c431e7582821ed95742bf2fac641f46e0130 Mon Sep 17 00:00:00 2001 From: StuartFerguson Date: Mon, 26 Oct 2026 18:50:08 +0000 Subject: [PATCH 1/3] add structured logging --- Directory.Packages.props | 40 +++++++++---------- .../Common/DockerHelper.cs | 7 ++-- .../Common/GenericSteps.cs | 5 ++- .../Common/RequestAuditMiddleware.cs | 6 ++- .../Handlers/MerchantHandlers.cs | 4 +- .../Handlers/ReportingHandlers.cs | 7 ++++ .../Handlers/TransactionHandlers.cs | 7 ++++ TransactionProcessorACL/Program.cs | 5 ++- 8 files changed, 51 insertions(+), 30 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 9361a83..ca4a42f 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -5,9 +5,9 @@ - + - + @@ -16,20 +16,20 @@ - - - - - - - - - + + + + + + + + + - + @@ -38,15 +38,15 @@ - - - - - + + + + + - - - + + + diff --git a/TransactionProcessorACL.IntegrationTests/Common/DockerHelper.cs b/TransactionProcessorACL.IntegrationTests/Common/DockerHelper.cs index aad38a6..f3935de 100644 --- a/TransactionProcessorACL.IntegrationTests/Common/DockerHelper.cs +++ b/TransactionProcessorACL.IntegrationTests/Common/DockerHelper.cs @@ -75,6 +75,8 @@ public override ContainerBuilder SetupKurrentDbContainer() { this.Trace("About to Start Kurrent Db Container"); + (String imageName, Boolean useLatest) imageDetails = this.GetImageDetails(ContainerType.KurrentDb).Data; + Dictionary environmentVariables = new(){ {"EVENTSTORE_RUN_PROJECTIONS","all"}, {"EVENTSTORE_START_STANDARD_PROJECTIONS","true"}, @@ -83,7 +85,7 @@ public override ContainerBuilder SetupKurrentDbContainer() {"KURRENTDB_PREPARE_TIMEOUT_MS","30000"}, {"KURRENTDB_COMMIT_TIMEOUT_MS","30000"}, }; - ContainerBuilder eventStoreContainer = new(); + ContainerBuilder eventStoreContainer = new(imageDetails.imageName); if (!this.IsSecureKurrentDb) { @@ -108,13 +110,12 @@ public override ContainerBuilder SetupKurrentDbContainer() String logfilePath = "/var/log/kurrentdb"; eventStoreContainer = eventStoreContainer.MountHostFolder(this.HostTraceFolder, logfilePath); - (String imageName, Boolean useLatest) imageDetails = this.GetImageDetails(ContainerType.KurrentDb).Data; + this.Trace($"About to Start Kurrent Db Container using image [{imageDetails.imageName}]"); eventStoreContainer = eventStoreContainer.WithName(this.KurrentDbContainerName) // similar to WithName() - .WithImage(imageDetails.imageName) .WithEnvironment(environmentVariables) .WithPortBinding(DockerPorts.KurrentDbHttpDockerPort, true); diff --git a/TransactionProcessorACL.IntegrationTests/Common/GenericSteps.cs b/TransactionProcessorACL.IntegrationTests/Common/GenericSteps.cs index b918b3d..8f8b15b 100644 --- a/TransactionProcessorACL.IntegrationTests/Common/GenericSteps.cs +++ b/TransactionProcessorACL.IntegrationTests/Common/GenericSteps.cs @@ -32,9 +32,10 @@ public async Task StartSystem() { // Initialise a logger String scenarioName = this.ScenarioContext.ScenarioInfo.Title.Replace(" ", String.Empty); - NlogLogger logger = new NlogLogger(); + NlogLogger logger = new(); logger.Initialise(LogManager.GetLogger(scenarioName), scenarioName); - LogManager.AddHiddenAssembly(typeof(NlogLogger).Assembly); + LogManager.Setup().SetupLogFactory(setup => + setup.AddCallSiteHiddenAssembly(typeof(NlogLogger).Assembly)); DockerServices dockerServices = DockerServices.CallbackHandler | DockerServices.KurrentDb | DockerServices.FileProcessor | DockerServices.MessagingService | DockerServices.SecurityService | diff --git a/TransactionProcessorACL/Common/RequestAuditMiddleware.cs b/TransactionProcessorACL/Common/RequestAuditMiddleware.cs index c77a573..23ed8e7 100644 --- a/TransactionProcessorACL/Common/RequestAuditMiddleware.cs +++ b/TransactionProcessorACL/Common/RequestAuditMiddleware.cs @@ -1,6 +1,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using NLog; +using System; namespace TransactionProcessorACL.Common; @@ -19,7 +20,8 @@ public async Task InvokeAsync(HttpContext context) { RequestAuditContext requestAuditContext = RequestAuditContextFactory.CreateForRequest(context); _accessor.Current = requestAuditContext; - MappedDiagnosticsLogicalContext.Set("CorrelationId", requestAuditContext.RequestId); + IDisposable pushResult = ScopeContext.PushProperty("CorrelationId", requestAuditContext.RequestId); + try { await _next(context).ConfigureAwait(false); @@ -27,7 +29,7 @@ public async Task InvokeAsync(HttpContext context) finally { _accessor.Current = null; - MappedDiagnosticsLogicalContext.Remove("CorrelationId"); + pushResult.Dispose(); } } } diff --git a/TransactionProcessorACL/Handlers/MerchantHandlers.cs b/TransactionProcessorACL/Handlers/MerchantHandlers.cs index d1b3174..f2f7f37 100644 --- a/TransactionProcessorACL/Handlers/MerchantHandlers.cs +++ b/TransactionProcessorACL/Handlers/MerchantHandlers.cs @@ -24,7 +24,7 @@ public static async Task GetMerchantContracts(IMediator mediator, string applicationVersion, CancellationToken cancellationToken) { - Logger.LogInformation($"Application version {applicationVersion}"); + Logger.LogInformation("Application version {ApplicationVersion}", applicationVersion); Result<(Guid estateId, Guid merchantId)> claimsResult = Helpers.GetRequiredClaims(user); if (claimsResult.IsFailed) @@ -41,6 +41,7 @@ public static async Task GetMerchant(IMediator mediator, string applicationVersion, CancellationToken cancellationToken) { + Logger.LogInformation("Application version {ApplicationVersion}", applicationVersion); Logger.LogWarning("In GetMerchant Handler"); Result<(Guid estateId, Guid merchantId)> claimsResult = Helpers.GetRequiredClaims(user); @@ -59,6 +60,7 @@ public static async Task GetMerchantSchedule(IMediator mediator, [FromQuery] Int32 year, CancellationToken cancellationToken) { + Logger.LogInformation("Application version {ApplicationVersion}", applicationVersion); Logger.LogWarning("In GetMerchantSchedule Handler"); Result<(Guid estateId, Guid merchantId)> claimsResult = Helpers.GetRequiredClaims(user); diff --git a/TransactionProcessorACL/Handlers/ReportingHandlers.cs b/TransactionProcessorACL/Handlers/ReportingHandlers.cs index 1985712..311cf23 100644 --- a/TransactionProcessorACL/Handlers/ReportingHandlers.cs +++ b/TransactionProcessorACL/Handlers/ReportingHandlers.cs @@ -6,6 +6,7 @@ using MediatR; using Microsoft.AspNetCore.Http; using Shared.General; +using Shared.Logger; using Shared.Results.Web; using SimpleResults; using TransactionProcessorACL.BusinessLogic.Requests; @@ -22,6 +23,8 @@ public static async Task GetMerchantDailyPerformanceSummary(ClaimsPrinc IMediator mediator, CancellationToken cancellationToken) { + Logger.LogInformation("Application version {ApplicationVersion}", request.ApplicationVersion); + Result estateIdResult = Helpers.GetRequiredEstateClaim(user); if (estateIdResult.IsFailed) return ResponseFactory.FromResult(Result.Forbidden()); @@ -54,6 +57,8 @@ public static async Task GetMerchantTransactionMixSummary(ClaimsPrincip IMediator mediator, CancellationToken cancellationToken) { + Logger.LogInformation("Application version {ApplicationVersion}", request.ApplicationVersion); + Result estateIdResult = Helpers.GetRequiredEstateClaim(user); if (estateIdResult.IsFailed) return ResponseFactory.FromResult(Result.Forbidden()); @@ -93,6 +98,8 @@ public static async Task GetRecentActivityReceiptSearch(ClaimsPrincipal IMediator mediator, CancellationToken cancellationToken) { + Logger.LogInformation("Application version {ApplicationVersion}", request.ApplicationVersion); + Result estateIdResult = Helpers.GetRequiredEstateClaim(user); if (estateIdResult.IsFailed) return ResponseFactory.FromResult(Result.Forbidden()); diff --git a/TransactionProcessorACL/Handlers/TransactionHandlers.cs b/TransactionProcessorACL/Handlers/TransactionHandlers.cs index 1b6f0d3..ace5750 100644 --- a/TransactionProcessorACL/Handlers/TransactionHandlers.cs +++ b/TransactionProcessorACL/Handlers/TransactionHandlers.cs @@ -1,6 +1,7 @@ using MediatR; using Microsoft.AspNetCore.Http; using Shared.General; +using Shared.Logger; using Shared.Results.Web; using SimpleResults; using System; @@ -29,6 +30,8 @@ public static async Task PerformSaleTransaction(IMediator mediator, SaleTransactionRequestMessage transactionRequest, CancellationToken cancellationToken) { + Logger.LogInformation("Application version {ApplicationVersion}", transactionRequest.ApplicationVersion); + Result<(Guid estateId, Guid merchantId)> claimsResult = Helpers.GetRequiredClaims(user); if (claimsResult.IsFailed) { return ResponseFactory.FromResult(Result.Forbidden()); @@ -44,6 +47,8 @@ public static async Task PerformLogonTransaction(IMediator mediator, LogonTransactionRequestMessage transactionRequest, CancellationToken cancellationToken) { + Logger.LogInformation("Application version {ApplicationVersion}", transactionRequest.ApplicationVersion); + Result<(Guid estateId, Guid merchantId)> claimsResult = Helpers.GetRequiredClaims(user); if (claimsResult.IsFailed) { return ResponseFactory.FromResult(Result.Forbidden()); @@ -59,6 +64,8 @@ public static async Task PerformReconciliationTransaction(IMediator med ReconciliationRequestMessage transactionRequest, CancellationToken cancellationToken) { + Logger.LogInformation("Application version {ApplicationVersion}", transactionRequest.ApplicationVersion); + Result<(Guid estateId, Guid merchantId)> claimsResult = Helpers.GetRequiredClaims(user); if (claimsResult.IsFailed) { return ResponseFactory.FromResult(Result.Forbidden()); diff --git a/TransactionProcessorACL/Program.cs b/TransactionProcessorACL/Program.cs index ca8981d..eb97263 100644 --- a/TransactionProcessorACL/Program.cs +++ b/TransactionProcessorACL/Program.cs @@ -136,8 +136,9 @@ private static void ConfigurePipeline(WebApplication app, IConfigurationRoot con app.UseDeveloperExceptionPage(); } - Microsoft.Extensions.Logging.ILogger logger = app.Services.GetRequiredService().CreateLogger("TransactionProcessor"); - Shared.Logger.Logger.Initialise(logger); + LogManager.Setup().LoadConfigurationFromFile("NLog.config"); + NLog.Logger logger = LogManager.GetLogger("TransactionProcessorACL"); + Shared.Logger.Logger.Initialise(logger, "TransactionProcessorACL"); configuration.LogConfiguration(Shared.Logger.Logger.LogWarning); app.UseMiddleware(); From 7dcebe98e9c767855cdc910da72e34d932838c6f Mon Sep 17 00:00:00 2001 From: StuartFerguson Date: Mon, 26 Oct 2026 19:45:29 +0000 Subject: [PATCH 2/3] add logging config --- TransactionProcessorACL/nlog.config | 38 ++++++++++++----------------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/TransactionProcessorACL/nlog.config b/TransactionProcessorACL/nlog.config index 60c53ae..ba8adc9 100644 --- a/TransactionProcessorACL/nlog.config +++ b/TransactionProcessorACL/nlog.config @@ -4,21 +4,21 @@ - + fileName="/home/txnproc/trace/transactionprocessoracl.json" + archiveFileName="/home/txnproc/trace/transactionprocessoracl.{#####}.json" + archiveAboveSize="104857600" + archiveNumbering="Sequence" + concurrentWrites="true" + maxArchiveFiles="2"> + + + + + + + @@ -34,14 +34,6 @@ - - - - - - - - From 6f00deeb21a0796902fad83cf47b0c971c04eded Mon Sep 17 00:00:00 2001 From: StuartFerguson Date: Mon, 26 Oct 2026 19:46:59 +0000 Subject: [PATCH 3/3] fix test failures --- .../Handlers/ReportingHandlersTests.cs | 17 +++++++++++------ .../Handlers/TransactionHandlersTests.cs | 5 +++++ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/TransactionProcessorACL.Tests/Handlers/ReportingHandlersTests.cs b/TransactionProcessorACL.Tests/Handlers/ReportingHandlersTests.cs index 498e4fb..20f03ce 100644 --- a/TransactionProcessorACL.Tests/Handlers/ReportingHandlersTests.cs +++ b/TransactionProcessorACL.Tests/Handlers/ReportingHandlersTests.cs @@ -1,9 +1,11 @@ +using Ductus.FluentDocker.Common; using System; using System.Security.Claims; using System.Threading; using System.Threading.Tasks; using MediatR; using Imposter.Abstractions; +using Shared.Logger; using Shouldly; using SimpleResults; using TransactionProcessorACL.BusinessLogic.Requests; @@ -15,6 +17,9 @@ namespace TransactionProcessorACL.Tests.Handlers; public class ReportingHandlersTests { + public ReportingHandlersTests() { + Shared.Logger.Logger.Initialise(new NullLogger()); + } [Fact] public async Task GetMerchantDailyPerformanceSummary_PassesEstateClaimAndRequestToMediator() { @@ -34,7 +39,7 @@ public async Task GetMerchantDailyPerformanceSummary_PassesEstateClaimAndRequest var mediator = new IMediatorImposter(ImposterMode.Explicit); mediator - .Send>(Arg>>.Any(), Arg.Any()) + .Send>(Arg>>.Any(), Arg.Any()) .ReturnsAsync(Result.Success(new TransactionProcessorACL.Models.MerchantDailyPerformanceSummaryResponse())) .Callback((payload, _) => { capturedQuery = (ReportingQueries.GetMerchantDailyPerformanceSummaryQuery)payload; return Task.CompletedTask; }); @@ -44,7 +49,7 @@ public async Task GetMerchantDailyPerformanceSummary_PassesEstateClaimAndRequest capturedQuery.ShouldNotBeNull(); capturedQuery!.EstateId.ShouldBe(Guid.Parse("1C8354B7-B97A-46EA-9AD1-C43F33F7E3C3")); capturedQuery.Request.MerchantReportingId.ShouldBe(12345); - mediator.Send>(Arg>>.Any(), Arg.Any()).Called(Count.Once()); + mediator.Send>(Arg>>.Any(), Arg.Any()).Called(Count.Once()); } [Fact] @@ -69,7 +74,7 @@ public async Task GetMerchantTransactionMixSummary_PassesEstateClaimAndRequestTo var mediator = new IMediatorImposter(ImposterMode.Explicit); mediator - .Send>(Arg>>.Any(), Arg.Any()) + .Send>(Arg>>.Any(), Arg.Any()) .ReturnsAsync(Result.Success(new TransactionProcessorACL.Models.MerchantTransactionMixSummaryResponse())) .Callback((payload, _) => { capturedQuery = (ReportingQueries.GetMerchantTransactionMixSummaryQuery)payload; return Task.CompletedTask; }); @@ -81,7 +86,7 @@ public async Task GetMerchantTransactionMixSummary_PassesEstateClaimAndRequestTo capturedQuery.Request.MerchantReportingId.ShouldBe(12345); capturedQuery.Request.Breakdown.ShouldBe(TransactionMixBreakdown.Product); capturedQuery.Request.Measure.ShouldBe(TransactionMixMeasure.Count); - mediator.Send>(Arg>>.Any(), Arg.Any()).Called(Count.Once()); + mediator.Send>(Arg>>.Any(), Arg.Any()).Called(Count.Once()); } [Fact] @@ -105,7 +110,7 @@ public async Task GetRecentActivityReceiptSearch_PassesEstateClaimAndRequestToMe var mediator = new IMediatorImposter(ImposterMode.Explicit); mediator - .Send>(Arg>>.Any(), Arg.Any()) + .Send>(Arg>>.Any(), Arg.Any()) .ReturnsAsync(Result.Success(new TransactionProcessorACL.Models.RecentActivityReceiptSearchResponse())) .Callback((payload, _) => { capturedQuery = (ReportingQueries.GetRecentActivityReceiptSearchQuery)payload; return Task.CompletedTask; }); @@ -119,6 +124,6 @@ public async Task GetRecentActivityReceiptSearch_PassesEstateClaimAndRequestToMe capturedQuery.Request.SearchText.ShouldBe("abc"); capturedQuery.Request.PageNumber.ShouldBe(2); capturedQuery.Request.PageSize.ShouldBe(5); - mediator.Send>(Arg>>.Any(), Arg.Any()).Called(Count.Once()); + mediator.Send>(Arg>>.Any(), Arg.Any()).Called(Count.Once()); } } diff --git a/TransactionProcessorACL.Tests/Handlers/TransactionHandlersTests.cs b/TransactionProcessorACL.Tests/Handlers/TransactionHandlersTests.cs index 83da4df..a0d4f50 100644 --- a/TransactionProcessorACL.Tests/Handlers/TransactionHandlersTests.cs +++ b/TransactionProcessorACL.Tests/Handlers/TransactionHandlersTests.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using MediatR; using Imposter.Abstractions; +using Shared.Logger; using Shouldly; using SimpleResults; using TransactionProcessorACL.BusinessLogic.Requests; @@ -17,6 +18,10 @@ namespace TransactionProcessorACL.Tests.Handlers; public class TransactionHandlersTests { + public TransactionHandlersTests() { + Shared.Logger.Logger.Initialise(new NullLogger()); + } + [Fact] public async Task PerformSaleTransaction_PassesBusinessFieldsIntoCommand() {