mirror of
https://github.com/wabbajack-tools/wabbajack.git
synced 2024-08-30 18:42:17 +00:00
Add metrics reporting, some work on the app
This commit is contained in:
parent
226af90698
commit
f8db7d4386
9
Wabbajack.App.Wpf/App.xaml
Normal file
9
Wabbajack.App.Wpf/App.xaml
Normal 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>
|
17
Wabbajack.App.Wpf/App.xaml.cs
Normal file
17
Wabbajack.App.Wpf/App.xaml.cs
Normal 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
|
||||
{
|
||||
}
|
||||
}
|
10
Wabbajack.App.Wpf/AssemblyInfo.cs
Normal file
10
Wabbajack.App.Wpf/AssemblyInfo.cs
Normal 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)
|
||||
)]
|
12
Wabbajack.App.Wpf/MainWindow.xaml
Normal file
12
Wabbajack.App.Wpf/MainWindow.xaml
Normal 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>
|
28
Wabbajack.App.Wpf/MainWindow.xaml.cs
Normal file
28
Wabbajack.App.Wpf/MainWindow.xaml.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
34
Wabbajack.App.Wpf/Support/ViewModel.cs
Normal file
34
Wabbajack.App.Wpf/Support/ViewModel.cs
Normal 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);
|
||||
}
|
||||
}
|
19
Wabbajack.App.Wpf/Wabbajack.App.Wpf.csproj
Normal file
19
Wabbajack.App.Wpf/Wabbajack.App.Wpf.csproj
Normal 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>
|
@ -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;
|
||||
}
|
||||
|
||||
|
12
Wabbajack.Common/DateTimeExtensions.cs
Normal file
12
Wabbajack.Common/DateTimeExtensions.cs
Normal 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);
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
@ -106,6 +105,60 @@ public class MetricsController : ControllerBase
|
||||
await Response.Body.WriteAsync(EOL);
|
||||
}
|
||||
}
|
||||
|
||||
[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
|
||||
{
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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}
|
||||
|
Loading…
Reference in New Issue
Block a user