Search code examples
c#.net-corecultureinfo

ILogger displays incorrect currency Symbol


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?


Solution

  • 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.