When I try to output a numeric value with the currency format specifier using ILogger.LogInformation()
I get an unexpected symbol different from when I use Console.Log(string.Format())
. The later displays the expected dollar sign as the symbol where as the former displays something unprintable.
Sample Code
var services = new ServiceCollection();
services.AddLogging(x =>
{
x.AddDebug();
x.AddConsole();
});
var svcProvider = services.BuildServiceProvider();
var logger = svcProvider.GetRequiredService<ILoggerFactory().CreateLogger<Program>();
logger.LogInformation("Amount {0:C}", 100.0);
System.Diagnostics.Debug.WriteLine(string.Format("Amount {0:C}", 100.0));
Output from Debug
xyz.Program:Information: Amount ¤100.00
Amount $100.00
I see know way of configuring CultureInfo for the ILogger and I don't want to specify it each time I write. Also, I don't think this is relevant, but the code is being executed inside an async
method.
So is this a bug, are my expectations unrealistic, or am I doing something wrong?
Apparently the reason for this behavior is that logs shouldn't be specific to any locale. I searched for a work around or setting in the Microsoft.Extensions.Logging.Abstractions repo, but there appears no way to circumvent this behavior.
(Almost) all of the logging methods for an ILogger come from a static extensions class, LoggerExtensions (ILogger defines one Log
method which would be a pain to use directly). All of the methods in that class end up calling the same Log
method that converts the message format and its arguments into a FormattedLogValues object.
The FormattedLogValues object has a static cache keyed by the format string with the values of LogValuesFormatter. These formatters are responsible for converting the message and args into a string and they explicitly set the culture to CultureInfo.InvariantCulture when calling string.Format
. This is why the "scarab" symbol (¤) is displayed when using the currency format specifier.
Since I know all of my amounts are going to be in dollars, the simplest and most correct solution was to eschew the currency specifier for a customer numeric format string.
logger.LogInformation("Amount {0:$#,##0.00}", 100.0);
Thanks to @Amy and @PanagiotisKanavos for all of their help.