feat: replace App.Metrics with prometheus-net
This commit is contained in:
parent
df8af75dd4
commit
be01fb1d53
8 changed files with 113 additions and 137 deletions
|
|
@ -1,8 +1,8 @@
|
|||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using App.Metrics;
|
||||
using Catalogger.Backend.Cache;
|
||||
using System.Text.Json;
|
||||
using System.Web;
|
||||
using Catalogger.Backend.Cache.InMemoryCache;
|
||||
using Catalogger.Backend.Extensions;
|
||||
using Humanizer;
|
||||
|
|
@ -10,10 +10,7 @@ using Remora.Commands.Attributes;
|
|||
using Remora.Commands.Groups;
|
||||
using Remora.Discord.API.Abstractions.Objects;
|
||||
using Remora.Discord.API.Abstractions.Rest;
|
||||
using Remora.Discord.Commands.Contexts;
|
||||
using Remora.Discord.Commands.Extensions;
|
||||
using Remora.Discord.Commands.Feedback.Services;
|
||||
using Remora.Discord.Commands.Services;
|
||||
using Remora.Discord.Extensions.Embeds;
|
||||
using Remora.Discord.Gateway;
|
||||
using Remora.Results;
|
||||
|
|
@ -24,16 +21,18 @@ namespace Catalogger.Backend.Bot.Commands;
|
|||
|
||||
[Group("catalogger")]
|
||||
public class MetaCommands(
|
||||
ILogger logger,
|
||||
IClock clock,
|
||||
IMetrics metrics,
|
||||
Config config,
|
||||
DiscordGatewayClient client,
|
||||
IFeedbackService feedbackService,
|
||||
ContextInjectionService contextInjection,
|
||||
IInviteCache inviteCache,
|
||||
GuildCache guildCache,
|
||||
ChannelCache channelCache,
|
||||
IDiscordRestChannelAPI channelApi) : CommandGroup
|
||||
{
|
||||
private readonly ILogger _logger = logger.ForContext<MetaCommands>();
|
||||
private readonly HttpClient _client = new();
|
||||
|
||||
[Command("ping")]
|
||||
[Description("Ping pong! See the bot's latency")]
|
||||
public async Task<IResult> PingAsync()
|
||||
|
|
@ -53,16 +52,15 @@ public class MetaCommands(
|
|||
inline: true);
|
||||
embed.AddField("Memory usage", memoryUsage.Bytes().Humanize(), inline: true);
|
||||
|
||||
var messagesReceived = metrics.Snapshot.GetForContext("Bot").Meters
|
||||
.FirstOrDefault(m => m.MultidimensionalName == CataloggerMetrics.MessagesReceived.Name)?.Value;
|
||||
if (messagesReceived != null)
|
||||
embed.AddField("Messages received", $"{messagesReceived.OneMinuteRate * 60:F1}/m", true);
|
||||
|
||||
var messageCount = metrics.Snapshot.GetForContext("Bot").Gauges
|
||||
.FirstOrDefault(m => m.MultidimensionalName == CataloggerMetrics.MessagesStored.Name)?.Value ?? 0;
|
||||
var messageRate = await MessagesRate();
|
||||
embed.AddField("Messages received",
|
||||
messageRate != null
|
||||
? $"{messageRate / 5:F1}/m\n({CataloggerMetrics.MessagesReceived.Value:N0} since last restart)"
|
||||
: $"{CataloggerMetrics.MessagesReceived.Value:N0} since last restart",
|
||||
true);
|
||||
|
||||
embed.AddField("Numbers",
|
||||
$"{messageCount:N0} messages from {guildCache.Size:N0} servers\nCached {channelCache.Size:N0} channels",
|
||||
$"{CataloggerMetrics.MessagesStored.Value:N0} messages from {guildCache.Size:N0} servers\nCached {channelCache.Size:N0} channels",
|
||||
inline: false);
|
||||
|
||||
IEmbed[] embeds = [embed.Build().GetOrThrow()];
|
||||
|
|
@ -70,16 +68,35 @@ public class MetaCommands(
|
|||
return (Result)await channelApi.EditMessageAsync(msg.ChannelID, msg.ID, content: "", embeds: embeds);
|
||||
}
|
||||
|
||||
[Command("debug-invites")]
|
||||
[Description("Show a representation of this server's invites")]
|
||||
public async Task<IResult> DebugInvitesAsync()
|
||||
// TODO: add more checks around response format, configurable prometheus endpoint
|
||||
private async Task<double?> MessagesRate()
|
||||
{
|
||||
if (contextInjection.Context is not IInteractionCommandContext ctx) throw new CataloggerError("No context");
|
||||
if (!ctx.TryGetGuildID(out var guildId)) throw new CataloggerError("No guild ID in context");
|
||||
if (!config.Logging.EnableMetrics) return null;
|
||||
|
||||
var invites = await inviteCache.TryGetAsync(guildId);
|
||||
var text = invites.Select(i => $"{i.Code} in {i.Channel?.ID.Value}");
|
||||
try
|
||||
{
|
||||
var query = HttpUtility.UrlEncode("delta(catalogger_received_messages[5m])");
|
||||
var resp = await _client.GetAsync($"http://localhost:9090/api/v1/query?query={query}");
|
||||
resp.EnsureSuccessStatusCode();
|
||||
|
||||
return await feedbackService.SendContextualAsync(string.Join("\n", text));
|
||||
var data = await resp.Content.ReadFromJsonAsync<PrometheusResponse>();
|
||||
_logger.Debug("Raw json: {Data}", JsonSerializer.Serialize(data));
|
||||
var rawNumber = (data?.data.result[0].value[1] as JsonElement?)?.GetString();
|
||||
_logger.Debug("Raw data: {Raw}", rawNumber);
|
||||
return double.TryParse(rawNumber, out var rate) ? rate : null;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Warning(e, "Failed querying Prometheus for message rate");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// ReSharper disable InconsistentNaming, ClassNeverInstantiated.Local
|
||||
private record PrometheusResponse(PrometheusData data);
|
||||
|
||||
private record PrometheusData(PrometheusResult[] result);
|
||||
|
||||
private record PrometheusResult(object[] value);
|
||||
// ReSharper restore InconsistentNaming, ClassNeverInstantiated.Local
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue