Skip to content

Commit a3401aa

Browse files
committed
Enhance validation logging by restructuring log state and updating log message format
1 parent 7cbb77c commit a3401aa

File tree

2 files changed

+56
-16
lines changed

2 files changed

+56
-16
lines changed

src/server/FakeSurveyGenerator.Api.Tests.Integration/Surveys/SurveyEndpointsTests.cs

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System.Net;
22
using System.Net.Http.Json;
3+
using System.Linq;
34
using AutoFixture;
45
using FakeSurveyGenerator.Api.Tests.Integration.Setup;
56
using FakeSurveyGenerator.Application.Features.Surveys;
@@ -123,12 +124,22 @@ public async Task
123124

124125
await Assert.That(validationLog).IsNotNull();
125126

126-
// LoggerMessage payload doesn't include structured state in this test host, so validate via message text.
127127
await Assert.That(validationLog!.Message.Contains("Validation failure on Endpoint: CreateSurvey")).IsTrue();
128128
await Assert.That(validationLog.Message.Contains("User:")).IsTrue();
129129
await Assert.That(validationLog.Message.Contains("Unknown Identity")).IsFalse();
130-
await Assert.That(validationLog.Message.Contains("SurveyTopic")).IsTrue();
131-
await Assert.That(validationLog.Message.Contains("SurveyOptions[0].OptionText")).IsTrue();
130+
131+
var state = validationLog.State;
132+
await Assert.That(state).IsNotNull();
133+
await Assert.That(HasStateKey(state, "Error.SurveyTopic")).IsTrue();
134+
await Assert.That(HasStateKey(state, "Error.SurveyOptions[0].OptionText")).IsTrue();
135+
136+
var surveyTopicErrors = GetStateStringArray(state, "Error.SurveyTopic");
137+
var optionTextErrors = GetStateStringArray(state, "Error.SurveyOptions[0].OptionText");
138+
139+
await Assert.That(surveyTopicErrors).IsNotNull();
140+
await Assert.That(optionTextErrors).IsNotNull();
141+
await Assert.That(surveyTopicErrors!.Length).IsGreaterThan(0);
142+
await Assert.That(optionTextErrors!.Length).IsGreaterThan(0);
132143
}
133144

134145
[Test]
@@ -251,4 +262,18 @@ private async Task<SurveyModel> CreateSurvey()
251262
var survey = await response.Content.ReadFromJsonAsync<SurveyModel>();
252263
return survey!;
253264
}
265+
266+
private static bool HasStateKey(
267+
IReadOnlyList<KeyValuePair<string, object?>> state,
268+
string key)
269+
{
270+
return state.Any(item => item.Key == key);
271+
}
272+
273+
private static string[]? GetStateStringArray(
274+
IReadOnlyList<KeyValuePair<string, object?>> state,
275+
string key)
276+
{
277+
return state.FirstOrDefault(item => item.Key == key).Value as string[];
278+
}
254279
}

src/server/FakeSurveyGenerator.Api/Filters/ValidationLoggingEndpointFilter.cs

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using FakeSurveyGenerator.Application.Shared.Identity;
22
using Microsoft.AspNetCore.Http;
3+
using System.Linq;
34

45
namespace FakeSurveyGenerator.Api.Filters;
56

@@ -21,24 +22,38 @@ public sealed class ValidationLoggingEndpointFilter(ILoggerFactory loggerFactory
2122
&& value is IDictionary<string, string[]> errors
2223
&& errors.Count > 0)
2324
{
25+
if (!_logger.IsEnabled(LogLevel.Warning))
26+
{
27+
return result;
28+
}
29+
2430
var userIdentity = userService?.GetUserIdentity() ?? "Unknown Identity";
31+
var state = BuildLogState(endpointName, userIdentity, errors);
32+
var message = $"Validation failure on Endpoint: {endpointName} for User: {userIdentity}.";
2533

26-
_logger.LogValidationErrors(endpointName, userIdentity, errors);
34+
_logger.Log(LogLevel.Warning, new EventId(1, "ValidationErrors"), state, null,
35+
(_, _) => message);
2736
}
2837

2938
return result;
3039
}
31-
}
3240

33-
public static partial class ValidationLoggingEndpointFilterLogging
34-
{
35-
[LoggerMessage(
36-
EventId = 1,
37-
Level = LogLevel.Warning,
38-
Message = "Validation failure on Endpoint: {EndpointName} for User: {UserIdentity}. Errors: {Errors}")]
39-
public static partial void LogValidationErrors(
40-
this ILogger logger,
41-
string endpointName,
42-
string userIdentity,
43-
IDictionary<string, string[]> errors);
41+
private static IReadOnlyList<KeyValuePair<string, object?>> BuildLogState(
42+
string endpointName,
43+
string userIdentity,
44+
IDictionary<string, string[]> errors)
45+
{
46+
var state = new List<KeyValuePair<string, object?>>
47+
{
48+
new("EndpointName", endpointName),
49+
new("UserIdentity", userIdentity),
50+
};
51+
52+
foreach (var error in errors.OrderBy(pair => pair.Key))
53+
{
54+
state.Add(new($"Error.{error.Key}", error.Value));
55+
}
56+
57+
return state;
58+
}
4459
}

0 commit comments

Comments
 (0)