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”
    }

     
     
  • 相关阅读:
    协程方法的开启、关闭以及传参
    五种访问修饰符
    多态之虚方法、抽象类、接口
    递归算法
    继承之构造方法
    鼠标相关操作(Cursor类及相关API)
    遇到的问题(七)
    遇见的问题(六)
    遇见的问题(五)
    函数VS对象
  • 原文地址:https://www.cnblogs.com/bisslot/p/12331025.html
Copyright © 2011-2022 走看看