简体   繁体   English

为什么 DictionaryValue 在 ASP.NET Core 中的 Serilog 中转换为 ScalarValue

[英]Why the DictionaryValue is converted to ScalarValue in Serilog in ASP.NET Core

My Serilog configuration is the following:我的 Serilog 配置如下:

    LevelSwitch.MinimumLevel = LogEventLevel.Verbose;

    var loggerConfiguration =
        new LoggerConfiguration()
            .MinimumLevel.ControlledBy(LevelSwitch)
            .Enrich.FromLogContext()
            .WriteTo.Conditional(
                IsDictionaryValue,
                cfg => cfg.Console());

    services.AddLogging(configure => configure.AddSerilog());

where the IsDictionaryValue is defined as:其中IsDictionaryValue定义为:

    static bool IsDictionaryValue(LogEvent logEvent)
    {
        if (logEvent.Properties.TryGetValue("LOG_TEST", out LogEventPropertyValue value))
        {
            return value is DictionaryValue;
        }

        return false;
    }

trying to log trace and information message:尝试记录跟踪和信息消息:

    var logger = loggerFactory.CreateLogger<Program>();

    var dict = new Dictionary<string, object>
    {
        { "val1", 1 },
        { "val2", 2 },
        { "val3", "_3" },
    };

    logger.LogTrace("{@LOG_TEST}", dict);

    logger.LogInformation("{@LOG_TEST}", dict);

The question is:问题是:
Why in ASP.NET Core web app the log trace message correctly creates DictionaryValue and the result of IsDictionaryValue is true , but when I log information message, the LogEventPropertyValue value is ScalarValue .为什么在 ASP.NET Core web 应用程序中,日志跟踪消息正确创建DictionaryValue并且IsDictionaryValue的结果为true ,但是当我记录信息消息时, LogEventPropertyValue值为ScalarValue

BUT
This "bug" is only in ASP.NET Core web app.此“错误”仅存在于 ASP.NET Core web 应用程序中。 When I use the same Serilog configuration in Console app, both LogTrace and LogInformation, correctly represents the dict dictionary as DictionaryValue .当我在控制台应用程序中使用相同的 Serilog 配置时,LogTrace 和 LogInformation 都正确地将dict字典表示为DictionaryValue

Update:更新:
type of LogEventPropertyValue in DictionaryValue DictionaryValueLogEventPropertyValue的类型

Log method日志方法 Console App控制台应用 Web app Web 应用程序
LogTrace日志跟踪 DictionaryValue字典值 DictionaryValue字典值
LogDebug日志调试 DictionaryValue字典值 DictionaryValue字典值
LogInformation日志信息 DictionaryValue字典值 ScalarValue标量值
LogWarning日志警告 DictionaryValue字典值 ScalarValue标量值
LogError日志错误 DictionaryValue字典值 ScalarValue标量值
LogCritical逻辑临界 DictionaryValue字典值 ScalarValue标量值

The problem:问题:
In ASP.NET Core are registered some default LoggerProviders like:在 ASP.NET Core 中注册了一些默认LoggerProviders ,例如:

1. Microsoft.Extensions.Logging.Console.ConsoleLogger
2. Microsoft.Extensions.Logging.Debug.DebugLogger
3. Microsoft.Extensions.Logging.EventSource.EventSourceLogger
4. Microsoft.Extensions.Logging.EventLog.EventLogLogger

and when you configure serilog当你配置 serilog

services.AddLogging(configure => configure.AddSerilog());

the fifth LoggerProvider was added:添加了第五个LoggerProvider

5. Serilog.Extensions.Logging.SerilogLogger

The default configuration for other providers is LogLevel:Information .其他提供者的默认配置是LogLevel:Information This is the reason why LogTrace and LogDebug works in Web app.这就是LogTraceLogDebug在 Web 应用程序中工作的原因。 So if you call LogInformation the first four logger providers hits the TState in因此,如果您调用LogInformation ,前四个记录器提供程序会命中TState

namespace Microsoft.Extensions.Logging
{
    internal class Logger : ILogger
    {
        public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
    }
}

and it converts the original dictionary to string .并将原始dictionary转换为string And when the fifth logger provider (out SerilogLogger ) comes to play, it cannot resolve DictionaryValue because the TState is string当第五个记录器提供程序(出SerilogLogger )开始播放时,它无法解析DictionaryValue因为TStatestring

The solution:解决方案:
Set the SerilogLogger as the first LoggerProvider :SerilogLogger设置为第一个LoggerProvider

    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                })
            .ConfigureLogging(cfg => cfg
                .ClearProviders()
                .AddSerilog()
                .AddConsole()
                .AddDebug()
                .AddEventSourceLogger()
                .AddEventLog());
    }

and because the SerilogLoggerProvider is registered in Program.cs within IHostBuilder , the AddSerilog() in services.AddLogging(configure => configure.AddSerilog());并且因为SerilogLoggerProvider是在IHostBuilderProgram.cs中注册的,所以在services.AddLogging(configure => configure.AddSerilog());中的AddSerilog() is not necessary.没有必要。

services.AddLogging();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM