使用数据库在 ASP.NET Core 5.0 应用程序中使用 Serilog 实现日志记录
Implement Logging Using Serilog In ASP.NET Core 5.0 Application With Database
在我的 asp.net 核心 5.0 应用程序中,每当我尝试使用 serilog 执行日志记录并将日志保存到我的数据库时。但是,当我 运行 api 时,它告诉我:
System.TypeInitializationException HResult=0x80131534 Message=The
type initializer for 'PaymentService.API.Program' threw an exception.
Source=PaymentService.API StackTrace: at
PaymentService.API.Program.get_Configuration() in API\Program.cs:line
21 at PaymentService.API.Program.Main(String[] args) in
API\Program.cs:line 34
This exception was originally thrown at this call stack:
[External Code]
Inner Exception 1: FormatException: Could not parse the JSON file.
Inner Exception 2: JsonReaderException: Expected depth to be zero at
the end of the JSON payload. There is an open JSON object or array
that should be closed. LineNumber: 7 | BytePositionInLine: 1.
第21行是:
public static IConfiguration Configuration { get; } = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", optional: true)
.Build();
第 34 行是:
string connectionString = Configuration.GetConnectionString("Default");
我是新手,但我是否必须对“ASPNETCORE_ENVIRONMENT”进行任何配置?
之后,我尝试将自定义列添加到名为 CorrelationId
的数据库中,并将 CorrelationId
发送到其特定列。我是按照这个 tutorial 来这样做的,但是我卡在了他们想要捕获用户以获取日志的步骤上。我想做同样的事情,但对日志使用 CorrelationId
。
Program.cs
:
public class Program
{
public static IConfiguration Configuration { get; } = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", optional: true)
.Build();
public static void Main(string[] args)
{
string connectionString = Configuration.GetConnectionString("Default");
var columnOptions = new ColumnOptions
{
AdditionalColumns = new Collection<SqlColumn>
{
new SqlColumn("CorrelationId", SqlDbType.NVarChar)
}
}; // through this columnsOptions we can dynamically add custom columns which we want to add in the db
Log.Logger = new LoggerConfiguration()
.Enrich.FromLogContext()
.WriteTo.MSSqlServer(connectionString, sinkOptions: new MSSqlServerSinkOptions { TableName = "PaymentLogs" }
, null, null, LogEventLevel.Information, null, columnOptions: columnOptions, null, null)
.CreateLogger();
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>().UseSerilog();
});
}
Startup.cs
:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "PaymentService.API", Version = "v1" });
});
services.AddHttpContextAccessor();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseMiddleware<LogHeaderMiddleware>();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "PaymentService.API v1"));
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
/* app.Use(async (httpContext, next) =>
{
var correlationId = httpContext.Session. // need to find a way to map correlationId and send it to the logs
})*/
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
appsettings.json
{
"ConnectionStrings": {
"Default": "Data Source=.\SQLExpress;Database=ElasticSearchService;Trusted_Connection=True;"
},
"Serilog": {
"MinimumLevel": "Information",
"AllowedHosts": "*"
}
PaymentController
[Route("api/[controller]")]
[ApiController]
public class PaymentController : ControllerBase
{
private readonly ILogger<PaymentServicesController> _logger;
public PaymentServicesController(ILogger<PaymentServicesController> logger)
{
_logger = logger;
}
// GET: api/<PaymentServices>
[HttpGet]
[Route("payment")]
public void MakePayment()
{
_logger.LogInformation("PAYMENT METHOD INVOLKED!!!");
}
}
此处 header
将保存我需要的 correlationId
,以便我可以将其发送到数据库。
public class LogHeaderMiddleware
{
private readonly RequestDelegate _next;
public LogHeaderMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
var header = context.Request.Headers["CorrelationId"];
if (header.Count > 0)
{
var logger = context.RequestServices.GetRequiredService<ILogger<LogHeaderMiddleware>>();
using (logger.BeginScope("{@CorrelationId}", header[0]))
{
await _next(context);
}
}
else
{
await _next(context);
}
}
}
您的 JSON 文件中缺少 Serilog 对象的右大括号,导致格式不正确 JSON。因此出现异常:内部异常 1:FormatException:无法解析 JSON 文件。
在我的 asp.net 核心 5.0 应用程序中,每当我尝试使用 serilog 执行日志记录并将日志保存到我的数据库时。但是,当我 运行 api 时,它告诉我:
System.TypeInitializationException HResult=0x80131534 Message=The type initializer for 'PaymentService.API.Program' threw an exception. Source=PaymentService.API StackTrace: at PaymentService.API.Program.get_Configuration() in API\Program.cs:line 21 at PaymentService.API.Program.Main(String[] args) in API\Program.cs:line 34
This exception was originally thrown at this call stack: [External Code]
Inner Exception 1: FormatException: Could not parse the JSON file.
Inner Exception 2: JsonReaderException: Expected depth to be zero at the end of the JSON payload. There is an open JSON object or array that should be closed. LineNumber: 7 | BytePositionInLine: 1.
第21行是:
public static IConfiguration Configuration { get; } = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", optional: true)
.Build();
第 34 行是:
string connectionString = Configuration.GetConnectionString("Default");
我是新手,但我是否必须对“ASPNETCORE_ENVIRONMENT”进行任何配置?
之后,我尝试将自定义列添加到名为 CorrelationId
的数据库中,并将 CorrelationId
发送到其特定列。我是按照这个 tutorial 来这样做的,但是我卡在了他们想要捕获用户以获取日志的步骤上。我想做同样的事情,但对日志使用 CorrelationId
。
Program.cs
:
public class Program
{
public static IConfiguration Configuration { get; } = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", optional: true)
.Build();
public static void Main(string[] args)
{
string connectionString = Configuration.GetConnectionString("Default");
var columnOptions = new ColumnOptions
{
AdditionalColumns = new Collection<SqlColumn>
{
new SqlColumn("CorrelationId", SqlDbType.NVarChar)
}
}; // through this columnsOptions we can dynamically add custom columns which we want to add in the db
Log.Logger = new LoggerConfiguration()
.Enrich.FromLogContext()
.WriteTo.MSSqlServer(connectionString, sinkOptions: new MSSqlServerSinkOptions { TableName = "PaymentLogs" }
, null, null, LogEventLevel.Information, null, columnOptions: columnOptions, null, null)
.CreateLogger();
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>().UseSerilog();
});
}
Startup.cs
:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "PaymentService.API", Version = "v1" });
});
services.AddHttpContextAccessor();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseMiddleware<LogHeaderMiddleware>();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "PaymentService.API v1"));
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
/* app.Use(async (httpContext, next) =>
{
var correlationId = httpContext.Session. // need to find a way to map correlationId and send it to the logs
})*/
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
appsettings.json
{
"ConnectionStrings": {
"Default": "Data Source=.\SQLExpress;Database=ElasticSearchService;Trusted_Connection=True;"
},
"Serilog": {
"MinimumLevel": "Information",
"AllowedHosts": "*"
}
PaymentController
[Route("api/[controller]")]
[ApiController]
public class PaymentController : ControllerBase
{
private readonly ILogger<PaymentServicesController> _logger;
public PaymentServicesController(ILogger<PaymentServicesController> logger)
{
_logger = logger;
}
// GET: api/<PaymentServices>
[HttpGet]
[Route("payment")]
public void MakePayment()
{
_logger.LogInformation("PAYMENT METHOD INVOLKED!!!");
}
}
此处 header
将保存我需要的 correlationId
,以便我可以将其发送到数据库。
public class LogHeaderMiddleware
{
private readonly RequestDelegate _next;
public LogHeaderMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
var header = context.Request.Headers["CorrelationId"];
if (header.Count > 0)
{
var logger = context.RequestServices.GetRequiredService<ILogger<LogHeaderMiddleware>>();
using (logger.BeginScope("{@CorrelationId}", header[0]))
{
await _next(context);
}
}
else
{
await _next(context);
}
}
}
您的 JSON 文件中缺少 Serilog 对象的右大括号,导致格式不正确 JSON。因此出现异常:内部异常 1:FormatException:无法解析 JSON 文件。