瀏覽代碼

Merge pull request #4326 from crobibero/purge-activity-log

Automatically clean activity log database
Bond-009 4 年之前
父節點
當前提交
51dc92c3a9

+ 2 - 0
Emby.Server.Implementations/Localization/Core/en-US.json

@@ -95,6 +95,8 @@
     "TasksLibraryCategory": "Library",
     "TasksApplicationCategory": "Application",
     "TasksChannelsCategory": "Internet Channels",
+    "TaskCleanActivityLog": "Clean Activity Log",
+    "TaskCleanActivityLogDescription": "Deletes activity log entries older than the configured age.",
     "TaskCleanCache": "Clean Cache Directory",
     "TaskCleanCacheDescription": "Deletes cache files no longer needed by the system.",
     "TaskRefreshChapterImages": "Extract Chapter Images",

+ 78 - 0
Emby.Server.Implementations/ScheduledTasks/Tasks/CleanActivityLogTask.cs

@@ -0,0 +1,78 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Model.Activity;
+using MediaBrowser.Model.Globalization;
+using MediaBrowser.Model.Tasks;
+
+namespace Emby.Server.Implementations.ScheduledTasks.Tasks
+{
+    /// <summary>
+    /// Deletes old activity log entries.
+    /// </summary>
+    public class CleanActivityLogTask : IScheduledTask, IConfigurableScheduledTask
+    {
+        private readonly ILocalizationManager _localization;
+        private readonly IActivityManager _activityManager;
+        private readonly IServerConfigurationManager _serverConfigurationManager;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CleanActivityLogTask"/> class.
+        /// </summary>
+        /// <param name="localization">Instance of the <see cref="ILocalizationManager"/> interface.</param>
+        /// <param name="activityManager">Instance of the <see cref="IActivityManager"/> interface.</param>
+        /// <param name="serverConfigurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</param>
+        public CleanActivityLogTask(
+            ILocalizationManager localization,
+            IActivityManager activityManager,
+            IServerConfigurationManager serverConfigurationManager)
+        {
+            _localization = localization;
+            _activityManager = activityManager;
+            _serverConfigurationManager = serverConfigurationManager;
+        }
+
+        /// <inheritdoc />
+        public string Name => _localization.GetLocalizedString("TaskCleanActivityLog");
+
+        /// <inheritdoc />
+        public string Key => "CleanActivityLog";
+
+        /// <inheritdoc />
+        public string Description => _localization.GetLocalizedString("TaskCleanActivityLogDescription");
+
+        /// <inheritdoc />
+        public string Category => _localization.GetLocalizedString("TasksMaintenanceCategory");
+
+        /// <inheritdoc />
+        public bool IsHidden => false;
+
+        /// <inheritdoc />
+        public bool IsEnabled => true;
+
+        /// <inheritdoc />
+        public bool IsLogged => true;
+
+        /// <inheritdoc />
+        public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
+        {
+            var retentionDays = _serverConfigurationManager.Configuration.ActivityLogRetentionDays;
+            if (!retentionDays.HasValue || retentionDays <= 0)
+            {
+                throw new Exception($"Activity Log Retention days must be at least 0. Currently: {retentionDays}");
+            }
+
+            var startDate = DateTime.UtcNow.AddDays(retentionDays.Value * -1);
+            return _activityManager.CleanAsync(startDate);
+        }
+
+        /// <inheritdoc />
+        public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
+        {
+            return Enumerable.Empty<TaskTriggerInfo>();
+        }
+    }
+}

+ 12 - 0
Jellyfin.Server.Implementations/Activity/ActivityManager.cs

@@ -72,6 +72,18 @@ namespace Jellyfin.Server.Implementations.Activity
             };
         }
 
+        /// <inheritdoc />
+        public async Task CleanAsync(DateTime startDate)
+        {
+            await using var dbContext = _provider.CreateContext();
+            var entries = dbContext.ActivityLogs
+                .AsQueryable()
+                .Where(entry => entry.DateCreated <= startDate);
+
+            dbContext.RemoveRange(entries);
+            await dbContext.SaveChangesAsync().ConfigureAwait(false);
+        }
+
         private static ActivityLogEntry ConvertToOldModel(ActivityLog entry)
         {
             return new ActivityLogEntry

+ 7 - 0
MediaBrowser.Model/Activity/IActivityManager.cs

@@ -16,5 +16,12 @@ namespace MediaBrowser.Model.Activity
         Task CreateAsync(ActivityLog entry);
 
         Task<QueryResult<ActivityLogEntry>> GetPagedResultAsync(ActivityLogQuery query);
+
+        /// <summary>
+        /// Remove all activity logs before the specified date.
+        /// </summary>
+        /// <param name="startDate">Activity log start date.</param>
+        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
+        Task CleanAsync(DateTime startDate);
     }
 }

+ 6 - 0
MediaBrowser.Model/Configuration/ServerConfiguration.cs

@@ -271,6 +271,11 @@ namespace MediaBrowser.Model.Configuration
         /// </summary>
         public string[] KnownProxies { get; set; }
 
+        /// <summary>
+        /// Gets or sets the number of days we should retain activity logs.
+        /// </summary>
+        public int? ActivityLogRetentionDays { get; set; }
+
         /// <summary>
         /// Initializes a new instance of the <see cref="ServerConfiguration" /> class.
         /// </summary>
@@ -381,6 +386,7 @@ namespace MediaBrowser.Model.Configuration
             SlowResponseThresholdMs = 500;
             CorsHosts = new[] { "*" };
             KnownProxies = Array.Empty<string>();
+            ActivityLogRetentionDays = 30;
         }
     }