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

 
 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM