Fixed statistics system
This commit is contained in:
@@ -1,47 +1,78 @@
|
|||||||
using Moonlight.App.Database;
|
using Logging.Net;
|
||||||
|
using Moonlight.App.Database;
|
||||||
|
using Moonlight.App.Database.Entities;
|
||||||
using Moonlight.App.Repositories;
|
using Moonlight.App.Repositories;
|
||||||
|
using Moonlight.App.Services.Sessions;
|
||||||
|
|
||||||
namespace Moonlight.App.Services.Statistics;
|
namespace Moonlight.App.Services.Statistics;
|
||||||
|
|
||||||
public class StatisticsCaptureService
|
public class StatisticsCaptureService
|
||||||
{
|
{
|
||||||
private readonly DataContext DataContext;
|
|
||||||
private readonly ConfigService ConfigService;
|
|
||||||
private readonly StatisticsRepository StatisticsRepository;
|
|
||||||
private readonly IServiceScopeFactory ServiceScopeFactory;
|
private readonly IServiceScopeFactory ServiceScopeFactory;
|
||||||
private readonly WebSpaceService WebSpaceService;
|
private readonly DateTimeService DateTimeService;
|
||||||
private readonly PeriodicTimer Timer;
|
private readonly PeriodicTimer Timer;
|
||||||
|
|
||||||
public StatisticsCaptureService(IServiceScopeFactory serviceScopeFactory, ConfigService configService)
|
public StatisticsCaptureService(IServiceScopeFactory serviceScopeFactory, ConfigService configService, DateTimeService dateTimeService)
|
||||||
{
|
{
|
||||||
ServiceScopeFactory = serviceScopeFactory;
|
ServiceScopeFactory = serviceScopeFactory;
|
||||||
var provider = ServiceScopeFactory.CreateScope().ServiceProvider;
|
DateTimeService = dateTimeService;
|
||||||
|
|
||||||
DataContext = provider.GetRequiredService<DataContext>();
|
|
||||||
ConfigService = configService;
|
|
||||||
StatisticsRepository = provider.GetRequiredService<StatisticsRepository>();
|
|
||||||
WebSpaceService = provider.GetRequiredService<WebSpaceService>();
|
|
||||||
|
|
||||||
var config = ConfigService.GetSection("Moonlight").GetSection("Statistics");
|
var config = configService
|
||||||
|
.GetSection("Moonlight")
|
||||||
|
.GetSection("Statistics");
|
||||||
|
|
||||||
if(!config.GetValue<bool>("Enabled"))
|
if(!config.GetValue<bool>("Enabled"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var _period = config.GetValue<int>("Wait");
|
var period = TimeSpan.FromMinutes(config.GetValue<int>("Wait"));
|
||||||
var period = TimeSpan.FromMinutes(_period);
|
|
||||||
Timer = new(period);
|
Timer = new(period);
|
||||||
|
|
||||||
|
Logger.Info("Starting statistics system");
|
||||||
Task.Run(Run);
|
Task.Run(Run);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task Run()
|
private async Task Run()
|
||||||
{
|
{
|
||||||
while (await Timer.WaitForNextTickAsync())
|
try
|
||||||
{
|
{
|
||||||
StatisticsRepository.Add("statistics.usersCount", DataContext.Users.Count());
|
while (await Timer.WaitForNextTickAsync())
|
||||||
StatisticsRepository.Add("statistics.serversCount", DataContext.Servers.Count());
|
{
|
||||||
StatisticsRepository.Add("statistics.domainsCount", DataContext.Domains.Count());
|
Logger.Warn("Creating statistics");
|
||||||
StatisticsRepository.Add("statistics.webspacesCount", DataContext.WebSpaces.Count());
|
|
||||||
StatisticsRepository.Add("statistics.databasesCount", DataContext.Databases.Count());
|
using var scope = ServiceScopeFactory.CreateScope();
|
||||||
|
|
||||||
|
var statisticsRepo = scope.ServiceProvider.GetRequiredService<Repository<StatisticsData>>();
|
||||||
|
var usersRepo = scope.ServiceProvider.GetRequiredService<Repository<User>>();
|
||||||
|
var serversRepo = scope.ServiceProvider.GetRequiredService<Repository<Server>>();
|
||||||
|
var domainsRepo = scope.ServiceProvider.GetRequiredService<Repository<Domain>>();
|
||||||
|
var webspacesRepo = scope.ServiceProvider.GetRequiredService<Repository<WebSpace>>();
|
||||||
|
var databasesRepo = scope.ServiceProvider.GetRequiredService<Repository<MySqlDatabase>>();
|
||||||
|
var sessionService = scope.ServiceProvider.GetRequiredService<SessionService>();
|
||||||
|
|
||||||
|
void AddEntry(string chart, int value)
|
||||||
|
{
|
||||||
|
statisticsRepo!.Add(new StatisticsData()
|
||||||
|
{
|
||||||
|
Chart = chart,
|
||||||
|
Value = value,
|
||||||
|
Date = DateTimeService.GetCurrent()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
AddEntry("usersCount", usersRepo.Get().Count());
|
||||||
|
AddEntry("serversCount", serversRepo.Get().Count());
|
||||||
|
AddEntry("domainsCount", domainsRepo.Get().Count());
|
||||||
|
AddEntry("webspacesCount", webspacesRepo.Get().Count());
|
||||||
|
AddEntry("databasesCount", databasesRepo.Get().Count());
|
||||||
|
AddEntry("sessionsCount", sessionService.GetAll().Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.Log("Statistics are weird");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.Error("An unexpected error occured while capturing statistics");
|
||||||
|
Logger.Error(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,94 +1,125 @@
|
|||||||
@page "/admin/statistics"
|
@page "/admin/statistics"
|
||||||
|
|
||||||
@using Moonlight.App.Models.Misc
|
@using Moonlight.App.Models.Misc
|
||||||
@using Moonlight.App.Services.Statistics
|
@using Moonlight.App.Services.Statistics
|
||||||
@using Moonlight.App.Database.Entities
|
@using Moonlight.App.Database.Entities
|
||||||
@using ApexCharts
|
@using ApexCharts
|
||||||
|
@using Moonlight.App.Helpers
|
||||||
|
@using Moonlight.App.Services
|
||||||
|
|
||||||
@inject StatisticsViewService StatisticsViewService
|
@inject StatisticsViewService StatisticsViewService
|
||||||
|
@inject SmartTranslateService SmartTranslateService
|
||||||
|
|
||||||
<OnlyAdmin>
|
<OnlyAdmin>
|
||||||
<div class="row mt-4 mb-2">
|
<div class="row mt-4 mb-2">
|
||||||
<div class="col-12 col-lg-6 col-xl">
|
<div class="col-12 col-lg-6 col-xl">
|
||||||
<div class="card card-body">
|
<div class="card card-body">
|
||||||
<select class="form-select" @bind="bind">
|
<select class="form-select" @bind="TimeSpanBind">
|
||||||
<option value="1"><TL>Hour</TL></option>
|
<option value="1">
|
||||||
<option value="24"><TL>Day</TL></option>
|
<TL>Hour</TL>
|
||||||
<option value="744"><TL>Month</TL></option>
|
</option>
|
||||||
<option value="8760"><TL>Year</TL></option>
|
<option value="24">
|
||||||
<option value="867240"><TL>All time</TL></option>
|
<TL>Day</TL>
|
||||||
|
</option>
|
||||||
|
<option value="744">
|
||||||
|
<TL>Month</TL>
|
||||||
|
</option>
|
||||||
|
<option value="8760">
|
||||||
|
<TL>Year</TL>
|
||||||
|
</option>
|
||||||
|
<option value="867240">
|
||||||
|
<TL>All time</TL>
|
||||||
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<LazyLoader @ref="Loader" Load="Load">
|
<LazyLoader @ref="Loader" Load="Load">
|
||||||
@foreach (var charts in Charts.Chunk(2))
|
@foreach (var charts in Charts.Chunk(2))
|
||||||
{
|
{
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@foreach (var chart in charts)
|
@foreach (var chart in charts)
|
||||||
{
|
{
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<div class="card mt-4">
|
<div class="card mt-4">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<div class="card-title">
|
<div class="card-title">
|
||||||
<TL>@chart.Header</TL>
|
<TL>@chart.Key</TL>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<ApexChart TItem="StatisticsData"
|
|
||||||
Options="GenerateOptions()"
|
|
||||||
OnRendered="OnChartRendered">
|
|
||||||
<ApexPointSeries TItem="StatisticsData"
|
|
||||||
Items="chart.Data"
|
|
||||||
SeriesType="SeriesType.Area"
|
|
||||||
Name=""
|
|
||||||
ShowDataLabels="false"
|
|
||||||
XValue="@(e => FormatDate(e.Date))"
|
|
||||||
YValue="@(e => (decimal) Math.Round(e.Value))"/>
|
|
||||||
</ApexChart>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<ApexChart TItem="StatisticsData"
|
||||||
|
Options="GenerateOptions()"
|
||||||
|
OnRendered="OnChartRendered">
|
||||||
|
<ApexPointSeries TItem="StatisticsData"
|
||||||
|
Items="chart.Value"
|
||||||
|
SeriesType="SeriesType.Area"
|
||||||
|
Name=""
|
||||||
|
ShowDataLabels="false"
|
||||||
|
XValue="@(e => Formatter.FormatDate(e.Date))"
|
||||||
|
YValue="@(e => (decimal)Math.Round(e.Value))"/>
|
||||||
|
</ApexChart>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
</div>
|
||||||
</div>
|
}
|
||||||
}
|
</div>
|
||||||
|
}
|
||||||
</LazyLoader>
|
</LazyLoader>
|
||||||
</OnlyAdmin>
|
</OnlyAdmin>
|
||||||
|
|
||||||
@code {
|
@code
|
||||||
|
{
|
||||||
private StatisticsTimeSpan StatisticsTimeSpan = StatisticsTimeSpan.Day;
|
private StatisticsTimeSpan StatisticsTimeSpan = StatisticsTimeSpan.Day;
|
||||||
private LazyLoader Loader;
|
private LazyLoader Loader;
|
||||||
private List<(string Header, StatisticsData[] Data)> Charts = new();
|
private Dictionary<string, StatisticsData[]> Charts = new();
|
||||||
|
|
||||||
private int bind
|
private int TimeSpanBind
|
||||||
{
|
{
|
||||||
get { return (int) StatisticsTimeSpan; }
|
get => (int)StatisticsTimeSpan;
|
||||||
set { StatisticsTimeSpan = (StatisticsTimeSpan) value;
|
set
|
||||||
Task.Run(async() => await Loader.Reload());
|
{
|
||||||
|
StatisticsTimeSpan = (StatisticsTimeSpan)value;
|
||||||
|
Task.Run(async () => await Loader.Reload());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task Load(LazyLoader loader)
|
private Task Load(LazyLoader loader)
|
||||||
{
|
{
|
||||||
Charts.Clear();
|
Charts.Clear();
|
||||||
|
|
||||||
Charts.Add(("Servers", StatisticsViewService.GetData("statistics.serversCount", StatisticsTimeSpan)));
|
Charts.Add(
|
||||||
Charts.Add(("Users", StatisticsViewService.GetData("statistics.usersCount", StatisticsTimeSpan)));
|
SmartTranslateService.Translate("Servers"),
|
||||||
Charts.Add(("Domains", StatisticsViewService.GetData("statistics.domainsCount", StatisticsTimeSpan)));
|
StatisticsViewService.GetData("serversCount", StatisticsTimeSpan)
|
||||||
Charts.Add(("Databases", StatisticsViewService.GetData("statistics.databasesCount", StatisticsTimeSpan)));
|
);
|
||||||
Charts.Add(("Websites", StatisticsViewService.GetData("statistics.websitesCount", StatisticsTimeSpan)));
|
|
||||||
}
|
Charts.Add(
|
||||||
|
SmartTranslateService.Translate("Users"),
|
||||||
private string FormatDate(DateTime e)
|
StatisticsViewService.GetData("usersCount", StatisticsTimeSpan)
|
||||||
{
|
);
|
||||||
string i2s(int i)
|
|
||||||
{
|
Charts.Add(
|
||||||
if (i.ToString().Length < 2)
|
SmartTranslateService.Translate("Domains"),
|
||||||
return "0" + i;
|
StatisticsViewService.GetData("domainsCount", StatisticsTimeSpan)
|
||||||
return i.ToString();
|
);
|
||||||
}
|
|
||||||
|
Charts.Add(
|
||||||
return $"{i2s(e.Day)}.{i2s(e.Month)}.{e.Year} {i2s(e.Hour)}:{i2s(e.Minute)}";
|
SmartTranslateService.Translate("Databases"),
|
||||||
|
StatisticsViewService.GetData("databasesCount", StatisticsTimeSpan)
|
||||||
|
);
|
||||||
|
|
||||||
|
Charts.Add(
|
||||||
|
SmartTranslateService.Translate("Webspaces"),
|
||||||
|
StatisticsViewService.GetData("webspacesCount", StatisticsTimeSpan)
|
||||||
|
);
|
||||||
|
|
||||||
|
Charts.Add(
|
||||||
|
SmartTranslateService.Translate("Sessions"),
|
||||||
|
StatisticsViewService.GetData("sessionsCount", StatisticsTimeSpan)
|
||||||
|
);
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ApexChartOptions<StatisticsData> GenerateOptions()
|
private ApexChartOptions<StatisticsData> GenerateOptions()
|
||||||
@@ -121,8 +152,9 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task OnChartRendered()
|
private Task OnChartRendered()
|
||||||
{
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -78,6 +78,10 @@
|
|||||||
"DiscordNotifications": {
|
"DiscordNotifications": {
|
||||||
"Enable": false,
|
"Enable": false,
|
||||||
"WebHook": ""
|
"WebHook": ""
|
||||||
|
},
|
||||||
|
"Statistics": {
|
||||||
|
"Enabled": true,
|
||||||
|
"Wait": 15
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user