zoukankan      html  css  js  c++  java
  • ASP.NET Core 3中的自定义日志记录

    根据我的经验,通常在API中记录请求和响应。这样做可以帮助开发人员调试问题并提供有价值的性能指标。在本教程中,我将介绍如何为ASP.NET Core 3 Web API创建基本的日志记录解决方案。在这篇文章的结尾,我们将有一个有效的日志记录解决方案,它将记录每个请求以及对控制台和文件系统的响应,并且日志将包括API处理每个请求所花费的时间。以下是概述:

    1. 先决条件
    2. 创建RequestLog和ResponseLog模型
    3. 创建ILogForWebAPI
    4. 创建WebAPIConsoleLogger
    5. 创建WebAPIFileLogger
    6. 创建CustomLoggingMiddleware
    7. 在启动中添加自定义日志记录,然后进行测试


    先决条件

    您应该熟悉 ASP.NET Core Web API请求管道。

    首先,创建一个ASP.NET Core 3 Web API项目。

    创建RequestLog和ResponseLog模型

    这些类将携带我们要记录的请求和响应数据。

    1  public class RequestLog
    2     {
    3         public Guid Id { get; set; }
    4         public string Action { get; set; }
    5         public string URL { get; set; }
    6         public string IPAddress { get; set; }
    7         public DateTime TimeStampUtc { get; set; }
    8     }
    1  public class ResponseLog
    2 {
    3         public Guid Id { get; set; }
    4         public string Action { get; set; }
    5         public string URL { get; set; }
    6         public int StatusCode { get; set; }
    7         public long ResponseTimeInMilliseconds { get; set; }
    8         public DateTime TimeStampUtc { get; set; }
    9 }

    创建ILogForWebAPI

    在这里,我们创建了可以执行两个操作的日志记录抽象—日志记录请求和日志记录响应。

    1  public interface ILogForWebAPIs
    2     {
    3         Task LogAsync(RequestLog requestLog);
    4         Task LogAsync(ResponseLog responseLog);
    5     }

    创建WebAPIConsoleLogger

    遵循单一职责原则(SRP),我们将创建ILogForWebAPI的两个实现。WebAPIConsoleLogger将负责登录到控制台,而WebAPIFileLogger将负责登录到文件系统。我们可以使用Decorator Pattern在单个ILogForWebAPI实例中提供两个记录器的功能。每个ILogForWebAPIs实现都将包含ILogForWebAPIs的嵌套实例,如果该实例不为null,则将其调用。

     1  public class WebAPIConsoleLogger : ILogForWebAPIs
     2     {
     3         private readonly ILogForWebAPIs _nextLogger;
     4         private readonly string _dateTimeFormat = "hh:mm:ss tt";
     5 
     6         public WebAPIConsoleLogger(ILogForWebAPIs nextLogger = null)
     7         {
     8             _nextLogger = nextLogger;
     9         }
    10 
    11         public async Task LogAsync(RequestLog requestLog)
    12         {
    13             Console.WriteLine($"Request received from {requestLog.IPAddress} @ {requestLog.TimeStampUtc.ToString(_dateTimeFormat)} (Utc)");
    14             Console.WriteLine($"{requestLog.Action} {requestLog.URL}");
    15             Console.WriteLine();
    16 
    17             if (_nextLogger != null)
    18             {
    19                 await _nextLogger.LogAsync(requestLog);
    20             }
    21         }
    22 
    23         public async Task LogAsync(ResponseLog responseLog)
    24         {
    25             Console.WriteLine($"Response sent @ {responseLog.TimeStampUtc.ToString(_dateTimeFormat)} (Utc)");
    26             Console.WriteLine($"{responseLog.StatusCode}: {responseLog.Action} {responseLog.URL}");
    27             Console.WriteLine($"Response time: {responseLog.ResponseTimeInMilliseconds} ms");
    28             Console.WriteLine();
    29 
    30             if (_nextLogger != null)
    31             {
    32                 await _nextLogger.LogAsync(responseLog);
    33             }
    34         }
    35     }

    创建WebAPIFileLogger

    WebAPIFileLogger将序列化模型并将其ID用作文件名,从而为每个请求和响应创建一个json文件。

     1  public class WebAPIFileLogger : ILogForWebAPIs
     2     {
     3         private readonly string _requestDirectory;
     4         private readonly string _responseDirectory;
     5         private readonly ILogForWebAPIs _nextLogger;
     6 
     7         public WebAPIFileLogger(string path, ILogForWebAPIs nextLogger = null)
     8         {
     9             if (string.IsNullOrWhiteSpace(path))
    10             {
    11                 throw new ArgumentNullException(nameof(path));
    12             }
    13 
    14             _requestDirectory = Path.Combine(path, "requests");
    15             _responseDirectory = Path.Combine(path, "responses");
    16 
    17             if (!Directory.Exists(_requestDirectory))
    18             {
    19                 Directory.CreateDirectory(_requestDirectory);
    20             }
    21 
    22             if (!Directory.Exists(_responseDirectory))
    23             {
    24                 Directory.CreateDirectory(_responseDirectory);
    25             }
    26 
    27             _nextLogger = nextLogger;
    28         }
    29 
    30         public async Task LogAsync(RequestLog requestLog)
    31         {
    32             var serializedLog = JsonConvert.SerializeObject(requestLog, Formatting.Indented);
    33             var filePath = Path.Combine(_requestDirectory, $"{requestLog.Id}.json");
    34             await File.WriteAllTextAsync(filePath, serializedLog);
    35 
    36             if (_nextLogger != null)
    37             {
    38                 await _nextLogger.LogAsync(requestLog);
    39             }
    40         }
    41 
    42         public async Task LogAsync(ResponseLog responseLog)
    43         {
    44             var serializedLog = JsonConvert.SerializeObject(responseLog, Formatting.Indented);
    45             var filePath = Path.Combine(_responseDirectory, $"{responseLog.Id}.json");
    46             await File.WriteAllTextAsync(filePath, serializedLog);
    47 
    48             if (_nextLogger != null)
    49             {
    50                 await _nextLogger.LogAsync(responseLog);
    51             }
    52         }
    53     }

    创建CustomLoggingMiddleware

    CustomLoggingMiddleware需要将自身附加到请求管道,然后使用ApplicationServices提供的记录器记录请求,最后执行请求管道并记录响应。

     1  public static class CustomLoggingMiddleware
     2     {
     3         public static void UseCustomLogging(this IApplicationBuilder app)
     4         {
     5             app.Use(async (context, next) =>
     6             {
     7                 var logger = app.ApplicationServices.GetService<ILogForWebAPIs>();
     8 
     9                 if (logger is null)
    10                 {
    11                     throw new Exception($"Add ILogForWebAPIs to your service provider in {nameof(Startup)}.{nameof(Startup.ConfigureServices)}");
    12                 }
    13 
    14                 await LogRequestAsync(context, logger);
    15                 var stopWatch = new Stopwatch();
    16                 stopWatch.Start();
    17 
    18                 // execute request pipeline
    19                 await next?.Invoke();
    20 
    21                 stopWatch.Stop();
    22 
    23                 await LogResponseAsync(context, stopWatch.ElapsedMilliseconds, logger);
    24             });
    25         }
    26 
    27         private static async Task LogRequestAsync(HttpContext context, ILogForWebAPIs logger)
    28         {
    29             var requestLog = new RequestLog
    30             {
    31                 Id = Guid.NewGuid(),
    32                 Action = context.Request.Method,
    33                 URL = context.Request.Path,
    34                 IPAddress = context.Request.HttpContext.Connection.RemoteIpAddress.ToString(),
    35                 TimeStampUtc = DateTime.UtcNow
    36             };
    37 
    38             await logger.LogAsync(requestLog);
    39         }
    40 
    41         private static async Task LogResponseAsync(HttpContext context, long responseTimeInMilliseconds, ILogForWebAPIs logger)
    42         {
    43             var responseLog = new ResponseLog
    44             {
    45                 Id = Guid.NewGuid(),
    46                 Action = context.Request.Method,
    47                 URL = context.Request.Path,
    48                 StatusCode = context.Response.StatusCode,
    49                 ResponseTimeInMilliseconds = responseTimeInMilliseconds,
    50                 TimeStampUtc = DateTime.UtcNow
    51             };
    52 
    53             await logger.LogAsync(responseLog);
    54         }
    55     }

    在启动中添加自定义日志记录,然后进行测试

    要获取我们的API日志记录,我们只需要做两件事:

    1. 将记录器添加到Startup.ConfigureServices中的IServiceCollection中
    2. 在Startup.Configure中调用UseCustomLogging

    注意:如果像下面的示例那样使用https重定向,建议将自定义日志记录添加到请求管道中。这样,您可以确保不记录重定向。

     1  public class Startup
     2     {
     3         public Startup(IConfiguration configuration)
     4         {
     5             Configuration = configuration;
     6         }
     7 
     8         public IConfiguration Configuration { get; }
     9 
    10         // This method gets called by the runtime. Use this method to add services to the container.
    11         public void ConfigureServices(IServiceCollection services)
    12         {
    13             services.AddControllers();
    14             services.AddTransient<ILogForWebAPIs>((serviceProvider) => new WebAPIConsoleLogger(new WebAPIFileLogger("APILogs")));
    15         }
    16 
    17         // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    18         public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    19         {
    20             if (env.IsDevelopment())
    21             {
    22                 app.UseDeveloperExceptionPage();
    23             }
    24 
    25             app.UseHttpsRedirection();
    26 
    27             app.UseCustomLogging();
    28 
    29             app.UseRouting();
    30 
    31             app.UseAuthorization();
    32 
    33             app.UseEndpoints(endpoints =>
    34             {
    35                 endpoints.MapControllers();
    36             });
    37         }
    38     }

    要在Visual Studio中查看控制台输出,请使用项目配置文件运行应用程序并进行测试。

    5

    6

    导航到日志目录以检查日志文件

    7

    {
    “ Id”:“ 0c7ffe14-66c3-428c-bffe-0da1dccd9546”,
    “ Action”:“ GET”,
    “ URL”:“ / weatherforecast”,
    “ IPAddress”:“ :: 1”,
    “ TimeStampUtc”:“ 2020 -02-13T15:05:27.3373827Z”
    }

     
     
  • 相关阅读:
    (Good Bye 2019) Codeforces 1270B Interesting Subarray
    (Good Bye 2019) Codeforces 1270A Card Game
    Codeforces 1283D Christmas Trees(BFS)
    Codeforces 1283C Friends and Gifts
    Codeforces 1283B Candies Division
    1095 Cars on Campus (30)
    1080 Graduate Admission (30)
    1099 Build A Binary Search Tree (30)
    1018 Public Bike Management (30)
    1087 All Roads Lead to Rome (30)
  • 原文地址:https://www.cnblogs.com/bisslot/p/12331025.html
Copyright © 2011-2022 走看看