Browse Source

New option to disable the request log at all.

pull/683/head
Sebastian 5 years ago
parent
commit
27013565cf
  1. 5
      backend/src/Squidex.Domain.Apps.Entities/Apps/DefaultAppLogStore.cs
  2. 29
      backend/src/Squidex.Infrastructure/Log/BackgroundRequestLogStore.cs
  3. 2
      backend/src/Squidex.Infrastructure/Log/IRequestLogStore.cs
  4. 6
      backend/src/Squidex.Infrastructure/Log/RequestLogStoreOptions.cs
  5. 5
      backend/src/Squidex/appsettings.json
  6. 15
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DefaultAppLogStoreTests.cs
  7. 33
      backend/tests/Squidex.Infrastructure.Tests/Log/BackgroundRequestLogStoreTests.cs

5
backend/src/Squidex.Domain.Apps.Entities/Apps/DefaultAppLogStore.cs

@ -46,6 +46,11 @@ namespace Squidex.Domain.Apps.Entities.Apps
public Task LogAsync(DomainId appId, RequestLog request) public Task LogAsync(DomainId appId, RequestLog request)
{ {
if (!requestLogStore.IsEnabled)
{
return Task.CompletedTask;
}
var storedRequest = new Request var storedRequest = new Request
{ {
Key = appId.ToString(), Key = appId.ToString(),

29
backend/src/Squidex.Infrastructure/Log/BackgroundRequestLogStore.cs

@ -10,6 +10,7 @@ using System.Collections.Concurrent;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Options;
using Squidex.Infrastructure.Timers; using Squidex.Infrastructure.Timers;
using Squidex.Log; using Squidex.Log;
@ -17,23 +18,30 @@ namespace Squidex.Infrastructure.Log
{ {
public sealed class BackgroundRequestLogStore : DisposableObjectBase, IRequestLogStore public sealed class BackgroundRequestLogStore : DisposableObjectBase, IRequestLogStore
{ {
private const int Intervall = 10 * 1000;
private const int BatchSize = 1000;
private readonly IRequestLogRepository logRepository; private readonly IRequestLogRepository logRepository;
private readonly ISemanticLog log; private readonly ISemanticLog log;
private readonly CompletionTimer timer; private readonly CompletionTimer timer;
private readonly RequestLogStoreOptions options;
private ConcurrentQueue<Request> jobs = new ConcurrentQueue<Request>(); private ConcurrentQueue<Request> jobs = new ConcurrentQueue<Request>();
public BackgroundRequestLogStore(IRequestLogRepository logRepository, ISemanticLog log) public bool IsEnabled
{ {
get => options.StoreEnabled;
}
public BackgroundRequestLogStore(IOptions<RequestLogStoreOptions> options,
IRequestLogRepository logRepository, ISemanticLog log)
{
Guard.NotNull(options, nameof(options));
Guard.NotNull(logRepository, nameof(logRepository)); Guard.NotNull(logRepository, nameof(logRepository));
Guard.NotNull(log, nameof(log)); Guard.NotNull(log, nameof(log));
this.logRepository = logRepository; this.options = options.Value;
this.logRepository = logRepository;
this.log = log; this.log = log;
timer = new CompletionTimer(Intervall, ct => TrackAsync(), Intervall); timer = new CompletionTimer(options.Value.WriteIntervall, ct => TrackAsync(), options.Value.WriteIntervall);
} }
protected override void DisposeObject(bool disposing) protected override void DisposeObject(bool disposing)
@ -53,17 +61,24 @@ namespace Squidex.Infrastructure.Log
private async Task TrackAsync() private async Task TrackAsync()
{ {
if (!IsEnabled)
{
return;
}
try try
{ {
var batchSize = options.BatchSize;
var localJobs = Interlocked.Exchange(ref jobs, new ConcurrentQueue<Request>()); var localJobs = Interlocked.Exchange(ref jobs, new ConcurrentQueue<Request>());
if (!localJobs.IsEmpty) if (!localJobs.IsEmpty)
{ {
var pages = (int)Math.Ceiling((double)localJobs.Count / BatchSize); var pages = (int)Math.Ceiling((double)localJobs.Count / batchSize);
for (var i = 0; i < pages; i++) for (var i = 0; i < pages; i++)
{ {
await logRepository.InsertManyAsync(localJobs.Skip(i * BatchSize).Take(BatchSize)); await logRepository.InsertManyAsync(localJobs.Skip(i * batchSize).Take(batchSize));
} }
} }
} }

2
backend/src/Squidex.Infrastructure/Log/IRequestLogStore.cs

@ -13,6 +13,8 @@ namespace Squidex.Infrastructure.Log
{ {
public interface IRequestLogStore public interface IRequestLogStore
{ {
bool IsEnabled { get; }
Task LogAsync(Request request); Task LogAsync(Request request);
Task QueryAllAsync(Func<Request, Task> callback, string key, DateTime fromDate, DateTime toDate, CancellationToken ct = default); Task QueryAllAsync(Func<Request, Task> callback, string key, DateTime fromDate, DateTime toDate, CancellationToken ct = default);

6
backend/src/Squidex.Infrastructure/Log/RequestLogStoreOptions.cs

@ -9,6 +9,12 @@ namespace Squidex.Infrastructure.Log
{ {
public sealed class RequestLogStoreOptions public sealed class RequestLogStoreOptions
{ {
public bool StoreEnabled { get; set; }
public int StoreRetentionInDays { get; set; } = 90; public int StoreRetentionInDays { get; set; } = 90;
public int BatchSize { get; set; } = 1000;
public int WriteIntervall { get; set; } = 1000;
} }
} }

5
backend/src/Squidex/appsettings.json

@ -338,6 +338,11 @@
*/ */
"logProfiler": false, "logProfiler": false,
/*
* False to disable the log store.
*/
"storeEnabled": true,
/* /*
* The number of days request log items will be stored. * The number of days request log items will be stored.
*/ */

15
backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DefaultAppLogStoreTests.cs

@ -27,11 +27,26 @@ namespace Squidex.Domain.Apps.Entities.Apps
sut = new DefaultAppLogStore(requestLogStore); sut = new DefaultAppLogStore(requestLogStore);
} }
[Fact]
public async Task Should_not_forward_request_if_disabled()
{
A.CallTo(() => requestLogStore.IsEnabled)
.Returns(false);
await sut.LogAsync(DomainId.NewGuid(), default);
A.CallTo(() => requestLogStore.LogAsync(A<Request>._))
.MustNotHaveHappened();
}
[Fact] [Fact]
public async Task Should_forward_request_log_to_store() public async Task Should_forward_request_log_to_store()
{ {
Request? recordedRequest = null; Request? recordedRequest = null;
A.CallTo(() => requestLogStore.IsEnabled)
.Returns(true);
A.CallTo(() => requestLogStore.LogAsync(A<Request>._)) A.CallTo(() => requestLogStore.LogAsync(A<Request>._))
.Invokes((Request request) => recordedRequest = request); .Invokes((Request request) => recordedRequest = request);

33
backend/tests/Squidex.Infrastructure.Tests/Log/BackgroundRequestLogStoreTests.cs

@ -9,6 +9,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using FakeItEasy; using FakeItEasy;
using Microsoft.Extensions.Options;
using Squidex.Log; using Squidex.Log;
using Xunit; using Xunit;
@ -17,11 +18,41 @@ namespace Squidex.Infrastructure.Log
public class BackgroundRequestLogStoreTests public class BackgroundRequestLogStoreTests
{ {
private readonly IRequestLogRepository requestLogRepository = A.Fake<IRequestLogRepository>(); private readonly IRequestLogRepository requestLogRepository = A.Fake<IRequestLogRepository>();
private readonly RequestLogStoreOptions options = new RequestLogStoreOptions();
private readonly BackgroundRequestLogStore sut; private readonly BackgroundRequestLogStore sut;
public BackgroundRequestLogStoreTests() public BackgroundRequestLogStoreTests()
{ {
sut = new BackgroundRequestLogStore(requestLogRepository, A.Fake<ISemanticLog>()); options.StoreEnabled = true;
sut = new BackgroundRequestLogStore(Options.Create(options), requestLogRepository, A.Fake<ISemanticLog>());
}
[Theory]
[InlineData(true)]
[InlineData(false)]
public void Should_provide_disabled_from_options(bool enabled)
{
options.StoreEnabled = enabled;
Assert.Equal(enabled, sut.IsEnabled);
}
[Fact]
public async Task Should_not_if_disabled()
{
options.StoreEnabled = false;
for (var i = 0; i < 2500; i++)
{
await sut.LogAsync(new Request { Key = i.ToString() });
}
sut.Next();
sut.Dispose();
A.CallTo(() => requestLogRepository.InsertManyAsync(A<IEnumerable<Request>>._))
.MustNotHaveHappened();
} }
[Fact] [Fact]

Loading…
Cancel
Save