RequestResponseLogging.cs 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. using AipGateway.API.Application;
  2. using AipGateway.API.Domain.IRepositories.IGenericRepositories;
  3. using AipGateway.API.Domain.Models;
  4. using AipGateway.API.Domain.Models.Request;
  5. using AipGateway.API.Domain.Models.Response;
  6. using AipGateway.API.Services.Interfaces;
  7. using AipGateway.Messaging.Models;
  8. using Microsoft.AspNetCore.Http.Features;
  9. using Newtonsoft.Json;
  10. using System.Diagnostics;
  11. using AipGateway.API.Utils;
  12. namespace AipGateway.API.Middlewares
  13. {
  14. public class RequestResponseLogging
  15. {
  16. private readonly ILogger<RequestResponseLogging> _log;
  17. private readonly RequestDelegate _next;
  18. public RequestResponseLogging(ILogger<RequestResponseLogging> log, RequestDelegate next)
  19. {
  20. _next = next ?? throw new ArgumentNullException(nameof(next));
  21. _log = log;
  22. _next = next;
  23. }
  24. public async Task Invoke(HttpContext httpContext, IAipDbLoggingService aipDbLoggingService)
  25. {
  26. if (httpContext == null) throw new ArgumentNullException(nameof(httpContext));
  27. string requestUrl = httpContext.Request.Path;
  28. string? remoteIpAddr = httpContext.Connection.RemoteIpAddress?.ToString();
  29. try
  30. {
  31. if (!requestUrl.Contains(GlobalConstants.API_PREFIX))
  32. {
  33. await _next(httpContext);
  34. }
  35. else
  36. {
  37. string fileExt = "";
  38. string dispName = "";
  39. long fileSize = 0;
  40. var start = Stopwatch.GetTimestamp();
  41. string guid = Guid.NewGuid().ToString();
  42. ApiCallLog apiLog = new ApiCallLog
  43. {
  44. ApiGuid = guid,
  45. RequestAt = DateTime.Now,
  46. ApiEndPoint = httpContext.Request.Path,
  47. IPAddress = httpContext.Connection.RemoteIpAddress?.ToString(),
  48. ErrorMessage = "",
  49. };
  50. httpContext.Items[GlobalConstants.API_GUID] = guid;
  51. httpContext.Items[GlobalConstants.API_START_TM] = DateTime.Now;
  52. await _next(httpContext);
  53. var statusCode = httpContext.Response.StatusCode;
  54. apiLog.ResponseStatusCode = statusCode;
  55. apiLog.ErrorCode = GlobalConstants.getAttributeInt(httpContext, GlobalConstants.API_RESULT_CODE);
  56. apiLog.ErrorMessage = GlobalConstants.getAttributeStr(httpContext, GlobalConstants.API_RESULT_MESSAGE);
  57. apiLog.ResponseAt = DateTime.Now;
  58. TimeSpan timeDiff = apiLog.ResponseAt - apiLog.RequestAt;
  59. apiLog.ResponseTime = timeDiff.Milliseconds;
  60. apiLog.TimeStamp = DateTime.Now;
  61. aipDbLoggingService.Send(apiLog);
  62. if (httpContext.Request.Method != HttpMethod.Post.ToString())
  63. {
  64. return;
  65. }
  66. int apiId = GlobalConstants.GetApiId(httpContext);
  67. if ((apiId >= GlobalConstants.API_FILE_INFO && apiId <= GlobalConstants.API_FILE_DELETE_LABEL_PROTECTION) ||
  68. (apiId >= GlobalConstants.API_STREAM_INFO && apiId <= GlobalConstants.API_STREAM_DELETE_LABEL_PROTECTION))
  69. {
  70. FileJobLog fileJobLog = new FileJobLog
  71. {
  72. FileId = guid,
  73. FileName = "",
  74. FileExt = "",
  75. FileOwner = "",
  76. FileLabelGuid = "",
  77. FileProtectionGuid = "",
  78. FileSize = 0,
  79. NewFileName = string.Empty,
  80. NewFileExt = string.Empty,
  81. NewFileOwner = string.Empty,
  82. NewFileLabelGuid = string.Empty,
  83. NewFileProtectionGuid = string.Empty,
  84. NewFileSize = 0,
  85. ApiGuid = guid,
  86. ApiId = apiId,
  87. ServerIpAddr = remoteIpAddr,
  88. JobOwner = string.Empty,
  89. ApiKey = string.Empty,
  90. DecryptKey = string.Empty,
  91. JobResult = 0,
  92. JobMessage = string.Empty,
  93. JobTime = apiLog.ResponseTime,
  94. };
  95. if (httpContext.Items[GlobalConstants.API_REQUEST] is RequestBase req)
  96. {
  97. fileJobLog.ApiKey = req.apiKey;
  98. fileJobLog.DecryptKey = req.decryptKey;
  99. fileJobLog.JobOwner = req.email;
  100. }
  101. if (httpContext.Items[GlobalConstants.API_RESULT] is ResponseBase res)
  102. {
  103. dispName = res.dispFileName;
  104. fileJobLog.JobResult = res.errorCode;
  105. fileJobLog.JobMessage = res.errorMessage;
  106. fileJobLog.FileName = res.dispFileName;
  107. fileJobLog.FileOwner = res.FileOwner;
  108. fileJobLog.FileExt = Path.GetExtension(res.dispFileName);
  109. fileJobLog.FileSize = res.FileSize;
  110. fileJobLog.FileLabelGuid = res.FileLabelGuid;
  111. fileJobLog.FileProtectionGuid = res.FileProtectionGuid;
  112. fileJobLog.NewFileName = res.NewFileName;
  113. fileJobLog.NewFileOwner = res.NewFileOwner;
  114. fileJobLog.NewFileExt = Path.GetExtension(res.NewFileName);
  115. fileJobLog.NewFileSize = res.NewFileSize;
  116. fileJobLog.NewFileLabelGuid = res.NewFileLabelGuid;
  117. fileJobLog.NewFileProtectionGuid = res.NewFileProtectionGuid;
  118. }
  119. fileExt = fileJobLog.FileExt;
  120. fileSize = fileJobLog.FileSize;
  121. fileJobLog.TimeStamp = DateTime.Now;
  122. aipDbLoggingService.Send(fileJobLog);
  123. long apiElapsed = TimeUtils.GetElapsedMilliseconds(start, Stopwatch.GetTimestamp());
  124. if (httpContext.Items[GlobalConstants.API_START_TM] is DateTime startTime)
  125. {
  126. TimeSpan apiTimeDiff = DateTime.Now - startTime;
  127. if (apiTimeDiff.Milliseconds > apiElapsed)
  128. {
  129. apiElapsed = apiTimeDiff.Milliseconds;
  130. }
  131. }
  132. double fileSizekb = Math.Round((double)(fileSize / 1024), 2);
  133. if (apiElapsed > 1500)
  134. {
  135. _log.LogWarning("API Processing: {0}, {1,6} ms. {2,7} KB. {3,-6}, {4}", requestUrl, apiElapsed.ToString("#,##0"), fileSizekb.ToString("#,###,##0"), fileExt, dispName);
  136. }
  137. else
  138. {
  139. _log.LogInformation("API Processing: {0}, {1,6} ms. {2,7} KB. {3,-6}, {4}", requestUrl, apiElapsed.ToString("#,##0"), fileSizekb.ToString("#,###,##0"), fileExt, dispName);
  140. }
  141. }
  142. }
  143. }
  144. catch (Exception e)
  145. {
  146. _log.LogError($"Invoke Exception: {httpContext.Request.Method}, {httpContext.Request.Path}: Excepton Error: {e}");
  147. throw;
  148. }
  149. }
  150. class BenchmarkToken : IDisposable
  151. {
  152. private readonly Stopwatch _stopwatch;
  153. public BenchmarkToken(Stopwatch stopwatch)
  154. {
  155. _stopwatch = stopwatch;
  156. _stopwatch.Start();
  157. }
  158. public void Dispose() => _stopwatch.Stop();
  159. }
  160. string GetPath(HttpContext httpContext, bool includeQueryInRequestPath)
  161. {
  162. /*
  163. In some cases, like when running integration tests with WebApplicationFactory<T>
  164. the Path returns an empty string instead of null, in that case we can't use
  165. ?? as fallback.
  166. */
  167. var requestPath = includeQueryInRequestPath
  168. ? httpContext.Features.Get<IHttpRequestFeature>()?.RawTarget
  169. : httpContext.Features.Get<IHttpRequestFeature>()?.Path;
  170. if (string.IsNullOrEmpty(requestPath))
  171. {
  172. requestPath = httpContext.Request.Path.ToString();
  173. }
  174. return requestPath!;
  175. }
  176. private static async Task<ApiCallLog> FormatRequest(HttpContext context)
  177. {
  178. context.Request.EnableBuffering();
  179. var buffer = new byte[Convert.ToInt32(context.Request.ContentLength)];
  180. await context.Request.Body.ReadAsync(buffer);
  181. //var bodyAsText = Encoding.UTF8.GetString(buffer);
  182. context.Request.Body.Position = 0;
  183. var logDto = new ApiCallLog
  184. {
  185. RequestAt = DateTime.Now,
  186. ApiEndPoint = context.Request.Path,
  187. IPAddress = context.Connection.RemoteIpAddress?.ToString(),
  188. ErrorMessage = "",
  189. };
  190. return logDto;
  191. }
  192. private static async Task<string> FormatResponse(HttpResponse response)
  193. {
  194. response.Body.Seek(0, SeekOrigin.Begin);
  195. string text = await new StreamReader(response.Body).ReadToEndAsync();
  196. response.Body.Seek(0, SeekOrigin.Begin);
  197. return text;
  198. }
  199. }
  200. }