Implement metrics reading from CouchDB

This commit is contained in:
Timothy Baldridge 2022-06-25 14:22:06 -06:00
parent 03742367d3
commit dc530a52b2
4 changed files with 37 additions and 18 deletions

View File

@ -10,6 +10,7 @@ public class AppSettings
config.Bind("WabbajackSettings", this); config.Bind("WabbajackSettings", this);
} }
public bool TestMode { get; set; } public bool TestMode { get; set; }
public bool RunBackendNexusRoutines { get; set; } = true;
public string AuthorAPIKeyFile { get; set; } public string AuthorAPIKeyFile { get; set; }
public string TarKeyFile { get; set; } public string TarKeyFile { get; set; }

View File

@ -2,6 +2,7 @@
using System.Text.Json; using System.Text.Json;
using Chronic.Core; using Chronic.Core;
using CouchDB.Driver; using CouchDB.Driver;
using CouchDB.Driver.Views;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Nettle; using Nettle;
@ -98,6 +99,7 @@ public class MetricsController : ControllerBase
[Route("dump")] [Route("dump")]
public async Task GetMetrics([FromQuery] string action, [FromQuery] string from, [FromQuery] string? to, [FromQuery] string? subject) public async Task GetMetrics([FromQuery] string action, [FromQuery] string from, [FromQuery] string? to, [FromQuery] string? subject)
{ {
throw new NotImplementedException();
var parser = new Parser(); var parser = new Parser();
to ??= "now"; to ??= "now";
@ -121,7 +123,7 @@ public class MetricsController : ControllerBase
[HttpGet] [HttpGet]
[Route("report")] [Route("report")]
[ResponseCache(Duration = 60 * 60 * 4, VaryByQueryKeys = new [] {"action", "from", "to"})] [ResponseCache(Duration = 60 * 60 * 4, VaryByQueryKeys = new [] {"action", "from", "to"})]
public void GetReport([FromQuery] string action, [FromQuery] string from, [FromQuery] string? to) public async Task GetReport([FromQuery] string action, [FromQuery] string from, [FromQuery] string? to)
{ {
var parser = new Parser(); var parser = new Parser();
@ -132,21 +134,15 @@ public class MetricsController : ControllerBase
var groupFilterStart = parser.Parse("three days ago").Start!.Value.TruncateToDate(); var groupFilterStart = parser.Parse("three days ago").Start!.Value.TruncateToDate();
toDate = new DateTime(toDate.Year, toDate.Month, toDate.Day); toDate = new DateTime(toDate.Year, toDate.Month, toDate.Day);
var prefetch = _metricsStore.GetRecordsParallel(groupFilterStart, toDate, action) var prefetch = (await GetByAction(action, groupFilterStart, toDate))
.Where(d => d.Action != d.Subject) .Select(d => d.Subject)
.Select(d => d.GroupingSubject) .ToHashSet();
.ToHashSet();;
var fromDate = parser.Parse(from).Start!.Value.TruncateToDate(); var fromDate = parser.Parse(from).Start!.Value.TruncateToDate();
var counts = _metricsStore.GetRecordsParallel(fromDate, toDate, action) var counts = (await GetByAction(action, fromDate, toDate))
.Where(r => r.Subject != r.Action) .Where(r => prefetch.Contains(r.Subject))
.Where(r => prefetch.Contains(r.GroupingSubject)) .ToDictionary(kv => (kv.Date, kv.Subject), kv => kv.Count);
.Select(r => (r.Timestamp.TruncateToDate(), r.GroupingSubject))
.ToLookup(r => r, v => 1)
.AsParallel()
.Select(entry => KeyValuePair.Create(entry.Key, entry.Count()))
.ToDictionary(kv => kv.Key, kv => kv.Value);
Response.Headers.ContentType = "application/json"; Response.Headers.ContentType = "application/json";
var row = new Dictionary<string, object>(); var row = new Dictionary<string, object>();
@ -162,7 +158,7 @@ public class MetricsController : ControllerBase
else else
row[group] = 0; row[group] = 0;
} }
JsonSerializer.Serialize(Response.Body, row); await JsonSerializer.SerializeAsync(Response.Body, row);
Response.Body.Write(EOL); Response.Body.Write(EOL);
if (d != toDate) if (d != toDate)
Response.Body.Write(COMMA); Response.Body.Write(COMMA);
@ -173,6 +169,25 @@ public class MetricsController : ControllerBase
} }
private async Task<IReadOnlyList<(DateTime Date, string Subject, long Count)>> GetByAction(string action, DateTime from, DateTime to)
{
var records = await _db.GetViewAsync<object?[], long>("Indexes", "ActionDaySubject",
new CouchViewOptions<object?[]>
{
StartKey = new object?[]{action, from.Year, from.Month, from.Day, null},
EndKey = new object?[]{action, to.Year, to.Month, to.Day, new()},
Reduce = true,
GroupLevel = 10,
Group = true
});
var results = records
.Where(r => r.Key.Length >= 4 && r.Key[4] != null)
.Select(r =>
(new DateTime((int)(long)r.Key[1]!, (int)(long)r.Key[2]!, (int)(long)r.Key[3]!), (string)r.Key[4]!, r.Value));
return results.ToList();
}
public class Result public class Result
{ {

View File

@ -34,10 +34,12 @@ public class NexusCacheManager
_nexusAPI = nexusApi; _nexusAPI = nexusApi;
_discord = discord; _discord = discord;
if (configuration.RunBackendNexusRoutines)
{
_timer = new Timer(_ => UpdateNexusCacheAPI().FireAndForget(), null, TimeSpan.FromSeconds(2), _timer = new Timer(_ => UpdateNexusCacheAPI().FireAndForget(), null, TimeSpan.FromSeconds(2),
TimeSpan.FromHours(4)); TimeSpan.FromHours(4));
} }
}
private AbsolutePath CacheFile(string key) private AbsolutePath CacheFile(string key)

View File

@ -7,6 +7,7 @@
} }
}, },
"WabbajackSettings": { "WabbajackSettings": {
"RunBackendNexusRoutines": false,
"TempFolder": "c:\\tmp\\server_temp", "TempFolder": "c:\\tmp\\server_temp",
"MetricsFolder": "c:\\tmp\\server_metrics", "MetricsFolder": "c:\\tmp\\server_metrics",
"AuthoredFilesFolder": "c:\\tmp\\server_authored_files", "AuthoredFilesFolder": "c:\\tmp\\server_authored_files",