Browse Source

Usage tracker

pull/65/head
Sebastian Stehle 10 years ago
parent
commit
c19664d740
  1. 6
      src/Squidex.Infrastructure.MongoDb/UsageTracker/MongoUsage.cs
  2. 5
      src/Squidex.Infrastructure.MongoDb/UsageTracker/MongoUsageStore.cs
  3. 34
      src/Squidex.Infrastructure/UsageTracking/BackgroundUsageTracker.cs
  4. 4
      tests/Squidex.Infrastructure.Tests/UsageTracking/BackgroundUsageTrackerTests.cs

6
src/Squidex.Infrastructure.MongoDb/UsageTracker/MongoUsage.cs

@ -17,13 +17,17 @@ namespace Squidex.Infrastructure.MongoDb.UsageTracker
[BsonId] [BsonId]
[BsonElement] [BsonElement]
[BsonRepresentation(BsonType.String)] [BsonRepresentation(BsonType.String)]
public string Key { get; set; } public string Id { get; set; }
[BsonRequired] [BsonRequired]
[BsonElement] [BsonElement]
[BsonDateTimeOptions(DateOnly = true)] [BsonDateTimeOptions(DateOnly = true)]
public DateTime Date { get; set; } public DateTime Date { get; set; }
[BsonRequired]
[BsonElement]
public string Key { get; set; }
[BsonRequired] [BsonRequired]
[BsonElement] [BsonElement]
public long TotalCount { get; set; } public long TotalCount { get; set; }

5
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) 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 Update
.Inc(x => x.TotalCount, count) .Inc(x => x.TotalCount, count)
.Inc(x => x.TotalElapsedMs, elapsedMs) .Inc(x => x.TotalElapsedMs, elapsedMs)
.SetOnInsert(x => x.Id, id)
.SetOnInsert(x => x.Key, key) .SetOnInsert(x => x.Key, key)
.SetOnInsert(x => x.Date, date), .SetOnInsert(x => x.Date, date),
Upsert); Upsert);

34
src/Squidex.Infrastructure/UsageTracking/BackgroundUsageTracker.cs

@ -12,6 +12,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Squidex.Infrastructure.Log;
using Squidex.Infrastructure.Tasks; using Squidex.Infrastructure.Tasks;
using Squidex.Infrastructure.Timers; using Squidex.Infrastructure.Timers;
@ -20,6 +21,7 @@ namespace Squidex.Infrastructure.UsageTracking
public sealed class BackgroundUsageTracker : DisposableObjectBase, IUsageTracker public sealed class BackgroundUsageTracker : DisposableObjectBase, IUsageTracker
{ {
private readonly IUsageStore usageStore; private readonly IUsageStore usageStore;
private readonly ISemanticLog log;
private readonly CompletionTimer timer; private readonly CompletionTimer timer;
private ConcurrentDictionary<string, Usage> usages = new ConcurrentDictionary<string, Usage>(); private ConcurrentDictionary<string, Usage> usages = new ConcurrentDictionary<string, Usage>();
@ -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(usageStore, nameof(usageStore));
Guard.NotNull(log, nameof(log));
this.usageStore = usageStore; this.usageStore = usageStore;
this.log = log;
timer = new CompletionTimer(60 * 1000, ct => TrackAsync()); timer = new CompletionTimer(60 * 1000, ct => TrackAsync());
} }
@ -65,18 +70,27 @@ namespace Squidex.Infrastructure.UsageTracking
timer.Trigger(); 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<string, Usage>()); var localUsages = Interlocked.Exchange(ref usages, new ConcurrentDictionary<string, Usage>());
return Task.WhenAll(localUsages.Select(x => await Task.WhenAll(localUsages.Select(x =>
usageStore.TrackUsagesAsync( usageStore.TrackUsagesAsync(
today, today,
x.Key, x.Key,
x.Value.Count, x.Value.Count,
x.Value.ElapsedMs))); x.Value.ElapsedMs)));
}
catch (Exception ex)
{
log.LogError(ex, w => w
.WriteProperty("action", "TrackUsage")
.WriteProperty("status", "Failed"));
}
} }
public Task TrackAsync(string key, long elapsedMs) public Task TrackAsync(string key, long elapsedMs)

4
tests/Squidex.Infrastructure.Tests/UsageTracking/BackgroundUsageTrackerTests.cs

@ -11,6 +11,7 @@ using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using FluentAssertions; using FluentAssertions;
using Moq; using Moq;
using Squidex.Infrastructure.Log;
using Squidex.Infrastructure.Tasks; using Squidex.Infrastructure.Tasks;
using Xunit; using Xunit;
@ -19,11 +20,12 @@ namespace Squidex.Infrastructure.UsageTracking
public class BackgroundUsageTrackerTests public class BackgroundUsageTrackerTests
{ {
private readonly Mock<IUsageStore> usageStore = new Mock<IUsageStore>(); private readonly Mock<IUsageStore> usageStore = new Mock<IUsageStore>();
private readonly Mock<ISemanticLog> log = new Mock<ISemanticLog>();
private readonly BackgroundUsageTracker sut; private readonly BackgroundUsageTracker sut;
public BackgroundUsageTrackerTests() public BackgroundUsageTrackerTests()
{ {
sut = new BackgroundUsageTracker(usageStore.Object); sut = new BackgroundUsageTracker(usageStore.Object, log.Object);
} }
[Fact] [Fact]

Loading…
Cancel
Save