TaskCompletedLogger.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Globalization;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using Jellyfin.Data.Entities;
  7. using MediaBrowser.Controller.Events;
  8. using MediaBrowser.Model.Activity;
  9. using MediaBrowser.Model.Globalization;
  10. using MediaBrowser.Model.Notifications;
  11. using MediaBrowser.Model.Tasks;
  12. using Microsoft.Extensions.Logging;
  13. namespace Jellyfin.Server.Implementations.Events.Consumers.System
  14. {
  15. /// <summary>
  16. /// Creates an activity log entry whenever a task is completed.
  17. /// </summary>
  18. public class TaskCompletedLogger : IEventConsumer<TaskCompletionEventArgs>
  19. {
  20. private readonly ILocalizationManager _localizationManager;
  21. private readonly IActivityManager _activityManager;
  22. /// <summary>
  23. /// Initializes a new instance of the <see cref="TaskCompletedLogger"/> class.
  24. /// </summary>
  25. /// <param name="localizationManager">The localization manager.</param>
  26. /// <param name="activityManager">The activity manager.</param>
  27. public TaskCompletedLogger(ILocalizationManager localizationManager, IActivityManager activityManager)
  28. {
  29. _localizationManager = localizationManager;
  30. _activityManager = activityManager;
  31. }
  32. /// <inheritdoc />
  33. public async Task OnEvent(TaskCompletionEventArgs eventArgs)
  34. {
  35. var result = eventArgs.Result;
  36. var task = eventArgs.Task;
  37. if (task.ScheduledTask is IConfigurableScheduledTask activityTask
  38. && !activityTask.IsLogged)
  39. {
  40. return;
  41. }
  42. var time = result.EndTimeUtc - result.StartTimeUtc;
  43. var runningTime = string.Format(
  44. CultureInfo.InvariantCulture,
  45. _localizationManager.GetLocalizedString("LabelRunningTimeValue"),
  46. ToUserFriendlyString(time));
  47. if (result.Status == TaskCompletionStatus.Failed)
  48. {
  49. var vals = new List<string>();
  50. if (!string.IsNullOrEmpty(eventArgs.Result.ErrorMessage))
  51. {
  52. vals.Add(eventArgs.Result.ErrorMessage);
  53. }
  54. if (!string.IsNullOrEmpty(eventArgs.Result.LongErrorMessage))
  55. {
  56. vals.Add(eventArgs.Result.LongErrorMessage);
  57. }
  58. await _activityManager.CreateAsync(new ActivityLog(
  59. string.Format(CultureInfo.InvariantCulture, _localizationManager.GetLocalizedString("ScheduledTaskFailedWithName"), task.Name),
  60. NotificationType.TaskFailed.ToString(),
  61. Guid.Empty)
  62. {
  63. LogSeverity = LogLevel.Error,
  64. Overview = string.Join(Environment.NewLine, vals),
  65. ShortOverview = runningTime
  66. }).ConfigureAwait(false);
  67. }
  68. }
  69. private static string ToUserFriendlyString(TimeSpan span)
  70. {
  71. const int DaysInYear = 365;
  72. const int DaysInMonth = 30;
  73. // Get each non-zero value from TimeSpan component
  74. var values = new List<string>();
  75. // Number of years
  76. int days = span.Days;
  77. if (days >= DaysInYear)
  78. {
  79. int years = days / DaysInYear;
  80. values.Add(CreateValueString(years, "year"));
  81. days %= DaysInYear;
  82. }
  83. // Number of months
  84. if (days >= DaysInMonth)
  85. {
  86. int months = days / DaysInMonth;
  87. values.Add(CreateValueString(months, "month"));
  88. days = days % DaysInMonth;
  89. }
  90. // Number of days
  91. if (days >= 1)
  92. {
  93. values.Add(CreateValueString(days, "day"));
  94. }
  95. // Number of hours
  96. if (span.Hours >= 1)
  97. {
  98. values.Add(CreateValueString(span.Hours, "hour"));
  99. }
  100. // Number of minutes
  101. if (span.Minutes >= 1)
  102. {
  103. values.Add(CreateValueString(span.Minutes, "minute"));
  104. }
  105. // Number of seconds (include when 0 if no other components included)
  106. if (span.Seconds >= 1 || values.Count == 0)
  107. {
  108. values.Add(CreateValueString(span.Seconds, "second"));
  109. }
  110. // Combine values into string
  111. var builder = new StringBuilder();
  112. for (int i = 0; i < values.Count; i++)
  113. {
  114. if (builder.Length > 0)
  115. {
  116. builder.Append(i == values.Count - 1 ? " and " : ", ");
  117. }
  118. builder.Append(values[i]);
  119. }
  120. // Return result
  121. return builder.ToString();
  122. }
  123. /// <summary>
  124. /// Constructs a string description of a time-span value.
  125. /// </summary>
  126. /// <param name="value">The value of this item.</param>
  127. /// <param name="description">The name of this item (singular form).</param>
  128. private static string CreateValueString(int value, string description)
  129. {
  130. return string.Format(
  131. CultureInfo.InvariantCulture,
  132. "{0:#,##0} {1}",
  133. value,
  134. value == 1 ? description : string.Format(CultureInfo.InvariantCulture, "{0}s", description));
  135. }
  136. }
  137. }