[英]Why the DictionaryValue is converted to ScalarValue in Serilog in ASP.NET Core
我的 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());
其中IsDictionaryValue
定义为:
static bool IsDictionaryValue(LogEvent logEvent)
{
if (logEvent.Properties.TryGetValue("LOG_TEST", out LogEventPropertyValue value))
{
return value is DictionaryValue;
}
return false;
}
尝试记录跟踪和信息消息:
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);
问题是:
为什么在 ASP.NET Core web 应用程序中,日志跟踪消息正确创建DictionaryValue
并且IsDictionaryValue
的结果为true
,但是当我记录信息消息时, LogEventPropertyValue
值为ScalarValue
。
但
此“错误”仅存在于 ASP.NET Core web 应用程序中。 当我在控制台应用程序中使用相同的 Serilog 配置时,LogTrace 和 LogInformation 都正确地将dict
字典表示为DictionaryValue
。
更新:
DictionaryValue
中LogEventPropertyValue
的类型
日志方法 | 控制台应用 | Web 应用程序 |
---|---|---|
日志跟踪 | 字典值 | 字典值 |
日志调试 | 字典值 | 字典值 |
日志信息 | 字典值 | 标量值 |
日志警告 | 字典值 | 标量值 |
日志错误 | 字典值 | 标量值 |
逻辑临界 | 字典值 | 标量值 |
问题:
在 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
当你配置 serilog
services.AddLogging(configure => configure.AddSerilog());
添加了第五个LoggerProvider
:
5. Serilog.Extensions.Logging.SerilogLogger
其他提供者的默认配置是LogLevel:Information
。 这就是LogTrace
和LogDebug
在 Web 应用程序中工作的原因。 因此,如果您调用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)
}
}
并将原始dictionary
转换为string
。 当第五个记录器提供程序(出SerilogLogger
)开始播放时,它无法解析DictionaryValue
因为TState
是string
解决方案:
将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());
}
并且因为SerilogLoggerProvider
是在IHostBuilder
的Program.cs
中注册的,所以在services.AddLogging(configure => configure.AddSerilog());
中的AddSerilog()
没有必要。
services.AddLogging();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.