Serilog 在达到最大文件大小之前创建文件
Serilog creates files before reaching max file size
我使用 .NET core 2.1 创建了一个 API,并使用 Serilog 记录所有方法类型在 API 级别上的每个响应和请求:Get、Post .. . 尽管响应代码;下面是我添加到中间件的代码 class:
var request = context.Request;
var stopWatch = Stopwatch.StartNew();
var requestTime = DateTime.UtcNow;
var requestBodyContent = await ReadRequestBody(request);
var originalBodyStream = context.Response.Body;
generalError = Configuration["generalError"];
using (var memStream = new MemoryStream())
{
HttpResponse response = context.Response;
response.Body = memStream;
await next(context);
stopWatch.Stop();
string responseBodyContent = null;
responseBodyContent = ReadResponseBody(memStream);
memStream.CopyTo(originalBodyStream);
string infoToLog = "\r\n" +
"------------------------ \r\n" +
"Elapsed Milliseconds: " + stopWatch.ElapsedMilliseconds + "\r\n" +
"Status Code: " + context.Response.StatusCode + "\r\n" +
"Method: " + request.Method + "\r\n" +
"Path: " + request.Path + "\r\n" +
"QueryString: " + request.QueryString.ToString() + "\r\n" +
"Request Body: " + requestBodyContent + "\r\n" +
"Response Body: " + responseBodyContent + "\r\n" +
"------------------------" + "\r\n\r\n";
Log.Logger = new LoggerConfiguration()
.WriteTo.Async(a => a.File("Logs/myapp.log",
rollOnFileSizeLimit: true,
fileSizeLimitBytes: Convert.ToInt32(Configuration["MaxLogFileSize"])))
//shared:true,
.CreateLogger();
if (context.Response.StatusCode == 200)
{
Log.Information(infoToLog);
}
else {
Log.Error(infoToLog);
}
Log.CloseAndFlush();
context.Response.Body = originalBodyStream;
}
因此,如您所见,我实施了一种滚动日志记录方法,该方法仅在达到最大文件大小问题后才创建新文件。
主要问题是,在发布之后,当 API 从移动应用程序调用时,我们意识到同时创建了许多日志文件而没有达到最大文件大小,更具体地说,当应该使用多种方法时同时登录。无论如何我们可以解决这个问题吗?
您正在中间件中的每个 Web 请求上实例化一个新的记录器,我认为您也在使用 Log.CloseAndFlush();
关闭日志文件,如果我记得文档的话我认为它应该是一个单例。
据我所知,您只需要在应用程序期间创建记录器 bootstrap。我就是这样做的(program.cs with .NET core 2.2):
public class Program
{
private static readonly string _applicationName = System.Reflection.Assembly.GetEntryAssembly().GetName().Name;
public static IConfiguration Configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json", reloadOnChange: true, optional: true)
.AddEnvironmentVariables()
.Build();
public static int Main(string[] args)
{
// serilog
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(Configuration)
.Enrich.FromLogContext()
.CreateLogger();
try
{
if (string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")))
throw new Exception("Hosting environment variable not set");
Log.Information($"Bootstrapping application: {_applicationName}");
CreateWebHostBuilder(args).Build().Run();
Log.Information($"Gracefully closing application: {_applicationName}");
return 0; // returning a zero, indicates a successful shutdown.
}
catch (Exception e)
{
Log.Warning($"Host {_applicationName} - terminated unexpectedly.");
Log.Fatal(e.Message);
return 1; // returning a none-zero, indicates failure.
}
finally
{
Log.CloseAndFlush();
}
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseConfiguration(Configuration)
.UseSerilog();
}
因此,当您确实想要记录某些内容时,只需导入 using Serilog;
并调用 Log.Information("Your message.")
更多信息可以在底部找到:https://serilog.net/ or at https://github.com/serilog/serilog
编辑
这是我的配置,将控制台指定为接收器(您可以添加更多类似文件、elasticsearch、seq...其他)并且我还覆盖了 Microsoft 的默认记录器以仅显示日志级别警告或更高级别:
"Serilog": {
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"System": "Warning"
}
},
"WriteTo": [
{
"Name": "Console",
"Args": {
"outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss} {Level:u3}] {Message:lj} {SourceContext}>{NewLine}{Exception}"
}
}
]
},
更新
嗯,你把你的日志放在教程说 //TODO: Save log to chosen datastore
的地方,这只是 serilog 术语 Log.Information("Your message");
的意思。我在我的例子中用 // serilog
标记了 serilog 部分 - 所以如果你想配置记录器也记录到文件,就像你的一样添加你的配置部分:
// serilog
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(Configuration)
.Enrich.FromLogContext()
.WriteTo.Async(a => a.File("Logs/myapp.log",
rollOnFileSizeLimit: true,
fileSizeLimitBytes: Convert.ToInt32(Configuration["MaxLogFileSize"])))
.CreateLogger();
您还可以通过配置 appsettings.json
添加该部分 - 如果您不需要此部分 .ReadFrom.Configuration(Configuration).Enrich.FromLogContext()
只需将其删除。
因此您的中间件代码将如下所示:
var request = context.Request;
var stopWatch = Stopwatch.StartNew();
var requestTime = DateTime.UtcNow;
var requestBodyContent = await ReadRequestBody(request);
var originalBodyStream = context.Response.Body;
generalError = Configuration["generalError"];
using (var memStream = new MemoryStream())
{
HttpResponse response = context.Response;
response.Body = memStream;
await next(context);
stopWatch.Stop();
string responseBodyContent = null;
responseBodyContent = ReadResponseBody(memStream);
memStream.CopyTo(originalBodyStream);
string infoToLog = "\r\n" +
"------------------------ \r\n" +
"Elapsed Milliseconds: " + stopWatch.ElapsedMilliseconds + "\r\n" +
"Status Code: " + context.Response.StatusCode + "\r\n" +
"Method: " + request.Method + "\r\n" +
"Path: " + request.Path + "\r\n" +
"QueryString: " + request.QueryString.ToString() + "\r\n" +
"Request Body: " + requestBodyContent + "\r\n" +
"Response Body: " + responseBodyContent + "\r\n" +
"------------------------" + "\r\n\r\n";
if (context.Response.StatusCode == 200)
{
Log.Information(infoToLog);
}
else
{
Log.Error(infoToLog);
}
context.Response.Body = originalBodyStream;
}
另请注意,我在 program.cs
中对此方法 public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
调用了 .UseSerilog();
以覆盖 Microsfts 默认记录器(我更喜欢所有日志的 serilog)。
我使用 .NET core 2.1 创建了一个 API,并使用 Serilog 记录所有方法类型在 API 级别上的每个响应和请求:Get、Post .. . 尽管响应代码;下面是我添加到中间件的代码 class:
var request = context.Request;
var stopWatch = Stopwatch.StartNew();
var requestTime = DateTime.UtcNow;
var requestBodyContent = await ReadRequestBody(request);
var originalBodyStream = context.Response.Body;
generalError = Configuration["generalError"];
using (var memStream = new MemoryStream())
{
HttpResponse response = context.Response;
response.Body = memStream;
await next(context);
stopWatch.Stop();
string responseBodyContent = null;
responseBodyContent = ReadResponseBody(memStream);
memStream.CopyTo(originalBodyStream);
string infoToLog = "\r\n" +
"------------------------ \r\n" +
"Elapsed Milliseconds: " + stopWatch.ElapsedMilliseconds + "\r\n" +
"Status Code: " + context.Response.StatusCode + "\r\n" +
"Method: " + request.Method + "\r\n" +
"Path: " + request.Path + "\r\n" +
"QueryString: " + request.QueryString.ToString() + "\r\n" +
"Request Body: " + requestBodyContent + "\r\n" +
"Response Body: " + responseBodyContent + "\r\n" +
"------------------------" + "\r\n\r\n";
Log.Logger = new LoggerConfiguration()
.WriteTo.Async(a => a.File("Logs/myapp.log",
rollOnFileSizeLimit: true,
fileSizeLimitBytes: Convert.ToInt32(Configuration["MaxLogFileSize"])))
//shared:true,
.CreateLogger();
if (context.Response.StatusCode == 200)
{
Log.Information(infoToLog);
}
else {
Log.Error(infoToLog);
}
Log.CloseAndFlush();
context.Response.Body = originalBodyStream;
}
因此,如您所见,我实施了一种滚动日志记录方法,该方法仅在达到最大文件大小问题后才创建新文件。 主要问题是,在发布之后,当 API 从移动应用程序调用时,我们意识到同时创建了许多日志文件而没有达到最大文件大小,更具体地说,当应该使用多种方法时同时登录。无论如何我们可以解决这个问题吗?
您正在中间件中的每个 Web 请求上实例化一个新的记录器,我认为您也在使用 Log.CloseAndFlush();
关闭日志文件,如果我记得文档的话我认为它应该是一个单例。
据我所知,您只需要在应用程序期间创建记录器 bootstrap。我就是这样做的(program.cs with .NET core 2.2):
public class Program
{
private static readonly string _applicationName = System.Reflection.Assembly.GetEntryAssembly().GetName().Name;
public static IConfiguration Configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json", reloadOnChange: true, optional: true)
.AddEnvironmentVariables()
.Build();
public static int Main(string[] args)
{
// serilog
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(Configuration)
.Enrich.FromLogContext()
.CreateLogger();
try
{
if (string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")))
throw new Exception("Hosting environment variable not set");
Log.Information($"Bootstrapping application: {_applicationName}");
CreateWebHostBuilder(args).Build().Run();
Log.Information($"Gracefully closing application: {_applicationName}");
return 0; // returning a zero, indicates a successful shutdown.
}
catch (Exception e)
{
Log.Warning($"Host {_applicationName} - terminated unexpectedly.");
Log.Fatal(e.Message);
return 1; // returning a none-zero, indicates failure.
}
finally
{
Log.CloseAndFlush();
}
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseConfiguration(Configuration)
.UseSerilog();
}
因此,当您确实想要记录某些内容时,只需导入 using Serilog;
并调用 Log.Information("Your message.")
更多信息可以在底部找到:https://serilog.net/ or at https://github.com/serilog/serilog
编辑
这是我的配置,将控制台指定为接收器(您可以添加更多类似文件、elasticsearch、seq...其他)并且我还覆盖了 Microsoft 的默认记录器以仅显示日志级别警告或更高级别:
"Serilog": {
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"System": "Warning"
}
},
"WriteTo": [
{
"Name": "Console",
"Args": {
"outputTemplate": "[{Timestamp:yyyy-MM-dd HH:mm:ss} {Level:u3}] {Message:lj} {SourceContext}>{NewLine}{Exception}"
}
}
]
},
更新
嗯,你把你的日志放在教程说 //TODO: Save log to chosen datastore
的地方,这只是 serilog 术语 Log.Information("Your message");
的意思。我在我的例子中用 // serilog
标记了 serilog 部分 - 所以如果你想配置记录器也记录到文件,就像你的一样添加你的配置部分:
// serilog
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(Configuration)
.Enrich.FromLogContext()
.WriteTo.Async(a => a.File("Logs/myapp.log",
rollOnFileSizeLimit: true,
fileSizeLimitBytes: Convert.ToInt32(Configuration["MaxLogFileSize"])))
.CreateLogger();
您还可以通过配置 appsettings.json
添加该部分 - 如果您不需要此部分 .ReadFrom.Configuration(Configuration).Enrich.FromLogContext()
只需将其删除。
因此您的中间件代码将如下所示:
var request = context.Request;
var stopWatch = Stopwatch.StartNew();
var requestTime = DateTime.UtcNow;
var requestBodyContent = await ReadRequestBody(request);
var originalBodyStream = context.Response.Body;
generalError = Configuration["generalError"];
using (var memStream = new MemoryStream())
{
HttpResponse response = context.Response;
response.Body = memStream;
await next(context);
stopWatch.Stop();
string responseBodyContent = null;
responseBodyContent = ReadResponseBody(memStream);
memStream.CopyTo(originalBodyStream);
string infoToLog = "\r\n" +
"------------------------ \r\n" +
"Elapsed Milliseconds: " + stopWatch.ElapsedMilliseconds + "\r\n" +
"Status Code: " + context.Response.StatusCode + "\r\n" +
"Method: " + request.Method + "\r\n" +
"Path: " + request.Path + "\r\n" +
"QueryString: " + request.QueryString.ToString() + "\r\n" +
"Request Body: " + requestBodyContent + "\r\n" +
"Response Body: " + responseBodyContent + "\r\n" +
"------------------------" + "\r\n\r\n";
if (context.Response.StatusCode == 200)
{
Log.Information(infoToLog);
}
else
{
Log.Error(infoToLog);
}
context.Response.Body = originalBodyStream;
}
另请注意,我在 program.cs
中对此方法 public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
调用了 .UseSerilog();
以覆盖 Microsfts 默认记录器(我更喜欢所有日志的 serilog)。