diff --git a/src/Squidex.Infrastructure.MongoDb/UsageTracker/MongoUsage.cs b/src/Squidex.Infrastructure.MongoDb/UsageTracker/MongoUsage.cs index 7819cb569..4f62d3f9d 100644 --- a/src/Squidex.Infrastructure.MongoDb/UsageTracker/MongoUsage.cs +++ b/src/Squidex.Infrastructure.MongoDb/UsageTracker/MongoUsage.cs @@ -17,13 +17,17 @@ namespace Squidex.Infrastructure.MongoDb.UsageTracker [BsonId] [BsonElement] [BsonRepresentation(BsonType.String)] - public string Key { get; set; } + public string Id { get; set; } [BsonRequired] [BsonElement] [BsonDateTimeOptions(DateOnly = true)] public DateTime Date { get; set; } + [BsonRequired] + [BsonElement] + public string Key { get; set; } + [BsonRequired] [BsonElement] public long TotalCount { get; set; } diff --git a/src/Squidex.Infrastructure.MongoDb/UsageTracker/MongoUsageStore.cs b/src/Squidex.Infrastructure.MongoDb/UsageTracker/MongoUsageStore.cs index d910edf91..fedc0ec5d 100644 --- a/src/Squidex.Infrastructure.MongoDb/UsageTracker/MongoUsageStore.cs +++ b/src/Squidex.Infrastructure.MongoDb/UsageTracker/MongoUsageStore.cs @@ -36,10 +36,13 @@ namespace Squidex.Infrastructure.MongoDb.UsageTracker public Task TrackUsagesAsync(DateTime date, string key, long count, long elapsedMs) { - return Collection.UpdateOneAsync(x => x.Key == key && x.Date == date, + var id = $"{key}_{date:yyyy-MM-dd}"; + + return Collection.UpdateOneAsync(x => x.Id == id, Update .Inc(x => x.TotalCount, count) .Inc(x => x.TotalElapsedMs, elapsedMs) + .SetOnInsert(x => x.Id, id) .SetOnInsert(x => x.Key, key) .SetOnInsert(x => x.Date, date), Upsert); diff --git a/src/Squidex.Infrastructure/UsageTracking/BackgroundUsageTracker.cs b/src/Squidex.Infrastructure/UsageTracking/BackgroundUsageTracker.cs index adefee578..6cbefe0c8 100644 --- a/src/Squidex.Infrastructure/UsageTracking/BackgroundUsageTracker.cs +++ b/src/Squidex.Infrastructure/UsageTracking/BackgroundUsageTracker.cs @@ -12,6 +12,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Squidex.Infrastructure.Log; using Squidex.Infrastructure.Tasks; using Squidex.Infrastructure.Timers; @@ -20,6 +21,7 @@ namespace Squidex.Infrastructure.UsageTracking public sealed class BackgroundUsageTracker : DisposableObjectBase, IUsageTracker { private readonly IUsageStore usageStore; + private readonly ISemanticLog log; private readonly CompletionTimer timer; private ConcurrentDictionary usages = new ConcurrentDictionary(); @@ -41,12 +43,15 @@ namespace Squidex.Infrastructure.UsageTracking } } - public BackgroundUsageTracker(IUsageStore usageStore) + public BackgroundUsageTracker(IUsageStore usageStore, ISemanticLog log) { Guard.NotNull(usageStore, nameof(usageStore)); + Guard.NotNull(log, nameof(log)); this.usageStore = usageStore; + this.log = log; + timer = new CompletionTimer(60 * 1000, ct => TrackAsync()); } @@ -65,18 +70,27 @@ namespace Squidex.Infrastructure.UsageTracking timer.Trigger(); } - private Task TrackAsync() + private async Task TrackAsync() { - var today = DateTime.Today; + try + { + var today = DateTime.Today; - var localUsages = Interlocked.Exchange(ref usages, new ConcurrentDictionary()); + var localUsages = Interlocked.Exchange(ref usages, new ConcurrentDictionary()); - return Task.WhenAll(localUsages.Select(x => - usageStore.TrackUsagesAsync( - today, - x.Key, - x.Value.Count, - x.Value.ElapsedMs))); + await Task.WhenAll(localUsages.Select(x => + usageStore.TrackUsagesAsync( + today, + x.Key, + x.Value.Count, + x.Value.ElapsedMs))); + } + catch (Exception ex) + { + log.LogError(ex, w => w + .WriteProperty("action", "TrackUsage") + .WriteProperty("status", "Failed")); + } } public Task TrackAsync(string key, long elapsedMs) diff --git a/tests/Squidex.Infrastructure.Tests/UsageTracking/BackgroundUsageTrackerTests.cs b/tests/Squidex.Infrastructure.Tests/UsageTracking/BackgroundUsageTrackerTests.cs index 3f145fb0b..6467f3223 100644 --- a/tests/Squidex.Infrastructure.Tests/UsageTracking/BackgroundUsageTrackerTests.cs +++ b/tests/Squidex.Infrastructure.Tests/UsageTracking/BackgroundUsageTrackerTests.cs @@ -11,6 +11,7 @@ using System.Collections.Generic; using System.Threading.Tasks; using FluentAssertions; using Moq; +using Squidex.Infrastructure.Log; using Squidex.Infrastructure.Tasks; using Xunit; @@ -19,11 +20,12 @@ namespace Squidex.Infrastructure.UsageTracking public class BackgroundUsageTrackerTests { private readonly Mock usageStore = new Mock(); + private readonly Mock log = new Mock(); private readonly BackgroundUsageTracker sut; public BackgroundUsageTrackerTests() { - sut = new BackgroundUsageTracker(usageStore.Object); + sut = new BackgroundUsageTracker(usageStore.Object, log.Object); } [Fact]