Add metrics reporting, some work on the app

This commit is contained in:
Timothy Baldridge 2021-11-30 22:14:14 -07:00
parent 226af90698
commit f8db7d4386
12 changed files with 217 additions and 6 deletions

View File

@ -0,0 +1,9 @@
<Application x:Class="Wabbajack.App.Wpf.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Wabbajack.App.Wpf"
StartupUri="MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>

View File

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
namespace Wabbajack.App.Wpf
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
}
}

View File

@ -0,0 +1,10 @@
using System.Windows;
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]

View File

@ -0,0 +1,12 @@
<Window x:Class="Wabbajack.App.Wpf.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Wabbajack.App.Wpf"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
</Grid>
</Window>

View File

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Wabbajack.App.Wpf
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
}

View File

@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Reactive.Disposables;
using System.Runtime.CompilerServices;
using System.Text.Json.Serialization;
using ReactiveUI;
namespace Wabbajack.App.Wpf.Support;
public class ViewModel : ReactiveObject, IDisposable
{
private readonly Lazy<CompositeDisposable> _compositeDisposable = new();
[JsonIgnore]
public CompositeDisposable CompositeDisposable => _compositeDisposable.Value;
public virtual void Dispose()
{
if (_compositeDisposable.IsValueCreated)
{
_compositeDisposable.Value.Dispose();
}
}
protected void RaiseAndSetIfChanged<T>(
ref T item,
T newItem,
[CallerMemberName] string? propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(item, newItem)) return;
item = newItem;
this.RaisePropertyChanged(propertyName);
}
}

View File

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<UseWPF>true</UseWPF>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="CefNet.Wpf" Version="97.0.21326.1706" />
<PackageReference Include="ReactiveUI" Version="16.3.10" />
</ItemGroup>
<ItemGroup>
<Folder Include="Screens" />
</ItemGroup>
</Project>

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.CommandLine;
using System.CommandLine.Invocation;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using Wabbajack.Common;
@ -36,9 +37,18 @@ public class GenerateMetricsReports : IVerb
private async Task<int> Run(AbsolutePath output)
{
var subjects = await GetMetrics("one day ago", "now", "finish_install")
.Where(d => d.Action != d.Subject)
.Select(async d => d.GroupingSubject)
.ToHashSet();
var allTime = await GetMetrics("10 days ago", "now", "finish_install")
.Where(d => subjects.Contains(d.GroupingSubject))
.ToList();
var grouped = allTime.GroupBy(g => (g.Timestamp.ToString("yyyy-MM-dd"), g.GroupingSubject)).ToArray();
return 0;
}

View File

@ -0,0 +1,12 @@
using System;
namespace Wabbajack.Common;
public static class DateTimeExtensions
{
public static DateTime TruncateToDate(this DateTime d)
{
return new DateTime(d.Year, d.Month, d.Day);
}
}

View File

@ -1,13 +1,11 @@
using System;
using System.Linq;
using System.Reflection;
using System.Reflection;
using System.Text.Json;
using System.Threading.Tasks;
using Chronic.Core;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Nettle;
using Wabbajack.Common;
using Wabbajack.DTOs.ServerResponses;
using Wabbajack.Server.DataModels;
using Wabbajack.Server.DTOs;
@ -86,8 +84,9 @@ public class MetricsController : ControllerBase
}
private static byte[] EOL = {(byte)'\n'};
[HttpGet]
[Route("report")]
[Route("dump")]
public async Task GetMetrics([FromQuery] string action, [FromQuery] string from, [FromQuery] string? to)
{
var parser = new Parser();
@ -107,6 +106,60 @@ public class MetricsController : ControllerBase
}
}
[HttpGet]
[Route("report")]
public async Task GetReport([FromQuery] string action, [FromQuery] string from, [FromQuery] string? to)
{
var parser = new Parser();
to ??= "now";
var toDate = parser.Parse(to).Start!.Value.TruncateToDate();
var groupFilterStart = parser.Parse("three days ago").Start!.Value.TruncateToDate();
toDate = new DateTime(toDate.Year, toDate.Month, toDate.Day);
var prefetch = await _metricsStore.GetRecords(groupFilterStart, toDate, action)
.Where((Func<MetricResult, bool>) (d => d.Action != d.Subject))
.Select(async d => d.GroupingSubject)
.ToHashSet();;
var fromDate = parser.Parse(from).Start!.Value.TruncateToDate();
var counts = new Dictionary<(DateTime, string), long>();
await foreach (var record in _metricsStore.GetRecords(fromDate, toDate, action))
{
if (record.Subject == record.Action) continue;
if (!prefetch.Contains(record.GroupingSubject)) continue;
var key = (record.Timestamp.TruncateToDate(), record.GroupingSubject);
if (counts.TryGetValue(key, out var old))
counts[key] = old + 1;
else
counts[key] = 1;
}
Response.Headers.ContentType = "application/json";
var row = new Dictionary<string, object>();
for (var d = fromDate; d <= toDate; d = d.AddDays(1))
{
row["_Timestamp"] = d;
foreach (var group in prefetch)
{
if (counts.TryGetValue((d, group), out var found))
row[group] = found;
else
row[group] = 0;
}
await JsonSerializer.SerializeAsync(Response.Body, row);
await Response.Body.WriteAsync(EOL);
}
}
public class Result
{
public DateTime Timestamp { get; set; }

View File

@ -86,7 +86,8 @@ public class Metrics
{
try
{
return groupingRegex.Match(metricSubject).Groups[0].ToString();
var result = groupingRegex.Match(metricSubject).Groups[0].ToString();
return string.IsNullOrEmpty(result) ? metricSubject : result;
}
catch (Exception)
{

View File

@ -116,6 +116,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wabbajack.Downloaders.GameF
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wabbajack.Launcher", "Wabbajack.Launcher\Wabbajack.Launcher.csproj", "{23D49FCC-A6CB-4873-879B-F90DA1871AA3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wabbajack.App.Wpf", "Wabbajack.App.Wpf\Wabbajack.App.Wpf.csproj", "{638F0057-8DF2-4702-BC13-AD599E921F71}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -322,6 +324,10 @@ Global
{23D49FCC-A6CB-4873-879B-F90DA1871AA3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{23D49FCC-A6CB-4873-879B-F90DA1871AA3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{23D49FCC-A6CB-4873-879B-F90DA1871AA3}.Release|Any CPU.Build.0 = Release|Any CPU
{638F0057-8DF2-4702-BC13-AD599E921F71}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{638F0057-8DF2-4702-BC13-AD599E921F71}.Debug|Any CPU.Build.0 = Debug|Any CPU
{638F0057-8DF2-4702-BC13-AD599E921F71}.Release|Any CPU.ActiveCfg = Release|Any CPU
{638F0057-8DF2-4702-BC13-AD599E921F71}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{4057B668-8595-44FE-9805-007B284A838F} = {98B731EE-4FC0-4482-A069-BCBA25497871}