ResponseTimeMiddleware.cs 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. using System.Diagnostics;
  2. using System.Globalization;
  3. using System.Threading.Tasks;
  4. using MediaBrowser.Common.Extensions;
  5. using MediaBrowser.Controller.Configuration;
  6. using Microsoft.AspNetCore.Http;
  7. using Microsoft.AspNetCore.Http.Extensions;
  8. using Microsoft.Extensions.Logging;
  9. namespace Jellyfin.Server.Middleware
  10. {
  11. /// <summary>
  12. /// Response time middleware.
  13. /// </summary>
  14. public class ResponseTimeMiddleware
  15. {
  16. private const string ResponseHeaderResponseTime = "X-Response-Time-ms";
  17. private readonly RequestDelegate _next;
  18. private readonly ILogger<ResponseTimeMiddleware> _logger;
  19. private readonly bool _enableWarning;
  20. private readonly long _warningThreshold;
  21. /// <summary>
  22. /// Initializes a new instance of the <see cref="ResponseTimeMiddleware"/> class.
  23. /// </summary>
  24. /// <param name="next">Next request delegate.</param>
  25. /// <param name="logger">Instance of the <see cref="ILogger{ExceptionMiddleware}"/> interface.</param>
  26. /// <param name="serverConfigurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</param>
  27. public ResponseTimeMiddleware(
  28. RequestDelegate next,
  29. ILogger<ResponseTimeMiddleware> logger,
  30. IServerConfigurationManager serverConfigurationManager)
  31. {
  32. _next = next;
  33. _logger = logger;
  34. _enableWarning = serverConfigurationManager.Configuration.EnableSlowResponseWarning;
  35. _warningThreshold = serverConfigurationManager.Configuration.SlowResponseThresholdMs;
  36. }
  37. /// <summary>
  38. /// Invoke request.
  39. /// </summary>
  40. /// <param name="context">Request context.</param>
  41. /// <returns>Task.</returns>
  42. public async Task Invoke(HttpContext context)
  43. {
  44. var watch = new Stopwatch();
  45. watch.Start();
  46. context.Response.OnStarting(() =>
  47. {
  48. watch.Stop();
  49. LogWarning(context, watch);
  50. var responseTimeForCompleteRequest = watch.ElapsedMilliseconds;
  51. context.Response.Headers[ResponseHeaderResponseTime] = responseTimeForCompleteRequest.ToString(CultureInfo.InvariantCulture);
  52. return Task.CompletedTask;
  53. });
  54. // Call the next delegate/middleware in the pipeline
  55. await this._next(context).ConfigureAwait(false);
  56. }
  57. private void LogWarning(HttpContext context, Stopwatch watch)
  58. {
  59. if (_enableWarning && watch.ElapsedMilliseconds > _warningThreshold)
  60. {
  61. _logger.LogWarning(
  62. "Slow HTTP Response from {url} to {remoteIp} in {elapsed:g} with Status Code {statusCode}",
  63. context.Request.GetDisplayUrl(),
  64. context.GetNormalizedRemoteIp(),
  65. watch.Elapsed,
  66. context.Response.StatusCode);
  67. }
  68. }
  69. }
  70. }