2019-07-18 15:13:42 +00:00
using System.Diagnostics ;
2019-07-16 21:34:22 +00:00
using System.Threading.Tasks ;
using App.Metrics ;
2020-04-17 21:10:01 +00:00
2020-06-13 17:15:29 +00:00
using Dapper ;
2021-01-31 13:59:45 +00:00
using Myriad.Cache ;
using Myriad.Types ;
2020-04-17 21:10:01 +00:00
2019-07-18 15:13:42 +00:00
using NodaTime.Extensions ;
2019-07-16 21:34:22 +00:00
using PluralKit.Core ;
2020-02-12 14:16:19 +00:00
2019-07-18 15:13:42 +00:00
using Serilog ;
2019-07-16 21:34:22 +00:00
namespace PluralKit.Bot
{
public class PeriodicStatCollector
{
2020-08-29 11:46:27 +00:00
private readonly IMetrics _metrics ;
2021-01-31 13:59:45 +00:00
private readonly IDiscordCache _cache ;
2020-08-29 11:46:27 +00:00
private readonly CpuStatService _cpu ;
2019-07-16 21:34:22 +00:00
2020-08-29 11:46:27 +00:00
private readonly IDatabase _db ;
2019-07-16 21:34:22 +00:00
2020-08-29 11:46:27 +00:00
private readonly WebhookCacheService _webhookCache ;
2019-07-21 02:15:47 +00:00
2020-08-29 11:46:27 +00:00
private readonly DbConnectionCountHolder _countHolder ;
2019-08-11 20:56:20 +00:00
2020-08-29 11:46:27 +00:00
private readonly ILogger _logger ;
2019-07-18 15:13:42 +00:00
2021-01-31 13:59:45 +00:00
public PeriodicStatCollector ( IMetrics metrics , ILogger logger , WebhookCacheService webhookCache , DbConnectionCountHolder countHolder , CpuStatService cpu , IDatabase db , IDiscordCache cache )
2019-07-16 21:34:22 +00:00
{
_metrics = metrics ;
2019-07-21 02:15:47 +00:00
_webhookCache = webhookCache ;
2019-08-11 20:56:20 +00:00
_countHolder = countHolder ;
2019-12-22 11:50:47 +00:00
_cpu = cpu ;
2020-06-13 17:15:29 +00:00
_db = db ;
2021-01-31 13:59:45 +00:00
_cache = cache ;
2019-07-18 15:13:42 +00:00
_logger = logger . ForContext < PeriodicStatCollector > ( ) ;
2019-07-16 21:34:22 +00:00
}
public async Task CollectStats ( )
{
2019-07-18 15:13:42 +00:00
var stopwatch = new Stopwatch ( ) ;
stopwatch . Start ( ) ;
2019-07-16 21:34:22 +00:00
// Aggregate guild/channel stats
2020-04-17 21:10:01 +00:00
var guildCount = 0 ;
var channelCount = 0 ;
2021-01-31 13:59:45 +00:00
2020-04-17 21:10:01 +00:00
// No LINQ today, sorry
2021-01-31 13:59:45 +00:00
await foreach ( var guild in _cache . GetAllGuilds ( ) )
2020-04-17 21:10:01 +00:00
{
2021-01-31 13:59:45 +00:00
guildCount + + ;
foreach ( var channel in _cache . GetGuildChannels ( guild . Id ) )
{
if ( channel . Type = = Channel . ChannelType . GuildText )
2020-04-17 21:10:01 +00:00
channelCount + + ;
2021-01-31 13:59:45 +00:00
}
2020-04-17 21:10:01 +00:00
}
_metrics . Measure . Gauge . SetValue ( BotMetrics . Guilds , guildCount ) ;
_metrics . Measure . Gauge . SetValue ( BotMetrics . Channels , channelCount ) ;
2019-07-16 21:34:22 +00:00
// Aggregate DB stats
2020-08-25 16:26:30 +00:00
var counts = await _db . Execute ( c = > c . QueryFirstAsync < Counts > ( "select (select count(*) from systems) as systems, (select count(*) from members) as members, (select count(*) from switches) as switches, (select count(*) from messages) as messages, (select count(*) from groups) as groups" ) ) ;
2020-06-13 17:15:29 +00:00
_metrics . Measure . Gauge . SetValue ( CoreMetrics . SystemCount , counts . Systems ) ;
_metrics . Measure . Gauge . SetValue ( CoreMetrics . MemberCount , counts . Members ) ;
_metrics . Measure . Gauge . SetValue ( CoreMetrics . SwitchCount , counts . Switches ) ;
_metrics . Measure . Gauge . SetValue ( CoreMetrics . MessageCount , counts . Messages ) ;
2020-08-25 16:26:30 +00:00
_metrics . Measure . Gauge . SetValue ( CoreMetrics . GroupCount , counts . Groups ) ;
2019-07-20 22:01:02 +00:00
// Process info
var process = Process . GetCurrentProcess ( ) ;
_metrics . Measure . Gauge . SetValue ( CoreMetrics . ProcessPhysicalMemory , process . WorkingSet64 ) ;
_metrics . Measure . Gauge . SetValue ( CoreMetrics . ProcessVirtualMemory , process . VirtualMemorySize64 ) ;
_metrics . Measure . Gauge . SetValue ( CoreMetrics . ProcessPrivateMemory , process . PrivateMemorySize64 ) ;
_metrics . Measure . Gauge . SetValue ( CoreMetrics . ProcessThreads , process . Threads . Count ) ;
_metrics . Measure . Gauge . SetValue ( CoreMetrics . ProcessHandles , process . HandleCount ) ;
2019-12-22 11:50:47 +00:00
_metrics . Measure . Gauge . SetValue ( CoreMetrics . CpuUsage , await _cpu . EstimateCpuUsage ( ) ) ;
2019-07-21 02:15:47 +00:00
2019-08-11 20:56:20 +00:00
// Database info
_metrics . Measure . Gauge . SetValue ( CoreMetrics . DatabaseConnections , _countHolder . ConnectionCount ) ;
2019-07-21 02:15:47 +00:00
// Other shiz
_metrics . Measure . Gauge . SetValue ( BotMetrics . WebhookCacheSize , _webhookCache . CacheSize ) ;
2019-07-18 15:13:42 +00:00
stopwatch . Stop ( ) ;
2020-08-27 19:28:36 +00:00
_logger . Debug ( "Updated metrics in {Time}" , stopwatch . ElapsedDuration ( ) ) ;
2019-07-16 21:34:22 +00:00
}
2020-06-13 17:15:29 +00:00
public class Counts
{
public int Systems { get ; }
public int Members { get ; }
public int Switches { get ; }
public int Messages { get ; }
2020-08-25 16:26:30 +00:00
public int Groups { get ; }
2020-06-13 17:15:29 +00:00
}
2019-07-16 21:34:22 +00:00
}
}