Serilog 在通用记录器中缺少异常
Serilog missing exception in generic logger
在控制器方法中,通用记录器似乎没有定义的增强器。
这是控制器:
public class TestController : Controller
{
ILogger _logger;
public TestController(ILogger<TestController> logger)
{
_logger = logger;
}
public IActionResult action()
{
try
{
throw new NullReferenceException();
}
catch(Exception e)
{
Serilog.Log.Error(ex, "action KO");
_logger.LogError("action KO", ex);
}
}
}
appsettings.json:
{
"Serilog": {
"MinimumLevel": {
"Default": "Debug",
},
"WriteTo": [
{
"Name": "Console"
},
{
"Name": "File",
"Args": {
"path": "Log/api.log",
"outputTemplate": "{Timestamp} [{Level:u3}] ({SourceContext}) {Message}{NewLine}{Exception}",
"rollingInterval": "Day",
"retainedFileCountLimit": 7
}
}
],
"Enrich": [
"FromLogContext",
"WithExceptionDetails"
]
}
}
主办大楼:
IHost host = Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
webBuilder.UseUrls($"http://*:12345");
})
.UseSerilog((hostingContext, loggerConfiguration) => loggerConfiguration
.ReadFrom.Configuration(hostingContext.Configuration)
)
.Build()
;
文件/控制台输出:
02/18/2021 12:24:57 +01:00 [ERR] () action KO
System.NullReferenceException: Object reference not set to an instance of an object.
at App.TestController`1.action()
02/18/2021 12:24:57 +01:00 [ERR] (App.TestController) action KO
所以当我尝试使用通用记录器时,异常被忽略了。鉴于静态记录器写入它。
我是否遗漏了诸如控制器记录器提供程序之类的东西,还是应该由 UseSerilog
完成?
编辑
已尝试 UseSerilog
和 writeToProviders: true
=> 无效
已尝试 AddSerilog
作为日志生成器 => 无效
services.AddLogging(loggingBuilder => loggingBuilder.AddSerilog(
new LoggerConfiguration().ReadFrom.Configuration(Configuration).CreateLogger(), true));
尝试了 AddSerilogServices => 无效
public static IServiceCollection AddSerilogServices(
this IServiceCollection services,
LoggerConfiguration configuration)
{
Log.Logger = configuration.CreateLogger();
AppDomain.CurrentDomain.ProcessExit += (s, e) => Log.CloseAndFlush();
return services.AddSingleton(Log.Logger);
}
首先,请更改
_logger.LogError("action KO", ex);
至
_logger.LogError(ex, "action KO");
正在测试以下内容try/catch
try
{
throw new NullReferenceException();
}
catch (Exception ex)
{
_logger.LogError(ex, "action KO");
}
...将此写入日志文件:
02/27/2021 22:55:59 +01:00 [ERR] (MyMicroservice.Controllers.WeatherForecastController) action KO
System.NullReferenceException: Object reference not set to an instance of an object.
at MyMicroservice.Controllers.WeatherForecastController.Get() in C:\Prosjekter\MyMicroservice\WebApp\Controllers\WeatherForecastController.cs:line 51
在使用文档检查您的配置并进行一些测试后,您添加到问题中的部分对我来说似乎没问题。
我在测试和阅读文档时添加了一些关于有趣发现的文字,最后有一个 Program.cs
你可能想看看。
TL;DR: Serilog recommends two-stage initialization in order to have a
temporary logger before starting the host. The code below shows
how to skip stage #1 with a tiny change and still get a logger before starting the host.
Serilog.AspNetCore 文档:
https://github.com/serilog/serilog-aspnetcore#inline-initialization
在 Program#Main
的最开始,您将有一个 Serilog.Core.Pipeline.SilentLogger
。
如果您遵循建议,您将在第 1 阶段后获得 Serilog.Extensions.Hosting.ReloadableLogger
。
第 1 阶段看起来像这样并且需要 Nuget Serilog.Extensions.Hosting
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
.Enrich.FromLogContext()
.WriteTo.Console()
.CreateBootstrapLogger();
为了尝试为我们节省一些代码行和额外的依赖项,请注释掉阶段 #1,让我们尝试以下方法以查看我们是否可以在启动 Web 主机之前获得初始化的记录器。
var webHost = CreateHostBuilder(args).Build();
在这一行之后,我们确实有一个 Serilog.Core.Logger
的实例,这与我们在使用 CreateHostBuilder(args).Build().Run()
时最终得到的实例相同。因此,我最终得到了下面的 Program.cs
,其中我完全省略了阶段 #1,但保留了阶段 #2。
这应该没有任何副作用,医生说:
To address this, Serilog supports two-stage initialization. An initial
"bootstrap" logger is configured immediately when the program starts,
and this is replaced by the fully-configured logger once the host has
loaded.
请注意,在注释掉文档中的代码行后,UseSerilog
部分现在等于问题中的配置。
我正在使用你问题中的appsettings.json
。
我在 Startup.cs
中没有 Serilog 配置。
using System;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Serilog;
using Microsoft.Extensions.DependencyInjection;
namespace MyMicroservice
{
public class Program
{
public static void Main(string[] args)
{
// Serilog.Core.Pipeline.SilentLogger at this stage
var webHost = CreateHostBuilder(args).Build();
// Serilog.Core.Logger at this stage
// proof-of-concept: This will log to file before starting the host
var logger = webHost.Services.GetService<ILogger<Program>>();
logger.LogWarning("Hello from Program.cs");
try
{
Log.Information("Starting up");
webHost.Run();
}
catch (Exception ex)
{
Log.Fatal(ex, "Application start-up failed");
}
finally
{
Log.CloseAndFlush();
}
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseSerilog((context, services, configuration) => configuration
.ReadFrom.Configuration(context.Configuration)
/*.ReadFrom.Services(services) not required for this case */
/*.Enrich.FromLogContext() already configured in appsettings.json */
/*.WriteTo.Console() already configured in appsettings.json */
)
.ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup<Startup>());
}
}
在控制器方法中,通用记录器似乎没有定义的增强器。
这是控制器:
public class TestController : Controller
{
ILogger _logger;
public TestController(ILogger<TestController> logger)
{
_logger = logger;
}
public IActionResult action()
{
try
{
throw new NullReferenceException();
}
catch(Exception e)
{
Serilog.Log.Error(ex, "action KO");
_logger.LogError("action KO", ex);
}
}
}
appsettings.json:
{
"Serilog": {
"MinimumLevel": {
"Default": "Debug",
},
"WriteTo": [
{
"Name": "Console"
},
{
"Name": "File",
"Args": {
"path": "Log/api.log",
"outputTemplate": "{Timestamp} [{Level:u3}] ({SourceContext}) {Message}{NewLine}{Exception}",
"rollingInterval": "Day",
"retainedFileCountLimit": 7
}
}
],
"Enrich": [
"FromLogContext",
"WithExceptionDetails"
]
}
}
主办大楼:
IHost host = Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
webBuilder.UseUrls($"http://*:12345");
})
.UseSerilog((hostingContext, loggerConfiguration) => loggerConfiguration
.ReadFrom.Configuration(hostingContext.Configuration)
)
.Build()
;
文件/控制台输出:
02/18/2021 12:24:57 +01:00 [ERR] () action KO
System.NullReferenceException: Object reference not set to an instance of an object.
at App.TestController`1.action()
02/18/2021 12:24:57 +01:00 [ERR] (App.TestController) action KO
所以当我尝试使用通用记录器时,异常被忽略了。鉴于静态记录器写入它。
我是否遗漏了诸如控制器记录器提供程序之类的东西,还是应该由 UseSerilog
完成?
编辑
已尝试
UseSerilog
和writeToProviders: true
=> 无效已尝试
AddSerilog
作为日志生成器 => 无效services.AddLogging(loggingBuilder => loggingBuilder.AddSerilog( new LoggerConfiguration().ReadFrom.Configuration(Configuration).CreateLogger(), true));
尝试了 AddSerilogServices => 无效
public static IServiceCollection AddSerilogServices( this IServiceCollection services, LoggerConfiguration configuration) { Log.Logger = configuration.CreateLogger(); AppDomain.CurrentDomain.ProcessExit += (s, e) => Log.CloseAndFlush(); return services.AddSingleton(Log.Logger); }
首先,请更改
_logger.LogError("action KO", ex);
至
_logger.LogError(ex, "action KO");
正在测试以下内容try/catch
try
{
throw new NullReferenceException();
}
catch (Exception ex)
{
_logger.LogError(ex, "action KO");
}
...将此写入日志文件:
02/27/2021 22:55:59 +01:00 [ERR] (MyMicroservice.Controllers.WeatherForecastController) action KO
System.NullReferenceException: Object reference not set to an instance of an object.
at MyMicroservice.Controllers.WeatherForecastController.Get() in C:\Prosjekter\MyMicroservice\WebApp\Controllers\WeatherForecastController.cs:line 51
在使用文档检查您的配置并进行一些测试后,您添加到问题中的部分对我来说似乎没问题。
我在测试和阅读文档时添加了一些关于有趣发现的文字,最后有一个 Program.cs
你可能想看看。
TL;DR: Serilog recommends two-stage initialization in order to have a temporary logger before starting the host. The code below shows how to skip stage #1 with a tiny change and still get a logger before starting the host.
Serilog.AspNetCore 文档: https://github.com/serilog/serilog-aspnetcore#inline-initialization
在 Program#Main
的最开始,您将有一个 Serilog.Core.Pipeline.SilentLogger
。
如果您遵循建议,您将在第 1 阶段后获得 Serilog.Extensions.Hosting.ReloadableLogger
。
第 1 阶段看起来像这样并且需要 Nuget Serilog.Extensions.Hosting
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
.Enrich.FromLogContext()
.WriteTo.Console()
.CreateBootstrapLogger();
为了尝试为我们节省一些代码行和额外的依赖项,请注释掉阶段 #1,让我们尝试以下方法以查看我们是否可以在启动 Web 主机之前获得初始化的记录器。
var webHost = CreateHostBuilder(args).Build();
在这一行之后,我们确实有一个 Serilog.Core.Logger
的实例,这与我们在使用 CreateHostBuilder(args).Build().Run()
时最终得到的实例相同。因此,我最终得到了下面的 Program.cs
,其中我完全省略了阶段 #1,但保留了阶段 #2。
这应该没有任何副作用,医生说:
To address this, Serilog supports two-stage initialization. An initial "bootstrap" logger is configured immediately when the program starts, and this is replaced by the fully-configured logger once the host has loaded.
请注意,在注释掉文档中的代码行后,UseSerilog
部分现在等于问题中的配置。
我正在使用你问题中的appsettings.json
。
我在 Startup.cs
中没有 Serilog 配置。
using System;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Serilog;
using Microsoft.Extensions.DependencyInjection;
namespace MyMicroservice
{
public class Program
{
public static void Main(string[] args)
{
// Serilog.Core.Pipeline.SilentLogger at this stage
var webHost = CreateHostBuilder(args).Build();
// Serilog.Core.Logger at this stage
// proof-of-concept: This will log to file before starting the host
var logger = webHost.Services.GetService<ILogger<Program>>();
logger.LogWarning("Hello from Program.cs");
try
{
Log.Information("Starting up");
webHost.Run();
}
catch (Exception ex)
{
Log.Fatal(ex, "Application start-up failed");
}
finally
{
Log.CloseAndFlush();
}
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseSerilog((context, services, configuration) => configuration
.ReadFrom.Configuration(context.Configuration)
/*.ReadFrom.Services(services) not required for this case */
/*.Enrich.FromLogContext() already configured in appsettings.json */
/*.WriteTo.Console() already configured in appsettings.json */
)
.ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup<Startup>());
}
}