From e0cebd1b2952784eebf7f06b36ab4dfead50edfd Mon Sep 17 00:00:00 2001 From: Iliar Turdushev Date: Mon, 9 Oct 2023 16:01:23 +0200 Subject: [PATCH 01/19] Fixed naming of HttpClient logs, Http Middleware logs, and LoggerMessage parameters --- .../Logging/HttpLoggingTagNames.cs | 18 +++++++++--------- .../Logging/Log.cs | 7 ++++--- .../HeaderParsingFeature.cs | 6 +++--- .../Log.cs | 4 ++-- .../Log.cs | 2 +- .../HostTerminatorService.cs | 2 +- .../Logging/HttpClientLoggingTagNames.cs | 18 +++++++++--------- .../Logging/Internal/Log.cs | 7 ++++--- .../Logging/AcceptanceTests.cs | 4 ++-- 9 files changed, 35 insertions(+), 33 deletions(-) diff --git a/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/HttpLoggingTagNames.cs b/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/HttpLoggingTagNames.cs index a91e687c462..801048d8ccd 100644 --- a/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/HttpLoggingTagNames.cs +++ b/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/HttpLoggingTagNames.cs @@ -14,47 +14,47 @@ public static class HttpLoggingTagNames /// /// HTTP Request duration in milliseconds. /// - public const string Duration = "duration"; + public const string Duration = "Duration"; /// /// HTTP Host. /// - public const string Host = "httpHost"; + public const string Host = "HttpHost"; /// /// HTTP Method. /// - public const string Method = "httpMethod"; + public const string Method = "HttpMethod"; /// /// HTTP Path. /// - public const string Path = "httpPath"; + public const string Path = "HttpPath"; /// /// HTTP Request Headers prefix. /// - public const string RequestHeaderPrefix = "httpRequestHeader_"; + public const string RequestHeaderPrefix = "HttpRequestHeader."; /// /// HTTP Response Headers prefix. /// - public const string ResponseHeaderPrefix = "httpResponseHeader_"; + public const string ResponseHeaderPrefix = "HttpResponseHeader."; /// /// HTTP Request Body. /// - public const string RequestBody = "httpRequestBody"; + public const string RequestBody = "HttpRequestBody"; /// /// HTTP Response Body. /// - public const string ResponseBody = "httpResponseBody"; + public const string ResponseBody = "HttpResponseBody"; /// /// HTTP Status Code. /// - public const string StatusCode = "httpStatusCode"; + public const string StatusCode = "HttpStatusCode"; /// /// Gets a list of all dimension names. diff --git a/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/Log.cs b/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/Log.cs index 388bc8f7791..41f24ae96be 100644 --- a/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/Log.cs +++ b/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/Log.cs @@ -17,7 +17,8 @@ internal static partial class Log internal const LogLevel DefaultLogLevel = LogLevel.Information; internal const LogLevel ErrorLogLevel = LogLevel.Error; internal const string OriginalFormat = "{OriginalFormat}"; - internal const string OriginalFormatValue = "{httpMethod} {httpHost}/{httpPath}"; + internal const string OriginalFormatValue = + $"{HttpLoggingTagNames.Method} {HttpLoggingTagNames.Host}/{HttpLoggingTagNames.Path}"; internal const string ReadingRequestBodyError = "Error on reading HTTP request body."; internal const string ReadingResponseBodyError = "Error on reading HTTP response body."; @@ -127,8 +128,8 @@ IEnumerator IEnumerable.GetEnumerator() #pragma warning disable LOGGEN000 [LoggerMessage(5, LogLevel.Warning, - $"HttpLogging middleware is injected into application pipeline, but {nameof(LogLevel)} '{{logLevel}}' is disabled in logger. " + - "Remove {methodName}() call from pipeline configuration in that case.")] + $"HttpLogging middleware is injected into application pipeline, but {nameof(LogLevel)} '{{LogLevel}}' is disabled in logger. " + + "Remove {MethodName}() call from pipeline configuration in that case.")] public static partial void MiddlewareIsMisused(this ILogger logger, LogLevel logLevel, string methodName); #pragma warning restore LOGGEN000 diff --git a/src/Libraries/Microsoft.AspNetCore.HeaderParsing/HeaderParsingFeature.cs b/src/Libraries/Microsoft.AspNetCore.HeaderParsing/HeaderParsingFeature.cs index 86f49b3aaeb..b3974603efb 100644 --- a/src/Libraries/Microsoft.AspNetCore.HeaderParsing/HeaderParsingFeature.cs +++ b/src/Libraries/Microsoft.AspNetCore.HeaderParsing/HeaderParsingFeature.cs @@ -198,12 +198,12 @@ private void CopyTo(Box to) } } - [LoggerMessage(LogLevel.Debug, "Can't parse header '{headerName}' due to '{error}'.")] + [LoggerMessage(LogLevel.Debug, "Can't parse header '{HeaderName}' due to '{Error}'.")] private partial void LogParsingError(string headerName, string error); - [LoggerMessage(LogLevel.Debug, "Using a default value for header '{headerName}'.")] + [LoggerMessage(LogLevel.Debug, "Using a default value for header '{HeaderName}'.")] private partial void LogDefaultUsage(string headerName); - [LoggerMessage(LogLevel.Debug, "Header '{headerName}' not found.")] + [LoggerMessage(LogLevel.Debug, "Header '{HeaderName}' not found.")] private partial void LogNotFound(string headerName); } diff --git a/src/Libraries/Microsoft.Extensions.Diagnostics.HealthChecks.Common/Log.cs b/src/Libraries/Microsoft.Extensions.Diagnostics.HealthChecks.Common/Log.cs index 7c4927540ee..8ed8eaf7639 100644 --- a/src/Libraries/Microsoft.Extensions.Diagnostics.HealthChecks.Common/Log.cs +++ b/src/Libraries/Microsoft.Extensions.Diagnostics.HealthChecks.Common/Log.cs @@ -8,13 +8,13 @@ namespace Microsoft.Extensions.Diagnostics.HealthChecks; internal static partial class Log { - [LoggerMessage(0, LogLevel.Warning, "Process reporting unhealthy: {status}. Health check entries are {entries}")] + [LoggerMessage(0, LogLevel.Warning, "Process reporting unhealthy: {Status}. Health check entries are {Entries}")] public static partial void Unhealthy( ILogger logger, HealthStatus status, StringBuilder entries); - [LoggerMessage(1, LogLevel.Debug, "Process reporting healthy: {status}.")] + [LoggerMessage(1, LogLevel.Debug, "Process reporting healthy: {Status}.")] public static partial void Healthy( ILogger logger, HealthStatus status); diff --git a/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/Log.cs b/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/Log.cs index 9e241aa0a4d..d81e431fa7e 100644 --- a/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/Log.cs +++ b/src/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring/Log.cs @@ -14,6 +14,6 @@ internal static partial class Log [LoggerMessage(1, LogLevel.Error, "Unable to gather utilization statistics.")] public static partial void HandledGatherStatisticsException(ILogger logger, Exception e); - [LoggerMessage(2, LogLevel.Error, "Publisher `{publisher}` was unable to publish utilization statistics.")] + [LoggerMessage(2, LogLevel.Error, "Publisher `{Publisher}` was unable to publish utilization statistics.")] public static partial void HandlePublishUtilizationException(ILogger logger, Exception e, string publisher); } diff --git a/src/Libraries/Microsoft.Extensions.Hosting.Testing/HostTerminatorService.cs b/src/Libraries/Microsoft.Extensions.Hosting.Testing/HostTerminatorService.cs index 54b807a1a14..d72936a312d 100644 --- a/src/Libraries/Microsoft.Extensions.Hosting.Testing/HostTerminatorService.cs +++ b/src/Libraries/Microsoft.Extensions.Hosting.Testing/HostTerminatorService.cs @@ -60,7 +60,7 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) _host.Dispose(); } - [LoggerMessage(0, LogLevel.Warning, "FakeHostOptions.TimeToLive set to {timeToLive} is up, disposing the host.")] + [LoggerMessage(0, LogLevel.Warning, "FakeHostOptions.TimeToLive set to {TimeToLive} is up, disposing the host.")] private partial void LogTimeToLiveUp(TimeSpan timeToLive); [LoggerMessage(1, LogLevel.Information, "Debugger is attached. The host won't be automatically disposed.")] diff --git a/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Logging/HttpClientLoggingTagNames.cs b/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Logging/HttpClientLoggingTagNames.cs index 134db3f16e6..e729427b92c 100644 --- a/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Logging/HttpClientLoggingTagNames.cs +++ b/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Logging/HttpClientLoggingTagNames.cs @@ -14,47 +14,47 @@ public static class HttpClientLoggingTagNames /// /// HTTP Request duration. /// - public const string Duration = "duration"; + public const string Duration = "Duration"; /// /// HTTP Host. /// - public const string Host = "httpHost"; + public const string Host = "HttpHost"; /// /// HTTP Method. /// - public const string Method = "httpMethod"; + public const string Method = "HttpMethod"; /// /// HTTP Path. /// - public const string Path = "httpPath"; + public const string Path = "HttpPath"; /// /// HTTP Request Body. /// - public const string RequestBody = "httpRequestBody"; + public const string RequestBody = "HttpRequestBody"; /// /// HTTP Response Body. /// - public const string ResponseBody = "httpResponseBody"; + public const string ResponseBody = "HttpResponseBody"; /// /// HTTP Request Headers prefix. /// - public const string RequestHeaderPrefix = "httpRequestHeader_"; + public const string RequestHeaderPrefix = "HttpRequestHeader."; /// /// HTTP Response Headers prefix. /// - public const string ResponseHeaderPrefix = "httpResponseHeader_"; + public const string ResponseHeaderPrefix = "HttpResponseHeader."; /// /// HTTP Status Code. /// - public const string StatusCode = "httpStatusCode"; + public const string StatusCode = "HttpStatusCode"; /// /// Gets a list of all tag names. diff --git a/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Logging/Internal/Log.cs b/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Logging/Internal/Log.cs index eda39c9833b..6d6e7ae105d 100644 --- a/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Logging/Internal/Log.cs +++ b/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Logging/Internal/Log.cs @@ -15,7 +15,8 @@ namespace Microsoft.Extensions.Http.Logging.Internal; internal static partial class Log { internal const string OriginalFormat = "{OriginalFormat}"; - internal const string OriginalFormatValue = "{httpMethod} {httpHost}/{httpPath}"; + internal const string OriginalFormatValue = + $"{HttpClientLoggingTagNames.Method} {HttpClientLoggingTagNames.Host}/{HttpClientLoggingTagNames.Path}"; private const int MinimalPropertyCount = 4; @@ -28,10 +29,10 @@ internal static partial class Log $"{{{HttpClientLoggingTagNames.Method}}} {{{HttpClientLoggingTagNames.Host}}}/{{{HttpClientLoggingTagNames.Path}}}"; private const string LoggerContextMissingMessage = - $"The logger couldn't read its context for {{requestState}} request: {{{HttpClientLoggingTagNames.Method}}} {{{HttpClientLoggingTagNames.Host}}}"; + $"The logger couldn't read its context for {{RequestState}} request: {{{HttpClientLoggingTagNames.Method}}} {{{HttpClientLoggingTagNames.Host}}}"; private const string EnrichmentErrorMessage = - "An error occurred in enricher '{enricherType}' while enriching the logger context for request: " + + "An error occurred in enricher '{EnricherType}' while enriching the logger context for request: " + $"{{{HttpClientLoggingTagNames.Method}}} {{{HttpClientLoggingTagNames.Host}}}/{{{HttpClientLoggingTagNames.Path}}}"; private static readonly Func _originalFormatValueFMTFunc = OriginalFormatValueFMT; diff --git a/test/Libraries/Microsoft.Extensions.Http.Diagnostics.Tests/Logging/AcceptanceTests.cs b/test/Libraries/Microsoft.Extensions.Http.Diagnostics.Tests/Logging/AcceptanceTests.cs index 3b9b1327183..cdfb3c6e45e 100644 --- a/test/Libraries/Microsoft.Extensions.Http.Diagnostics.Tests/Logging/AcceptanceTests.cs +++ b/test/Libraries/Microsoft.Extensions.Http.Diagnostics.Tests/Logging/AcceptanceTests.cs @@ -321,7 +321,7 @@ public async Task AddHttpClientLogging_RedactSensitivePrams(HttpRouteParameterRe var collector = sp.GetFakeLogCollector(); var logRecord = collector.GetSnapshot().Single(logRecord => logRecord.Category == LoggingCategory); var state = logRecord.State as List>; - state!.Single(kvp => kvp.Key == "httpPath").Value.Should().Be(redactedPath); + state!.Single(kvp => kvp.Key == "HttpPath").Value.Should().Be(redactedPath); } [Theory] @@ -362,7 +362,7 @@ public async Task AddHttpClientLogging_NamedHttpClient_RedactSensitivePrams(Http var collector = sp.GetFakeLogCollector(); var logRecord = collector.GetSnapshot().Single(logRecord => logRecord.Category == LoggingCategory); var state = logRecord.State as List>; - state!.Single(kvp => kvp.Key == "httpPath").Value.Should().Be(redactedPath); + state!.Single(kvp => kvp.Key == "HttpPath").Value.Should().Be(redactedPath); } [Fact] From 5e63fcabc2ded39e69f99c9a07585e777554c82e Mon Sep 17 00:00:00 2001 From: Iliar Turdushev Date: Mon, 9 Oct 2023 18:55:32 +0200 Subject: [PATCH 02/19] Renamed enrichment properties --- .../Enrichment/ApplicationEnricherTags.cs | 8 ++++---- .../Enrichment/ProcessEnricherTagNames.cs | 4 ++-- .../Logging/ExtendedLogger.cs | 2 +- .../Logging/ExtendedLoggerTests.cs | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Libraries/Microsoft.Extensions.Diagnostics.Extra/Enrichment/ApplicationEnricherTags.cs b/src/Libraries/Microsoft.Extensions.Diagnostics.Extra/Enrichment/ApplicationEnricherTags.cs index c8adcb3755f..046f2e476f0 100644 --- a/src/Libraries/Microsoft.Extensions.Diagnostics.Extra/Enrichment/ApplicationEnricherTags.cs +++ b/src/Libraries/Microsoft.Extensions.Diagnostics.Extra/Enrichment/ApplicationEnricherTags.cs @@ -14,22 +14,22 @@ public static class ApplicationEnricherTags /// /// Application name. /// - public const string ApplicationName = "env_app_name"; + public const string ApplicationName = "App.Name"; /// /// Environment name. /// - public const string EnvironmentName = "env_cloud_env"; + public const string EnvironmentName = "Cloud.Env"; /// /// Deployment ring. /// - public const string DeploymentRing = "env_cloud_deploymentRing"; + public const string DeploymentRing = "Cloud.DeploymentRing"; /// /// Build version. /// - public const string BuildVersion = "env_cloud_roleVer"; + public const string BuildVersion = "Cloud.RoleVer"; /// /// Gets a list of all dimension names. diff --git a/src/Libraries/Microsoft.Extensions.Diagnostics.Extra/Enrichment/ProcessEnricherTagNames.cs b/src/Libraries/Microsoft.Extensions.Diagnostics.Extra/Enrichment/ProcessEnricherTagNames.cs index 807b1c122ef..a1c52f357e7 100644 --- a/src/Libraries/Microsoft.Extensions.Diagnostics.Extra/Enrichment/ProcessEnricherTagNames.cs +++ b/src/Libraries/Microsoft.Extensions.Diagnostics.Extra/Enrichment/ProcessEnricherTagNames.cs @@ -14,12 +14,12 @@ public static class ProcessEnricherTagNames /// /// Process ID. /// - public const string ProcessId = "pid"; + public const string ProcessId = "Pid"; /// /// Thread ID. /// - public const string ThreadId = "tid"; + public const string ThreadId = "Tid"; /// /// Gets a list of all dimension names. diff --git a/src/Libraries/Microsoft.Extensions.Diagnostics.Extra/Logging/ExtendedLogger.cs b/src/Libraries/Microsoft.Extensions.Diagnostics.Extra/Logging/ExtendedLogger.cs index d895c6e8d20..6282894ff52 100644 --- a/src/Libraries/Microsoft.Extensions.Diagnostics.Extra/Logging/ExtendedLogger.cs +++ b/src/Libraries/Microsoft.Extensions.Diagnostics.Extra/Logging/ExtendedLogger.cs @@ -21,7 +21,7 @@ namespace Microsoft.Extensions.Logging; internal sealed partial class ExtendedLogger : ILogger { - private const string ExceptionStackTrace = "stackTrace"; + private const string ExceptionStackTrace = "StackTrace"; private readonly ExtendedLoggerFactory _factory; diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.Extra.Tests/Logging/ExtendedLoggerTests.cs b/test/Libraries/Microsoft.Extensions.Diagnostics.Extra.Tests/Logging/ExtendedLoggerTests.cs index 9752d07e743..94aacd7fe71 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.Extra.Tests/Logging/ExtendedLoggerTests.cs +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.Extra.Tests/Logging/ExtendedLoggerTests.cs @@ -485,7 +485,7 @@ public static void Exceptions(bool includeExceptionMessage) Assert.Equal(new EventId(2, "ID2b"), snap[5].Id); Assert.Equal("MSG2b", snap[5].Message); - var stackTrace = snap[5].StructuredState!.GetValue("stackTrace")!; + var stackTrace = snap[5].StructuredState!.GetValue("StackTrace")!; Assert.Contains("AggregateException", stackTrace); Assert.Contains("ArgumentNullException", stackTrace); Assert.Contains("ArgumentOutOfRangeException", stackTrace); From ec04952dfea4fc826b3928459eb9bb3fffff574c Mon Sep 17 00:00:00 2001 From: Iliar Turdushev Date: Tue, 10 Oct 2023 10:48:05 +0200 Subject: [PATCH 03/19] ComplexObjectLogging: use "." instead of "_" --- .../Emission/Emitter.Method.cs | 21 +- .../Generated/LogMethodTests.cs | 4 +- .../Generated/LogPropertiesRedactionTests.cs | 44 ++-- .../Generated/LogPropertiesTests.cs | 198 +++++++++--------- 4 files changed, 135 insertions(+), 132 deletions(-) diff --git a/src/Generators/Microsoft.Gen.Logging/Emission/Emitter.Method.cs b/src/Generators/Microsoft.Gen.Logging/Emission/Emitter.Method.cs index 9a8f48d4bbb..4972fed6b19 100644 --- a/src/Generators/Microsoft.Gen.Logging/Emission/Emitter.Method.cs +++ b/src/Generators/Microsoft.Gen.Logging/Emission/Emitter.Method.cs @@ -14,6 +14,9 @@ namespace Microsoft.Gen.Logging.Emission; internal sealed partial class Emitter : EmitterBase { + private const string PropertySeparator = "."; + private const string NullablePropertySeparator = "?."; + #pragma warning disable CA1505 // Avoid unmaintainable code private void GenLogMethod(LoggingMethod lm) #pragma warning restore CA1505 @@ -316,8 +319,8 @@ void GenPropertyLoads(LoggingMethod lm, string stateName, out int numReservedUnc { if (!member.HasDataClassification) { - var propName = PropertyChainToString(propertyChain, member, "_", omitReferenceName: p.OmitReferenceName); - var accessExpression = PropertyChainToString(propertyChain, member, "?.", nonNullSeparator: "."); + var propName = PropertyChainToString(propertyChain, member, PropertySeparator, omitReferenceName: p.OmitReferenceName); + var accessExpression = PropertyChainToString(propertyChain, member, NullablePropertySeparator, nonNullSeparator: PropertySeparator); var ts = ShouldStringifyProperty(member) ? ConvertPropertyToString(member, accessExpression) @@ -367,8 +370,8 @@ void GenPropertyLoads(LoggingMethod lm, string stateName, out int numReservedUnc { if (member.HasDataClassification) { - var propName = PropertyChainToString(propertyChain, member, "_", omitReferenceName: p.OmitReferenceName); - var accessExpression = PropertyChainToString(propertyChain, member, "?.", nonNullSeparator: "."); + var propName = PropertyChainToString(propertyChain, member, PropertySeparator, omitReferenceName: p.OmitReferenceName); + var accessExpression = PropertyChainToString(propertyChain, member, NullablePropertySeparator, nonNullSeparator: PropertySeparator); var value = ShouldStringifyProperty(member) ? ConvertPropertyToString(member, accessExpression) @@ -391,8 +394,8 @@ void GenPropertyLoads(LoggingMethod lm, string stateName, out int numReservedUnc { if (member.HasDataClassification) { - var propName = PropertyChainToString(propertyChain, member, "_", omitReferenceName: p.OmitReferenceName); - var accessExpression = PropertyChainToString(propertyChain, member, "?.", nonNullSeparator: "."); + var propName = PropertyChainToString(propertyChain, member, PropertySeparator, omitReferenceName: p.OmitReferenceName); + var accessExpression = PropertyChainToString(propertyChain, member, NullablePropertySeparator, nonNullSeparator: PropertySeparator); var value = ShouldStringifyProperty(member) ? ConvertPropertyToString(member, accessExpression) @@ -418,8 +421,8 @@ void GenPropertyLoads(LoggingMethod lm, string stateName, out int numReservedUnc } else { - var propName = PropertyChainToString(propertyChain, member, "_", omitReferenceName: p.OmitReferenceName); - var accessExpression = PropertyChainToString(propertyChain, member, "?.", nonNullSeparator: "."); + var propName = PropertyChainToString(propertyChain, member, PropertySeparator, omitReferenceName: p.OmitReferenceName); + var accessExpression = PropertyChainToString(propertyChain, member, NullablePropertySeparator, nonNullSeparator: PropertySeparator); var ts = ShouldStringifyProperty(member) ? ConvertPropertyToString(member, accessExpression) @@ -630,7 +633,7 @@ private string PropertyChainToString( string? nonNullSeparator = null, bool omitReferenceName = false) { - bool needAts = nonNullSeparator == "."; + bool needAts = nonNullSeparator == PropertySeparator; var adjustedNonNullSeparator = nonNullSeparator ?? separator; var localStringBuilder = _sbPool.GetStringBuilder(); try diff --git a/test/Generators/Microsoft.Gen.Logging/Generated/LogMethodTests.cs b/test/Generators/Microsoft.Gen.Logging/Generated/LogMethodTests.cs index 19e9d8e450b..06fdbb84e68 100644 --- a/test/Generators/Microsoft.Gen.Logging/Generated/LogMethodTests.cs +++ b/test/Generators/Microsoft.Gen.Logging/Generated/LogMethodTests.cs @@ -751,7 +751,7 @@ public void AtSymbolsTest() collector.Clear(); AtSymbolsTestExtensions.M3(logger, LogLevel.Debug, o); - Assert.Equal("42", collector.LatestRecord.StructuredState!.GetValue("event_class")); + Assert.Equal("42", collector.LatestRecord.StructuredState!.GetValue("event.class")); collector.Clear(); AtSymbolsTestExtensions.M5(logger, LogLevel.Debug, o); @@ -892,7 +892,7 @@ public void FormattableTest() collector.Clear(); FormattableTestExtensions.Method2(logger, new FormattableTestExtensions.ComplexObj()); Assert.Equal(1, collector.Count); - Assert.Equal("Formatted!", collector.LatestRecord.StructuredState!.GetValue("p1_P1")); + Assert.Equal("Formatted!", collector.LatestRecord.StructuredState!.GetValue("p1.P1")); collector.Clear(); FormattableTestExtensions.Method3(logger, default); diff --git a/test/Generators/Microsoft.Gen.Logging/Generated/LogPropertiesRedactionTests.cs b/test/Generators/Microsoft.Gen.Logging/Generated/LogPropertiesRedactionTests.cs index a8171954bfe..c42b599b31f 100644 --- a/test/Generators/Microsoft.Gen.Logging/Generated/LogPropertiesRedactionTests.cs +++ b/test/Generators/Microsoft.Gen.Logging/Generated/LogPropertiesRedactionTests.cs @@ -33,7 +33,7 @@ public void RedactsWhenRedactorProviderIsAvailableInTheInstance() var expectedState = new Dictionary { ["P0"] = "----", - ["p1_StringPropertyBase"] = new('-', classToRedact.StringPropertyBase.Length), + ["p1.StringPropertyBase"] = new('-', classToRedact.StringPropertyBase.Length), ["{OriginalFormat}"] = "LogProperties with redaction: {P0}" }; @@ -59,7 +59,7 @@ public void RedactsWhenDefaultAttrCtorAndRedactorProviderIsInTheInstance() var expectedState = new Dictionary { ["p0"] = "----", - ["p1_StringPropertyBase"] = new('-', classToRedact.StringPropertyBase.Length), + ["p1.StringPropertyBase"] = new('-', classToRedact.StringPropertyBase.Length), }; collector.LatestRecord.StructuredState.Should().NotBeNull().And.Equal(expectedState); @@ -81,14 +81,14 @@ public void RedactsWhenLogMethodIsStaticNoParams() var expectedState = new Dictionary { - ["classToLog_StringProperty"] = new('+', classToRedact.StringProperty.Length), - ["classToLog_StringPropertyBase"] = new('-', classToRedact.StringPropertyBase.Length), - ["classToLog_SimplifiedNullableIntProperty"] = classToRedact.SimplifiedNullableIntProperty.ToString(CultureInfo.InvariantCulture), - ["classToLog_GetOnlyProperty"] = new('-', classToRedact.GetOnlyProperty.Length), - ["classToLog_TransitiveProp_TransitiveNumberProp"] = classToRedact.TransitiveProp.TransitiveNumberProp.ToString(CultureInfo.InvariantCulture), - ["classToLog_TransitiveProp_TransitiveStringProp"] = new('-', classToRedact.TransitiveProp.TransitiveStringProp.Length), - ["classToLog_NoRedactionProp"] = classToRedact.NoRedactionProp, - ["classToLog_NonFormattableProperty"] = new('-', classToRedact.NonFormattableProperty.ToString().Length), + ["classToLog.StringProperty"] = new('+', classToRedact.StringProperty.Length), + ["classToLog.StringPropertyBase"] = new('-', classToRedact.StringPropertyBase.Length), + ["classToLog.SimplifiedNullableIntProperty"] = classToRedact.SimplifiedNullableIntProperty.ToString(CultureInfo.InvariantCulture), + ["classToLog.GetOnlyProperty"] = new('-', classToRedact.GetOnlyProperty.Length), + ["classToLog.TransitiveProp.TransitiveNumberProp"] = classToRedact.TransitiveProp.TransitiveNumberProp.ToString(CultureInfo.InvariantCulture), + ["classToLog.TransitiveProp.TransitiveStringProp"] = new('-', classToRedact.TransitiveProp.TransitiveStringProp.Length), + ["classToLog.NoRedactionProp"] = classToRedact.NoRedactionProp, + ["classToLog.NonFormattableProperty"] = new('-', classToRedact.NonFormattableProperty.ToString().Length), ["{OriginalFormat}"] = "No template params" }; @@ -112,14 +112,14 @@ public void RedactsWhenDefaultAttrCtorAndIsStaticNoParams() var expectedState = new Dictionary { - ["classToLog_StringProperty"] = new('+', classToRedact.StringProperty.Length), - ["classToLog_StringPropertyBase"] = new('-', classToRedact.StringPropertyBase.Length), - ["classToLog_SimplifiedNullableIntProperty"] = classToRedact.SimplifiedNullableIntProperty.ToString(CultureInfo.InvariantCulture), - ["classToLog_GetOnlyProperty"] = new('-', classToRedact.GetOnlyProperty.Length), - ["classToLog_TransitiveProp_TransitiveNumberProp"] = classToRedact.TransitiveProp.TransitiveNumberProp.ToString(CultureInfo.InvariantCulture), - ["classToLog_TransitiveProp_TransitiveStringProp"] = new('-', classToRedact.TransitiveProp.TransitiveStringProp.Length), - ["classToLog_NoRedactionProp"] = classToRedact.NoRedactionProp, - ["classToLog_NonFormattableProperty"] = new('-', classToRedact.NonFormattableProperty.ToString().Length), + ["classToLog.StringProperty"] = new('+', classToRedact.StringProperty.Length), + ["classToLog.StringPropertyBase"] = new('-', classToRedact.StringPropertyBase.Length), + ["classToLog.SimplifiedNullableIntProperty"] = classToRedact.SimplifiedNullableIntProperty.ToString(CultureInfo.InvariantCulture), + ["classToLog.GetOnlyProperty"] = new('-', classToRedact.GetOnlyProperty.Length), + ["classToLog.TransitiveProp.TransitiveNumberProp"] = classToRedact.TransitiveProp.TransitiveNumberProp.ToString(CultureInfo.InvariantCulture), + ["classToLog.TransitiveProp.TransitiveStringProp"] = new('-', classToRedact.TransitiveProp.TransitiveStringProp.Length), + ["classToLog.NoRedactionProp"] = classToRedact.NoRedactionProp, + ["classToLog.NonFormattableProperty"] = new('-', classToRedact.NonFormattableProperty.ToString().Length), }; collector.LatestRecord.StructuredState.Should().NotBeNull().And.Equal(expectedState); @@ -142,8 +142,8 @@ public void RedactsWhenLogMethodIsStaticTwoParams() var expectedState = new Dictionary { ["StringProperty"] = "-----------", - ["complexParam_TransitiveNumberProp"] = classToRedact.TransitiveNumberProp.ToString(CultureInfo.InvariantCulture), - ["complexParam_TransitiveStringProp"] = new('-', classToRedact.TransitiveStringProp.Length), + ["complexParam.TransitiveNumberProp"] = classToRedact.TransitiveNumberProp.ToString(CultureInfo.InvariantCulture), + ["complexParam.TransitiveStringProp"] = new('-', classToRedact.TransitiveStringProp.Length), ["{OriginalFormat}"] = "Only {StringProperty} as param" }; @@ -168,8 +168,8 @@ public void RedactsWhenDefaultAttrCtorAndIsStaticTwoParams() var expectedState = new Dictionary { ["stringProperty"] = "-----------", - ["complexParam_TransitiveNumberProp"] = classToRedact.TransitiveNumberProp.ToString(CultureInfo.InvariantCulture), - ["complexParam_TransitiveStringProp"] = new('-', classToRedact.TransitiveStringProp.Length), + ["complexParam.TransitiveNumberProp"] = classToRedact.TransitiveNumberProp.ToString(CultureInfo.InvariantCulture), + ["complexParam.TransitiveStringProp"] = new('-', classToRedact.TransitiveStringProp.Length), }; collector.LatestRecord.StructuredState.Should().NotBeNull().And.Equal(expectedState); diff --git a/test/Generators/Microsoft.Gen.Logging/Generated/LogPropertiesTests.cs b/test/Generators/Microsoft.Gen.Logging/Generated/LogPropertiesTests.cs index a27f0e08584..7c1ff022259 100644 --- a/test/Generators/Microsoft.Gen.Logging/Generated/LogPropertiesTests.cs +++ b/test/Generators/Microsoft.Gen.Logging/Generated/LogPropertiesTests.cs @@ -43,9 +43,9 @@ public void LogPropertiesEnumerables() Assert.Equal(1, _logger.Collector.Count); var ss = _logger.LatestRecord.StructuredState!.ToDictionary(x => x.Key, x => x.Value); - Assert.Equal("[\"1\",\"2\",\"3\"]", ss["myProps_P5"]); - Assert.Equal("[\"4\",\"5\",\"6\"]", ss["myProps_P6"]); - Assert.Equal("{\"Seven\"=\"7\",\"Eight\"=\"8\",\"Nine\"=\"9\"}", ss["myProps_P7"]); + Assert.Equal("[\"1\",\"2\",\"3\"]", ss["myProps.P5"]); + Assert.Equal("[\"4\",\"5\",\"6\"]", ss["myProps.P6"]); + Assert.Equal("{\"Seven\"=\"7\",\"Eight\"=\"8\",\"Nine\"=\"9\"}", ss["myProps.P7"]); } [Fact] @@ -122,29 +122,29 @@ public void LogPropertiesSpecialTypes() Assert.Equal(19, state.Count); #endif - Assert.Equal(props.P0.ToString(CultureInfo.InvariantCulture), state!.GetValue("p_P0")); - Assert.Equal(props.P1.ToString(CultureInfo.InvariantCulture), state!.GetValue("p_P1")); - Assert.Equal(props.P2.ToString(null, CultureInfo.InvariantCulture), state!.GetValue("p_P2")); - Assert.Equal(props.P3.ToString(), state!.GetValue("p_P3")); - Assert.Equal(props.P4.ToString(), state!.GetValue("p_P4")); - Assert.Equal(props.P5.ToString(), state!.GetValue("p_P5")); - Assert.Equal(props.P6.ToString(), state!.GetValue("p_P6")); - Assert.Equal(props.P7.ToString(), state!.GetValue("p_P7")); - Assert.Equal(props.P8.ToString(), state!.GetValue("p_P8")); - Assert.Equal(props.P9.ToString(), state!.GetValue("p_P9")); - Assert.Equal(props.P10.ToString(CultureInfo.InvariantCulture), state!.GetValue("p_P10")); - Assert.Equal(props.P11.ToString(CultureInfo.InvariantCulture), state!.GetValue("p_P11")); - Assert.Equal(props.P12.ToString(), state!.GetValue("p_P12")); - Assert.Equal(props.P13.ToString(), state!.GetValue("p_P13")); - Assert.Equal(props.P14.ToString(), state!.GetValue("p_P14")); - Assert.Equal(props.P15.ToString(), state!.GetValue("p_P15")); - Assert.Equal(props.P16.ToString(), state!.GetValue("p_P16")); - Assert.Equal(props.P17.ToString(), state!.GetValue("p_P17")); - Assert.Equal(props.P18.ToString(), state!.GetValue("p_P18")); + Assert.Equal(props.P0.ToString(CultureInfo.InvariantCulture), state!.GetValue("p.P0")); + Assert.Equal(props.P1.ToString(CultureInfo.InvariantCulture), state!.GetValue("p.P1")); + Assert.Equal(props.P2.ToString(null, CultureInfo.InvariantCulture), state!.GetValue("p.P2")); + Assert.Equal(props.P3.ToString(), state!.GetValue("p.P3")); + Assert.Equal(props.P4.ToString(), state!.GetValue("p.P4")); + Assert.Equal(props.P5.ToString(), state!.GetValue("p.P5")); + Assert.Equal(props.P6.ToString(), state!.GetValue("p.P6")); + Assert.Equal(props.P7.ToString(), state!.GetValue("p.P7")); + Assert.Equal(props.P8.ToString(), state!.GetValue("p.P8")); + Assert.Equal(props.P9.ToString(), state!.GetValue("p.P9")); + Assert.Equal(props.P10.ToString(CultureInfo.InvariantCulture), state!.GetValue("p.P10")); + Assert.Equal(props.P11.ToString(CultureInfo.InvariantCulture), state!.GetValue("p.P11")); + Assert.Equal(props.P12.ToString(), state!.GetValue("p.P12")); + Assert.Equal(props.P13.ToString(), state!.GetValue("p.P13")); + Assert.Equal(props.P14.ToString(), state!.GetValue("p.P14")); + Assert.Equal(props.P15.ToString(), state!.GetValue("p.P15")); + Assert.Equal(props.P16.ToString(), state!.GetValue("p.P16")); + Assert.Equal(props.P17.ToString(), state!.GetValue("p.P17")); + Assert.Equal(props.P18.ToString(), state!.GetValue("p.P18")); #if NET6_0_OR_GREATER - Assert.Equal(props.P19.ToString(CultureInfo.InvariantCulture), state!.GetValue("p_P19")); - Assert.Equal(props.P20.ToString(CultureInfo.InvariantCulture), state!.GetValue("p_P20")); + Assert.Equal(props.P19.ToString(CultureInfo.InvariantCulture), state!.GetValue("p.P19")); + Assert.Equal(props.P20.ToString(CultureInfo.InvariantCulture), state!.GetValue("p.P20")); #endif } @@ -175,17 +175,17 @@ public void LogPropertiesNullHandling() var ss = collector.LatestRecord.StructuredState!.ToDictionary(x => x.Key, x => x.Value); Assert.Equal(11, ss.Count); - Assert.Null(ss["p_P0"]); - Assert.Null(ss["p_P1"]); - Assert.Equal(props.P2.ToString(null, CultureInfo.InvariantCulture), ss["p_P2"]); - Assert.Null(ss["p_P3"]); - Assert.Equal("I refuse to be formatted", ss["p_P4"]); - Assert.Null(ss["p_P5"]); - Assert.Null(ss["p_P6"]); - Assert.Equal("-", ss["p_P7"]); - Assert.Null(ss["p_P8"]); - Assert.Equal("------------------------", ss["p_P9"]); - Assert.Equal("null", ss["p_P10"]); + Assert.Null(ss["p.P0"]); + Assert.Null(ss["p.P1"]); + Assert.Equal(props.P2.ToString(null, CultureInfo.InvariantCulture), ss["p.P2"]); + Assert.Null(ss["p.P3"]); + Assert.Equal("I refuse to be formatted", ss["p.P4"]); + Assert.Null(ss["p.P5"]); + Assert.Null(ss["p.P6"]); + Assert.Equal("-", ss["p.P7"]); + Assert.Null(ss["p.P8"]); + Assert.Equal("------------------------", ss["p.P9"]); + Assert.Equal("null", ss["p.P10"]); collector.Clear(); LogPropertiesNullHandlingExtensions.M1(logger, props); @@ -193,10 +193,10 @@ public void LogPropertiesNullHandling() ss = collector.LatestRecord.StructuredState!.ToDictionary(x => x.Key, x => x.Value); Assert.Equal(4, ss.Count); - Assert.Equal(props.P2.ToString(null, CultureInfo.InvariantCulture), ss["p_P2"]); - Assert.Equal("I refuse to be formatted", ss["p_P4"]); - Assert.Equal("-", ss["p_P7"]); - Assert.Equal("------------------------", ss["p_P9"]); + Assert.Equal(props.P2.ToString(null, CultureInfo.InvariantCulture), ss["p.P2"]); + Assert.Equal("I refuse to be formatted", ss["p.P4"]); + Assert.Equal("-", ss["p.P7"]); + Assert.Equal("------------------------", ss["p.P9"]); } [Fact] @@ -231,60 +231,60 @@ public void LogPropertiesTest() var expectedState = new Dictionary { ["classToLog_StringProperty_1"] = "microsoft.com", - ["classToLog_StringProperty"] = classToLog.StringProperty, - ["classToLog_SimplifiedNullableIntProperty"] = null, - ["classToLog_ExplicitNullableIntProperty"] = classToLog.ExplicitNullableIntProperty.ToString(), - ["classToLog_GetOnlyProperty"] = classToLog.GetOnlyProperty.ToString(CultureInfo.InvariantCulture), - ["classToLog_VirtualPropertyBase"] = classToLog.VirtualPropertyBase, - ["classToLog_NonVirtualPropertyBase"] = classToLog.NonVirtualPropertyBase, - ["classToLog_TransitivePropertyArray"] = LogMethodHelper.Stringify(classToLog.TransitivePropertyArray), - ["classToLog_TransitiveProperty_TransitiveNumberProp"] + ["classToLog.StringProperty"] = classToLog.StringProperty, + ["classToLog.SimplifiedNullableIntProperty"] = null, + ["classToLog.ExplicitNullableIntProperty"] = classToLog.ExplicitNullableIntProperty.ToString(), + ["classToLog.GetOnlyProperty"] = classToLog.GetOnlyProperty.ToString(CultureInfo.InvariantCulture), + ["classToLog.VirtualPropertyBase"] = classToLog.VirtualPropertyBase, + ["classToLog.NonVirtualPropertyBase"] = classToLog.NonVirtualPropertyBase, + ["classToLog.TransitivePropertyArray"] = LogMethodHelper.Stringify(classToLog.TransitivePropertyArray), + ["classToLog.TransitiveProperty.TransitiveNumberProp"] = classToLog.TransitiveProperty.TransitiveNumberProp.ToString(CultureInfo.InvariantCulture), - ["classToLog_TransitiveProperty_TransitiveStringProp"] = classToLog.TransitiveProperty.TransitiveStringProp, - ["classToLog_TransitiveProperty_InnerTransitiveProperty_IntegerProperty"] + ["classToLog.TransitiveProperty.TransitiveStringProp"] = classToLog.TransitiveProperty.TransitiveStringProp, + ["classToLog.TransitiveProperty.InnerTransitiveProperty.IntegerProperty"] = classToLog.TransitiveProperty.InnerTransitiveProperty.IntegerProperty.ToString(CultureInfo.InvariantCulture), - ["classToLog_TransitiveProperty_InnerTransitiveProperty_DateTimeProperty"] + ["classToLog.TransitiveProperty.InnerTransitiveProperty.DateTimeProperty"] = classToLog.TransitiveProperty.InnerTransitiveProperty.DateTimeProperty.ToString(CultureInfo.InvariantCulture), - ["classToLog_AnotherTransitiveProperty_IntegerProperty"] = null, // Since AnotherTransitiveProperty is null - ["classToLog_StringPropertyBase"] = classToLog.StringPropertyBase, - ["classToLog_VirtualInterimProperty"] = classToLog.VirtualInterimProperty.ToInvariantString(), - ["classToLog_InterimProperty"] = classToLog.InterimProperty.ToString(CultureInfo.InvariantCulture), - ["classToLog_TransitiveProperty_TransitiveDerivedProp"] = classToLog.TransitiveProperty.TransitiveDerivedProp.ToInvariantString(), - ["classToLog_TransitiveProperty_TransitiveVirtualProp"] = classToLog.TransitiveProperty.TransitiveVirtualProp.ToInvariantString(), - ["classToLog_TransitiveProperty_TransitiveGenericProp_GenericProp"] + ["classToLog.AnotherTransitiveProperty.IntegerProperty"] = null, // Since AnotherTransitiveProperty is null + ["classToLog.StringPropertyBase"] = classToLog.StringPropertyBase, + ["classToLog.VirtualInterimProperty"] = classToLog.VirtualInterimProperty.ToInvariantString(), + ["classToLog.InterimProperty"] = classToLog.InterimProperty.ToString(CultureInfo.InvariantCulture), + ["classToLog.TransitiveProperty.TransitiveDerivedProp"] = classToLog.TransitiveProperty.TransitiveDerivedProp.ToInvariantString(), + ["classToLog.TransitiveProperty.TransitiveVirtualProp"] = classToLog.TransitiveProperty.TransitiveVirtualProp.ToInvariantString(), + ["classToLog.TransitiveProperty.TransitiveGenericProp.GenericProp"] = classToLog.TransitiveProperty.TransitiveGenericProp.GenericProp, - ["classToLog_PropertyOfGenerics_GenericProp"] = classToLog.PropertyOfGenerics.GenericProp.ToInvariantString(), - ["classToLog_CustomStructProperty_LongProperty"] = classToLog.CustomStructProperty.LongProperty.ToInvariantString(), - ["classToLog_CustomStructProperty_TransitiveStructProperty_DateTimeOffsetProperty"] + ["classToLog.PropertyOfGenerics.GenericProp"] = classToLog.PropertyOfGenerics.GenericProp.ToInvariantString(), + ["classToLog.CustomStructProperty.LongProperty"] = classToLog.CustomStructProperty.LongProperty.ToInvariantString(), + ["classToLog.CustomStructProperty.TransitiveStructProperty.DateTimeOffsetProperty"] = classToLog.CustomStructProperty.TransitiveStructProperty.DateTimeOffsetProperty.ToString(CultureInfo.InvariantCulture), - ["classToLog_CustomStructProperty_NullableTransitiveStructProperty_DateTimeOffsetProperty"] + ["classToLog.CustomStructProperty.NullableTransitiveStructProperty.DateTimeOffsetProperty"] = classToLog.CustomStructProperty.NullableTransitiveStructProperty?.DateTimeOffsetProperty.ToString(CultureInfo.InvariantCulture), - ["classToLog_CustomStructProperty_NullableTransitiveStructProperty2_DateTimeOffsetProperty"] + ["classToLog.CustomStructProperty.NullableTransitiveStructProperty2.DateTimeOffsetProperty"] = classToLog.CustomStructProperty.NullableTransitiveStructProperty2?.DateTimeOffsetProperty.ToString(CultureInfo.InvariantCulture), - ["classToLog_CustomStructNullableProperty_LongProperty"] = classToLog.CustomStructNullableProperty?.LongProperty.ToInvariantString(), - ["classToLog_CustomStructNullableProperty_TransitiveStructProperty_DateTimeOffsetProperty"] + ["classToLog.CustomStructNullableProperty.LongProperty"] = classToLog.CustomStructNullableProperty?.LongProperty.ToInvariantString(), + ["classToLog.CustomStructNullableProperty.TransitiveStructProperty.DateTimeOffsetProperty"] = classToLog.CustomStructNullableProperty?.TransitiveStructProperty.DateTimeOffsetProperty.ToString(CultureInfo.InvariantCulture), - ["classToLog_CustomStructNullableProperty_NullableTransitiveStructProperty_DateTimeOffsetProperty"] + ["classToLog.CustomStructNullableProperty.NullableTransitiveStructProperty.DateTimeOffsetProperty"] = classToLog.CustomStructNullableProperty?.NullableTransitiveStructProperty?.DateTimeOffsetProperty.ToString(CultureInfo.InvariantCulture), - ["classToLog_CustomStructNullableProperty_NullableTransitiveStructProperty2_DateTimeOffsetProperty"] + ["classToLog.CustomStructNullableProperty.NullableTransitiveStructProperty2.DateTimeOffsetProperty"] = classToLog.CustomStructNullableProperty?.NullableTransitiveStructProperty2?.DateTimeOffsetProperty.ToString(CultureInfo.InvariantCulture), - ["classToLog_CustomStructNullableProperty2_LongProperty"] = classToLog.CustomStructNullableProperty2?.LongProperty.ToInvariantString(), - ["classToLog_CustomStructNullableProperty2_TransitiveStructProperty_DateTimeOffsetProperty"] + ["classToLog.CustomStructNullableProperty2.LongProperty"] = classToLog.CustomStructNullableProperty2?.LongProperty.ToInvariantString(), + ["classToLog.CustomStructNullableProperty2.TransitiveStructProperty.DateTimeOffsetProperty"] = classToLog.CustomStructNullableProperty2?.TransitiveStructProperty.DateTimeOffsetProperty.ToString(CultureInfo.InvariantCulture), - ["classToLog_CustomStructNullableProperty2_NullableTransitiveStructProperty_DateTimeOffsetProperty"] + ["classToLog.CustomStructNullableProperty2.NullableTransitiveStructProperty.DateTimeOffsetProperty"] = classToLog.CustomStructNullableProperty2?.NullableTransitiveStructProperty?.DateTimeOffsetProperty.ToString(CultureInfo.InvariantCulture), - ["classToLog_CustomStructNullableProperty2_NullableTransitiveStructProperty2_DateTimeOffsetProperty"] + ["classToLog.CustomStructNullableProperty2.NullableTransitiveStructProperty2.DateTimeOffsetProperty"] = classToLog.CustomStructNullableProperty2?.NullableTransitiveStructProperty2?.DateTimeOffsetProperty.ToString(CultureInfo.InvariantCulture), ["{OriginalFormat}"] = "Only {classToLog_StringProperty_1} as param" @@ -306,7 +306,7 @@ public void LogPropertiesInTemplateTest() { ["StringProperty"] = StringProperty, ["ComplexParam"] = classToLog.ToString(), - ["complexParam_MyProperty"] = classToLog.MyProperty.ToInvariantString(), + ["complexParam.MyProperty"] = classToLog.MyProperty.ToInvariantString(), ["{OriginalFormat}"] = "Both {StringProperty} and {ComplexParam} as params" }; @@ -329,9 +329,9 @@ public void LogPropertiesNonStaticClassTest() var expectedState = new Dictionary { ["P0"] = StringParamValue, - ["p1_MyIntProperty"] = classToLog.MyIntProperty.ToInvariantString(), - ["p1_MyStringProperty"] = classToLog.MyStringProperty, - ["p1_AnotherStringProperty"] = classToLog.AnotherStringProperty, + ["p1.MyIntProperty"] = classToLog.MyIntProperty.ToInvariantString(), + ["p1.MyStringProperty"] = classToLog.MyStringProperty, + ["p1.AnotherStringProperty"] = classToLog.AnotherStringProperty, ["{OriginalFormat}"] = "LogProperties: {P0}" }; @@ -352,14 +352,14 @@ public void LogPropertyTestCustomStruct() var expectedState = new Dictionary { - ["structParam_LongProperty"] = structToLog.LongProperty.ToInvariantString(), - ["structParam_TransitiveStructProperty_DateTimeOffsetProperty"] + ["structParam.LongProperty"] = structToLog.LongProperty.ToInvariantString(), + ["structParam.TransitiveStructProperty.DateTimeOffsetProperty"] = structToLog.TransitiveStructProperty.DateTimeOffsetProperty.ToString(CultureInfo.InvariantCulture), - ["structParam_NullableTransitiveStructProperty_DateTimeOffsetProperty"] + ["structParam.NullableTransitiveStructProperty.DateTimeOffsetProperty"] = structToLog.NullableTransitiveStructProperty?.DateTimeOffsetProperty.ToString(CultureInfo.InvariantCulture), - ["structParam_NullableTransitiveStructProperty2_DateTimeOffsetProperty"] + ["structParam.NullableTransitiveStructProperty2.DateTimeOffsetProperty"] = structToLog.NullableTransitiveStructProperty2.Value.DateTimeOffsetProperty.ToString(CultureInfo.InvariantCulture), ["{OriginalFormat}"] = "Testing non-nullable struct here..." @@ -382,14 +382,14 @@ public void LogPropertyTestCustomNullableStruct() var expectedState = new Dictionary { - ["structParam_LongProperty"] = structToLog.Value.LongProperty.ToInvariantString(), - ["structParam_TransitiveStructProperty_DateTimeOffsetProperty"] + ["structParam.LongProperty"] = structToLog.Value.LongProperty.ToInvariantString(), + ["structParam.TransitiveStructProperty.DateTimeOffsetProperty"] = structToLog.Value.TransitiveStructProperty.DateTimeOffsetProperty.ToString(CultureInfo.InvariantCulture), - ["structParam_NullableTransitiveStructProperty_DateTimeOffsetProperty"] + ["structParam.NullableTransitiveStructProperty.DateTimeOffsetProperty"] = structToLog.Value.NullableTransitiveStructProperty.Value.DateTimeOffsetProperty.ToString(CultureInfo.InvariantCulture), - ["structParam_NullableTransitiveStructProperty2_DateTimeOffsetProperty"] + ["structParam.NullableTransitiveStructProperty2.DateTimeOffsetProperty"] = structToLog.Value.NullableTransitiveStructProperty2?.DateTimeOffsetProperty.ToString(CultureInfo.InvariantCulture), ["{OriginalFormat}"] = "Testing nullable struct here..." @@ -411,10 +411,10 @@ public void LogPropertyTestCustomExplicitNullableStruct() var expectedState = new Dictionary { - ["structParam_LongProperty"] = null, - ["structParam_TransitiveStructProperty_DateTimeOffsetProperty"] = null, - ["structParam_NullableTransitiveStructProperty_DateTimeOffsetProperty"] = null, - ["structParam_NullableTransitiveStructProperty2_DateTimeOffsetProperty"] = null, + ["structParam.LongProperty"] = null, + ["structParam.TransitiveStructProperty.DateTimeOffsetProperty"] = null, + ["structParam.NullableTransitiveStructProperty.DateTimeOffsetProperty"] = null, + ["structParam.NullableTransitiveStructProperty2.DateTimeOffsetProperty"] = null, ["{OriginalFormat}"] = "Testing explicit nullable struct here..." }; @@ -437,7 +437,7 @@ public void LogPropertiesDefaultAttrCtor() var expectedState = new Dictionary { - ["complexParam_MyProperty"] = classToLog.MyProperty.ToInvariantString() + ["complexParam.MyProperty"] = classToLog.MyProperty.ToInvariantString() }; latestRecord.StructuredState.Should().NotBeNull().And.Equal(expectedState); @@ -464,8 +464,8 @@ public void LogPropertiesInterfaceArgument() var expectedState = new Dictionary { - ["complexParam_IntProperty"] = classToLog.IntProperty.ToInvariantString(), - ["complexParam_TransitiveProp_IntegerProperty"] = classToLog.TransitiveProp.IntegerProperty.ToInvariantString(), + ["complexParam.IntProperty"] = classToLog.IntProperty.ToInvariantString(), + ["complexParam.TransitiveProp.IntegerProperty"] = classToLog.TransitiveProp.IntegerProperty.ToInvariantString(), ["{OriginalFormat}"] = "Testing interface-typed argument here..." }; @@ -488,10 +488,10 @@ public void LogPropertiesRecordClassArgument() var expectedState = new Dictionary { - ["p0_Value"] = recordToLog.Value.ToInvariantString(), - ["p0_class"] = recordToLog.@class, - ["p0_GetOnlyValue"] = recordToLog.GetOnlyValue.ToInvariantString(), - ["p0_event"] = recordToLog.@event.ToString(CultureInfo.InvariantCulture) + ["p0.Value"] = recordToLog.Value.ToInvariantString(), + ["p0.class"] = recordToLog.@class, + ["p0.GetOnlyValue"] = recordToLog.GetOnlyValue.ToInvariantString(), + ["p0.event"] = recordToLog.@event.ToString(CultureInfo.InvariantCulture) }; latestRecord.StructuredState.Should().NotBeNull().And.Equal(expectedState); @@ -514,9 +514,9 @@ public void LogPropertiesRecordStructArgument() var expectedState = new Dictionary { ["p0"] = recordToLog.ToString(), - ["p0_IntValue"] = recordToLog.IntValue.ToInvariantString(), - ["p0_StringValue"] = recordToLog.StringValue, - ["p0_GetOnlyValue"] = recordToLog.GetOnlyValue.ToInvariantString(), + ["p0.IntValue"] = recordToLog.IntValue.ToInvariantString(), + ["p0.StringValue"] = recordToLog.StringValue, + ["p0.GetOnlyValue"] = recordToLog.GetOnlyValue.ToInvariantString(), ["{OriginalFormat}"] = "Struct is: {p0}" }; @@ -540,9 +540,9 @@ public void LogPropertiesReadonlyRecordStructArgument() var expectedState = new Dictionary { ["p0"] = recordToLog.ToString(), - ["p0_IntValue"] = recordToLog.IntValue.ToInvariantString(), - ["p0_StringValue"] = recordToLog.StringValue, - ["p0_GetOnlyValue"] = recordToLog.GetOnlyValue.ToInvariantString(), + ["p0.IntValue"] = recordToLog.IntValue.ToInvariantString(), + ["p0.StringValue"] = recordToLog.StringValue, + ["p0.GetOnlyValue"] = recordToLog.GetOnlyValue.ToInvariantString(), ["{OriginalFormat}"] = "Readonly struct is: {p0}" }; From 0fb8cd823ce525f7ec072284b266a6c7089bb61d Mon Sep 17 00:00:00 2001 From: Iliar Turdushev Date: Tue, 10 Oct 2023 10:54:51 +0200 Subject: [PATCH 04/19] Fixed a test --- .../Microsoft.Gen.Logging/Generated/TagProviderTests.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/Generators/Microsoft.Gen.Logging/Generated/TagProviderTests.cs b/test/Generators/Microsoft.Gen.Logging/Generated/TagProviderTests.cs index 2ecbbfaf193..f290d9b1e50 100644 --- a/test/Generators/Microsoft.Gen.Logging/Generated/TagProviderTests.cs +++ b/test/Generators/Microsoft.Gen.Logging/Generated/TagProviderTests.cs @@ -313,9 +313,9 @@ public void LogsWhenProviderCombinedWithLogProperties() var expectedState = new Dictionary { - ["param1_MyIntProperty"] = classToLog.MyIntProperty.ToInvariantString(), - ["param1_MyStringProperty"] = classToLog.MyStringProperty, - ["param1_AnotherStringProperty"] = classToLog.AnotherStringProperty, + ["param1.MyIntProperty"] = classToLog.MyIntProperty.ToInvariantString(), + ["param1.MyStringProperty"] = classToLog.MyStringProperty, + ["param1.AnotherStringProperty"] = classToLog.AnotherStringProperty, ["param2_MyIntProperty"] = classToLog.MyIntProperty.ToInvariantString(), ["param2_Custom_property_name"] = classToLog.MyStringProperty, ["{OriginalFormat}"] = "No params." From 8f00e79deb2bc0706c99a3c223231bab0e7c5cba Mon Sep 17 00:00:00 2001 From: Iliar Turdushev Date: Tue, 10 Oct 2023 13:39:34 +0200 Subject: [PATCH 05/19] Make dimension names in HTTP Client Logging consistent with HTTP Logging --- .../Logging/HttpClientLoggingTagNames.cs | 16 ++++++++-------- .../Logging/Internal/Log.cs | 10 +++++----- .../Logging/AcceptanceTests.cs | 8 ++++---- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Logging/HttpClientLoggingTagNames.cs b/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Logging/HttpClientLoggingTagNames.cs index e729427b92c..97d729b8c04 100644 --- a/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Logging/HttpClientLoggingTagNames.cs +++ b/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Logging/HttpClientLoggingTagNames.cs @@ -19,42 +19,42 @@ public static class HttpClientLoggingTagNames /// /// HTTP Host. /// - public const string Host = "HttpHost"; + public const string Host = "Host"; /// /// HTTP Method. /// - public const string Method = "HttpMethod"; + public const string Method = "Method"; /// /// HTTP Path. /// - public const string Path = "HttpPath"; + public const string Path = "Path"; /// /// HTTP Request Body. /// - public const string RequestBody = "HttpRequestBody"; + public const string RequestBody = "RequestBody"; /// /// HTTP Response Body. /// - public const string ResponseBody = "HttpResponseBody"; + public const string ResponseBody = "ResponseBody"; /// /// HTTP Request Headers prefix. /// - public const string RequestHeaderPrefix = "HttpRequestHeader."; + public const string RequestHeaderPrefix = "RequestHeader."; /// /// HTTP Response Headers prefix. /// - public const string ResponseHeaderPrefix = "HttpResponseHeader."; + public const string ResponseHeaderPrefix = "ResponseHeader."; /// /// HTTP Status Code. /// - public const string StatusCode = "HttpStatusCode"; + public const string StatusCode = "StatusCode"; /// /// Gets a list of all tag names. diff --git a/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Logging/Internal/Log.cs b/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Logging/Internal/Log.cs index 6d6e7ae105d..964891e9f06 100644 --- a/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Logging/Internal/Log.cs +++ b/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Logging/Internal/Log.cs @@ -32,7 +32,7 @@ internal static partial class Log $"The logger couldn't read its context for {{RequestState}} request: {{{HttpClientLoggingTagNames.Method}}} {{{HttpClientLoggingTagNames.Host}}}"; private const string EnrichmentErrorMessage = - "An error occurred in enricher '{EnricherType}' while enriching the logger context for request: " + + "An error occurred in enricher '{Enricher}' while enriching the logger context for request: " + $"{{{HttpClientLoggingTagNames.Method}}} {{{HttpClientLoggingTagNames.Host}}}/{{{HttpClientLoggingTagNames.Path}}}"; private static readonly Func _originalFormatValueFMTFunc = OriginalFormatValueFMT; @@ -48,16 +48,16 @@ public static void OutgoingRequestError(ILogger logger, LogRecord record, Except } [LoggerMessage(LogLevel.Error, RequestReadErrorMessage)] - public static partial void RequestReadError(ILogger logger, Exception exception, HttpMethod httpMethod, string? httpHost, string? httpPath); + public static partial void RequestReadError(ILogger logger, Exception exception, HttpMethod method, string? host, string? path); [LoggerMessage(LogLevel.Error, ResponseReadErrorMessage)] - public static partial void ResponseReadError(ILogger logger, Exception exception, HttpMethod httpMethod, string httpHost, string httpPath); + public static partial void ResponseReadError(ILogger logger, Exception exception, HttpMethod method, string host, string path); [LoggerMessage(LogLevel.Error, LoggerContextMissingMessage)] - public static partial void LoggerContextMissing(ILogger logger, Exception? exception, string requestState, HttpMethod httpMethod, string? httpHost); + public static partial void LoggerContextMissing(ILogger logger, Exception? exception, string requestState, HttpMethod method, string? host); [LoggerMessage(LogLevel.Error, EnrichmentErrorMessage)] - public static partial void EnrichmentError(ILogger logger, Exception exception, string? enricherType, HttpMethod httpMethod, string httpHost, string httpPath); + public static partial void EnrichmentError(ILogger logger, Exception exception, string? enricher, HttpMethod method, string host, string path); // Using the code below instead of generated logging method because we have a custom formatter and custom tag keys for headers. private static void OutgoingRequest( diff --git a/test/Libraries/Microsoft.Extensions.Http.Diagnostics.Tests/Logging/AcceptanceTests.cs b/test/Libraries/Microsoft.Extensions.Http.Diagnostics.Tests/Logging/AcceptanceTests.cs index cdfb3c6e45e..57e40989b92 100644 --- a/test/Libraries/Microsoft.Extensions.Http.Diagnostics.Tests/Logging/AcceptanceTests.cs +++ b/test/Libraries/Microsoft.Extensions.Http.Diagnostics.Tests/Logging/AcceptanceTests.cs @@ -287,7 +287,7 @@ public async Task AddHttpClientLogging_WithTypedHttpClients_WorksCorrectly() [InlineData(HttpRouteParameterRedactionMode.Strict, "v1/unit/REDACTED/users/REDACTED:123")] [InlineData(HttpRouteParameterRedactionMode.Loose, "v1/unit/999/users/REDACTED:123")] [InlineData(HttpRouteParameterRedactionMode.None, "/v1/unit/999/users/123")] - public async Task AddHttpClientLogging_RedactSensitivePrams(HttpRouteParameterRedactionMode parameterRedactionMode, string redactedPath) + public async Task AddHttpClientLogging_RedactSensitiveParams(HttpRouteParameterRedactionMode parameterRedactionMode, string redactedPath) { const string RequestPath = "https://fake.com/v1/unit/999/users/123"; @@ -321,13 +321,13 @@ public async Task AddHttpClientLogging_RedactSensitivePrams(HttpRouteParameterRe var collector = sp.GetFakeLogCollector(); var logRecord = collector.GetSnapshot().Single(logRecord => logRecord.Category == LoggingCategory); var state = logRecord.State as List>; - state!.Single(kvp => kvp.Key == "HttpPath").Value.Should().Be(redactedPath); + state!.Single(kvp => kvp.Key == HttpClientLoggingTagNames.Path).Value.Should().Be(redactedPath); } [Theory] [InlineData(HttpRouteParameterRedactionMode.Strict, "v1/unit/REDACTED/users/REDACTED:123")] [InlineData(HttpRouteParameterRedactionMode.Loose, "v1/unit/999/users/REDACTED:123")] - public async Task AddHttpClientLogging_NamedHttpClient_RedactSensitivePrams(HttpRouteParameterRedactionMode parameterRedactionMode, string redactedPath) + public async Task AddHttpClientLogging_NamedHttpClient_RedactSensitiveParams(HttpRouteParameterRedactionMode parameterRedactionMode, string redactedPath) { const string RequestPath = "https://fake.com/v1/unit/999/users/123"; @@ -362,7 +362,7 @@ public async Task AddHttpClientLogging_NamedHttpClient_RedactSensitivePrams(Http var collector = sp.GetFakeLogCollector(); var logRecord = collector.GetSnapshot().Single(logRecord => logRecord.Category == LoggingCategory); var state = logRecord.State as List>; - state!.Single(kvp => kvp.Key == "HttpPath").Value.Should().Be(redactedPath); + state!.Single(kvp => kvp.Key == HttpClientLoggingTagNames.Path).Value.Should().Be(redactedPath); } [Fact] From c93c1a012a22197be5cfdef82565dda25d9a2dd5 Mon Sep 17 00:00:00 2001 From: Iliar Turdushev Date: Tue, 10 Oct 2023 13:46:04 +0200 Subject: [PATCH 06/19] Renamed AppEnricher's dimensions --- .../Enrichment/ApplicationEnricherTags.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Libraries/Microsoft.Extensions.Diagnostics.Extra/Enrichment/ApplicationEnricherTags.cs b/src/Libraries/Microsoft.Extensions.Diagnostics.Extra/Enrichment/ApplicationEnricherTags.cs index ea0807b0d44..046f2e476f0 100644 --- a/src/Libraries/Microsoft.Extensions.Diagnostics.Extra/Enrichment/ApplicationEnricherTags.cs +++ b/src/Libraries/Microsoft.Extensions.Diagnostics.Extra/Enrichment/ApplicationEnricherTags.cs @@ -14,22 +14,22 @@ public static class ApplicationEnricherTags /// /// Application name. /// - public const string ApplicationName = "AppName"; + public const string ApplicationName = "App.Name"; /// /// Environment name. /// - public const string EnvironmentName = "CloudEnv"; + public const string EnvironmentName = "Cloud.Env"; /// /// Deployment ring. /// - public const string DeploymentRing = "CloudDeploymentRing"; + public const string DeploymentRing = "Cloud.DeploymentRing"; /// /// Build version. /// - public const string BuildVersion = "CloudRoleVer"; + public const string BuildVersion = "Cloud.RoleVer"; /// /// Gets a list of all dimension names. From 58afe44ad92925728840d9b10e43047da9cc2d33 Mon Sep 17 00:00:00 2001 From: Iliar Turdushev Date: Wed, 11 Oct 2023 11:17:45 +0200 Subject: [PATCH 07/19] Addressing PR comments --- .../Latency/Internal/HttpClientLatencyLogEnricher.cs | 2 +- .../Logging/Internal/Log.cs | 2 -- .../Latency/Internal/HttpClientLatencyLogEnricherTest.cs | 4 ++-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Latency/Internal/HttpClientLatencyLogEnricher.cs b/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Latency/Internal/HttpClientLatencyLogEnricher.cs index 12cc3d98149..bad9b23a415 100644 --- a/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Latency/Internal/HttpClientLatencyLogEnricher.cs +++ b/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Latency/Internal/HttpClientLatencyLogEnricher.cs @@ -50,7 +50,7 @@ public void Enrich(IEnrichmentTagCollector collector, HttpRequestMessage request AppendCheckpoints(lc, stringBuilder); } - collector.Add("latencyInfo", stringBuilder.ToString()); + collector.Add("LatencyInfo", stringBuilder.ToString()); _builderPool.Return(stringBuilder); } diff --git a/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Logging/Internal/Log.cs b/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Logging/Internal/Log.cs index 964891e9f06..0de61da9e10 100644 --- a/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Logging/Internal/Log.cs +++ b/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Logging/Internal/Log.cs @@ -15,8 +15,6 @@ namespace Microsoft.Extensions.Http.Logging.Internal; internal static partial class Log { internal const string OriginalFormat = "{OriginalFormat}"; - internal const string OriginalFormatValue = - $"{HttpClientLoggingTagNames.Method} {HttpClientLoggingTagNames.Host}/{HttpClientLoggingTagNames.Path}"; private const int MinimalPropertyCount = 4; diff --git a/test/Libraries/Microsoft.Extensions.Http.Diagnostics.Tests/Latency/Internal/HttpClientLatencyLogEnricherTest.cs b/test/Libraries/Microsoft.Extensions.Http.Diagnostics.Tests/Latency/Internal/HttpClientLatencyLogEnricherTest.cs index 7c298cc46d5..71941df0e7e 100644 --- a/test/Libraries/Microsoft.Extensions.Http.Diagnostics.Tests/Latency/Internal/HttpClientLatencyLogEnricherTest.cs +++ b/test/Libraries/Microsoft.Extensions.Http.Diagnostics.Tests/Latency/Internal/HttpClientLatencyLogEnricherTest.cs @@ -48,7 +48,7 @@ public void HttpClientLatencyLogEnricher_Enriches_OnResponseWithoutHeader() Mock mockEnrichmentPropertyBag = new Mock(); enricher.Enrich(mockEnrichmentPropertyBag.Object, null!, httpResponseMessage, null); - mockEnrichmentPropertyBag.Verify(m => m.Add(It.Is(s => s.Equals("latencyInfo")), It.Is(s => s.Contains("a/b"))), Times.Once); + mockEnrichmentPropertyBag.Verify(m => m.Add(It.Is(s => s.Equals("LatencyInfo")), It.Is(s => s.Contains("a/b"))), Times.Once); } [Fact] @@ -70,6 +70,6 @@ public void HttpClientLatencyLogEnricher_Enriches_OnResponseWithHeader() Mock mockEnrichmentPropertyBag = new Mock(); enricher.Enrich(mockEnrichmentPropertyBag.Object, null!, httpResponseMessage, null); - mockEnrichmentPropertyBag.Verify(m => m.Add(It.Is(s => s.Equals("latencyInfo")), It.Is(s => s.Contains("a/b") && s.Contains(serverName))), Times.Once); + mockEnrichmentPropertyBag.Verify(m => m.Add(It.Is(s => s.Equals("LatencyInfo")), It.Is(s => s.Contains("a/b") && s.Contains(serverName))), Times.Once); } } From 8ea197b962174f1c3aeefb5801eb0d8958fce16b Mon Sep 17 00:00:00 2001 From: Iliar Turdushev Date: Thu, 12 Oct 2023 11:00:14 +0200 Subject: [PATCH 08/19] Reverted changes to StackTrace logging Use dot "." instead of underscore "_" for tags provider --- .../Logging/ExtendedLogger.cs | 2 +- .../LoggerMessageState.TagCollector.cs | 2 +- .../Generated/TagProviderTests.cs | 54 +++++++++---------- .../Logging/ExtendedLoggerTests.cs | 2 +- .../Logging/LoggerMessageStateTests.cs | 6 +-- 5 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/Libraries/Microsoft.Extensions.Diagnostics.Extra/Logging/ExtendedLogger.cs b/src/Libraries/Microsoft.Extensions.Diagnostics.Extra/Logging/ExtendedLogger.cs index 23889067d48..02711d97be7 100644 --- a/src/Libraries/Microsoft.Extensions.Diagnostics.Extra/Logging/ExtendedLogger.cs +++ b/src/Libraries/Microsoft.Extensions.Diagnostics.Extra/Logging/ExtendedLogger.cs @@ -21,7 +21,7 @@ namespace Microsoft.Extensions.Logging; internal sealed partial class ExtendedLogger : ILogger { - private const string ExceptionStackTrace = "StackTrace"; + private const string ExceptionStackTrace = "stackTrace"; private readonly ExtendedLoggerFactory _factory; diff --git a/src/Libraries/Microsoft.Extensions.Diagnostics.ExtraAbstractions/Logging/LoggerMessageState.TagCollector.cs b/src/Libraries/Microsoft.Extensions.Diagnostics.ExtraAbstractions/Logging/LoggerMessageState.TagCollector.cs index c9b9dbe6296..501ce699aad 100644 --- a/src/Libraries/Microsoft.Extensions.Diagnostics.ExtraAbstractions/Logging/LoggerMessageState.TagCollector.cs +++ b/src/Libraries/Microsoft.Extensions.Diagnostics.ExtraAbstractions/Logging/LoggerMessageState.TagCollector.cs @@ -7,7 +7,7 @@ namespace Microsoft.Extensions.Logging; public partial class LoggerMessageState : ITagCollector { - private const char Separator = '_'; + private const char Separator = '.'; /// void ITagCollector.Add(string tagName, object? tagValue) diff --git a/test/Generators/Microsoft.Gen.Logging/Generated/TagProviderTests.cs b/test/Generators/Microsoft.Gen.Logging/Generated/TagProviderTests.cs index f290d9b1e50..1ce9ca8564a 100644 --- a/test/Generators/Microsoft.Gen.Logging/Generated/TagProviderTests.cs +++ b/test/Generators/Microsoft.Gen.Logging/Generated/TagProviderTests.cs @@ -37,7 +37,7 @@ public void LogsWithObject() var expectedState = new Dictionary { ["Param"] = obj.ToString(), - ["param_ToString"] = obj + " ProvidePropertiesCall", + ["param.ToString"] = obj + " ProvidePropertiesCall", ["{OriginalFormat}"] = "Custom provided properties for {Param}." }; @@ -61,8 +61,8 @@ public void LogsWhenNonStaticClass() { ["P0"] = StringParamValue, ["P1"] = classToLog.ToString(), - ["p1_MyIntProperty"] = classToLog.MyIntProperty.ToInvariantString(), - ["p1_Custom_property_name"] = classToLog.MyStringProperty, + ["p1.MyIntProperty"] = classToLog.MyIntProperty.ToInvariantString(), + ["p1.Custom_property_name"] = classToLog.MyStringProperty, ["{OriginalFormat}"] = "LogProperties with provider: {P0}, {P1}" }; @@ -87,8 +87,8 @@ public void LogsWhenDefaultAttrCtorInNonStaticClass() var expectedState = new Dictionary { ["p0"] = StringParamValue, - ["p1_MyIntProperty"] = classToLog.MyIntProperty.ToInvariantString(), - ["p1_Custom_property_name"] = classToLog.MyStringProperty + ["p1.MyIntProperty"] = classToLog.MyIntProperty.ToInvariantString(), + ["p1.Custom_property_name"] = classToLog.MyStringProperty }; latestRecord.StructuredState.Should().NotBeNull().And.Equal(expectedState); @@ -109,8 +109,8 @@ public void LogsWhenDefaultAttrCtorInStaticClass() var expectedState = new Dictionary { - ["param_MyIntProperty"] = classToLog.MyIntProperty.ToInvariantString(), - ["param_Custom_property_name"] = classToLog.MyStringProperty + ["param.MyIntProperty"] = classToLog.MyIntProperty.ToInvariantString(), + ["param.Custom_property_name"] = classToLog.MyStringProperty }; latestRecord.StructuredState.Should().NotBeNull().And.Equal(expectedState); @@ -141,7 +141,7 @@ public void LogsWithNullable() var expectedState = new Dictionary { - ["param_P1"] = "42", + ["param.P1"] = "42", }; latestRecord.StructuredState.Should().NotBeNull().And.Equal(expectedState); @@ -250,8 +250,8 @@ public void LogsWhenNonNullStronglyTypedObject() var expectedState = new Dictionary { ["Param"] = classToLog.ToString(), - ["param_MyIntProperty"] = classToLog.MyIntProperty.ToInvariantString(), - ["param_Custom_property_name"] = classToLog.MyStringProperty, + ["param.MyIntProperty"] = classToLog.MyIntProperty.ToInvariantString(), + ["param.Custom_property_name"] = classToLog.MyStringProperty, ["{OriginalFormat}"] = "Custom provided properties for {Param}." }; @@ -271,8 +271,8 @@ public void LogsWhenStruct() var expectedState = new Dictionary { - ["param_MyIntProperty"] = structToLog.MyIntProperty.ToInvariantString(), - ["param_Custom_property_name"] = structToLog.MyStringProperty, + ["param.MyIntProperty"] = structToLog.MyIntProperty.ToInvariantString(), + ["param.Custom_property_name"] = structToLog.MyStringProperty, ["{OriginalFormat}"] = "Custom provided properties for struct." }; @@ -292,8 +292,8 @@ public void LogsWhenInterface() var expectedState = new Dictionary { - ["param_MyIntProperty"] = interfaceToLog.MyIntProperty.ToInvariantString(), - ["param_Custom_property_name"] = interfaceToLog.MyStringProperty, + ["param.MyIntProperty"] = interfaceToLog.MyIntProperty.ToInvariantString(), + ["param.Custom_property_name"] = interfaceToLog.MyStringProperty, ["{OriginalFormat}"] = "Custom provided properties for interface." }; @@ -316,8 +316,8 @@ public void LogsWhenProviderCombinedWithLogProperties() ["param1.MyIntProperty"] = classToLog.MyIntProperty.ToInvariantString(), ["param1.MyStringProperty"] = classToLog.MyStringProperty, ["param1.AnotherStringProperty"] = classToLog.AnotherStringProperty, - ["param2_MyIntProperty"] = classToLog.MyIntProperty.ToInvariantString(), - ["param2_Custom_property_name"] = classToLog.MyStringProperty, + ["param2.MyIntProperty"] = classToLog.MyIntProperty.ToInvariantString(), + ["param2.Custom_property_name"] = classToLog.MyStringProperty, ["{OriginalFormat}"] = "No params." }; @@ -341,10 +341,10 @@ public void LogsTwoStronglyTypedParams() var expectedState = new Dictionary { ["StringParam"] = StringParamValue, - ["param_MyIntProperty"] = classToLog1.MyIntProperty.ToInvariantString(), - ["param_Custom_property_name"] = classToLog1.MyStringProperty, - ["param2_Another_property_name"] = classToLog2.MyStringProperty.ToUpperInvariant(), - ["param2_MyIntProperty_test"] = classToLog2.MyIntProperty.ToInvariantString(), + ["param.MyIntProperty"] = classToLog1.MyIntProperty.ToInvariantString(), + ["param.Custom_property_name"] = classToLog1.MyStringProperty, + ["param2.Another_property_name"] = classToLog2.MyStringProperty.ToUpperInvariant(), + ["param2.MyIntProperty_test"] = classToLog2.MyIntProperty.ToInvariantString(), ["{OriginalFormat}"] = "Custom provided properties for both complex params and {StringParam}." }; @@ -356,8 +356,8 @@ public void LogsTwoStronglyTypedParams() TagProviderExtensions.LogMethodCustomPropsProviderTwoParams(_logger, StringParamValue, classToLog1, classToLog2); Assert.Equal(2, _logger.Collector.Count); - expectedState["param_MyIntProperty"] = classToLog1.MyIntProperty.ToInvariantString(); - expectedState["param2_MyIntProperty_test"] = classToLog2.MyIntProperty.ToInvariantString(); + expectedState["param.MyIntProperty"] = classToLog1.MyIntProperty.ToInvariantString(); + expectedState["param2.MyIntProperty_test"] = classToLog2.MyIntProperty.ToInvariantString(); _logger.Collector.LatestRecord.StructuredState.Should().NotBeNull().And.Equal(expectedState); } @@ -379,9 +379,9 @@ public void LogsTwoObjectParams() var expectedState = new Dictionary { ["StringParam"] = StringParamValue, - ["param_ToString"] = obj1 + " ProvidePropertiesCall", - ["param2_Type"] = obj2.GetType().ToString(), - ["param2_ToString"] = obj2 + " ProvideOtherPropertiesCall", + ["param.ToString"] = obj1 + " ProvidePropertiesCall", + ["param2.Type"] = obj2.GetType().ToString(), + ["param2.ToString"] = obj2 + " ProvideOtherPropertiesCall", ["{OriginalFormat}"] = "Custom provided properties for both complex params and {StringParam}." }; @@ -404,8 +404,8 @@ public void LogsTwoNullObjectParams() var expectedState = new Dictionary { ["StringParam"] = StringParamValue, - ["param2_Type"] = null, - ["param2_ToString"] = " ProvideOtherPropertiesCall", + ["param2.Type"] = null, + ["param2.ToString"] = " ProvideOtherPropertiesCall", ["{OriginalFormat}"] = "Custom provided properties for both complex params and {StringParam}." }; diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.Extra.Tests/Logging/ExtendedLoggerTests.cs b/test/Libraries/Microsoft.Extensions.Diagnostics.Extra.Tests/Logging/ExtendedLoggerTests.cs index fdbd1d6f36e..4b699558376 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.Extra.Tests/Logging/ExtendedLoggerTests.cs +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.Extra.Tests/Logging/ExtendedLoggerTests.cs @@ -429,7 +429,7 @@ public static void Exceptions(bool includeExceptionMessage) Assert.Equal(new EventId(2, "ID2b"), snap[3].Id); Assert.Equal("MSG2b", snap[3].Message); - var stackTrace = snap[3].StructuredState!.GetValue("StackTrace")!; + var stackTrace = snap[3].StructuredState!.GetValue("stackTrace")!; Assert.Contains("AggregateException", stackTrace); Assert.Contains("ArgumentNullException", stackTrace); Assert.Contains("ArgumentOutOfRangeException", stackTrace); diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ExtraAbstractions.Tests/Logging/LoggerMessageStateTests.cs b/test/Libraries/Microsoft.Extensions.Diagnostics.ExtraAbstractions.Tests/Logging/LoggerMessageStateTests.cs index 62ddebbe72a..e2123fc7010 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ExtraAbstractions.Tests/Logging/LoggerMessageStateTests.cs +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ExtraAbstractions.Tests/Logging/LoggerMessageStateTests.cs @@ -93,16 +93,16 @@ public static void CollectorContract() collector.Add(PropName, Value); Assert.Equal(1, lms.TagsCount); - Assert.Equal(PropertyNamPrefix + "_" + PropName, lms.TagArray[0].Key); + Assert.Equal(PropertyNamPrefix + "." + PropName, lms.TagArray[0].Key); Assert.Equal(Value, lms.TagArray[0].Value); collector.Add(PropName, Value, FakeClassifications.PrivateData); Assert.Equal(1, lms.TagsCount); - Assert.Equal(PropertyNamPrefix + "_" + PropName, lms.TagArray[0].Key); + Assert.Equal(PropertyNamPrefix + "." + PropName, lms.TagArray[0].Key); Assert.Equal(Value, lms.TagArray[0].Value); Assert.Equal(1, lms.ClassifiedTagsCount); - Assert.Equal(PropertyNamPrefix + "_" + PropName, lms.ClassifiedTagArray[0].Name); + Assert.Equal(PropertyNamPrefix + "." + PropName, lms.ClassifiedTagArray[0].Name); Assert.Equal(Value, lms.ClassifiedTagArray[0].Value); Assert.Equal(FakeClassifications.PrivateData, lms.ClassifiedTagArray[0].Classification); From 274efcd3e1600147ec72017c16d9f062e073ffd4 Mon Sep 17 00:00:00 2001 From: Iliar Turdushev Date: Thu, 12 Oct 2023 14:27:21 +0200 Subject: [PATCH 09/19] Apply semantic-conventions to Application and Process enrichers --- .../Enrichment/ApplicationEnricherTags.cs | 8 ++++---- .../Enrichment/ProcessEnricherTagNames.cs | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Libraries/Microsoft.Extensions.Diagnostics.Extra/Enrichment/ApplicationEnricherTags.cs b/src/Libraries/Microsoft.Extensions.Diagnostics.Extra/Enrichment/ApplicationEnricherTags.cs index 046f2e476f0..60c4017c63c 100644 --- a/src/Libraries/Microsoft.Extensions.Diagnostics.Extra/Enrichment/ApplicationEnricherTags.cs +++ b/src/Libraries/Microsoft.Extensions.Diagnostics.Extra/Enrichment/ApplicationEnricherTags.cs @@ -14,22 +14,22 @@ public static class ApplicationEnricherTags /// /// Application name. /// - public const string ApplicationName = "App.Name"; + public const string ApplicationName = "service.name"; /// /// Environment name. /// - public const string EnvironmentName = "Cloud.Env"; + public const string EnvironmentName = "deployment.environment"; /// /// Deployment ring. /// - public const string DeploymentRing = "Cloud.DeploymentRing"; + public const string DeploymentRing = "DeploymentRing"; /// /// Build version. /// - public const string BuildVersion = "Cloud.RoleVer"; + public const string BuildVersion = "service.version"; /// /// Gets a list of all dimension names. diff --git a/src/Libraries/Microsoft.Extensions.Diagnostics.Extra/Enrichment/ProcessEnricherTagNames.cs b/src/Libraries/Microsoft.Extensions.Diagnostics.Extra/Enrichment/ProcessEnricherTagNames.cs index a1c52f357e7..fc7698f3caa 100644 --- a/src/Libraries/Microsoft.Extensions.Diagnostics.Extra/Enrichment/ProcessEnricherTagNames.cs +++ b/src/Libraries/Microsoft.Extensions.Diagnostics.Extra/Enrichment/ProcessEnricherTagNames.cs @@ -14,12 +14,12 @@ public static class ProcessEnricherTagNames /// /// Process ID. /// - public const string ProcessId = "Pid"; + public const string ProcessId = "process.pid"; /// /// Thread ID. /// - public const string ThreadId = "Tid"; + public const string ThreadId = "thread.id"; /// /// Gets a list of all dimension names. From 2f324a7ffb26e946fc97581194c1578f48424c81 Mon Sep 17 00:00:00 2001 From: Iliar Turdushev Date: Fri, 13 Oct 2023 07:02:13 +0200 Subject: [PATCH 10/19] Apply semantic-conventions to HttpLogging --- .../Logging/HttpLoggingTagNames.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/HttpLoggingTagNames.cs b/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/HttpLoggingTagNames.cs index 548c82babfc..4ce5bb6055b 100644 --- a/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/HttpLoggingTagNames.cs +++ b/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/HttpLoggingTagNames.cs @@ -19,7 +19,7 @@ public static class HttpLoggingTagNames /// /// HTTP Host. /// - public const string Host = "Host"; + public const string Host = "server.address"; /// /// HTTP Method. @@ -34,12 +34,12 @@ public static class HttpLoggingTagNames /// /// HTTP Request Headers prefix. /// - public const string RequestHeaderPrefix = "RequestHeader."; + public const string RequestHeaderPrefix = "http.request.header."; /// /// HTTP Response Headers prefix. /// - public const string ResponseHeaderPrefix = "ResponseHeader."; + public const string ResponseHeaderPrefix = "http.response.header."; /// /// HTTP Request Body. From 00c9cd38be4919e6d14f263773cc79c308e4edcd Mon Sep 17 00:00:00 2001 From: Iliar Turdushev Date: Sun, 15 Oct 2023 10:46:14 +0200 Subject: [PATCH 11/19] Dimension names in HttpClient Logging --- .../Logging/HttpClientLoggingTagNames.cs | 12 +- .../Logging/Internal/Log.cs | 116 ++++++++++++++++-- 2 files changed, 113 insertions(+), 15 deletions(-) diff --git a/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Logging/HttpClientLoggingTagNames.cs b/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Logging/HttpClientLoggingTagNames.cs index 97d729b8c04..803eb03d082 100644 --- a/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Logging/HttpClientLoggingTagNames.cs +++ b/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Logging/HttpClientLoggingTagNames.cs @@ -19,17 +19,17 @@ public static class HttpClientLoggingTagNames /// /// HTTP Host. /// - public const string Host = "Host"; + public const string Host = "server.address"; /// /// HTTP Method. /// - public const string Method = "Method"; + public const string Method = "http.request.method"; /// /// HTTP Path. /// - public const string Path = "Path"; + public const string Path = "url.path"; /// /// HTTP Request Body. @@ -44,17 +44,17 @@ public static class HttpClientLoggingTagNames /// /// HTTP Request Headers prefix. /// - public const string RequestHeaderPrefix = "RequestHeader."; + public const string RequestHeaderPrefix = "http.request.header."; /// /// HTTP Response Headers prefix. /// - public const string ResponseHeaderPrefix = "ResponseHeader."; + public const string ResponseHeaderPrefix = "http.response.header."; /// /// HTTP Status Code. /// - public const string StatusCode = "StatusCode"; + public const string StatusCode = "http.response.status_code"; /// /// Gets a list of all tag names. diff --git a/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Logging/Internal/Log.cs b/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Logging/Internal/Log.cs index 0de61da9e10..f7e6896b14b 100644 --- a/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Logging/Internal/Log.cs +++ b/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Logging/Internal/Log.cs @@ -12,9 +12,10 @@ namespace Microsoft.Extensions.Http.Logging.Internal; /// Logs , and the exceptions due to errors of request/response. /// [SuppressMessage("Major Code Smell", "S109:Magic numbers should not be used", Justification = "Event ID's.")] -internal static partial class Log +internal static class Log { internal const string OriginalFormat = "{OriginalFormat}"; + private const string NullString = "(null)"; private const int MinimalPropertyCount = 4; @@ -45,17 +46,114 @@ public static void OutgoingRequestError(ILogger logger, LogRecord record, Except OutgoingRequest(logger, LogLevel.Error, 2, nameof(OutgoingRequestError), record, exception); } - [LoggerMessage(LogLevel.Error, RequestReadErrorMessage)] - public static partial void RequestReadError(ILogger logger, Exception exception, HttpMethod method, string? host, string? path); + public static void RequestReadError(ILogger logger, Exception exception, HttpMethod method, string? host, string? path) + { + var state = LoggerMessageHelper.ThreadLocalState; + + _ = state.ReserveTagSpace(4); + state.TagArray[3] = new(HttpClientLoggingTagNames.Method, method); + state.TagArray[2] = new(HttpClientLoggingTagNames.Host, host); + state.TagArray[1] = new(HttpClientLoggingTagNames.Path, path); + state.TagArray[0] = new(OriginalFormat, RequestReadErrorMessage); + + logger.Log( + LogLevel.Error, + new(0, nameof(RequestReadError)), + state, + exception, + static (s, _) => + { + var method = s.TagArray[3].Value ?? NullString; + var host = s.TagArray[2].Value ?? NullString; + var path = s.TagArray[1].Value ?? NullString; + return FormattableString.Invariant( + $"An error occurred while reading the request data to fill the logger context for request: {method} {host}/{path}"); + }); + + state.Clear(); + } - [LoggerMessage(LogLevel.Error, ResponseReadErrorMessage)] - public static partial void ResponseReadError(ILogger logger, Exception exception, HttpMethod method, string host, string path); + public static void ResponseReadError(ILogger logger, Exception exception, HttpMethod method, string host, string path) + { + var state = LoggerMessageHelper.ThreadLocalState; - [LoggerMessage(LogLevel.Error, LoggerContextMissingMessage)] - public static partial void LoggerContextMissing(ILogger logger, Exception? exception, string requestState, HttpMethod method, string? host); + _ = state.ReserveTagSpace(4); + state.TagArray[3] = new(HttpClientLoggingTagNames.Method, method); + state.TagArray[2] = new(HttpClientLoggingTagNames.Host, host); + state.TagArray[1] = new(HttpClientLoggingTagNames.Path, path); + state.TagArray[0] = new(OriginalFormat, ResponseReadErrorMessage); + + logger.Log( + LogLevel.Error, + new(0, nameof(ResponseReadError)), + state, + exception, + static (s, _) => + { + var method = s.TagArray[3].Value ?? NullString; + var host = s.TagArray[2].Value ?? NullString; + var path = s.TagArray[1].Value ?? NullString; + return FormattableString.Invariant( + $"An error occurred while reading the response data to fill the logger context for request: {method} {host}/{path}"); + }); + + state.Clear(); + } + + public static void LoggerContextMissing(ILogger logger, Exception? exception, string requestState, HttpMethod method, string? host) + { + var state = LoggerMessageHelper.ThreadLocalState; - [LoggerMessage(LogLevel.Error, EnrichmentErrorMessage)] - public static partial void EnrichmentError(ILogger logger, Exception exception, string? enricher, HttpMethod method, string host, string path); + _ = state.ReserveTagSpace(4); + state.TagArray[3] = new("RequestState", requestState); + state.TagArray[2] = new(HttpClientLoggingTagNames.Method, method); + state.TagArray[1] = new(HttpClientLoggingTagNames.Host, host); + state.TagArray[0] = new(OriginalFormat, LoggerContextMissingMessage); + + logger.Log( + LogLevel.Error, + new(0, nameof(LoggerContextMissing)), + state, + exception, + (s, _) => + { + var requestState = s.TagArray[3].Value ?? NullString; + var method = s.TagArray[2].Value ?? NullString; + var host = s.TagArray[1].Value ?? NullString; + return FormattableString.Invariant($"The logger couldn't read its context for {requestState} request: {method} {host}"); + }); + + state.Clear(); + } + + public static void EnrichmentError(ILogger logger, Exception exception, string? enricher, HttpMethod method, string host, string path) + { + var state = LoggerMessageHelper.ThreadLocalState; + + _ = state.ReserveTagSpace(5); + state.TagArray[4] = new("Enricher", enricher); + state.TagArray[3] = new(HttpClientLoggingTagNames.Method, method); + state.TagArray[2] = new(HttpClientLoggingTagNames.Host, host); + state.TagArray[1] = new(HttpClientLoggingTagNames.Path, path); + state.TagArray[0] = new(OriginalFormat, EnrichmentErrorMessage); + + logger.Log( + LogLevel.Error, + new(0, nameof(EnrichmentError)), + state, + exception, + (s, _) => + { + var enricher = s.TagArray[4].Value ?? NullString; + var method = s.TagArray[3].Value ?? NullString; + var host = s.TagArray[2].Value ?? NullString; + var path = s.TagArray[1].Value ?? NullString; + return FormattableString.Invariant( + $"An error occurred in enricher '{enricher}' while enriching the logger context for request: {method} {host}/{path}"); + }); + + state.Clear(); + } // Using the code below instead of generated logging method because we have a custom formatter and custom tag keys for headers. private static void OutgoingRequest( From 8282a7844e6637c21a825cf2e50260b5d6e270d2 Mon Sep 17 00:00:00 2001 From: Iliar Turdushev Date: Tue, 17 Oct 2023 11:27:30 +0200 Subject: [PATCH 12/19] Inlined PropertySeparator and NonNullablePropertySeparator constants --- .../Emission/Emitter.Method.cs | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/Generators/Microsoft.Gen.Logging/Emission/Emitter.Method.cs b/src/Generators/Microsoft.Gen.Logging/Emission/Emitter.Method.cs index 4972fed6b19..d08792a0776 100644 --- a/src/Generators/Microsoft.Gen.Logging/Emission/Emitter.Method.cs +++ b/src/Generators/Microsoft.Gen.Logging/Emission/Emitter.Method.cs @@ -14,9 +14,6 @@ namespace Microsoft.Gen.Logging.Emission; internal sealed partial class Emitter : EmitterBase { - private const string PropertySeparator = "."; - private const string NullablePropertySeparator = "?."; - #pragma warning disable CA1505 // Avoid unmaintainable code private void GenLogMethod(LoggingMethod lm) #pragma warning restore CA1505 @@ -319,8 +316,8 @@ void GenPropertyLoads(LoggingMethod lm, string stateName, out int numReservedUnc { if (!member.HasDataClassification) { - var propName = PropertyChainToString(propertyChain, member, PropertySeparator, omitReferenceName: p.OmitReferenceName); - var accessExpression = PropertyChainToString(propertyChain, member, NullablePropertySeparator, nonNullSeparator: PropertySeparator); + var propName = PropertyChainToString(propertyChain, member, ".", omitReferenceName: p.OmitReferenceName); + var accessExpression = PropertyChainToString(propertyChain, member, "?.", nonNullSeparator: "."); var ts = ShouldStringifyProperty(member) ? ConvertPropertyToString(member, accessExpression) @@ -370,8 +367,8 @@ void GenPropertyLoads(LoggingMethod lm, string stateName, out int numReservedUnc { if (member.HasDataClassification) { - var propName = PropertyChainToString(propertyChain, member, PropertySeparator, omitReferenceName: p.OmitReferenceName); - var accessExpression = PropertyChainToString(propertyChain, member, NullablePropertySeparator, nonNullSeparator: PropertySeparator); + var propName = PropertyChainToString(propertyChain, member, ".", omitReferenceName: p.OmitReferenceName); + var accessExpression = PropertyChainToString(propertyChain, member, "?.", nonNullSeparator: "."); var value = ShouldStringifyProperty(member) ? ConvertPropertyToString(member, accessExpression) @@ -394,8 +391,8 @@ void GenPropertyLoads(LoggingMethod lm, string stateName, out int numReservedUnc { if (member.HasDataClassification) { - var propName = PropertyChainToString(propertyChain, member, PropertySeparator, omitReferenceName: p.OmitReferenceName); - var accessExpression = PropertyChainToString(propertyChain, member, NullablePropertySeparator, nonNullSeparator: PropertySeparator); + var propName = PropertyChainToString(propertyChain, member, ".", omitReferenceName: p.OmitReferenceName); + var accessExpression = PropertyChainToString(propertyChain, member, "?.", nonNullSeparator: "."); var value = ShouldStringifyProperty(member) ? ConvertPropertyToString(member, accessExpression) @@ -421,8 +418,8 @@ void GenPropertyLoads(LoggingMethod lm, string stateName, out int numReservedUnc } else { - var propName = PropertyChainToString(propertyChain, member, PropertySeparator, omitReferenceName: p.OmitReferenceName); - var accessExpression = PropertyChainToString(propertyChain, member, NullablePropertySeparator, nonNullSeparator: PropertySeparator); + var propName = PropertyChainToString(propertyChain, member, ".", omitReferenceName: p.OmitReferenceName); + var accessExpression = PropertyChainToString(propertyChain, member, "?.", nonNullSeparator: "."); var ts = ShouldStringifyProperty(member) ? ConvertPropertyToString(member, accessExpression) @@ -633,7 +630,7 @@ private string PropertyChainToString( string? nonNullSeparator = null, bool omitReferenceName = false) { - bool needAts = nonNullSeparator == PropertySeparator; + bool needAts = nonNullSeparator == "."; var adjustedNonNullSeparator = nonNullSeparator ?? separator; var localStringBuilder = _sbPool.GetStringBuilder(); try From 2992316ec7892633b0a776b1b089240b6de990d3 Mon Sep 17 00:00:00 2001 From: Iliar Turdushev Date: Thu, 19 Oct 2023 13:01:48 +0200 Subject: [PATCH 13/19] Adjusted code coverage --- .../Microsoft.Extensions.Http.Diagnostics.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Microsoft.Extensions.Http.Diagnostics.csproj b/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Microsoft.Extensions.Http.Diagnostics.csproj index a74f7ef6f10..b541f10f960 100644 --- a/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Microsoft.Extensions.Http.Diagnostics.csproj +++ b/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Microsoft.Extensions.Http.Diagnostics.csproj @@ -27,7 +27,7 @@ normal - 94 + 91 78 From 91968e3ede2d1dafa30443919b53669441088b4c Mon Sep 17 00:00:00 2001 From: Iliar Turdushev Date: Thu, 19 Oct 2023 19:38:02 +0200 Subject: [PATCH 14/19] Header normalization --- .../Logging/HeaderReader.cs | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/HeaderReader.cs b/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/HeaderReader.cs index eb5792dad40..ca86b19885c 100644 --- a/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/HeaderReader.cs +++ b/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/HeaderReader.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Compliance.Classification; @@ -16,12 +17,14 @@ internal sealed class HeaderReader { private readonly IRedactorProvider _redactorProvider; private readonly KeyValuePair[] _headers; + private readonly string[] _normalizedHeaders; public HeaderReader(IDictionary headersToLog, IRedactorProvider redactorProvider) { _redactorProvider = redactorProvider; _headers = headersToLog.Count == 0 ? [] : headersToLog.ToArray(); + _normalizedHeaders = NormalizeHeaders(_headers); } public void Read(IHeaderDictionary headers, IList> logContext, string prefix) @@ -31,15 +34,32 @@ public void Read(IHeaderDictionary headers, IList> return; } - foreach (var header in _headers) + for (int i = 0; i < _headers.Length; i++) { + var header = _headers[i]; + if (headers.TryGetValue(header.Key, out var headerValue)) { var provider = _redactorProvider.GetRedactor(header.Value); var redacted = provider.Redact(headerValue.ToString()); - logContext.Add(new(prefix + header.Key, redacted)); + var normalizedHeader = _normalizedHeaders[i]; + logContext.Add(new(prefix + normalizedHeader, redacted)); } } } + + [SuppressMessage("Globalization", "CA1308:Normalize strings to uppercase", + Justification = "Normalization to lower case is required by OTel's semantic conventions")] + private static string[] NormalizeHeaders(KeyValuePair[] headers) + { + var normalizedHeaders = new string[headers.Length]; + + for (int i = 0; i < headers.Length; i++) + { + normalizedHeaders[i] = headers[i].Key.ToLowerInvariant().Replace('-', '_'); + } + + return normalizedHeaders; + } } #endif From 466b9a133460ac6fda611380625885014ad85f83 Mon Sep 17 00:00:00 2001 From: Iliar Turdushev Date: Fri, 20 Oct 2023 17:07:16 +0200 Subject: [PATCH 15/19] HttpLogging header name normalization --- .../Logging/HeaderNormalizer.cs | 14 ++++++++++++++ .../Logging/HeaderReader.cs | 5 +---- .../Logging/AcceptanceTests.cs | 18 ++++++++++++------ .../Logging/HeaderNormalizerTests.cs | 13 +++++++++++++ .../Logging/HeaderReaderTests.cs | 19 +++++++++++++++---- 5 files changed, 55 insertions(+), 14 deletions(-) create mode 100644 src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/HeaderNormalizer.cs create mode 100644 test/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware.Tests/Logging/HeaderNormalizerTests.cs diff --git a/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/HeaderNormalizer.cs b/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/HeaderNormalizer.cs new file mode 100644 index 00000000000..4823f8475e9 --- /dev/null +++ b/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/HeaderNormalizer.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics.CodeAnalysis; + +internal static class HeaderNormalizer +{ + [SuppressMessage("Globalization", "CA1308:Normalize strings to uppercase", + Justification = "Normalization to lower case is required by OTel's semantic conventions")] + public static string Normalize(string header) + { + return header.ToLowerInvariant().Replace('-', '_'); + } +} diff --git a/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/HeaderReader.cs b/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/HeaderReader.cs index ca86b19885c..fd0a7f486ba 100644 --- a/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/HeaderReader.cs +++ b/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/HeaderReader.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using System.Linq; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Compliance.Classification; @@ -48,15 +47,13 @@ public void Read(IHeaderDictionary headers, IList> } } - [SuppressMessage("Globalization", "CA1308:Normalize strings to uppercase", - Justification = "Normalization to lower case is required by OTel's semantic conventions")] private static string[] NormalizeHeaders(KeyValuePair[] headers) { var normalizedHeaders = new string[headers.Length]; for (int i = 0; i < headers.Length; i++) { - normalizedHeaders[i] = headers[i].Key.ToLowerInvariant().Replace('-', '_'); + normalizedHeaders[i] = HeaderNormalizer.Normalize(headers[i].Key); } return normalizedHeaders; diff --git a/test/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware.Tests/Logging/AcceptanceTests.cs b/test/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware.Tests/Logging/AcceptanceTests.cs index 1e195026f57..8c73cdde57f 100644 --- a/test/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware.Tests/Logging/AcceptanceTests.cs +++ b/test/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware.Tests/Logging/AcceptanceTests.cs @@ -285,6 +285,9 @@ async static (logCollector, client) => { const string Content = "Client: hello!"; + const string NormalizedRequestHeader = "accept"; + const string NormalizedResponseHeader = "transfer_encoding"; + using var request = new HttpRequestMessage(HttpMethod.Post, "/") { Content = new StringContent(Content) @@ -313,7 +316,7 @@ async static (logCollector, client) => Assert.DoesNotContain(requestState, x => x.Key.StartsWith(HttpLoggingTagNames.ResponseHeaderPrefix)); Assert.DoesNotContain(requestState, x => x.Key == HttpLoggingTagNames.StatusCode); Assert.DoesNotContain(requestState, x => x.Key == HttpLoggingTagNames.Duration); - Assert.Single(requestState, x => x.Key == HttpLoggingTagNames.RequestHeaderPrefix + HeaderNames.Accept); + Assert.Single(requestState, x => x.Key == HttpLoggingTagNames.RequestHeaderPrefix + NormalizedRequestHeader); Assert.Single(requestState, x => x.Key == HttpLoggingTagNames.Host && !string.IsNullOrEmpty(x.Value)); Assert.Single(requestState, x => x.Key == HttpLoggingTagNames.Path && x.Value == TelemetryConstants.Unknown); Assert.Single(requestState, x => x.Key == HttpLoggingTagNames.Method && x.Value == HttpMethod.Post.ToString()); @@ -323,7 +326,7 @@ async static (logCollector, client) => Assert.Single(requestBodyState, x => x.Key == "Body" && x.Value == Content); Assert.Equal(2, responseState!.Count); - Assert.Single(responseState, x => x.Key == HttpLoggingTagNames.ResponseHeaderPrefix + HeaderNames.TransferEncoding); + Assert.Single(responseState, x => x.Key == HttpLoggingTagNames.ResponseHeaderPrefix + NormalizedResponseHeader); Assert.Single(responseState, x => x.Key == HttpLoggingTagNames.StatusCode && x.Value == responseStatus); Assert.Equal(2, responseBodyState!.Count); @@ -346,6 +349,9 @@ await RunAsync( }), async static (logCollector, client) => { + const string NormalizedRequestHeader = "accept"; + const string NormalizedResponseHeader = "transfer_encoding"; + using var httpMessage = new HttpRequestMessage(HttpMethod.Get, "/"); httpMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(MediaTypeNames.Application.Json)); @@ -365,8 +371,8 @@ async static (logCollector, client) => var state = lastRecord.StructuredState; Assert.Equal(9, state!.Count); - Assert.Single(state, x => x.Key == HttpLoggingTagNames.RequestHeaderPrefix + HeaderNames.Accept); - Assert.Single(state, x => x.Key == HttpLoggingTagNames.ResponseHeaderPrefix + HeaderNames.TransferEncoding); + Assert.Single(state, x => x.Key == HttpLoggingTagNames.RequestHeaderPrefix + NormalizedRequestHeader); + Assert.Single(state, x => x.Key == HttpLoggingTagNames.ResponseHeaderPrefix + NormalizedResponseHeader); Assert.Single(state, x => x.Key == HttpLoggingTagNames.Host && !string.IsNullOrEmpty(x.Value)); Assert.Single(state, x => x.Key == HttpLoggingTagNames.Path && x.Value == TelemetryConstants.Unknown); Assert.Single(state, x => x.Key == HttpLoggingTagNames.StatusCode && x.Value == responseStatus); @@ -378,10 +384,10 @@ async static (logCollector, client) => Assert.DoesNotContain(state, x => x.Key == HttpLoggingTagNames.RequestBody); Assert.DoesNotContain(state, x => x.Key == HttpLoggingTagNames.ResponseBody); Assert.DoesNotContain(state, x => - x.Key.StartsWith(HttpLoggingTagNames.RequestHeaderPrefix) && !x.Key.EndsWith(HeaderNames.Accept)); + x.Key.StartsWith(HttpLoggingTagNames.RequestHeaderPrefix) && !x.Key.EndsWith(NormalizedRequestHeader)); Assert.DoesNotContain(state, x => - x.Key.StartsWith(HttpLoggingTagNames.ResponseHeaderPrefix) && !x.Key.EndsWith(HeaderNames.TransferEncoding)); + x.Key.StartsWith(HttpLoggingTagNames.ResponseHeaderPrefix) && !x.Key.EndsWith(NormalizedResponseHeader)); }); } diff --git a/test/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware.Tests/Logging/HeaderNormalizerTests.cs b/test/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware.Tests/Logging/HeaderNormalizerTests.cs new file mode 100644 index 00000000000..eaebc0f9fcd --- /dev/null +++ b/test/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware.Tests/Logging/HeaderNormalizerTests.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Xunit; + +public class HeaderNormalizerTests +{ + [Fact] + public void NormalizeHeaderNameTest() + { + Assert.Equal("accept_charset", HeaderNormalizer.Normalize("Accept-Charset")); + } +} diff --git a/test/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware.Tests/Logging/HeaderReaderTests.cs b/test/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware.Tests/Logging/HeaderReaderTests.cs index b3af0edffae..55d2715ed95 100644 --- a/test/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware.Tests/Logging/HeaderReaderTests.cs +++ b/test/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware.Tests/Logging/HeaderReaderTests.cs @@ -36,11 +36,22 @@ public void ShouldNotAddHeaders_WhenHeadersCollectionEmpty() [Fact] public void ShouldAddHeaders_WhenHeadersCollectionNotEmpty() { - var headersToLog = new Dictionary { [HeaderNames.Accept] = DataClassification.Unknown }; - var reader = new HeaderReader(headersToLog, new FakeRedactorProvider(new FakeRedactorOptions { RedactionFormat = "" })); + const string NormalizedHeader = "accept_charset"; + + var headersToLog = new Dictionary + { + [HeaderNames.AcceptCharset] = DataClassification.Unknown + }; + + var reader = new HeaderReader(headersToLog, new FakeRedactorProvider( + new FakeRedactorOptions + { + RedactionFormat = "" + })); + var headers = new Dictionary { - [HeaderNames.Accept] = MediaTypeNames.Text.Xml, + [HeaderNames.AcceptCharset] = MediaTypeNames.Text.Xml, [HeaderNames.ContentType] = MediaTypeNames.Application.Pdf }; @@ -50,7 +61,7 @@ public void ShouldAddHeaders_WhenHeadersCollectionNotEmpty() Assert.Single(listToFill); var redacted = listToFill[0]; - Assert.Equal(HeaderNames.Accept, redacted.Key); + Assert.Equal(NormalizedHeader, redacted.Key); Assert.Equal($"", redacted.Value); } } From fe0f6206c075a2f02031da05f7c06408d1924377 Mon Sep 17 00:00:00 2001 From: Iliar Turdushev Date: Fri, 20 Oct 2023 17:51:38 +0200 Subject: [PATCH 16/19] Normalize headers added by RequestHeadersLogEnricher --- .../Logging/HeaderNormalizer.cs | 16 ++++++++++++- .../Logging/HeaderReader.cs | 21 ++++------------- .../HttpLoggingRedactionInterceptor.cs | 8 +++---- .../Logging/RequestHeadersLogEnricher.cs | 23 +++++++++++-------- .../Logging/HeaderNormalizerTests.cs | 17 ++++++++++++-- .../Logging/HeaderReaderTests.cs | 18 +++++++-------- .../Logging/RequestHeadersEnricherTests.cs | 21 ++++++++++------- 7 files changed, 72 insertions(+), 52 deletions(-) diff --git a/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/HeaderNormalizer.cs b/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/HeaderNormalizer.cs index 4823f8475e9..fdf4fa3ce75 100644 --- a/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/HeaderNormalizer.cs +++ b/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/HeaderNormalizer.cs @@ -1,13 +1,27 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; +using Microsoft.Extensions.Compliance.Classification; internal static class HeaderNormalizer { + public static string[] PrepareNormalizedHeaderNames(KeyValuePair[] headers, string prefix) + { + var normalizedHeaders = new string[headers.Length]; + + for (int i = 0; i < headers.Length; i++) + { + normalizedHeaders[i] = prefix + Normalize(headers[i].Key); + } + + return normalizedHeaders; + } + [SuppressMessage("Globalization", "CA1308:Normalize strings to uppercase", Justification = "Normalization to lower case is required by OTel's semantic conventions")] - public static string Normalize(string header) + private static string Normalize(string header) { return header.ToLowerInvariant().Replace('-', '_'); } diff --git a/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/HeaderReader.cs b/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/HeaderReader.cs index fd0a7f486ba..3c02adb498f 100644 --- a/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/HeaderReader.cs +++ b/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/HeaderReader.cs @@ -18,15 +18,15 @@ internal sealed class HeaderReader private readonly KeyValuePair[] _headers; private readonly string[] _normalizedHeaders; - public HeaderReader(IDictionary headersToLog, IRedactorProvider redactorProvider) + public HeaderReader(IDictionary headersToLog, IRedactorProvider redactorProvider, string prefix) { _redactorProvider = redactorProvider; _headers = headersToLog.Count == 0 ? [] : headersToLog.ToArray(); - _normalizedHeaders = NormalizeHeaders(_headers); + _normalizedHeaders = HeaderNormalizer.PrepareNormalizedHeaderNames(_headers, prefix); } - public void Read(IHeaderDictionary headers, IList> logContext, string prefix) + public void Read(IHeaderDictionary headers, IList> logContext) { if (headers.Count == 0) { @@ -41,22 +41,9 @@ public void Read(IHeaderDictionary headers, IList> { var provider = _redactorProvider.GetRedactor(header.Value); var redacted = provider.Redact(headerValue.ToString()); - var normalizedHeader = _normalizedHeaders[i]; - logContext.Add(new(prefix + normalizedHeader, redacted)); + logContext.Add(new(_normalizedHeaders[i], redacted)); } } } - - private static string[] NormalizeHeaders(KeyValuePair[] headers) - { - var normalizedHeaders = new string[headers.Length]; - - for (int i = 0; i < headers.Length; i++) - { - normalizedHeaders[i] = HeaderNormalizer.Normalize(headers[i].Key); - } - - return normalizedHeaders; - } } #endif diff --git a/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/HttpLoggingRedactionInterceptor.cs b/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/HttpLoggingRedactionInterceptor.cs index 330c7d0c376..050f0bb092d 100644 --- a/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/HttpLoggingRedactionInterceptor.cs +++ b/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/HttpLoggingRedactionInterceptor.cs @@ -55,8 +55,8 @@ public HttpLoggingRedactionInterceptor( _requestPathLogMode = EnsureRequestPathLoggingModeIsValid(optionsValue.RequestPathLoggingMode); _parameterRedactionMode = optionsValue.RequestPathParameterRedactionMode; - _requestHeadersReader = new(optionsValue.RequestHeadersDataClasses, redactorProvider); - _responseHeadersReader = new(optionsValue.ResponseHeadersDataClasses, redactorProvider); + _requestHeadersReader = new(optionsValue.RequestHeadersDataClasses, redactorProvider, HttpLoggingTagNames.RequestHeaderPrefix); + _responseHeadersReader = new(optionsValue.ResponseHeadersDataClasses, redactorProvider, HttpLoggingTagNames.ResponseHeaderPrefix); _excludePathStartsWith = optionsValue.ExcludePathStartsWith.ToArray(); } @@ -126,7 +126,7 @@ public ValueTask OnRequestAsync(HttpLoggingInterceptorContext logContext) if (logContext.TryDisable(HttpLoggingFields.RequestHeaders)) { - _requestHeadersReader.Read(context.Request.Headers, logContext.Parameters, HttpLoggingTagNames.RequestHeaderPrefix); + _requestHeadersReader.Read(context.Request.Headers, logContext.Parameters); } return default; @@ -138,7 +138,7 @@ public ValueTask OnResponseAsync(HttpLoggingInterceptorContext logContext) if (logContext.TryDisable(HttpLoggingFields.ResponseHeaders)) { - _responseHeadersReader.Read(context.Response.Headers, logContext.Parameters, HttpLoggingTagNames.ResponseHeaderPrefix); + _responseHeadersReader.Read(context.Response.Headers, logContext.Parameters); } // Don't enrich if we're not going to log any part of the response diff --git a/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/RequestHeadersLogEnricher.cs b/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/RequestHeadersLogEnricher.cs index 47fff5f0f4d..be728c6c2f0 100644 --- a/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/RequestHeadersLogEnricher.cs +++ b/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/RequestHeadersLogEnricher.cs @@ -2,7 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Collections.Frozen; +using System.Collections.Generic; +using System.Linq; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Compliance.Classification; using Microsoft.Extensions.Compliance.Redaction; @@ -17,7 +18,8 @@ namespace Microsoft.AspNetCore.Diagnostics.Logging; /// internal sealed class RequestHeadersLogEnricher : ILogEnricher { - private readonly FrozenDictionary _headersDataClasses; + private readonly KeyValuePair[] _headersDataClasses; + private readonly string[] _normalizedHeaders; private readonly IHttpContextAccessor _httpContextAccessor; private readonly IRedactorProvider? _redactorProvider; @@ -33,11 +35,10 @@ public RequestHeadersLogEnricher(IHttpContextAccessor httpContextAccessor, IOpti var opt = Throw.IfMemberNull(options, options.Value); _httpContextAccessor = httpContextAccessor; - _headersDataClasses = opt.HeadersDataClasses.Count == 0 - ? FrozenDictionary.Empty - : opt.HeadersDataClasses.ToFrozenDictionary(StringComparer.Ordinal); + _headersDataClasses = opt.HeadersDataClasses.Count == 0 ? [] : opt.HeadersDataClasses.ToArray(); + _normalizedHeaders = HeaderNormalizer.PrepareNormalizedHeaderNames(_headersDataClasses, HttpLoggingTagNames.RequestHeaderPrefix); - if (_headersDataClasses.Count > 0) + if (_headersDataClasses.Length > 0) { _redactorProvider = Throw.IfNull(redactorProvider); } @@ -52,20 +53,22 @@ public void Enrich(IEnrichmentTagCollector collector) var request = _httpContextAccessor.HttpContext.Request; - if (_headersDataClasses.Count == 0) + if (_headersDataClasses.Length == 0) { return; } - if (_headersDataClasses.Count != 0) + if (_headersDataClasses.Length != 0) { - foreach (var header in _headersDataClasses) + for (int i = 0; i < _headersDataClasses.Length; i++) { + var header = _headersDataClasses[i]; + if (request.Headers.TryGetValue(header.Key, out var headerValue) && !string.IsNullOrEmpty(headerValue)) { var redactor = _redactorProvider!.GetRedactor(header.Value); var redacted = redactor.Redact(headerValue); - collector.Add(header.Key, redacted); + collector.Add(_normalizedHeaders[i], redacted); } } } diff --git a/test/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware.Tests/Logging/HeaderNormalizerTests.cs b/test/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware.Tests/Logging/HeaderNormalizerTests.cs index eaebc0f9fcd..5628c38f19a 100644 --- a/test/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware.Tests/Logging/HeaderNormalizerTests.cs +++ b/test/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware.Tests/Logging/HeaderNormalizerTests.cs @@ -1,13 +1,26 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Collections.Generic; +using Microsoft.Extensions.Compliance.Classification; using Xunit; public class HeaderNormalizerTests { [Fact] - public void NormalizeHeaderNameTest() + public void PrepareNormalizedHeaderNamesTest() { - Assert.Equal("accept_charset", HeaderNormalizer.Normalize("Accept-Charset")); + const string Prefix = "prefix."; + + var headers = HeaderNormalizer.PrepareNormalizedHeaderNames(new[] + { + new KeyValuePair("Accept-Charset", DataClassification.Unknown), + new KeyValuePair("CONTENT-TYPE", DataClassification.Unknown) + }, + Prefix); + + Assert.Equal(2, headers.Length); + Assert.Equal(Prefix + "accept_charset", headers[0]); + Assert.Equal(Prefix + "content_type", headers[1]); } } diff --git a/test/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware.Tests/Logging/HeaderReaderTests.cs b/test/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware.Tests/Logging/HeaderReaderTests.cs index 55d2715ed95..b3921c3a7f4 100644 --- a/test/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware.Tests/Logging/HeaderReaderTests.cs +++ b/test/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware.Tests/Logging/HeaderReaderTests.cs @@ -17,26 +17,27 @@ public class HeaderReaderTests [Fact] public void ShouldNotAddHeaders_WhenFilteringSetEmpty() { - var reader = new HeaderReader(new Dictionary(), null!); + var reader = new HeaderReader(new Dictionary(), null!, string.Empty); var listToFill = new List>(); var headers = new HeaderDictionary(new Dictionary { [HeaderNames.Accept] = MediaTypeNames.Text.Plain }); - reader.Read(headers, listToFill, string.Empty); + reader.Read(headers, listToFill); Assert.Empty(listToFill); } [Fact] public void ShouldNotAddHeaders_WhenHeadersCollectionEmpty() { - var reader = new HeaderReader(new Dictionary { [HeaderNames.Accept] = DataClassification.Unknown }, null!); + var reader = new HeaderReader(new Dictionary { [HeaderNames.Accept] = DataClassification.Unknown }, null!, string.Empty); var listToFill = new List>(); - reader.Read(new HeaderDictionary(), listToFill, string.Empty); + reader.Read(new HeaderDictionary(), listToFill); Assert.Empty(listToFill); } [Fact] public void ShouldAddHeaders_WhenHeadersCollectionNotEmpty() { - const string NormalizedHeader = "accept_charset"; + const string Prefix = "prefix."; + const string NormalizedHeader = Prefix + "accept_charset"; var headersToLog = new Dictionary { @@ -44,10 +45,7 @@ public void ShouldAddHeaders_WhenHeadersCollectionNotEmpty() }; var reader = new HeaderReader(headersToLog, new FakeRedactorProvider( - new FakeRedactorOptions - { - RedactionFormat = "" - })); + new FakeRedactorOptions { RedactionFormat = "" }), Prefix); var headers = new Dictionary { @@ -56,7 +54,7 @@ public void ShouldAddHeaders_WhenHeadersCollectionNotEmpty() }; var listToFill = new List>(); - reader.Read(new HeaderDictionary(headers), listToFill, string.Empty); + reader.Read(new HeaderDictionary(headers), listToFill); Assert.Single(listToFill); diff --git a/test/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware.Tests/Logging/RequestHeadersEnricherTests.cs b/test/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware.Tests/Logging/RequestHeadersEnricherTests.cs index fc0fccba72d..19341bb444c 100644 --- a/test/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware.Tests/Logging/RequestHeadersEnricherTests.cs +++ b/test/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware.Tests/Logging/RequestHeadersEnricherTests.cs @@ -21,6 +21,11 @@ public class RequestHeadersEnricherTests private const string RequestId = "RequestIdTestValue"; private const string TestValue = "TestValue"; + private const string NormalizedHeaderKey1 = HttpLoggingTagNames.RequestHeaderPrefix + "x_requestid"; + private const string NormalizedHeaderKey2 = HttpLoggingTagNames.RequestHeaderPrefix + "host"; + private const string NormalizedHeaderKey3 = HttpLoggingTagNames.RequestHeaderPrefix + "nullheader"; + private const string NormalizedHeaderKey4 = HttpLoggingTagNames.RequestHeaderPrefix + "x_platform"; + private readonly Mock _accessorMock; private readonly Mock _redactorProviderMock; @@ -95,8 +100,8 @@ public void RequestHeadersEnricher_GivenEnricherOptions_HeaderKeysDataClasses_En // Assert Assert.True(enrichedState.Count == 2); - Assert.Equal($"redacted:{RequestId}", enrichedState[HeaderKey1].ToString()); - Assert.Equal(TestValue, enrichedState[HeaderKey4].ToString()); + Assert.Equal($"redacted:{RequestId}", enrichedState[NormalizedHeaderKey1].ToString()); + Assert.Equal(TestValue, enrichedState[NormalizedHeaderKey4].ToString()); } [Fact] @@ -125,8 +130,8 @@ public void RequestHeadersEnricher_GivenEnricherOptions_OneHeaderValueIsEmpty_He // Assert Assert.Single(enrichedState); - Assert.Equal($"REDACTED:{RequestId}", enrichedState[HeaderKey1].ToString()); - Assert.False(enrichedState.ContainsKey(HeaderKey2)); + Assert.Equal($"REDACTED:{RequestId}", enrichedState[NormalizedHeaderKey1].ToString()); + Assert.False(enrichedState.ContainsKey(NormalizedHeaderKey2)); } [Fact] @@ -151,8 +156,8 @@ public void RequestHeadersEnricher_GivenEnricherOptions_OneHeaderValueIsNull_Hea // Assert Assert.Single(enrichedState); - Assert.Equal(RequestId, enrichedState[HeaderKey1].ToString()); - Assert.False(enrichedState.ContainsKey(HeaderKey3)); + Assert.Equal(RequestId, enrichedState[NormalizedHeaderKey1].ToString()); + Assert.False(enrichedState.ContainsKey(NormalizedHeaderKey3)); } [Fact] @@ -177,8 +182,8 @@ public void RequestHeadersEnricher_GivenEnricherOptions_OneHeaderValueIsMissing_ var enrichedState = enrichedProperties.Properties; // Assert - Assert.Equal(RequestId, enrichedState[HeaderKey1].ToString()); - Assert.False(enrichedState.ContainsKey(headerKey2)); + Assert.Equal(RequestId, enrichedState[NormalizedHeaderKey1].ToString()); + Assert.False(enrichedState.ContainsKey(HttpLoggingTagNames.RequestHeaderPrefix + headerKey2)); } [Fact] From dd45788211c489a84759f226c32ecc8201d9e34d Mon Sep 17 00:00:00 2001 From: Iliar Turdushev Date: Fri, 20 Oct 2023 18:57:32 +0200 Subject: [PATCH 17/19] Header name normalization in HttpClientLogging --- .../Internal/LoggerMessageStateExtensions.cs | 12 ++++- .../Logging/HttpClientLoggerTest.cs | 12 ++--- .../LoggerMessageStateExtensionsTests.cs | 53 +++++++++++++++++++ 3 files changed, 69 insertions(+), 8 deletions(-) create mode 100644 test/Libraries/Microsoft.Extensions.Http.Diagnostics.Tests/Logging/LoggerMessageStateExtensionsTests.cs diff --git a/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Logging/Internal/LoggerMessageStateExtensions.cs b/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Logging/Internal/LoggerMessageStateExtensions.cs index 744152fec0f..a10accc779a 100644 --- a/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Logging/Internal/LoggerMessageStateExtensions.cs +++ b/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Logging/Internal/LoggerMessageStateExtensions.cs @@ -3,6 +3,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using Microsoft.Extensions.Logging; namespace Microsoft.Extensions.Http.Logging.Internal; @@ -25,7 +26,7 @@ public static void AddRequestHeaders(this LoggerMessageState state, List p + x, + static (x, p) => p + Normalize(x), HttpClientLoggingTagNames.RequestHeaderPrefix); state.TagArray[index++] = new(key, items[i].Value); @@ -45,10 +46,17 @@ public static void AddResponseHeaders(this LoggerMessageState state, List p + x, + static (x, p) => p + Normalize(x), HttpClientLoggingTagNames.ResponseHeaderPrefix); state.TagArray[index++] = new(key, items[i].Value); } } + + [SuppressMessage("Globalization", "CA1308:Normalize strings to uppercase", + Justification = "Normalization to lower case is required by OTel's semantic conventions")] + private static string Normalize(string header) + { + return header.ToLowerInvariant().Replace('-', '_'); + } } diff --git a/test/Libraries/Microsoft.Extensions.Http.Diagnostics.Tests/Logging/HttpClientLoggerTest.cs b/test/Libraries/Microsoft.Extensions.Http.Diagnostics.Tests/Logging/HttpClientLoggerTest.cs index 95d2f7b5844..94025d33a6a 100644 --- a/test/Libraries/Microsoft.Extensions.Http.Diagnostics.Tests/Logging/HttpClientLoggerTest.cs +++ b/test/Libraries/Microsoft.Extensions.Http.Diagnostics.Tests/Logging/HttpClientLoggerTest.cs @@ -32,10 +32,10 @@ namespace Microsoft.Extensions.Http.Logging.Test; public class HttpClientLoggerTest { - private const string TestRequestHeader = "RequestHeader"; - private const string TestResponseHeader = "ResponseHeader"; - private const string TestExpectedRequestHeaderKey = $"{HttpClientLoggingTagNames.RequestHeaderPrefix}{TestRequestHeader}"; - private const string TestExpectedResponseHeaderKey = $"{HttpClientLoggingTagNames.ResponseHeaderPrefix}{TestResponseHeader}"; + private const string TestRequestHeader = "Request-Header"; + private const string TestResponseHeader = "Response-Header"; + private const string TestExpectedRequestHeaderKey = $"{HttpClientLoggingTagNames.RequestHeaderPrefix}request_header"; + private const string TestExpectedResponseHeaderKey = $"{HttpClientLoggingTagNames.ResponseHeaderPrefix}response_header"; private const string TextPlain = "text/plain"; @@ -164,8 +164,8 @@ public async Task HttpLoggingHandler_AllOptions_LogsOutgoingRequest() var testEnricher = new TestEnricher(); - var testSharedRequestHeaderKey = $"{HttpClientLoggingTagNames.RequestHeaderPrefix}Header3"; - var testSharedResponseHeaderKey = $"{HttpClientLoggingTagNames.ResponseHeaderPrefix}Header3"; + var testSharedRequestHeaderKey = $"{HttpClientLoggingTagNames.RequestHeaderPrefix}header3"; + var testSharedResponseHeaderKey = $"{HttpClientLoggingTagNames.ResponseHeaderPrefix}header3"; var expectedLogRecord = new LogRecord { diff --git a/test/Libraries/Microsoft.Extensions.Http.Diagnostics.Tests/Logging/LoggerMessageStateExtensionsTests.cs b/test/Libraries/Microsoft.Extensions.Http.Diagnostics.Tests/Logging/LoggerMessageStateExtensionsTests.cs new file mode 100644 index 00000000000..5f0ca87a5df --- /dev/null +++ b/test/Libraries/Microsoft.Extensions.Http.Diagnostics.Tests/Logging/LoggerMessageStateExtensionsTests.cs @@ -0,0 +1,53 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using Microsoft.Extensions.Http.Logging.Internal; +using Microsoft.Extensions.Logging; +using Xunit; + +namespace Microsoft.Extensions.Http.Logging.Test; + +public class LoggerMessageStateExtensionsTests +{ + [Fact] + public void AddRequestHeadersTest() + { + AddHeadersTest( + LoggerMessageStateExtensions.AddRequestHeaders, + HttpClientLoggingTagNames.RequestHeaderPrefix); + } + + [Fact] + public void AddResponseHeadersTest() + { + AddHeadersTest( + LoggerMessageStateExtensions.AddResponseHeaders, + HttpClientLoggingTagNames.ResponseHeaderPrefix); + } + + private static void AddHeadersTest(AddHeadersDelegate addHeaders, string prefix) + { + const string Header1 = "Accept-Charset"; + const string Header2 = "CONTENT-TYPE"; + + const string NormalizedHeader1 = "accept_charset"; + const string NormalizedHeader2 = "content_type"; + + List> headers = [new(Header1, "v1"), new(Header2, "v2")]; + + var state = new LoggerMessageState(); + int index = 0; + + state.ReserveTagSpace(2); + addHeaders(state, headers, ref index); + + Assert.Equal(prefix + NormalizedHeader1, state.TagArray[0].Key); + Assert.Equal("v1", state.TagArray[0].Value); + + Assert.Equal(prefix + NormalizedHeader2, state.TagArray[1].Key); + Assert.Equal("v2", state.TagArray[1].Value); + } + + private delegate void AddHeadersDelegate(LoggerMessageState state, List> items, ref int index); +} From 7fc9a02d33809641f46e2daebe980f7d4fca8a05 Mon Sep 17 00:00:00 2001 From: Iliar Turdushev Date: Fri, 20 Oct 2023 21:43:38 +0200 Subject: [PATCH 18/19] Updated API json files --- ...soft.AspNetCore.Diagnostics.Middleware.json | 6 +++--- ...Microsoft.Extensions.Diagnostics.Extra.json | 12 ++++++------ .../Microsoft.Extensions.Http.Diagnostics.json | 18 +++++++++--------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Microsoft.AspNetCore.Diagnostics.Middleware.json b/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Microsoft.AspNetCore.Diagnostics.Middleware.json index c5efcc382d5..e76e745c5f1 100644 --- a/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Microsoft.AspNetCore.Diagnostics.Middleware.json +++ b/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Microsoft.AspNetCore.Diagnostics.Middleware.json @@ -31,7 +31,7 @@ { "Member": "const string Microsoft.AspNetCore.Diagnostics.Logging.HttpLoggingTagNames.Host", "Stage": "Stable", - "Value": "Host" + "Value": "server.address" }, { "Member": "const string Microsoft.AspNetCore.Diagnostics.Logging.HttpLoggingTagNames.Method", @@ -51,7 +51,7 @@ { "Member": "const string Microsoft.AspNetCore.Diagnostics.Logging.HttpLoggingTagNames.RequestHeaderPrefix", "Stage": "Stable", - "Value": "RequestHeader." + "Value": "http.request.header." }, { "Member": "const string Microsoft.AspNetCore.Diagnostics.Logging.HttpLoggingTagNames.ResponseBody", @@ -61,7 +61,7 @@ { "Member": "const string Microsoft.AspNetCore.Diagnostics.Logging.HttpLoggingTagNames.ResponseHeaderPrefix", "Stage": "Stable", - "Value": "ResponseHeader." + "Value": "http.response.header." }, { "Member": "const string Microsoft.AspNetCore.Diagnostics.Logging.HttpLoggingTagNames.StatusCode", diff --git a/src/Libraries/Microsoft.Extensions.Diagnostics.Extra/Microsoft.Extensions.Diagnostics.Extra.json b/src/Libraries/Microsoft.Extensions.Diagnostics.Extra/Microsoft.Extensions.Diagnostics.Extra.json index ef9baefce11..92164273c8a 100644 --- a/src/Libraries/Microsoft.Extensions.Diagnostics.Extra/Microsoft.Extensions.Diagnostics.Extra.json +++ b/src/Libraries/Microsoft.Extensions.Diagnostics.Extra/Microsoft.Extensions.Diagnostics.Extra.json @@ -26,22 +26,22 @@ { "Member": "const string Microsoft.Extensions.Diagnostics.Enrichment.ApplicationEnricherTags.ApplicationName", "Stage": "Stable", - "Value": "AppName" + "Value": "service.name" }, { "Member": "const string Microsoft.Extensions.Diagnostics.Enrichment.ApplicationEnricherTags.BuildVersion", "Stage": "Stable", - "Value": "CloudRoleVer" + "Value": "service.version" }, { "Member": "const string Microsoft.Extensions.Diagnostics.Enrichment.ApplicationEnricherTags.DeploymentRing", "Stage": "Stable", - "Value": "CloudDeploymentRing" + "Value": "DeploymentRing" }, { "Member": "const string Microsoft.Extensions.Diagnostics.Enrichment.ApplicationEnricherTags.EnvironmentName", "Stage": "Stable", - "Value": "CloudEnv" + "Value": "deployment.environment" } ], "Properties": [ @@ -260,12 +260,12 @@ { "Member": "const string Microsoft.Extensions.Diagnostics.Enrichment.ProcessEnricherTagNames.ProcessId", "Stage": "Stable", - "Value": "pid" + "Value": "process.pid" }, { "Member": "const string Microsoft.Extensions.Diagnostics.Enrichment.ProcessEnricherTagNames.ThreadId", "Stage": "Stable", - "Value": "tid" + "Value": "thread.id" } ], "Properties": [ diff --git a/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Microsoft.Extensions.Http.Diagnostics.json b/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Microsoft.Extensions.Http.Diagnostics.json index 66b635f00b2..eabd53cbf75 100644 --- a/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Microsoft.Extensions.Http.Diagnostics.json +++ b/src/Libraries/Microsoft.Extensions.Http.Diagnostics/Microsoft.Extensions.Http.Diagnostics.json @@ -82,47 +82,47 @@ { "Member": "const string Microsoft.Extensions.Http.Logging.HttpClientLoggingTagNames.Duration", "Stage": "Stable", - "Value": "duration" + "Value": "Duration" }, { "Member": "const string Microsoft.Extensions.Http.Logging.HttpClientLoggingTagNames.Host", "Stage": "Stable", - "Value": "httpHost" + "Value": "server.address" }, { "Member": "const string Microsoft.Extensions.Http.Logging.HttpClientLoggingTagNames.Method", "Stage": "Stable", - "Value": "httpMethod" + "Value": "http.request.method" }, { "Member": "const string Microsoft.Extensions.Http.Logging.HttpClientLoggingTagNames.Path", "Stage": "Stable", - "Value": "httpPath" + "Value": "url.path" }, { "Member": "const string Microsoft.Extensions.Http.Logging.HttpClientLoggingTagNames.RequestBody", "Stage": "Stable", - "Value": "httpRequestBody" + "Value": "RequestBody" }, { "Member": "const string Microsoft.Extensions.Http.Logging.HttpClientLoggingTagNames.RequestHeaderPrefix", "Stage": "Stable", - "Value": "httpRequestHeader_" + "Value": "http.request.header." }, { "Member": "const string Microsoft.Extensions.Http.Logging.HttpClientLoggingTagNames.ResponseBody", "Stage": "Stable", - "Value": "httpResponseBody" + "Value": "ResponseBody" }, { "Member": "const string Microsoft.Extensions.Http.Logging.HttpClientLoggingTagNames.ResponseHeaderPrefix", "Stage": "Stable", - "Value": "httpResponseHeader_" + "Value": "http.response.header." }, { "Member": "const string Microsoft.Extensions.Http.Logging.HttpClientLoggingTagNames.StatusCode", "Stage": "Stable", - "Value": "httpStatusCode" + "Value": "http.response.status_code" } ], "Properties": [ From f44ed27c9b3f4a2d038793472c35b5d3825109c3 Mon Sep 17 00:00:00 2001 From: Iliar Turdushev Date: Mon, 23 Oct 2023 15:46:28 +0200 Subject: [PATCH 19/19] Header name normalization now doesn't require replacing '-' with '_' --- .../Logging/HeaderNormalizer.cs | 2 +- .../Logging/Internal/LoggerMessageStateExtensions.cs | 2 +- .../Logging/AcceptanceTests.cs | 4 ++-- .../Logging/HeaderNormalizerTests.cs | 4 ++-- .../Logging/HeaderReaderTests.cs | 2 +- .../Logging/RequestHeadersEnricherTests.cs | 4 ++-- .../Logging/HttpClientLoggerTest.cs | 4 ++-- .../Logging/LoggerMessageStateExtensionsTests.cs | 4 ++-- 8 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/HeaderNormalizer.cs b/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/HeaderNormalizer.cs index fdf4fa3ce75..600811d598a 100644 --- a/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/HeaderNormalizer.cs +++ b/src/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware/Logging/HeaderNormalizer.cs @@ -23,6 +23,6 @@ public static string[] PrepareNormalizedHeaderNames(KeyValuePair const string Content = "Client: hello!"; const string NormalizedRequestHeader = "accept"; - const string NormalizedResponseHeader = "transfer_encoding"; + const string NormalizedResponseHeader = "transfer-encoding"; using var request = new HttpRequestMessage(HttpMethod.Post, "/") { @@ -350,7 +350,7 @@ await RunAsync( async static (logCollector, client) => { const string NormalizedRequestHeader = "accept"; - const string NormalizedResponseHeader = "transfer_encoding"; + const string NormalizedResponseHeader = "transfer-encoding"; using var httpMessage = new HttpRequestMessage(HttpMethod.Get, "/"); httpMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(MediaTypeNames.Application.Json)); diff --git a/test/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware.Tests/Logging/HeaderNormalizerTests.cs b/test/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware.Tests/Logging/HeaderNormalizerTests.cs index 5628c38f19a..481a186a08d 100644 --- a/test/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware.Tests/Logging/HeaderNormalizerTests.cs +++ b/test/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware.Tests/Logging/HeaderNormalizerTests.cs @@ -20,7 +20,7 @@ public void PrepareNormalizedHeaderNamesTest() Prefix); Assert.Equal(2, headers.Length); - Assert.Equal(Prefix + "accept_charset", headers[0]); - Assert.Equal(Prefix + "content_type", headers[1]); + Assert.Equal(Prefix + "accept-charset", headers[0]); + Assert.Equal(Prefix + "content-type", headers[1]); } } diff --git a/test/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware.Tests/Logging/HeaderReaderTests.cs b/test/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware.Tests/Logging/HeaderReaderTests.cs index b3921c3a7f4..f6c59fc9704 100644 --- a/test/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware.Tests/Logging/HeaderReaderTests.cs +++ b/test/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware.Tests/Logging/HeaderReaderTests.cs @@ -37,7 +37,7 @@ public void ShouldNotAddHeaders_WhenHeadersCollectionEmpty() public void ShouldAddHeaders_WhenHeadersCollectionNotEmpty() { const string Prefix = "prefix."; - const string NormalizedHeader = Prefix + "accept_charset"; + const string NormalizedHeader = Prefix + "accept-charset"; var headersToLog = new Dictionary { diff --git a/test/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware.Tests/Logging/RequestHeadersEnricherTests.cs b/test/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware.Tests/Logging/RequestHeadersEnricherTests.cs index b0ee4463df4..e841feb3636 100644 --- a/test/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware.Tests/Logging/RequestHeadersEnricherTests.cs +++ b/test/Libraries/Microsoft.AspNetCore.Diagnostics.Middleware.Tests/Logging/RequestHeadersEnricherTests.cs @@ -23,10 +23,10 @@ public class RequestHeadersEnricherTests private const string RequestId = "RequestIdTestValue"; private const string TestValue = "TestValue"; - private const string NormalizedHeaderKey1 = HttpLoggingTagNames.RequestHeaderPrefix + "x_requestid"; + private const string NormalizedHeaderKey1 = HttpLoggingTagNames.RequestHeaderPrefix + "x-requestid"; private const string NormalizedHeaderKey2 = HttpLoggingTagNames.RequestHeaderPrefix + "host"; private const string NormalizedHeaderKey3 = HttpLoggingTagNames.RequestHeaderPrefix + "nullheader"; - private const string NormalizedHeaderKey4 = HttpLoggingTagNames.RequestHeaderPrefix + "x_platform"; + private const string NormalizedHeaderKey4 = HttpLoggingTagNames.RequestHeaderPrefix + "x-platform"; private readonly Mock _accessorMock; private readonly Mock _redactorProviderMock; diff --git a/test/Libraries/Microsoft.Extensions.Http.Diagnostics.Tests/Logging/HttpClientLoggerTest.cs b/test/Libraries/Microsoft.Extensions.Http.Diagnostics.Tests/Logging/HttpClientLoggerTest.cs index 94025d33a6a..0473f3b8394 100644 --- a/test/Libraries/Microsoft.Extensions.Http.Diagnostics.Tests/Logging/HttpClientLoggerTest.cs +++ b/test/Libraries/Microsoft.Extensions.Http.Diagnostics.Tests/Logging/HttpClientLoggerTest.cs @@ -34,8 +34,8 @@ public class HttpClientLoggerTest { private const string TestRequestHeader = "Request-Header"; private const string TestResponseHeader = "Response-Header"; - private const string TestExpectedRequestHeaderKey = $"{HttpClientLoggingTagNames.RequestHeaderPrefix}request_header"; - private const string TestExpectedResponseHeaderKey = $"{HttpClientLoggingTagNames.ResponseHeaderPrefix}response_header"; + private const string TestExpectedRequestHeaderKey = $"{HttpClientLoggingTagNames.RequestHeaderPrefix}request-header"; + private const string TestExpectedResponseHeaderKey = $"{HttpClientLoggingTagNames.ResponseHeaderPrefix}response-header"; private const string TextPlain = "text/plain"; diff --git a/test/Libraries/Microsoft.Extensions.Http.Diagnostics.Tests/Logging/LoggerMessageStateExtensionsTests.cs b/test/Libraries/Microsoft.Extensions.Http.Diagnostics.Tests/Logging/LoggerMessageStateExtensionsTests.cs index 5f0ca87a5df..00722f0317b 100644 --- a/test/Libraries/Microsoft.Extensions.Http.Diagnostics.Tests/Logging/LoggerMessageStateExtensionsTests.cs +++ b/test/Libraries/Microsoft.Extensions.Http.Diagnostics.Tests/Logging/LoggerMessageStateExtensionsTests.cs @@ -31,8 +31,8 @@ private static void AddHeadersTest(AddHeadersDelegate addHeaders, string prefix) const string Header1 = "Accept-Charset"; const string Header2 = "CONTENT-TYPE"; - const string NormalizedHeader1 = "accept_charset"; - const string NormalizedHeader2 = "content_type"; + const string NormalizedHeader1 = "accept-charset"; + const string NormalizedHeader2 = "content-type"; List> headers = [new(Header1, "v1"), new(Header2, "v2")];