[英]Serilog text formatting to contain valid json output
我正在使用 Serilog 進行日志記錄,並且有一個帶有 output 模板和控制台記錄器的(文本)文件接收器。
文本文件記錄器的output模板:
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff}|{Level:u3}|{SourceContext}|{Message}{NewLine:1}{Exception:1}"
控制台記錄器的 output 模板:
"outputTemplate": "{Timestamp:HH:mm:ss.fff} {Level:u3} {SourceContext} {Message:lj}{NewLine:1}{Exception:1}"
現在我們嘗試(為了簡單起見)以 JSON 格式記錄一些 class 數據。 我們希望它為 JSON,因為我們稍后會嘗試從日志文件中提取數據。
示例日志記錄代碼非常簡單:
protected void DoTestLogs()
{
Logger.LogInformation("HERE IT IS");
Logger.LogInformation("HERE IT IS {@Foo}", new { Foo = "bar" });
int x = 1;
string y = "2";
Logger.LogInformation("HERE IS ANOTHER ONE {@Other}", new { x, y });
var data = new My.Data
{
Name = "my data",
IsValid = true,
Value = 27.82859584
};
Logger.LogInformation("HERE IS DATA {@Data}", data);
}
控制台 output 看起來像預期的那樣有效(除了我可以忽略的序列化數據類型)
08:09:38.880 INF My.Test HERE IT IS
08:09:38.884 INF My.Test HERE IT IS {"Foo": "bar"}
08:09:38.888 INF My.Test HERE IS ANOTHER ONE {"x": 1, "y": "2"}
08:09:38.889 INF My.Test HERE IS DATA {"Name": "my data", "Value": 27.82859584, "IsValid": true, "$type": "Data"}
但是文本文件日志中的 json 似乎是“隨機”無效的。 我無法解釋為什么有或沒有引號
2023-01-27 08:09:38.880|INF|My.Test|HERE IT IS
2023-01-27 08:09:38.884|INF|My.Test|HERE IT IS { Foo: "bar" }
2023-01-27 08:09:38.888|INF|My.Test|HERE IS ANOTHER ONE { x: 1, y: "2" }
2023-01-27 08:09:38.889|INF|My.Test|HERE IS DATA Data { Name: "my data", Value: 27.82859584, IsValid: True }
有沒有人提示我如何像控制台接收器那樣欺騙文件接收器在名稱周圍加上引號,例如 Foo、x、y...?
如果有人想要復制它並且手頭沒有 serilog 設置:這里是設置。
首先從“ASP.NET Core Web API”模板創建一個新項目。 然后刪除 WeatherForecast.cs 和 WeatherForecastController。
將 Serilog nuget 添加到 cs.proj
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />
<PackageReference Include="Serilog.AspNetCore" Version="6.0.1" />
</ItemGroup>
</Project>
通過 appsettings.json 配置 Serilog
{
"AllowedHosts": "*",
"Serilog": {
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft.Hosting.Lifetime": "Information",
"Microsoft": "Warning",
"System": "Warning"
}
},
"Enrich": [ "FromLogContext" ],
"WriteTo": [
{
"Name": "Console",
"Args": {
"outputTemplate": "{Timestamp:HH:mm:ss.fff} {Level:u3} {SourceContext} {Message:lj}{NewLine:1}{Exception:1}"
}
},
{
"Name": "File",
"Args": {
"path": "logs/log.log",
"rollingInterval": "Day",
"outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff}|{Level:u3}|{SourceContext}|{Message}{NewLine:1}{Exception:1}"
}
}
]
}
}
在 Program.cs 中集成 Serilog
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Serilog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Stackoverflow.Question75255058
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseSerilog
(
(context, services, configuration) =>
configuration
.ReadFrom.Configuration(context.Configuration)
.ReadFrom.Services(services)
)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
無需更改 StartUp.cs
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.OpenApi.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Stackoverflow.Question75255058
{
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 = "Stackoverflow.Question75255058", Version = "v1" });
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Stackoverflow.Question75255058 v1"));
}
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
在控制器下創建一個新的 OutputController 和 My.Data class
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Stackoverflow.Question75255058.Controllers
{
[ApiController]
[Route("[controller]")]
public class LogOutputController : ControllerBase
{
public readonly ILogger<LogOutputController> Logger;
public LogOutputController(ILogger<LogOutputController> logger)
{
Logger = logger;
}
[HttpGet]
public IActionResult Get()
{
Logger.LogInformation("HERE IT IS");
Logger.LogInformation("HERE IT IS {@Foo}", new { Foo = "bar" });
int x = 1;
string y = "2";
Logger.LogInformation("HERE IS ANOTHER ONE {@Other}", new { x, y });
var data = new My.Data
{
Name = "my data",
IsValid = true,
Value = 27.82859584
};
Logger.LogInformation("HERE IS DATA {@Data}", data);
return NoContent();
}
}
}
namespace My
{
public class Data
{
public string Name { get; set; }
public bool IsValid { get; set; }
public double Value { get; set; }
}
}
啟動應用程序並執行Swagger提供的controller動作。
不同之處在於您的outputTemplate
- {Message:lj}
生成文字字符串和 JSON 對象,而默認{Message}
生成帶引號的字符串和早期的 C#-like object 格式。
對每個接收器使用相同的 output 模板應該會產生相同的結果。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.