我在 ASP.NET Core Web API 中使用 Serilog 时遇到问题。我想通过用列分隔事物来将 API 事件保存到数据库中。
ex.Column | ex.Value = Method | 'GET', URL | Localhost, RequestDate | 01/01/2023.
这是我的
appsetting.json
:
"ConnectionStrings": {
"ConnS": "Server=localhost; Port=5432; Database=DB; User ID=postgres; Password=12345678;"
},
"Serilog":{
"Using":["Serilog.Sinks.PostgreSQL"],
"MinimumLevel": "Information",
"WriteTo":[
{
"Name": "Console",
"Args": {
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff} [{Level:u3}] {Message:lj}
{CustomDateTimeColumn}"
}
},
{
"Name": "PostgreSQL",
"Args": {
"connectionString": "", //same as above.
"sinkOptionsSection": {
"tableName": "logs",
"schemaName" : "public",
"autoCreateSqlTable": false // because i've already migration this table.
},
"columnOptionsSection": {
"customColumns" : [
{
"ColumnName": "api_requestname",
"DataType": "nvarchar(255)",
"AllowNull": true,
"LogEventColumn": false
},
//Orthers
]
}
}
}
],
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ],
"Properties": { "Application": "Web_API" }
}
在我的
program.cs
我有:
using Web_API.Models;
using Microsoft.EntityFrameworkCore;
using Serilog;
// Other default build
// Configuration
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
// Log
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
.CreateLogger();
Log.CloseAndFlush();
// Register DbContext
builder.Services.AddDbContext<AppDBContext>(options =>
options.UseNpgsql(builder.Configuration.GetConnectionString("ConnS"))
);
// Other default builder and run
我创建了一个像这样的
AppDBContext.cs
:
public class AppDBContext : DbContext
{
public AppDBContext(DbContextOptions<AppDBContext> options) : base(options)
{
}
public virtual DbSet<User> User { get; set; }
public virtual DbSet<LogEvent> LogEvents { get; set; }
}
我的
User.cs
文件夹中有一个 LogEvent.cs
和 Models
可以正常工作。
让我们进入正题吧——这是我的
APILogger.cs
:
using Serilog;
namespace Web_API.Models
{
public class APILogger
{
private readonly Serilog.ILogger _logger;
public APILogger()
{
string connectionstring = "Server=localhost; Port=5432; Database=DB; User ID=postgres; Password=12345678;";
_logger = new LoggerConfiguration()
.WriteTo.PostgreSQL(
connectionString: connectionstring,
tableName: "Logs")
.CreateLogger();
}
public void LogApiRequest(string Api_requestName, string Api_requestDate, string Api_method, string Api_url, string Api_body, string Api_statusCode, string Api_responseMessage, string Api_responseDate)
{
_logger.Information(
"Api_requestName: {Api_requestName}, " +
"Api_requestDate: {Api_requestDate}, " +
"Api_method : {Api_method}," +
"Api_url : {Api_url}," +
"Api_body : {Api_body}," +
"Api_statusCode: {Api_statusCode}, " +
"Api_responseMessage : {Api_responseMessage}," +
"Api_responseDate : {Api_responseDate}"
,
Api_requestName,
Api_requestDate,
Api_method,
Api_url,
Api_body,
Api_statusCode,
Api_responseMessage,
Api_responseDate
);
}
}
}
这是我的 API 函数
GET
,用于从数据库获取数据,效果很好:
[HttpGet]
public IActionResult GetAirlineData()
{
DateTime reqDT = DateTime.Now;
string reqMethod = HttpContext.Request.Method;
string reqPath = HttpContext.Request.Path;
var reqBody = HttpContext.Request.Body;
using (LogContext.PushProperty("api_requestname", "Anonymous"))
using (LogContext.PushProperty("api_requestdate", reqDT))
using (LogContext.PushProperty("api_method", reqMethod))
using (LogContext.PushProperty("api_url", reqPath))
using (LogContext.PushProperty("api_body", reqBody.ToString()))
try
{
var data = _dbContext.Airline;
int statusCode = HttpContext.Response.StatusCode;
string resMessage = "Success";
DateTime resDT = DateTime.Now;
_logger.LogInformation("API request processed successfully - api_status: {@api_status}, api_responsemessage: {@api_responsemessage}, api_responsedate: {@api_responsedate}", statusCode.ToString(), resMessage, resDT);
return Ok(Newtonsoft.Json.JsonConvert.SerializeObject(data, Newtonsoft.Json.Formatting.Indented));
}
catch (Exception ex)
{
int statusCode = HttpContext.Response.StatusCode;
string resMessage = ex.Message.ToString();
DateTime resDT = DateTime.Now;
_logger.LogError("API request error - api_status: {api_status}, api_responsemessage: {api_responsemessage}, api_responsedate: {api_responsedate}", statusCode.ToString(), resMessage, resDT);
return BadRequest(ex.Message);
}
}
控制台:
API 请求处理成功 - api_status:200,api_responsemessage:成功,api_responsedate:10/11/2023 15:20:42
控制台显示日志信息,但没有保存到数据库中。那我该怎么办?
Log.CloseAndFlush();
可以关闭Serilog日志记录。如果您使用 Serilog.Sinks.Postgresql.Alternative 包,则在版本 4.0.1 中,列顺序发生了重大变化。
https://github.com/serilog-contrib/Serilog.Sinks.Postgresql.Alternative/issues/57
如果数据库中已有表,可以通过添加以下方式对列进行排序:
"Id": {
"Name": "IdAutoIncrement",
"Order": 0
}