Serilog создает файлы до достижения максимального размера файла - PullRequest
1 голос
/ 23 марта 2020

Я создал API с использованием. NET core 2.1 и использовал Serilog для регистрации каждого отдельного ответа и запроса на уровне API для всех типов методов: Get, Post ... несмотря на код ответа; Ниже мой код добавлен в класс промежуточного программного обеспечения:

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 стал вызываться из мобильного приложения, мы поняли, что многие файлы журналов создаются одновременно, не достигая максимального размера файла, более конкретно, когда несколько методов должны регистрироваться одновременно время. Есть ли в любом случае, мы можем решить эту проблему?

1 Ответ

1 голос
/ 23 марта 2020

Вы создаете новый регистратор при каждом веб-запросе в своем промежуточном программном обеспечении, и я думаю, что вы также закрываете файл журнала с помощью 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 для всех журналов).

...