From df1b383b3f934c3f9e1ed6a54b1a89f2a175edca Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Tue, 24 Jun 2025 21:19:49 -0400 Subject: [PATCH 1/2] Add missing CultureInfo.InvariantCulture use to LogValuesFormatter --- .../src/LogValuesFormatter.cs | 7 ++-- .../tests/Common/LoggerExtensionsTest.cs | 32 +++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/LogValuesFormatter.cs b/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/LogValuesFormatter.cs index 711b73d5ba4973..44951b8c84c931 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/LogValuesFormatter.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/LogValuesFormatter.cs @@ -66,7 +66,7 @@ public LogValuesFormatter(string format) formatDelimiterIndex = formatDelimiterIndex < 0 ? closeBraceIndex : formatDelimiterIndex + openBraceIndex; vsb.Append(format.AsSpan(scanIndex, openBraceIndex - scanIndex + 1)); - vsb.Append(_valueNames.Count.ToString()); + vsb.Append(_valueNames.Count.ToString(CultureInfo.InvariantCulture)); _valueNames.Add(format.Substring(openBraceIndex + 1, formatDelimiterIndex - openBraceIndex - 1)); vsb.Append(format.AsSpan(formatDelimiterIndex, closeBraceIndex - formatDelimiterIndex + 1)); @@ -270,7 +270,10 @@ private static bool TryFormatArgumentIfNullOrEnumerable(T? value, [NotNullWhe vsb.Append(", "); } - vsb.Append(e != null ? e.ToString() : NullValue); + vsb.Append( + e is IFormattable f ? f.ToString(null, CultureInfo.InvariantCulture) : + e is not null ? e.ToString() : + NullValue); first = false; } stringValue = vsb.ToString(); diff --git a/src/libraries/Microsoft.Extensions.Logging/tests/Common/LoggerExtensionsTest.cs b/src/libraries/Microsoft.Extensions.Logging/tests/Common/LoggerExtensionsTest.cs index 3c39d1d359683a..da537c7ef22275 100644 --- a/src/libraries/Microsoft.Extensions.Logging/tests/Common/LoggerExtensionsTest.cs +++ b/src/libraries/Microsoft.Extensions.Logging/tests/Common/LoggerExtensionsTest.cs @@ -4,6 +4,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Globalization; using System.Linq; using Microsoft.Extensions.Logging.Testing; using Xunit; @@ -134,6 +135,37 @@ public void FormatMessage_LogsCorrectValues() Assert.Null(debug.Exception); } + [Fact] + public void FormatMessage_UsesInvariantCulture() + { + // Arrange + var sink = new TestSink(); + var logger = SetUp(sink); + + CultureInfo existing = CultureInfo.CurrentCulture; + try + { + CultureInfo.CurrentCulture = new CultureInfo("fr-FR"); + + logger.Log(LogLevel.Trace, "{0}", new object[] { 1.23 }); + logger.Log(LogLevel.Information, "{0}", new object[] { new object[] { 1.23f } }); + + Assert.Equal(2, sink.Writes.Count()); + + Assert.True(sink.Writes.TryTake(out var trace)); + Assert.Equal(LogLevel.Trace, trace.LogLevel); + Assert.Equal("1.23", trace.State?.ToString()); + + Assert.True(sink.Writes.TryTake(out var info)); + Assert.Equal(LogLevel.Information, info.LogLevel); + Assert.Equal("1.23", info.State?.ToString()); + } + finally + { + CultureInfo.CurrentCulture = existing; + } + } + [Fact] public void MessageAndEventId_LogsCorrectValues() { From ccf8cac8ac94e7a4eddcad20c979203ea33edaca Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Thu, 26 Jun 2025 22:02:28 -0400 Subject: [PATCH 2/2] Address PR feedback --- .../tests/Common/LoggerExtensionsTest.cs | 31 +++++++------------ 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Logging/tests/Common/LoggerExtensionsTest.cs b/src/libraries/Microsoft.Extensions.Logging/tests/Common/LoggerExtensionsTest.cs index da537c7ef22275..06f24cffb18a73 100644 --- a/src/libraries/Microsoft.Extensions.Logging/tests/Common/LoggerExtensionsTest.cs +++ b/src/libraries/Microsoft.Extensions.Logging/tests/Common/LoggerExtensionsTest.cs @@ -4,8 +4,8 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Globalization; using System.Linq; +using System.Tests; using Microsoft.Extensions.Logging.Testing; using Xunit; @@ -139,31 +139,22 @@ public void FormatMessage_LogsCorrectValues() public void FormatMessage_UsesInvariantCulture() { // Arrange + using ThreadCultureChange _ = new("fr-FR"); var sink = new TestSink(); var logger = SetUp(sink); - CultureInfo existing = CultureInfo.CurrentCulture; - try - { - CultureInfo.CurrentCulture = new CultureInfo("fr-FR"); - - logger.Log(LogLevel.Trace, "{0}", new object[] { 1.23 }); - logger.Log(LogLevel.Information, "{0}", new object[] { new object[] { 1.23f } }); + logger.Log(LogLevel.Trace, "{0}", new object[] { 1.23 }); + logger.Log(LogLevel.Information, "{0}", new object[] { new object[] { 1.23f } }); - Assert.Equal(2, sink.Writes.Count()); + Assert.Equal(2, sink.Writes.Count()); - Assert.True(sink.Writes.TryTake(out var trace)); - Assert.Equal(LogLevel.Trace, trace.LogLevel); - Assert.Equal("1.23", trace.State?.ToString()); + Assert.True(sink.Writes.TryTake(out var trace)); + Assert.Equal(LogLevel.Trace, trace.LogLevel); + Assert.Equal("1.23", trace.State?.ToString()); - Assert.True(sink.Writes.TryTake(out var info)); - Assert.Equal(LogLevel.Information, info.LogLevel); - Assert.Equal("1.23", info.State?.ToString()); - } - finally - { - CultureInfo.CurrentCulture = existing; - } + Assert.True(sink.Writes.TryTake(out var info)); + Assert.Equal(LogLevel.Information, info.LogLevel); + Assert.Equal("1.23", info.State?.ToString()); } [Fact]