Вы создаете новый регистратор при каждом веб-запросе в своем промежуточном программном обеспечении, и я думаю, что вы также закрываете файл журнала с помощью Log.CloseAndFlush();
, когда я думаю, что он должен быть единичным, если я вспомню документы.
Из того, что я помню, вам нужно только создать регистратор во время приложения bootstrap. Вот как я это сделал (program.cs с. 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/ или по адресу https://github.com/serilog/serilog
Редактировать
И это мой конфиг, в котором консоль указана как приемник (вы также можете добавить больше таких файлов, какasticsearch, 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
, что просто означает в терминах серилога 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();
You можно также добавить эту часть через конфигурацию с помощью 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;
}
Также обратите внимание, что я вызываю .UseSerilog();
для этого метода public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
в program.cs
, чтобы переопределить регистратор Microsfts по умолчанию (мне больше нравится serilog для всех журналов).