using System.Diagnostics; using Catalogger.Backend.Cache.InMemoryCache; using Catalogger.Backend.Database; using Humanizer; using Microsoft.EntityFrameworkCore; using Prometheus; namespace Catalogger.Backend.Services; public class MetricsCollectionService( ILogger logger, GuildCache guildCache, ChannelCache channelCache, UserCache userCache, IServiceProvider services) { private readonly ILogger _logger = logger.ForContext(); public async Task CollectMetricsAsync(CancellationToken ct = default) { var timer = CataloggerMetrics.MetricsCollectionTime.NewTimer(); await using var scope = services.CreateAsyncScope(); await using var db = scope.ServiceProvider.GetRequiredService(); var messageCount = await db.Messages.CountAsync(ct); CataloggerMetrics.GuildsCached.Set(guildCache.Size); CataloggerMetrics.ChannelsCached.Set(channelCache.Size); CataloggerMetrics.UsersCached.Set(userCache.Size); CataloggerMetrics.MessagesStored.Set(messageCount); CataloggerMetrics.MessageRateMinute = messageCount - CataloggerMetrics.MessageRateMinute; var process = Process.GetCurrentProcess(); CataloggerMetrics.ProcessPhysicalMemory.Set(process.WorkingSet64); CataloggerMetrics.ProcessVirtualMemory.Set(process.VirtualMemorySize64); CataloggerMetrics.ProcessPrivateMemory.Set(process.PrivateMemorySize64); CataloggerMetrics.ProcessThreads.Set(process.Threads.Count); CataloggerMetrics.ProcessHandles.Set(process.HandleCount); _logger.Information("Collected metrics in {Duration}", timer.ObserveDuration()); } } public class BackgroundMetricsCollectionService(ILogger logger, MetricsCollectionService innerService) : BackgroundService { private readonly ILogger _logger = logger.ForContext(); protected override async Task ExecuteAsync(CancellationToken ct) { _logger.Information("Metrics are disabled, periodically collecting metrics manually"); using var timer = new PeriodicTimer(1.Minutes()); while (await timer.WaitForNextTickAsync(ct)) { _logger.Debug("Collecting metrics"); await innerService.CollectMetricsAsync(ct); } } }