Add basic InfluxDB reporter
This commit is contained in:
parent
2d58705e85
commit
02b41413b3
@ -18,6 +18,7 @@ using Microsoft.Extensions.DependencyInjection;
|
|||||||
using NodaTime;
|
using NodaTime;
|
||||||
using Npgsql;
|
using Npgsql;
|
||||||
using Npgsql.Logging;
|
using Npgsql.Logging;
|
||||||
|
using PluralKit.Core;
|
||||||
using Sentry;
|
using Sentry;
|
||||||
using Sentry.Extensibility;
|
using Sentry.Extensibility;
|
||||||
|
|
||||||
@ -94,7 +95,15 @@ namespace PluralKit.Bot
|
|||||||
.AddTransient<MessageStore>()
|
.AddTransient<MessageStore>()
|
||||||
.AddTransient<SwitchStore>()
|
.AddTransient<SwitchStore>()
|
||||||
|
|
||||||
.AddSingleton<IMetrics>(_ => AppMetrics.CreateDefaultBuilder().Build())
|
.AddSingleton<IMetrics>(svc =>
|
||||||
|
{
|
||||||
|
var cfg = svc.GetRequiredService<CoreConfig>();
|
||||||
|
var builder = AppMetrics.CreateDefaultBuilder();
|
||||||
|
if (cfg.InfluxUrl != null && cfg.InfluxDb != null)
|
||||||
|
builder.Report.ToInfluxDb(cfg.InfluxUrl, cfg.InfluxDb);
|
||||||
|
return builder.Build();
|
||||||
|
})
|
||||||
|
.AddSingleton<PeriodicStatCollector>()
|
||||||
|
|
||||||
.BuildServiceProvider();
|
.BuildServiceProvider();
|
||||||
}
|
}
|
||||||
@ -106,14 +115,16 @@ namespace PluralKit.Bot
|
|||||||
private ProxyService _proxy;
|
private ProxyService _proxy;
|
||||||
private Timer _updateTimer;
|
private Timer _updateTimer;
|
||||||
private IMetrics _metrics;
|
private IMetrics _metrics;
|
||||||
|
private PeriodicStatCollector _collector;
|
||||||
|
|
||||||
public Bot(IServiceProvider services, IDiscordClient client, CommandService commands, ProxyService proxy, IMetrics metrics)
|
public Bot(IServiceProvider services, IDiscordClient client, CommandService commands, ProxyService proxy, IMetrics metrics, PeriodicStatCollector collector)
|
||||||
{
|
{
|
||||||
this._services = services;
|
this._services = services;
|
||||||
this._client = client as DiscordShardedClient;
|
this._client = client as DiscordShardedClient;
|
||||||
this._commands = commands;
|
this._commands = commands;
|
||||||
this._proxy = proxy;
|
this._proxy = proxy;
|
||||||
_metrics = metrics;
|
_metrics = metrics;
|
||||||
|
_collector = collector;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Init()
|
public async Task Init()
|
||||||
@ -132,18 +143,28 @@ namespace PluralKit.Bot
|
|||||||
_client.MessageDeleted += async (message, channel) => _proxy.HandleMessageDeletedAsync(message, channel).CatchException(HandleRuntimeError);
|
_client.MessageDeleted += async (message, channel) => _proxy.HandleMessageDeletedAsync(message, channel).CatchException(HandleRuntimeError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method called every 60 seconds
|
||||||
private async Task UpdatePeriodic()
|
private async Task UpdatePeriodic()
|
||||||
{
|
{
|
||||||
// Method called every 60 seconds
|
// Change bot status
|
||||||
await _client.SetGameAsync($"pk;help | in {_client.Guilds.Count} servers");
|
await _client.SetGameAsync($"pk;help | in {_client.Guilds.Count} servers");
|
||||||
|
|
||||||
|
await _collector.CollectStats();
|
||||||
|
await Task.WhenAll(((IMetricsRoot) _metrics).ReportRunner.RunAllAsync());
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ShardReady(DiscordSocketClient shardClient)
|
private async Task ShardReady(DiscordSocketClient shardClient)
|
||||||
{
|
{
|
||||||
//_updateTimer = new Timer((_) => UpdatePeriodic(), null, 0, 60*1000);
|
|
||||||
|
|
||||||
Console.WriteLine($"Shard #{shardClient.ShardId} connected to {shardClient.Guilds.Sum(g => g.Channels.Count)} channels in {shardClient.Guilds.Count} guilds.");
|
Console.WriteLine($"Shard #{shardClient.ShardId} connected to {shardClient.Guilds.Sum(g => g.Channels.Count)} channels in {shardClient.Guilds.Count} guilds.");
|
||||||
//Console.WriteLine($"PluralKit started as {_client.CurrentUser.Username}#{_client.CurrentUser.Discriminator} ({_client.CurrentUser.Id}).");
|
|
||||||
|
if (shardClient.ShardId == 0)
|
||||||
|
{
|
||||||
|
_updateTimer = new Timer((_) => UpdatePeriodic().CatchException(HandleRuntimeError), null, 0, 60*1000);
|
||||||
|
|
||||||
|
Console.WriteLine(
|
||||||
|
$"PluralKit started as {_client.CurrentUser.Username}#{_client.CurrentUser.Discriminator} ({_client.CurrentUser.Id}).");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task CommandExecuted(Optional<CommandInfo> cmd, ICommandContext ctx, IResult _result)
|
private async Task CommandExecuted(Optional<CommandInfo> cmd, ICommandContext ctx, IResult _result)
|
||||||
|
@ -9,7 +9,10 @@ namespace PluralKit.Bot
|
|||||||
public static MeterOptions MessagesReceived => new MeterOptions {Name = "Messages processed", MeasurementUnit = Unit.Events, RateUnit = TimeUnit.Seconds, Context = "Bot"};
|
public static MeterOptions MessagesReceived => new MeterOptions {Name = "Messages processed", MeasurementUnit = Unit.Events, RateUnit = TimeUnit.Seconds, Context = "Bot"};
|
||||||
public static MeterOptions MessagesProxied => new MeterOptions {Name = "Messages proxied", MeasurementUnit = Unit.Events, RateUnit = TimeUnit.Seconds, Context = "Bot"};
|
public static MeterOptions MessagesProxied => new MeterOptions {Name = "Messages proxied", MeasurementUnit = Unit.Events, RateUnit = TimeUnit.Seconds, Context = "Bot"};
|
||||||
public static MeterOptions CommandsRun => new MeterOptions {Name = "Commands run", MeasurementUnit = Unit.Commands, RateUnit = TimeUnit.Seconds, Context = "Bot"};
|
public static MeterOptions CommandsRun => new MeterOptions {Name = "Commands run", MeasurementUnit = Unit.Commands, RateUnit = TimeUnit.Seconds, Context = "Bot"};
|
||||||
|
public static GaugeOptions MembersTotal => new GaugeOptions {Name = "Members total", MeasurementUnit = Unit.None, Context = "Bot"};
|
||||||
public static GaugeOptions MembersOnline => new GaugeOptions {Name = "Members online", MeasurementUnit = Unit.None, Context = "Bot"};
|
public static GaugeOptions MembersOnline => new GaugeOptions {Name = "Members online", MeasurementUnit = Unit.None, Context = "Bot"};
|
||||||
|
public static GaugeOptions Guilds => new GaugeOptions {Name = "Guilds", MeasurementUnit = Unit.None, Context = "Bot"};
|
||||||
|
public static GaugeOptions Channels => new GaugeOptions {Name = "Channels", MeasurementUnit = Unit.None, Context = "Bot"};
|
||||||
|
|
||||||
public static GaugeOptions DatabasePoolSize => new GaugeOptions { Name = "Database pool size", Context = "Database" };
|
public static GaugeOptions DatabasePoolSize => new GaugeOptions { Name = "Database pool size", Context = "Database" };
|
||||||
}
|
}
|
||||||
|
57
PluralKit.Bot/Services/PeriodicStatCollector.cs
Normal file
57
PluralKit.Bot/Services/PeriodicStatCollector.cs
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using App.Metrics;
|
||||||
|
using Discord;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using PluralKit.Core;
|
||||||
|
|
||||||
|
namespace PluralKit.Bot
|
||||||
|
{
|
||||||
|
public class PeriodicStatCollector
|
||||||
|
{
|
||||||
|
private DiscordShardedClient _client;
|
||||||
|
private IMetrics _metrics;
|
||||||
|
|
||||||
|
private SystemStore _systems;
|
||||||
|
private MemberStore _members;
|
||||||
|
private SwitchStore _switches;
|
||||||
|
private MessageStore _messages;
|
||||||
|
|
||||||
|
public PeriodicStatCollector(IDiscordClient client, IMetrics metrics, SystemStore systems, MemberStore members, SwitchStore switches, MessageStore messages)
|
||||||
|
{
|
||||||
|
_client = (DiscordShardedClient) client;
|
||||||
|
_metrics = metrics;
|
||||||
|
_systems = systems;
|
||||||
|
_members = members;
|
||||||
|
_switches = switches;
|
||||||
|
_messages = messages;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task CollectStats()
|
||||||
|
{
|
||||||
|
// Aggregate guild/channel stats
|
||||||
|
_metrics.Measure.Gauge.SetValue(BotMetrics.Guilds, _client.Guilds.Count);
|
||||||
|
_metrics.Measure.Gauge.SetValue(BotMetrics.Channels, _client.Guilds.Sum(g => g.TextChannels.Count));
|
||||||
|
|
||||||
|
// Aggregate member stats
|
||||||
|
var usersKnown = new HashSet<ulong>();
|
||||||
|
var usersOnline = new HashSet<ulong>();
|
||||||
|
foreach (var guild in _client.Guilds)
|
||||||
|
foreach (var user in guild.Users)
|
||||||
|
{
|
||||||
|
usersKnown.Add(user.Id);
|
||||||
|
if (user.Status == UserStatus.Online) usersOnline.Add(user.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
_metrics.Measure.Gauge.SetValue(BotMetrics.MembersTotal, usersKnown.Count);
|
||||||
|
_metrics.Measure.Gauge.SetValue(BotMetrics.MembersOnline, usersOnline.Count);
|
||||||
|
|
||||||
|
// Aggregate DB stats
|
||||||
|
_metrics.Measure.Gauge.SetValue(CoreMetrics.SystemCount, await _systems.Count());
|
||||||
|
_metrics.Measure.Gauge.SetValue(CoreMetrics.MemberCount, await _members.Count());
|
||||||
|
_metrics.Measure.Gauge.SetValue(CoreMetrics.SwitchCount, await _switches.Count());
|
||||||
|
_metrics.Measure.Gauge.SetValue(CoreMetrics.MessageCount, await _messages.Count());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,5 +4,7 @@ namespace PluralKit
|
|||||||
{
|
{
|
||||||
public string Database { get; set; }
|
public string Database { get; set; }
|
||||||
public string SentryUrl { get; set; }
|
public string SentryUrl { get; set; }
|
||||||
|
public string InfluxUrl { get; set; }
|
||||||
|
public string InfluxDb { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="App.Metrics" Version="3.1.0" />
|
<PackageReference Include="App.Metrics" Version="3.1.0" />
|
||||||
|
<PackageReference Include="App.Metrics.Reporting.InfluxDB" Version="3.1.0" />
|
||||||
<PackageReference Include="Dapper" Version="1.60.6" />
|
<PackageReference Include="Dapper" Version="1.60.6" />
|
||||||
<PackageReference Include="Dapper.Contrib" Version="1.60.1" />
|
<PackageReference Include="Dapper.Contrib" Version="1.60.1" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="2.2.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration" Version="2.2.0" />
|
||||||
|
@ -72,6 +72,12 @@ namespace PluralKit {
|
|||||||
using (var conn = await _conn.Obtain())
|
using (var conn = await _conn.Obtain())
|
||||||
return await conn.QueryAsync<ulong>("select uid from accounts where system = @Id", new { Id = system.Id });
|
return await conn.QueryAsync<ulong>("select uid from accounts where system = @Id", new { Id = system.Id });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<ulong> Count()
|
||||||
|
{
|
||||||
|
using (var conn = await _conn.Obtain())
|
||||||
|
return await conn.ExecuteScalarAsync<ulong>("select count(id) from systems");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class MemberStore {
|
public class MemberStore {
|
||||||
@ -138,6 +144,12 @@ namespace PluralKit {
|
|||||||
using (var conn = await _conn.Obtain())
|
using (var conn = await _conn.Obtain())
|
||||||
return await conn.ExecuteScalarAsync<int>("select count(*) from members where system = @Id", system);
|
return await conn.ExecuteScalarAsync<int>("select count(*) from members where system = @Id", system);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<ulong> Count()
|
||||||
|
{
|
||||||
|
using (var conn = await _conn.Obtain())
|
||||||
|
return await conn.ExecuteScalarAsync<ulong>("select count(id) from members");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class MessageStore {
|
public class MessageStore {
|
||||||
@ -185,6 +197,12 @@ namespace PluralKit {
|
|||||||
using (var conn = await _conn.Obtain())
|
using (var conn = await _conn.Obtain())
|
||||||
await conn.ExecuteAsync("delete from messages where mid = @Id", new { Id = id });
|
await conn.ExecuteAsync("delete from messages where mid = @Id", new { Id = id });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<ulong> Count()
|
||||||
|
{
|
||||||
|
using (var conn = await _conn.Obtain())
|
||||||
|
return await conn.ExecuteScalarAsync<ulong>("select count(mid) from messages");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SwitchStore
|
public class SwitchStore
|
||||||
@ -258,6 +276,12 @@ namespace PluralKit {
|
|||||||
await conn.ExecuteAsync("delete from switches where id = @Id", new {Id = sw.Id});
|
await conn.ExecuteAsync("delete from switches where id = @Id", new {Id = sw.Id});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<ulong> Count()
|
||||||
|
{
|
||||||
|
using (var conn = await _conn.Obtain())
|
||||||
|
return await conn.ExecuteScalarAsync<ulong>("select count(id) from switches");
|
||||||
|
}
|
||||||
|
|
||||||
public struct SwitchListEntry
|
public struct SwitchListEntry
|
||||||
{
|
{
|
||||||
public ICollection<PKMember> Members;
|
public ICollection<PKMember> Members;
|
||||||
|
@ -5,10 +5,13 @@ services:
|
|||||||
entrypoint: ["dotnet", "run", "--project", "PluralKit.Bot"]
|
entrypoint: ["dotnet", "run", "--project", "PluralKit.Bot"]
|
||||||
environment:
|
environment:
|
||||||
- "PluralKit:Database=Host=db;Username=postgres;Password=postgres;Database=postgres"
|
- "PluralKit:Database=Host=db;Username=postgres;Password=postgres;Database=postgres"
|
||||||
|
- "PluralKit:InfluxUrl=http://influx:8086"
|
||||||
|
- "PluralKit:InfluxDb=pluralkit
|
||||||
volumes:
|
volumes:
|
||||||
- "./pluralkit.conf:/app/pluralkit.conf:ro"
|
- "./pluralkit.conf:/app/pluralkit.conf:ro"
|
||||||
links:
|
links:
|
||||||
- db
|
- db
|
||||||
|
- influx
|
||||||
restart: always
|
restart: always
|
||||||
web:
|
web:
|
||||||
build: .
|
build: .
|
||||||
@ -35,6 +38,14 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- "db_data:/var/lib/postgresql/data"
|
- "db_data:/var/lib/postgresql/data"
|
||||||
restart: always
|
restart: always
|
||||||
|
influx:
|
||||||
|
image: influxdb:alpine
|
||||||
|
volumes:
|
||||||
|
- "influx_data:/var/lib/influxdb"
|
||||||
|
ports:
|
||||||
|
- 2839:8086
|
||||||
|
restart: always
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
db_data:
|
db_data:
|
||||||
|
influx_data:
|
Loading…
Reference in New Issue
Block a user