From 0b6010fb97e44062ab8ab9b176c04d2b52b376f7 Mon Sep 17 00:00:00 2001 From: Jimmy Vo Date: Thu, 30 Oct 2025 12:04:11 -0400 Subject: [PATCH 01/10] [PM-26401] Add logging logic --- .../Controllers/EventsController.cs | 19 ++++- .../Public/Controllers/EventsController.cs | 17 ++++- .../DiagnosticTools/EventDiagnosticLogger.cs | 69 +++++++++++++++++++ 3 files changed, 101 insertions(+), 4 deletions(-) create mode 100644 src/Api/Utilities/DiagnosticTools/EventDiagnosticLogger.cs diff --git a/src/Api/AdminConsole/Controllers/EventsController.cs b/src/Api/AdminConsole/Controllers/EventsController.cs index f868f0b3b603..1576decc7ccc 100644 --- a/src/Api/AdminConsole/Controllers/EventsController.cs +++ b/src/Api/AdminConsole/Controllers/EventsController.cs @@ -3,6 +3,8 @@ using Bit.Api.Models.Response; using Bit.Api.Utilities; +using Bit.Api.Utilities.DiagnosticTools; +using Bit.Core; using Bit.Core.AdminConsole.Repositories; using Bit.Core.Context; using Bit.Core.Enums; @@ -31,10 +33,11 @@ public class EventsController : Controller private readonly ISecretRepository _secretRepository; private readonly IProjectRepository _projectRepository; private readonly IServiceAccountRepository _serviceAccountRepository; + private readonly ILogger _logger; + private readonly IFeatureService _featureService; - public EventsController( - IUserService userService, + public EventsController(IUserService userService, ICipherRepository cipherRepository, IOrganizationUserRepository organizationUserRepository, IProviderUserRepository providerUserRepository, @@ -42,7 +45,9 @@ public EventsController( ICurrentContext currentContext, ISecretRepository secretRepository, IProjectRepository projectRepository, - IServiceAccountRepository serviceAccountRepository) + IServiceAccountRepository serviceAccountRepository, + ILogger logger, + IFeatureService featureService) { _userService = userService; _cipherRepository = cipherRepository; @@ -53,6 +58,8 @@ public EventsController( _secretRepository = secretRepository; _projectRepository = projectRepository; _serviceAccountRepository = serviceAccountRepository; + _logger = logger; + _featureService = featureService; } [HttpGet("")] @@ -114,6 +121,12 @@ public async Task> GetOrganization(string var result = await _eventRepository.GetManyByOrganizationAsync(orgId, dateRange.Item1, dateRange.Item2, new PageOptions { ContinuationToken = continuationToken }); var responses = result.Data.Select(e => new EventResponseModel(e)); + + if (_featureService.IsEnabled(FeatureFlagKeys.EventDiagnosticLogging)) + { + _logger.LogAggregateData(orgId, continuationToken, responses, start, end); + } + return new ListResponseModel(responses, result.ContinuationToken); } diff --git a/src/Api/AdminConsole/Public/Controllers/EventsController.cs b/src/Api/AdminConsole/Public/Controllers/EventsController.cs index 3dd55d51e2e8..621ecedb9323 100644 --- a/src/Api/AdminConsole/Public/Controllers/EventsController.cs +++ b/src/Api/AdminConsole/Public/Controllers/EventsController.cs @@ -4,9 +4,12 @@ using System.Net; using Bit.Api.Models.Public.Request; using Bit.Api.Models.Public.Response; +using Bit.Api.Utilities.DiagnosticTools; +using Bit.Core; using Bit.Core.Context; using Bit.Core.Models.Data; using Bit.Core.Repositories; +using Bit.Core.Services; using Bit.Core.Vault.Repositories; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -20,15 +23,21 @@ public class EventsController : Controller private readonly IEventRepository _eventRepository; private readonly ICipherRepository _cipherRepository; private readonly ICurrentContext _currentContext; + private readonly ILogger _logger; + private readonly IFeatureService _featureService; public EventsController( IEventRepository eventRepository, ICipherRepository cipherRepository, - ICurrentContext currentContext) + ICurrentContext currentContext, + ILogger logger, + IFeatureService featureService) { _eventRepository = eventRepository; _cipherRepository = cipherRepository; _currentContext = currentContext; + _logger = logger; + _featureService = featureService; } /// @@ -69,6 +78,12 @@ public async Task List([FromQuery] EventFilterRequestModel reques var eventResponses = result.Data.Select(e => new EventResponseModel(e)); var response = new PagedListResponseModel(eventResponses, result.ContinuationToken); + + if (_featureService.IsEnabled(FeatureFlagKeys.EventDiagnosticLogging)) + { + _logger.LogAggregateData(_currentContext.OrganizationId!.Value, response, request); + } + return new JsonResult(response); } } diff --git a/src/Api/Utilities/DiagnosticTools/EventDiagnosticLogger.cs b/src/Api/Utilities/DiagnosticTools/EventDiagnosticLogger.cs new file mode 100644 index 000000000000..bd54cb6e2721 --- /dev/null +++ b/src/Api/Utilities/DiagnosticTools/EventDiagnosticLogger.cs @@ -0,0 +1,69 @@ +using Bit.Api.Models.Public.Request; +using Bit.Api.Models.Public.Response; + +namespace Bit.Api.Utilities.DiagnosticTools; + +public static class EventDiagnosticLogger +{ + + public static void LogAggregateData(this ILogger logger, Guid organizationId, PagedListResponseModel data, EventFilterRequestModel request) + { + var recordCount = data.Data.Count(); + var oldestRecordDate = data.Data.FirstOrDefault()?.Date; + var newestRecordDate = data.Data.LastOrDefault()?.Date; + var hasMore = !string.IsNullOrEmpty(data.ContinuationToken); + + try + { + logger.LogInformation( + "Events query for Organization {OrgId}. Returned {Count} events, oldest record {oldestRecord}, newest record {newestRecord} HasMore: {HasMore}, " + + "Request Filters: Start={Start}, End={End}, ActingUserId={ActingUserId}, ItemId={ItemId},", + organizationId, + recordCount, + oldestRecordDate, + newestRecordDate, + hasMore, + request.Start, + request.End, + request.ActingUserId, + request.ItemId); + } + catch (Exception exception) + { + logger.LogWarning(exception, "Unexpected exception from EventDiagnosticLogger.LogAggregateData"); + } + } + + public static void LogAggregateData( + this ILogger logger, + Guid organizationId, + string continuationToken, + IEnumerable data, + DateTime? queryStart = null, + DateTime? queryEnd = null) + { + var list = data.ToList(); + var recordCount = list.Count; + var oldestRecordDate = list.FirstOrDefault()?.Date; + var newestRecordDate = list.LastOrDefault()?.Date; + var hasMore = !string.IsNullOrEmpty(continuationToken); + + try + { + logger.LogInformation( + "Events query for Organization {OrgId}. Returned {Count} events, oldest record {oldestRecord}, newest record {newestRecord} HasMore: {HasMore}, " + + "Request Filters: Start={queryStart}, End={End}", + organizationId, + recordCount, + oldestRecordDate, + newestRecordDate, + hasMore, + queryStart, + queryEnd); + } + catch (Exception exception) + { + logger.LogWarning(exception, "Unexpected exception from EventDiagnosticLogger.LogAggregateData"); + } + } +} From ad0cd49589a07a1b813be440319fbe15a113efd0 Mon Sep 17 00:00:00 2001 From: Jimmy Vo Date: Thu, 30 Oct 2025 12:15:13 -0400 Subject: [PATCH 02/10] [PM-26401] wip --- .../Controllers/EventsController.cs | 6 +---- .../Public/Controllers/EventsController.cs | 7 +----- .../DiagnosticTools/EventDiagnosticLogger.cs | 24 +++++++++++++++---- src/Core/Constants.cs | 1 + 4 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/Api/AdminConsole/Controllers/EventsController.cs b/src/Api/AdminConsole/Controllers/EventsController.cs index 1576decc7ccc..273bc35d7a00 100644 --- a/src/Api/AdminConsole/Controllers/EventsController.cs +++ b/src/Api/AdminConsole/Controllers/EventsController.cs @@ -4,7 +4,6 @@ using Bit.Api.Models.Response; using Bit.Api.Utilities; using Bit.Api.Utilities.DiagnosticTools; -using Bit.Core; using Bit.Core.AdminConsole.Repositories; using Bit.Core.Context; using Bit.Core.Enums; @@ -122,10 +121,7 @@ public async Task> GetOrganization(string new PageOptions { ContinuationToken = continuationToken }); var responses = result.Data.Select(e => new EventResponseModel(e)); - if (_featureService.IsEnabled(FeatureFlagKeys.EventDiagnosticLogging)) - { - _logger.LogAggregateData(orgId, continuationToken, responses, start, end); - } + _logger.LogAggregateData(_featureService, orgId, continuationToken, responses, start, end); return new ListResponseModel(responses, result.ContinuationToken); } diff --git a/src/Api/AdminConsole/Public/Controllers/EventsController.cs b/src/Api/AdminConsole/Public/Controllers/EventsController.cs index 621ecedb9323..19edbdd5a6e3 100644 --- a/src/Api/AdminConsole/Public/Controllers/EventsController.cs +++ b/src/Api/AdminConsole/Public/Controllers/EventsController.cs @@ -5,7 +5,6 @@ using Bit.Api.Models.Public.Request; using Bit.Api.Models.Public.Response; using Bit.Api.Utilities.DiagnosticTools; -using Bit.Core; using Bit.Core.Context; using Bit.Core.Models.Data; using Bit.Core.Repositories; @@ -79,11 +78,7 @@ public async Task List([FromQuery] EventFilterRequestModel reques var eventResponses = result.Data.Select(e => new EventResponseModel(e)); var response = new PagedListResponseModel(eventResponses, result.ContinuationToken); - if (_featureService.IsEnabled(FeatureFlagKeys.EventDiagnosticLogging)) - { - _logger.LogAggregateData(_currentContext.OrganizationId!.Value, response, request); - } - + _logger.LogAggregateData(_featureService, _currentContext.OrganizationId!.Value, response, request); return new JsonResult(response); } } diff --git a/src/Api/Utilities/DiagnosticTools/EventDiagnosticLogger.cs b/src/Api/Utilities/DiagnosticTools/EventDiagnosticLogger.cs index bd54cb6e2721..a55c2022fb46 100644 --- a/src/Api/Utilities/DiagnosticTools/EventDiagnosticLogger.cs +++ b/src/Api/Utilities/DiagnosticTools/EventDiagnosticLogger.cs @@ -1,20 +1,33 @@ using Bit.Api.Models.Public.Request; using Bit.Api.Models.Public.Response; +using Bit.Core.Services; namespace Bit.Api.Utilities.DiagnosticTools; public static class EventDiagnosticLogger { - public static void LogAggregateData(this ILogger logger, Guid organizationId, PagedListResponseModel data, EventFilterRequestModel request) + public static void LogAggregateData( + this ILogger logger, + IFeatureService _featureService, + Guid organizationId, + PagedListResponseModel data, EventFilterRequestModel request) { - var recordCount = data.Data.Count(); - var oldestRecordDate = data.Data.FirstOrDefault()?.Date; - var newestRecordDate = data.Data.LastOrDefault()?.Date; - var hasMore = !string.IsNullOrEmpty(data.ContinuationToken); try { + + if (_featureService.IsEnabled(organizationId)) + { + + } + + var recordCount = data.Data.Count(); + var oldestRecordDate = data.Data.FirstOrDefault()?.Date; + var newestRecordDate = data.Data.LastOrDefault()?.Date; + var hasMore = !string.IsNullOrEmpty(data.ContinuationToken); + + logger.LogInformation( "Events query for Organization {OrgId}. Returned {Count} events, oldest record {oldestRecord}, newest record {newestRecord} HasMore: {HasMore}, " + "Request Filters: Start={Start}, End={End}, ActingUserId={ActingUserId}, ItemId={ItemId},", @@ -36,6 +49,7 @@ public static void LogAggregateData(this ILogger logger, Guid organizationId, Pa public static void LogAggregateData( this ILogger logger, + IFeatureService _featureService, Guid organizationId, string continuationToken, IEnumerable data, diff --git a/src/Core/Constants.cs b/src/Core/Constants.cs index aa1f1c934b03..89c4cc6efc38 100644 --- a/src/Core/Constants.cs +++ b/src/Core/Constants.cs @@ -251,6 +251,7 @@ public static class FeatureFlagKeys /* DIRT Team */ public const string PM22887_RiskInsightsActivityTab = "pm-22887-risk-insights-activity-tab"; public const string EventManagementForDataDogAndCrowdStrike = "event-management-for-datadog-and-crowdstrike"; + public const string EventDiagnosticLogging = "pm-26401-event-diagnostic-logging"; public static List GetAllKeys() { From 24c7051668b0c21bd1938cec7a7d2221dff11945 Mon Sep 17 00:00:00 2001 From: Jimmy Vo Date: Thu, 30 Oct 2025 17:08:18 -0400 Subject: [PATCH 03/10] [PM-26401] wip --- .../DiagnosticTools/EventDiagnosticLogger.cs | 30 +++++++++++-------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/Api/Utilities/DiagnosticTools/EventDiagnosticLogger.cs b/src/Api/Utilities/DiagnosticTools/EventDiagnosticLogger.cs index a55c2022fb46..7ec29737121f 100644 --- a/src/Api/Utilities/DiagnosticTools/EventDiagnosticLogger.cs +++ b/src/Api/Utilities/DiagnosticTools/EventDiagnosticLogger.cs @@ -1,33 +1,31 @@ using Bit.Api.Models.Public.Request; using Bit.Api.Models.Public.Response; +using Bit.Core; using Bit.Core.Services; namespace Bit.Api.Utilities.DiagnosticTools; public static class EventDiagnosticLogger { - public static void LogAggregateData( this ILogger logger, - IFeatureService _featureService, + IFeatureService featureService, Guid organizationId, PagedListResponseModel data, EventFilterRequestModel request) { - try { - - if (_featureService.IsEnabled(organizationId)) + if (!featureService.IsEnabled(FeatureFlagKeys.EventDiagnosticLogging)) { - + return; } + var recordCount = data.Data.Count(); var oldestRecordDate = data.Data.FirstOrDefault()?.Date; var newestRecordDate = data.Data.LastOrDefault()?.Date; var hasMore = !string.IsNullOrEmpty(data.ContinuationToken); - logger.LogInformation( "Events query for Organization {OrgId}. Returned {Count} events, oldest record {oldestRecord}, newest record {newestRecord} HasMore: {HasMore}, " + "Request Filters: Start={Start}, End={End}, ActingUserId={ActingUserId}, ItemId={ItemId},", @@ -49,21 +47,27 @@ public static void LogAggregateData( public static void LogAggregateData( this ILogger logger, - IFeatureService _featureService, + IFeatureService featureService, Guid organizationId, string continuationToken, IEnumerable data, DateTime? queryStart = null, DateTime? queryEnd = null) { - var list = data.ToList(); - var recordCount = list.Count; - var oldestRecordDate = list.FirstOrDefault()?.Date; - var newestRecordDate = list.LastOrDefault()?.Date; - var hasMore = !string.IsNullOrEmpty(continuationToken); try { + if (!featureService.IsEnabled(FeatureFlagKeys.EventDiagnosticLogging)) + { + return; + } + + var list = data.ToList(); + var recordCount = list.Count; + var oldestRecordDate = list.FirstOrDefault()?.Date; + var newestRecordDate = list.LastOrDefault()?.Date; + var hasMore = !string.IsNullOrEmpty(continuationToken); + logger.LogInformation( "Events query for Organization {OrgId}. Returned {Count} events, oldest record {oldestRecord}, newest record {newestRecord} HasMore: {HasMore}, " + "Request Filters: Start={queryStart}, End={End}", From 7de51602dd8fdafcccabf7c4a009e69fadc40b09 Mon Sep 17 00:00:00 2001 From: Jimmy Vo Date: Thu, 30 Oct 2025 17:09:12 -0400 Subject: [PATCH 04/10] [PM-26401] add tests --- .../EventDiagnosticLoggerTests.cs | 253 ++++++++++++++++++ 1 file changed, 253 insertions(+) create mode 100644 test/Api.Test/Utilities/DiagnosticTools/EventDiagnosticLoggerTests.cs diff --git a/test/Api.Test/Utilities/DiagnosticTools/EventDiagnosticLoggerTests.cs b/test/Api.Test/Utilities/DiagnosticTools/EventDiagnosticLoggerTests.cs new file mode 100644 index 000000000000..050514ef60fc --- /dev/null +++ b/test/Api.Test/Utilities/DiagnosticTools/EventDiagnosticLoggerTests.cs @@ -0,0 +1,253 @@ +using Bit.Api.Models.Public.Request; +using Bit.Api.Models.Public.Response; +using Bit.Api.Utilities.DiagnosticTools; +using Bit.Core; +using Bit.Core.Models.Data; +using Bit.Core.Services; +using Bit.Test.Common.AutoFixture.Attributes; +using Microsoft.Extensions.Logging; +using NSubstitute; +using Xunit; + +namespace Bit.Api.Test.Utilities.DiagnosticTools; + +public class EventDiagnosticLoggerTests +{ + [Theory, BitAutoData] + public void LogAggregateData_PublicApi_FeatureFlagEnabled_LogsInformation( + Guid organizationId, + EventFilterRequestModel request) + { + // Arrange + var logger = Substitute.For(); + var featureService = Substitute.For(); + featureService.IsEnabled(FeatureFlagKeys.EventDiagnosticLogging).Returns(true); + + var ev1 = Substitute.For(); + ev1.Date.Returns(DateTime.UtcNow.AddDays(-2)); + var ev2 = Substitute.For(); + ev2.Date.Returns(DateTime.UtcNow.AddDays(-1)); + + var eventResponses = new List + { + new EventResponseModel(ev1), + new EventResponseModel(ev2) + }; + var response = new PagedListResponseModel(eventResponses, "continuation-token"); + + // Act + logger.LogAggregateData(featureService, organizationId, response, request); + + // Assert + logger.Received(1).Log( + LogLevel.Information, + Arg.Any(), + Arg.Is(o => o.ToString().Contains(organizationId.ToString())), + null, + Arg.Any>()); + } + + [Theory, BitAutoData] + public void LogAggregateData_PublicApi_FeatureFlagDisabled_DoesNotLog( + Guid organizationId, + EventFilterRequestModel request) + { + // Arrange + var logger = Substitute.For(); + var featureService = Substitute.For(); + featureService.IsEnabled(FeatureFlagKeys.EventDiagnosticLogging).Returns(false); + + var ev = Substitute.For(); + ev.Date.Returns(DateTime.UtcNow); + + var eventResponses = new List + { + new EventResponseModel(ev) + }; + var response = new PagedListResponseModel(eventResponses, "token"); + + // Act + logger.LogAggregateData(featureService, organizationId, response, request); + + // Assert + logger.DidNotReceive().Log( + LogLevel.Information, + Arg.Any(), + Arg.Any(), + Arg.Any(), + Arg.Any>()); + } + + [Theory, BitAutoData] + public void LogAggregateData_AdminConsoleApi_FeatureFlagEnabled_LogsInformation( + Guid organizationId, + DateTime start, + DateTime end) + { + // Arrange + var logger = Substitute.For(); + var featureService = Substitute.For(); + featureService.IsEnabled(FeatureFlagKeys.EventDiagnosticLogging).Returns(true); + + var ev1 = Substitute.For(); + ev1.Date.Returns(DateTime.UtcNow.AddDays(-3)); + var ev2 = Substitute.For(); + ev2.Date.Returns(DateTime.UtcNow.AddDays(-1)); + + var eventResponses = new List + { + new Bit.Api.Models.Response.EventResponseModel(ev1), + new Bit.Api.Models.Response.EventResponseModel(ev2) + }; + var continuationToken = "test-token"; + + // Act + logger.LogAggregateData(featureService, organizationId, continuationToken, eventResponses, start, end); + + // Assert + logger.Received(1).Log( + LogLevel.Information, + Arg.Any(), + Arg.Is(o => o.ToString().Contains(organizationId.ToString())), + null, + Arg.Any>()); + } + + [Theory, BitAutoData] + public void LogAggregateData_AdminConsoleApi_FeatureFlagDisabled_DoesNotLog( + Guid organizationId, + DateTime start, + DateTime end) + { + // Arrange + var logger = Substitute.For(); + var featureService = Substitute.For(); + featureService.IsEnabled(FeatureFlagKeys.EventDiagnosticLogging).Returns(false); + + var ev = Substitute.For(); + ev.Date.Returns(DateTime.UtcNow); + + var eventResponses = new List + { + new Bit.Api.Models.Response.EventResponseModel(ev) + }; + + // Act + logger.LogAggregateData(featureService, organizationId, "token", eventResponses, start, end); + + // Assert + logger.DidNotReceive().Log( + LogLevel.Information, + Arg.Any(), + Arg.Any(), + Arg.Any(), + Arg.Any>()); + } + + [Theory, BitAutoData] + public void LogAggregateData_PublicApi_EmptyData_LogsZeroCount( + Guid organizationId, + EventFilterRequestModel request) + { + // Arrange + var logger = Substitute.For(); + var featureService = Substitute.For(); + featureService.IsEnabled(FeatureFlagKeys.EventDiagnosticLogging).Returns(true); + + var response = new PagedListResponseModel(new List(), null); + + // Act + logger.LogAggregateData(featureService, organizationId, response, request); + + // Assert + logger.Received(1).Log( + LogLevel.Information, + Arg.Any(), + Arg.Any(), + null, + Arg.Any>()); + } + + [Theory, BitAutoData] + public void LogAggregateData_AdminConsoleApi_EmptyData_LogsZeroCount( + Guid organizationId) + { + // Arrange + var logger = Substitute.For(); + var featureService = Substitute.For(); + featureService.IsEnabled(FeatureFlagKeys.EventDiagnosticLogging).Returns(true); + + var eventResponses = new List(); + + // Act + logger.LogAggregateData(featureService, organizationId, null, eventResponses, null, null); + + // Assert + logger.Received(1).Log( + LogLevel.Information, + Arg.Any(), + Arg.Any(), + null, + Arg.Any>()); + } + + [Theory, BitAutoData] + public void LogAggregateData_PublicApi_HasContinuationToken_LogsHasMoreTrue( + Guid organizationId, + EventFilterRequestModel request) + { + // Arrange + var logger = Substitute.For(); + var featureService = Substitute.For(); + featureService.IsEnabled(FeatureFlagKeys.EventDiagnosticLogging).Returns(true); + + var ev = Substitute.For(); + ev.Date.Returns(DateTime.UtcNow); + + var eventResponses = new List + { + new EventResponseModel(ev) + }; + var response = new PagedListResponseModel(eventResponses, "has-more-token"); + + // Act + logger.LogAggregateData(featureService, organizationId, response, request); + + // Assert + logger.Received(1).Log( + LogLevel.Information, + Arg.Any(), + Arg.Is(o => o.ToString().Contains("HasMore")), + null, + Arg.Any>()); + } + + [Theory, BitAutoData] + public void LogAggregateData_AdminConsoleApi_NoContinuationToken_LogsHasMoreFalse( + Guid organizationId) + { + // Arrange + var logger = Substitute.For(); + var featureService = Substitute.For(); + featureService.IsEnabled(FeatureFlagKeys.EventDiagnosticLogging).Returns(true); + + var ev = Substitute.For(); + ev.Date.Returns(DateTime.UtcNow); + + var eventResponses = new List + { + new Bit.Api.Models.Response.EventResponseModel(ev) + }; + + // Act + logger.LogAggregateData(featureService, organizationId, null, eventResponses, null, null); + + // Assert + logger.Received(1).Log( + LogLevel.Information, + Arg.Any(), + Arg.Any(), + null, + Arg.Any>()); + } +} From 524975fe22c688b3a456d09763c6d68c575f9ec4 Mon Sep 17 00:00:00 2001 From: Jimmy Vo Date: Thu, 30 Oct 2025 17:13:50 -0400 Subject: [PATCH 05/10] [PM-26401] wip --- .../EventDiagnosticLoggerTests.cs | 25 +++---------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/test/Api.Test/Utilities/DiagnosticTools/EventDiagnosticLoggerTests.cs b/test/Api.Test/Utilities/DiagnosticTools/EventDiagnosticLoggerTests.cs index 050514ef60fc..0440ec79f8f1 100644 --- a/test/Api.Test/Utilities/DiagnosticTools/EventDiagnosticLoggerTests.cs +++ b/test/Api.Test/Utilities/DiagnosticTools/EventDiagnosticLoggerTests.cs @@ -57,17 +57,10 @@ public void LogAggregateData_PublicApi_FeatureFlagDisabled_DoesNotLog( var featureService = Substitute.For(); featureService.IsEnabled(FeatureFlagKeys.EventDiagnosticLogging).Returns(false); - var ev = Substitute.For(); - ev.Date.Returns(DateTime.UtcNow); - - var eventResponses = new List - { - new EventResponseModel(ev) - }; - var response = new PagedListResponseModel(eventResponses, "token"); + PagedListResponseModel dummy = null; // Act - logger.LogAggregateData(featureService, organizationId, response, request); + logger.LogAggregateData(featureService, organizationId, dummy, request); // Assert logger.DidNotReceive().Log( @@ -114,26 +107,16 @@ public void LogAggregateData_AdminConsoleApi_FeatureFlagEnabled_LogsInformation( } [Theory, BitAutoData] - public void LogAggregateData_AdminConsoleApi_FeatureFlagDisabled_DoesNotLog( - Guid organizationId, - DateTime start, - DateTime end) + public void LogAggregateData_AdminConsoleApi_FeatureFlagDisabled_DoesNotLog(Guid organizationId) { // Arrange var logger = Substitute.For(); var featureService = Substitute.For(); featureService.IsEnabled(FeatureFlagKeys.EventDiagnosticLogging).Returns(false); - var ev = Substitute.For(); - ev.Date.Returns(DateTime.UtcNow); - - var eventResponses = new List - { - new Bit.Api.Models.Response.EventResponseModel(ev) - }; // Act - logger.LogAggregateData(featureService, organizationId, "token", eventResponses, start, end); + logger.LogAggregateData(featureService, organizationId, "token", null, null, null); // Assert logger.DidNotReceive().Log( From 6ff5bf540eb86b2405026f08ecdccd4b2adb9fa2 Mon Sep 17 00:00:00 2001 From: Jimmy Vo Date: Thu, 30 Oct 2025 20:07:00 -0400 Subject: [PATCH 06/10] [PM-26401] wip --- .../DiagnosticTools/EventDiagnosticLogger.cs | 26 +++---- .../EventDiagnosticLoggerTests.cs | 75 ++++++++++++++----- 2 files changed, 69 insertions(+), 32 deletions(-) diff --git a/src/Api/Utilities/DiagnosticTools/EventDiagnosticLogger.cs b/src/Api/Utilities/DiagnosticTools/EventDiagnosticLogger.cs index 7ec29737121f..17bffcfbf35e 100644 --- a/src/Api/Utilities/DiagnosticTools/EventDiagnosticLogger.cs +++ b/src/Api/Utilities/DiagnosticTools/EventDiagnosticLogger.cs @@ -19,23 +19,23 @@ public static void LogAggregateData( { return; } + var orderedRecords = data.Data.OrderBy(e => e.Date).ToList(); + var recordCount = orderedRecords.Count; + var newestRecordDate = orderedRecords.LastOrDefault()?.Date.ToString("o"); + var oldestRecordDate = orderedRecords.FirstOrDefault()?.Date.ToString("o"); ; - - var recordCount = data.Data.Count(); - var oldestRecordDate = data.Data.FirstOrDefault()?.Date; - var newestRecordDate = data.Data.LastOrDefault()?.Date; var hasMore = !string.IsNullOrEmpty(data.ContinuationToken); logger.LogInformation( - "Events query for Organization {OrgId}. Returned {Count} events, oldest record {oldestRecord}, newest record {newestRecord} HasMore: {HasMore}, " + - "Request Filters: Start={Start}, End={End}, ActingUserId={ActingUserId}, ItemId={ItemId},", + "Events query for Organization:{OrgId}. Event count:{Count} newest record:{newestRecord} oldest record:{oldestRecord} HasMore:{HasMore} " + + "Request Filters Start:{QueryStart} End:{QueryEnd} ActingUserId:{ActingUserId} ItemId:{ItemId},", organizationId, recordCount, - oldestRecordDate, newestRecordDate, + oldestRecordDate, hasMore, - request.Start, - request.End, + request.Start?.ToString("o"), + request.End?.ToString("o"), request.ActingUserId, request.ItemId); } @@ -64,13 +64,13 @@ public static void LogAggregateData( var list = data.ToList(); var recordCount = list.Count; - var oldestRecordDate = list.FirstOrDefault()?.Date; - var newestRecordDate = list.LastOrDefault()?.Date; + var oldestRecordDate = list.FirstOrDefault()?.Date.ToString("o"); + var newestRecordDate = list.LastOrDefault()?.Date.ToString("o"); var hasMore = !string.IsNullOrEmpty(continuationToken); logger.LogInformation( - "Events query for Organization {OrgId}. Returned {Count} events, oldest record {oldestRecord}, newest record {newestRecord} HasMore: {HasMore}, " + - "Request Filters: Start={queryStart}, End={End}", + "Events query for Organization:{OrgId}. Event count:{Count} oldest record:{oldestRecord} newest record:{newestRecord} HasMore:{HasMore} " + + "Request Filters Start:{QueryStart} End:{QueryEnd}", organizationId, recordCount, oldestRecordDate, diff --git a/test/Api.Test/Utilities/DiagnosticTools/EventDiagnosticLoggerTests.cs b/test/Api.Test/Utilities/DiagnosticTools/EventDiagnosticLoggerTests.cs index 0440ec79f8f1..c4f9c6a04f6c 100644 --- a/test/Api.Test/Utilities/DiagnosticTools/EventDiagnosticLoggerTests.cs +++ b/test/Api.Test/Utilities/DiagnosticTools/EventDiagnosticLoggerTests.cs @@ -15,23 +15,33 @@ public class EventDiagnosticLoggerTests { [Theory, BitAutoData] public void LogAggregateData_PublicApi_FeatureFlagEnabled_LogsInformation( - Guid organizationId, - EventFilterRequestModel request) + Guid organizationId) { // Arrange var logger = Substitute.For(); var featureService = Substitute.For(); featureService.IsEnabled(FeatureFlagKeys.EventDiagnosticLogging).Returns(true); - var ev1 = Substitute.For(); - ev1.Date.Returns(DateTime.UtcNow.AddDays(-2)); - var ev2 = Substitute.For(); - ev2.Date.Returns(DateTime.UtcNow.AddDays(-1)); + var request = new EventFilterRequestModel() + { + Start = DateTime.UtcNow.AddMinutes(-3), + End = DateTime.UtcNow, + ActingUserId = Guid.NewGuid(), + ItemId = Guid.NewGuid(), + }; + + var newestEvent = Substitute.For(); + newestEvent.Date.Returns(DateTime.UtcNow); + var middleEvent = Substitute.For(); + middleEvent.Date.Returns(DateTime.UtcNow.AddDays(-1)); + var oldestEvent = Substitute.For(); + oldestEvent.Date.Returns(DateTime.UtcNow.AddDays(-2)); var eventResponses = new List { - new EventResponseModel(ev1), - new EventResponseModel(ev2) + new (newestEvent), + new (middleEvent), + new (oldestEvent) }; var response = new PagedListResponseModel(eventResponses, "continuation-token"); @@ -42,7 +52,14 @@ public void LogAggregateData_PublicApi_FeatureFlagEnabled_LogsInformation( logger.Received(1).Log( LogLevel.Information, Arg.Any(), - Arg.Is(o => o.ToString().Contains(organizationId.ToString())), + Arg.Is(o => + o.ToString().Contains(organizationId.ToString()) && + o.ToString().Contains($"Event count:{eventResponses.Count}") && + o.ToString().Contains("HasMore:True") && + o.ToString().Contains($"ActingUserId:{request.ActingUserId}") && + o.ToString().Contains($"ItemId:{request.ItemId}") && + o.ToString().Contains($"newest record:{newestEvent.Date:O}")) + , null, Arg.Any>()); } @@ -82,15 +99,18 @@ public void LogAggregateData_AdminConsoleApi_FeatureFlagEnabled_LogsInformation( var featureService = Substitute.For(); featureService.IsEnabled(FeatureFlagKeys.EventDiagnosticLogging).Returns(true); + var oldestDate = DateTime.UtcNow.AddDays(-3); + var newestDate = DateTime.UtcNow.AddDays(-1); + var ev1 = Substitute.For(); - ev1.Date.Returns(DateTime.UtcNow.AddDays(-3)); + ev1.Date.Returns(oldestDate); var ev2 = Substitute.For(); - ev2.Date.Returns(DateTime.UtcNow.AddDays(-1)); + ev2.Date.Returns(newestDate); var eventResponses = new List { - new Bit.Api.Models.Response.EventResponseModel(ev1), - new Bit.Api.Models.Response.EventResponseModel(ev2) + new (ev1), + new (ev2) }; var continuationToken = "test-token"; @@ -101,7 +121,12 @@ public void LogAggregateData_AdminConsoleApi_FeatureFlagEnabled_LogsInformation( logger.Received(1).Log( LogLevel.Information, Arg.Any(), - Arg.Is(o => o.ToString().Contains(organizationId.ToString())), + Arg.Is(o => + o.ToString().Contains(organizationId.ToString()) && + o.ToString().Contains("Returned 2 events") && + o.ToString().Contains("HasMore: True") && + o.ToString().Contains("oldest record") && + o.ToString().Contains("newest record")), null, Arg.Any>()); } @@ -146,7 +171,10 @@ public void LogAggregateData_PublicApi_EmptyData_LogsZeroCount( logger.Received(1).Log( LogLevel.Information, Arg.Any(), - Arg.Any(), + Arg.Is(o => + o.ToString().Contains(organizationId.ToString()) && + o.ToString().Contains("Returned 0 events") && + o.ToString().Contains("HasMore: False")), null, Arg.Any>()); } @@ -169,7 +197,10 @@ public void LogAggregateData_AdminConsoleApi_EmptyData_LogsZeroCount( logger.Received(1).Log( LogLevel.Information, Arg.Any(), - Arg.Any(), + Arg.Is(o => + o.ToString().Contains(organizationId.ToString()) && + o.ToString().Contains("Returned 0 events") && + o.ToString().Contains("HasMore: False")), null, Arg.Any>()); } @@ -200,7 +231,10 @@ public void LogAggregateData_PublicApi_HasContinuationToken_LogsHasMoreTrue( logger.Received(1).Log( LogLevel.Information, Arg.Any(), - Arg.Is(o => o.ToString().Contains("HasMore")), + Arg.Is(o => + o.ToString().Contains(organizationId.ToString()) && + o.ToString().Contains("Returned 1 events") && + o.ToString().Contains("HasMore: True")), null, Arg.Any>()); } @@ -219,7 +253,7 @@ public void LogAggregateData_AdminConsoleApi_NoContinuationToken_LogsHasMoreFals var eventResponses = new List { - new Bit.Api.Models.Response.EventResponseModel(ev) + new (ev) }; // Act @@ -229,7 +263,10 @@ public void LogAggregateData_AdminConsoleApi_NoContinuationToken_LogsHasMoreFals logger.Received(1).Log( LogLevel.Information, Arg.Any(), - Arg.Any(), + Arg.Is(o => + o.ToString().Contains(organizationId.ToString()) && + o.ToString().Contains("Returned 1 events") && + o.ToString().Contains("HasMore: False")), null, Arg.Any>()); } From c621a56b5479d5d3677c17b792fa46bc6446519d Mon Sep 17 00:00:00 2001 From: Jimmy Vo Date: Thu, 30 Oct 2025 20:24:10 -0400 Subject: [PATCH 07/10] [PM-26401] wip --- .../EventDiagnosticLoggerTests.cs | 63 ++++++------------- 1 file changed, 20 insertions(+), 43 deletions(-) diff --git a/test/Api.Test/Utilities/DiagnosticTools/EventDiagnosticLoggerTests.cs b/test/Api.Test/Utilities/DiagnosticTools/EventDiagnosticLoggerTests.cs index c4f9c6a04f6c..2de34cbd27d7 100644 --- a/test/Api.Test/Utilities/DiagnosticTools/EventDiagnosticLoggerTests.cs +++ b/test/Api.Test/Utilities/DiagnosticTools/EventDiagnosticLoggerTests.cs @@ -14,7 +14,7 @@ namespace Bit.Api.Test.Utilities.DiagnosticTools; public class EventDiagnosticLoggerTests { [Theory, BitAutoData] - public void LogAggregateData_PublicApi_FeatureFlagEnabled_LogsInformation( + public void LogAggregateData_WithPublicResponse_FeatureFlagEnabled_LogsInformation( Guid organizationId) { // Arrange @@ -55,17 +55,20 @@ public void LogAggregateData_PublicApi_FeatureFlagEnabled_LogsInformation( Arg.Is(o => o.ToString().Contains(organizationId.ToString()) && o.ToString().Contains($"Event count:{eventResponses.Count}") && - o.ToString().Contains("HasMore:True") && + o.ToString().Contains("Request Filters Start:") && + o.ToString().Contains("End:") && o.ToString().Contains($"ActingUserId:{request.ActingUserId}") && o.ToString().Contains($"ItemId:{request.ItemId}") && - o.ToString().Contains($"newest record:{newestEvent.Date:O}")) + o.ToString().Contains($"newest record:{newestEvent.Date:O}") && + o.ToString().Contains($"oldest record:{oldestEvent.Date:O}") && + o.ToString().Contains("HasMore:True")) , null, Arg.Any>()); } [Theory, BitAutoData] - public void LogAggregateData_PublicApi_FeatureFlagDisabled_DoesNotLog( + public void LogAggregateData_WithPublicResponse_FeatureFlagDisabled_DoesNotLog( Guid organizationId, EventFilterRequestModel request) { @@ -141,7 +144,7 @@ public void LogAggregateData_AdminConsoleApi_FeatureFlagDisabled_DoesNotLog(Guid // Act - logger.LogAggregateData(featureService, organizationId, "token", null, null, null); + logger.LogAggregateData(featureService, organizationId, null, null, null, null); // Assert logger.DidNotReceive().Log( @@ -153,15 +156,22 @@ public void LogAggregateData_AdminConsoleApi_FeatureFlagDisabled_DoesNotLog(Guid } [Theory, BitAutoData] - public void LogAggregateData_PublicApi_EmptyData_LogsZeroCount( - Guid organizationId, - EventFilterRequestModel request) + public void LogAggregateData_WithPublicResponse_EmptyData_LogsZeroCount( + Guid organizationId) { // Arrange var logger = Substitute.For(); var featureService = Substitute.For(); featureService.IsEnabled(FeatureFlagKeys.EventDiagnosticLogging).Returns(true); + var request = new EventFilterRequestModel() + { + Start = null, + End = null, + ActingUserId = null, + ItemId = null, + ContinuationToken = null, + }; var response = new PagedListResponseModel(new List(), null); // Act @@ -173,8 +183,8 @@ public void LogAggregateData_PublicApi_EmptyData_LogsZeroCount( Arg.Any(), Arg.Is(o => o.ToString().Contains(organizationId.ToString()) && - o.ToString().Contains("Returned 0 events") && - o.ToString().Contains("HasMore: False")), + o.ToString().Contains("Event count:0") && + o.ToString().Contains("HasMore:False")), null, Arg.Any>()); } @@ -205,39 +215,6 @@ public void LogAggregateData_AdminConsoleApi_EmptyData_LogsZeroCount( Arg.Any>()); } - [Theory, BitAutoData] - public void LogAggregateData_PublicApi_HasContinuationToken_LogsHasMoreTrue( - Guid organizationId, - EventFilterRequestModel request) - { - // Arrange - var logger = Substitute.For(); - var featureService = Substitute.For(); - featureService.IsEnabled(FeatureFlagKeys.EventDiagnosticLogging).Returns(true); - - var ev = Substitute.For(); - ev.Date.Returns(DateTime.UtcNow); - - var eventResponses = new List - { - new EventResponseModel(ev) - }; - var response = new PagedListResponseModel(eventResponses, "has-more-token"); - - // Act - logger.LogAggregateData(featureService, organizationId, response, request); - - // Assert - logger.Received(1).Log( - LogLevel.Information, - Arg.Any(), - Arg.Is(o => - o.ToString().Contains(organizationId.ToString()) && - o.ToString().Contains("Returned 1 events") && - o.ToString().Contains("HasMore: True")), - null, - Arg.Any>()); - } [Theory, BitAutoData] public void LogAggregateData_AdminConsoleApi_NoContinuationToken_LogsHasMoreFalse( From 911c35298b471136c2a36d022cbbb2257f657e30 Mon Sep 17 00:00:00 2001 From: Jimmy Vo Date: Thu, 30 Oct 2025 20:28:20 -0400 Subject: [PATCH 08/10] [PM-26401] wip --- .../DiagnosticTools/EventDiagnosticLogger.cs | 18 ++-- .../EventDiagnosticLoggerTests.cs | 100 ------------------ 2 files changed, 9 insertions(+), 109 deletions(-) diff --git a/src/Api/Utilities/DiagnosticTools/EventDiagnosticLogger.cs b/src/Api/Utilities/DiagnosticTools/EventDiagnosticLogger.cs index 17bffcfbf35e..b435f6acc9ff 100644 --- a/src/Api/Utilities/DiagnosticTools/EventDiagnosticLogger.cs +++ b/src/Api/Utilities/DiagnosticTools/EventDiagnosticLogger.cs @@ -19,11 +19,11 @@ public static void LogAggregateData( { return; } + var orderedRecords = data.Data.OrderBy(e => e.Date).ToList(); var recordCount = orderedRecords.Count; var newestRecordDate = orderedRecords.LastOrDefault()?.Date.ToString("o"); var oldestRecordDate = orderedRecords.FirstOrDefault()?.Date.ToString("o"); ; - var hasMore = !string.IsNullOrEmpty(data.ContinuationToken); logger.LogInformation( @@ -62,22 +62,22 @@ public static void LogAggregateData( return; } - var list = data.ToList(); - var recordCount = list.Count; - var oldestRecordDate = list.FirstOrDefault()?.Date.ToString("o"); - var newestRecordDate = list.LastOrDefault()?.Date.ToString("o"); + var orderedRecords = data.OrderBy(e => e.Date).ToList(); + var recordCount = orderedRecords.Count; + var newestRecordDate = orderedRecords.LastOrDefault()?.Date.ToString("o"); + var oldestRecordDate = orderedRecords.FirstOrDefault()?.Date.ToString("o"); ; var hasMore = !string.IsNullOrEmpty(continuationToken); logger.LogInformation( - "Events query for Organization:{OrgId}. Event count:{Count} oldest record:{oldestRecord} newest record:{newestRecord} HasMore:{HasMore} " + + "Events query for Organization:{OrgId}. Event count:{Count} newest record:{newestRecord} oldest record:{oldestRecord} HasMore:{HasMore} " + "Request Filters Start:{QueryStart} End:{QueryEnd}", organizationId, recordCount, - oldestRecordDate, newestRecordDate, + oldestRecordDate, hasMore, - queryStart, - queryEnd); + queryStart?.ToString("o"), + queryEnd?.ToString("o")); } catch (Exception exception) { diff --git a/test/Api.Test/Utilities/DiagnosticTools/EventDiagnosticLoggerTests.cs b/test/Api.Test/Utilities/DiagnosticTools/EventDiagnosticLoggerTests.cs index 2de34cbd27d7..a9dbff6bddb5 100644 --- a/test/Api.Test/Utilities/DiagnosticTools/EventDiagnosticLoggerTests.cs +++ b/test/Api.Test/Utilities/DiagnosticTools/EventDiagnosticLoggerTests.cs @@ -91,48 +91,6 @@ public void LogAggregateData_WithPublicResponse_FeatureFlagDisabled_DoesNotLog( Arg.Any>()); } - [Theory, BitAutoData] - public void LogAggregateData_AdminConsoleApi_FeatureFlagEnabled_LogsInformation( - Guid organizationId, - DateTime start, - DateTime end) - { - // Arrange - var logger = Substitute.For(); - var featureService = Substitute.For(); - featureService.IsEnabled(FeatureFlagKeys.EventDiagnosticLogging).Returns(true); - - var oldestDate = DateTime.UtcNow.AddDays(-3); - var newestDate = DateTime.UtcNow.AddDays(-1); - - var ev1 = Substitute.For(); - ev1.Date.Returns(oldestDate); - var ev2 = Substitute.For(); - ev2.Date.Returns(newestDate); - - var eventResponses = new List - { - new (ev1), - new (ev2) - }; - var continuationToken = "test-token"; - - // Act - logger.LogAggregateData(featureService, organizationId, continuationToken, eventResponses, start, end); - - // Assert - logger.Received(1).Log( - LogLevel.Information, - Arg.Any(), - Arg.Is(o => - o.ToString().Contains(organizationId.ToString()) && - o.ToString().Contains("Returned 2 events") && - o.ToString().Contains("HasMore: True") && - o.ToString().Contains("oldest record") && - o.ToString().Contains("newest record")), - null, - Arg.Any>()); - } [Theory, BitAutoData] public void LogAggregateData_AdminConsoleApi_FeatureFlagDisabled_DoesNotLog(Guid organizationId) @@ -189,62 +147,4 @@ public void LogAggregateData_WithPublicResponse_EmptyData_LogsZeroCount( Arg.Any>()); } - [Theory, BitAutoData] - public void LogAggregateData_AdminConsoleApi_EmptyData_LogsZeroCount( - Guid organizationId) - { - // Arrange - var logger = Substitute.For(); - var featureService = Substitute.For(); - featureService.IsEnabled(FeatureFlagKeys.EventDiagnosticLogging).Returns(true); - - var eventResponses = new List(); - - // Act - logger.LogAggregateData(featureService, organizationId, null, eventResponses, null, null); - - // Assert - logger.Received(1).Log( - LogLevel.Information, - Arg.Any(), - Arg.Is(o => - o.ToString().Contains(organizationId.ToString()) && - o.ToString().Contains("Returned 0 events") && - o.ToString().Contains("HasMore: False")), - null, - Arg.Any>()); - } - - - [Theory, BitAutoData] - public void LogAggregateData_AdminConsoleApi_NoContinuationToken_LogsHasMoreFalse( - Guid organizationId) - { - // Arrange - var logger = Substitute.For(); - var featureService = Substitute.For(); - featureService.IsEnabled(FeatureFlagKeys.EventDiagnosticLogging).Returns(true); - - var ev = Substitute.For(); - ev.Date.Returns(DateTime.UtcNow); - - var eventResponses = new List - { - new (ev) - }; - - // Act - logger.LogAggregateData(featureService, organizationId, null, eventResponses, null, null); - - // Assert - logger.Received(1).Log( - LogLevel.Information, - Arg.Any(), - Arg.Is(o => - o.ToString().Contains(organizationId.ToString()) && - o.ToString().Contains("Returned 1 events") && - o.ToString().Contains("HasMore: False")), - null, - Arg.Any>()); - } } From 0f4078cd07f3dea5f755599d46d796d18f698291 Mon Sep 17 00:00:00 2001 From: Jimmy Vo Date: Fri, 31 Oct 2025 10:23:10 -0400 Subject: [PATCH 09/10] [PM-26401] Add more tests --- .../Controllers/EventsController.cs | 2 +- .../DiagnosticTools/EventDiagnosticLogger.cs | 2 +- .../EventDiagnosticLoggerTests.cs | 107 +++++++++++++++--- 3 files changed, 91 insertions(+), 20 deletions(-) diff --git a/src/Api/AdminConsole/Controllers/EventsController.cs b/src/Api/AdminConsole/Controllers/EventsController.cs index 273bc35d7a00..7e058a7870d7 100644 --- a/src/Api/AdminConsole/Controllers/EventsController.cs +++ b/src/Api/AdminConsole/Controllers/EventsController.cs @@ -121,7 +121,7 @@ public async Task> GetOrganization(string new PageOptions { ContinuationToken = continuationToken }); var responses = result.Data.Select(e => new EventResponseModel(e)); - _logger.LogAggregateData(_featureService, orgId, continuationToken, responses, start, end); + _logger.LogAggregateData(_featureService, orgId, responses, continuationToken, start, end); return new ListResponseModel(responses, result.ContinuationToken); } diff --git a/src/Api/Utilities/DiagnosticTools/EventDiagnosticLogger.cs b/src/Api/Utilities/DiagnosticTools/EventDiagnosticLogger.cs index b435f6acc9ff..9f6a8d2639a8 100644 --- a/src/Api/Utilities/DiagnosticTools/EventDiagnosticLogger.cs +++ b/src/Api/Utilities/DiagnosticTools/EventDiagnosticLogger.cs @@ -49,8 +49,8 @@ public static void LogAggregateData( this ILogger logger, IFeatureService featureService, Guid organizationId, - string continuationToken, IEnumerable data, + string? continuationToken, DateTime? queryStart = null, DateTime? queryEnd = null) { diff --git a/test/Api.Test/Utilities/DiagnosticTools/EventDiagnosticLoggerTests.cs b/test/Api.Test/Utilities/DiagnosticTools/EventDiagnosticLoggerTests.cs index a9dbff6bddb5..ada75b148b0a 100644 --- a/test/Api.Test/Utilities/DiagnosticTools/EventDiagnosticLoggerTests.cs +++ b/test/Api.Test/Utilities/DiagnosticTools/EventDiagnosticLoggerTests.cs @@ -35,7 +35,7 @@ public void LogAggregateData_WithPublicResponse_FeatureFlagEnabled_LogsInformati var middleEvent = Substitute.For(); middleEvent.Date.Returns(DateTime.UtcNow.AddDays(-1)); var oldestEvent = Substitute.For(); - oldestEvent.Date.Returns(DateTime.UtcNow.AddDays(-2)); + oldestEvent.Date.Returns(DateTime.UtcNow.AddDays(-3)); var eventResponses = new List { @@ -55,13 +55,13 @@ public void LogAggregateData_WithPublicResponse_FeatureFlagEnabled_LogsInformati Arg.Is(o => o.ToString().Contains(organizationId.ToString()) && o.ToString().Contains($"Event count:{eventResponses.Count}") && - o.ToString().Contains("Request Filters Start:") && - o.ToString().Contains("End:") && - o.ToString().Contains($"ActingUserId:{request.ActingUserId}") && - o.ToString().Contains($"ItemId:{request.ItemId}") && o.ToString().Contains($"newest record:{newestEvent.Date:O}") && o.ToString().Contains($"oldest record:{oldestEvent.Date:O}") && - o.ToString().Contains("HasMore:True")) + o.ToString().Contains("HasMore:True") && + o.ToString().Contains($"Start:{request.Start:o}") && + o.ToString().Contains($"End:{request.End:o}") && + o.ToString().Contains($"ActingUserId:{request.ActingUserId}") && + o.ToString().Contains($"ItemId:{request.ItemId}")) , null, Arg.Any>()); @@ -91,9 +91,42 @@ public void LogAggregateData_WithPublicResponse_FeatureFlagDisabled_DoesNotLog( Arg.Any>()); } + [Theory, BitAutoData] + public void LogAggregateData_WithPublicResponse_EmptyData_LogsZeroCount( + Guid organizationId) + { + // Arrange + var logger = Substitute.For(); + var featureService = Substitute.For(); + featureService.IsEnabled(FeatureFlagKeys.EventDiagnosticLogging).Returns(true); + + var request = new EventFilterRequestModel() + { + Start = null, + End = null, + ActingUserId = null, + ItemId = null, + ContinuationToken = null, + }; + var response = new PagedListResponseModel(new List(), null); + + // Act + logger.LogAggregateData(featureService, organizationId, response, request); + + // Assert + logger.Received(1).Log( + LogLevel.Information, + Arg.Any(), + Arg.Is(o => + o.ToString().Contains(organizationId.ToString()) && + o.ToString().Contains("Event count:0") && + o.ToString().Contains("HasMore:False")), + null, + Arg.Any>()); + } [Theory, BitAutoData] - public void LogAggregateData_AdminConsoleApi_FeatureFlagDisabled_DoesNotLog(Guid organizationId) + public void LogAggregateData_WithInternalResponse_FeatureFlagDisabled_DoesNotLog(Guid organizationId) { // Arrange var logger = Substitute.For(); @@ -114,7 +147,7 @@ public void LogAggregateData_AdminConsoleApi_FeatureFlagDisabled_DoesNotLog(Guid } [Theory, BitAutoData] - public void LogAggregateData_WithPublicResponse_EmptyData_LogsZeroCount( + public void LogAggregateData_WithInternalResponse_EmptyData_LogsZeroCount( Guid organizationId) { // Arrange @@ -122,18 +155,10 @@ public void LogAggregateData_WithPublicResponse_EmptyData_LogsZeroCount( var featureService = Substitute.For(); featureService.IsEnabled(FeatureFlagKeys.EventDiagnosticLogging).Returns(true); - var request = new EventFilterRequestModel() - { - Start = null, - End = null, - ActingUserId = null, - ItemId = null, - ContinuationToken = null, - }; - var response = new PagedListResponseModel(new List(), null); + Bit.Api.Models.Response.EventResponseModel[] emptyEvents = []; // Act - logger.LogAggregateData(featureService, organizationId, response, request); + logger.LogAggregateData(featureService, organizationId, emptyEvents, null, null, null); // Assert logger.Received(1).Log( @@ -147,4 +172,50 @@ public void LogAggregateData_WithPublicResponse_EmptyData_LogsZeroCount( Arg.Any>()); } + [Theory, BitAutoData] + public void LogAggregateData_WithInternalResponse_FeatureFlagEnabled_LogsInformation( + Guid organizationId) + { + // Arrange + var logger = Substitute.For(); + var featureService = Substitute.For(); + featureService.IsEnabled(FeatureFlagKeys.EventDiagnosticLogging).Returns(true); + + var newestEvent = Substitute.For(); + newestEvent.Date.Returns(DateTime.UtcNow); + var middleEvent = Substitute.For(); + middleEvent.Date.Returns(DateTime.UtcNow.AddDays(-1)); + var oldestEvent = Substitute.For(); + oldestEvent.Date.Returns(DateTime.UtcNow.AddDays(-2)); + + var events = new List + { + new (newestEvent), + new (middleEvent), + new (oldestEvent) + }; + + var queryStart = DateTime.UtcNow.AddMinutes(-3); + var queryEnd = DateTime.UtcNow; + const string continuationToken = "continuation-token"; + + // Act + logger.LogAggregateData(featureService, organizationId, events, continuationToken, queryStart, queryEnd); + + // Assert + logger.Received(1).Log( + LogLevel.Information, + Arg.Any(), + Arg.Is(o => + o.ToString().Contains(organizationId.ToString()) && + o.ToString().Contains($"Event count:{events.Count}") && + o.ToString().Contains($"newest record:{newestEvent.Date:O}") && + o.ToString().Contains($"oldest record:{oldestEvent.Date:O}") && + o.ToString().Contains("HasMore:True") && + o.ToString().Contains($"Start:{queryStart:o}") && + o.ToString().Contains($"End:{queryEnd:o}")) + , + null, + Arg.Any>()); + } } From 3021caa72cc0ab527f537cd328b54f7a8cdfbd68 Mon Sep 17 00:00:00 2001 From: Jimmy Vo Date: Fri, 31 Oct 2025 10:29:29 -0400 Subject: [PATCH 10/10] [PM-26401] Fix ff key --- src/Core/Constants.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Core/Constants.cs b/src/Core/Constants.cs index 89c4cc6efc38..bc7f87d7d7f9 100644 --- a/src/Core/Constants.cs +++ b/src/Core/Constants.cs @@ -251,7 +251,7 @@ public static class FeatureFlagKeys /* DIRT Team */ public const string PM22887_RiskInsightsActivityTab = "pm-22887-risk-insights-activity-tab"; public const string EventManagementForDataDogAndCrowdStrike = "event-management-for-datadog-and-crowdstrike"; - public const string EventDiagnosticLogging = "pm-26401-event-diagnostic-logging"; + public const string EventDiagnosticLogging = "pm-27666-siem-event-log-debugging"; public static List GetAllKeys() {