Exceptions are now forwarded to the JoinLeaveLog channel (now renamed to GuildLogging; see the example config)

This commit is contained in:
Leah Husted 2019-08-17 00:50:20 -05:00
parent cb467d9110
commit ad1691d709
6 changed files with 68 additions and 24 deletions

View file

@ -19,8 +19,8 @@
//same as above but for failures //same as above but for failures
"log_all_commands": true, "log_all_commands": true,
//whether or not to log all commands to the bot's console; enabled by default //whether or not to log all commands to the bot's console; enabled by default
"join_leave_log": { "guild_logging": {
//send a log of the bot's joins/leaves to a channel within a certain guild //send a log of the bot's guild joins/leaves, as well as any exceptions that occur
"enabled": false, "enabled": false,
"guild_id": 0, "guild_id": 0,
"channel_id": 0 "channel_id": 0

View file

@ -1,4 +1,5 @@
using System.Diagnostics; using System;
using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Discord.WebSocket; using Discord.WebSocket;

View file

@ -31,7 +31,7 @@ namespace Volte.Core
SuccessEmbedColor = 0x7000FB, SuccessEmbedColor = 0x7000FB,
ErrorEmbedColor = 0xFF0000, ErrorEmbedColor = 0xFF0000,
LogAllCommands = true, LogAllCommands = true,
JoinLeaveLog = new JoinLeaveLog(), GuildLogging = new GuildLogging(),
BlacklistedGuildOwners = new ulong[] { }, BlacklistedGuildOwners = new ulong[] { },
EnabledFeatures = new EnabledFeatures() EnabledFeatures = new EnabledFeatures()
}; };
@ -90,7 +90,7 @@ namespace Volte.Core
public static bool LogAllCommands => _configuration.LogAllCommands; public static bool LogAllCommands => _configuration.LogAllCommands;
public static JoinLeaveLog JoinLeaveLog => _configuration.JoinLeaveLog; public static GuildLogging GuildLogging => _configuration.GuildLogging;
public static IEnumerable<ulong> BlacklistedOwners => _configuration.BlacklistedGuildOwners; public static IEnumerable<ulong> BlacklistedOwners => _configuration.BlacklistedGuildOwners;
@ -126,8 +126,8 @@ namespace Volte.Core
[JsonProperty("log_all_commands")] [JsonProperty("log_all_commands")]
public bool LogAllCommands { get; internal set; } public bool LogAllCommands { get; internal set; }
[JsonProperty("join_leave_log")] [JsonProperty("guild_logging")]
public JoinLeaveLog JoinLeaveLog { get; internal set; } public GuildLogging GuildLogging { get; internal set; }
[JsonProperty("blacklisted_guild_owners")] [JsonProperty("blacklisted_guild_owners")]
public ulong[] BlacklistedGuildOwners { get; internal set; } public ulong[] BlacklistedGuildOwners { get; internal set; }

View file

@ -2,9 +2,9 @@ using Newtonsoft.Json;
namespace Volte.Core.Models.BotConfig namespace Volte.Core.Models.BotConfig
{ {
public sealed class JoinLeaveLog public sealed class GuildLogging
{ {
internal JoinLeaveLog() internal GuildLogging()
{ {
Enabled = false; Enabled = false;
GuildId = ulong.MinValue; GuildId = ulong.MinValue;

View file

@ -1,5 +1,5 @@
using System;
using System.Linq; using System.Linq;
using System.Net;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Discord; using Discord;
@ -48,7 +48,7 @@ namespace Volte.Services
.ToString()) .ToString())
.AddField("Support Server", "[Join my support Discord here](https://discord.gg/H8bcFr2)"); .AddField("Support Server", "[Join my support Discord here](https://discord.gg/H8bcFr2)");
_logger.Error(LogSource.Volte, _logger.Debug(LogSource.Volte,
"Attempting to send the guild owner the introduction message."); "Attempting to send the guild owner the introduction message.");
try try
{ {
@ -56,7 +56,7 @@ namespace Volte.Services
_logger.Error(LogSource.Volte, _logger.Error(LogSource.Volte,
"Sent the guild owner the introduction message."); "Sent the guild owner the introduction message.");
} }
catch (HttpException ex) when (ex.DiscordCode is 50007) catch (HttpException ex) when (ex.HttpCode is HttpStatusCode.Forbidden)
{ {
var c = args.Guild.TextChannels.OrderByDescending(x => x.Position).FirstOrDefault(); var c = args.Guild.TextChannels.OrderByDescending(x => x.Position).FirstOrDefault();
_logger.Error(LogSource.Volte, _logger.Error(LogSource.Volte,
@ -64,20 +64,20 @@ namespace Volte.Services
if (c != null) await embed.SendToAsync(c); if (c != null) await embed.SendToAsync(c);
} }
if (!Config.JoinLeaveLog.Enabled) return; if (!Config.GuildLogging.Enabled) return;
var joinLeave = Config.JoinLeaveLog; var guildLogging = Config.GuildLogging;
if (joinLeave.GuildId is 0 || joinLeave.ChannelId is 0) if (guildLogging.GuildId is 0 || guildLogging.ChannelId is 0)
{ {
_logger.Error(LogSource.Volte, _logger.Error(LogSource.Volte,
"Invalid value set for the GuildId or ChannelId in the JoinLeaveLog config option. " + "Invalid value set for the guild_id or channel_id in the guild_logging config section. " +
"To fix, set Enabled to false, or correctly fill in your options."); "To fix, set enabled to false, or correctly fill in your options.");
return; return;
} }
var channel = _client.GetGuild(joinLeave.GuildId).GetTextChannel(joinLeave.ChannelId); var channel = _client.GetGuild(guildLogging.GuildId)?.GetTextChannel(guildLogging.ChannelId);
if (channel is null) if (channel is null)
{ {
_logger.Error(LogSource.Volte, "Invalid JoinLeaveLog.GuildId/JoinLeaveLog.ChannelId configuration. Check your IDs and try again."); _logger.Error(LogSource.Volte, "Invalid guild_logging.guild_id/guild_logging.channel_id configuration. Check your IDs and try again.");
return; return;
} }
@ -100,14 +100,14 @@ namespace Volte.Services
$"{_client.GetOwner().Mention}: Joined a guild with more bots than users.", false, $"{_client.GetOwner().Mention}: Joined a guild with more bots than users.", false,
e.WithSuccessColor().Build()); e.WithSuccessColor().Build());
else else
await channel.SendMessageAsync("", false, e.WithSuccessColor().Build()); await e.WithSuccessColor().SendToAsync(channel);
} }
public async Task OnLeaveAsync(LeftGuildEventArgs args) public async Task OnLeaveAsync(LeftGuildEventArgs args)
{ {
_logger.Debug(LogSource.Volte, "Left a guild."); _logger.Debug(LogSource.Volte, "Left a guild.");
if (!Config.JoinLeaveLog.Enabled) return; if (!Config.GuildLogging.Enabled) return;
var joinLeave = Config.JoinLeaveLog; var joinLeave = Config.GuildLogging;
if (joinLeave.GuildId is 0 || joinLeave.ChannelId is 0) if (joinLeave.GuildId is 0 || joinLeave.ChannelId is 0)
{ {
_logger.Error(LogSource.Volte, _logger.Error(LogSource.Volte,

View file

@ -1,10 +1,16 @@
using System; using System;
using System.IO; using System.IO;
using System.Net.Http;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Xml;
using Discord; using Discord;
using Discord.WebSocket;
using Gommon; using Gommon;
using Humanizer; using Humanizer;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RestSharp;
using Volte.Core; using Volte.Core;
using Volte.Core.Models; using Volte.Core.Models;
using Volte.Core.Models.EventArgs; using Volte.Core.Models.EventArgs;
@ -15,8 +21,18 @@ namespace Volte.Services
{ {
public sealed class LoggingService : VolteEventService public sealed class LoggingService : VolteEventService
{ {
private readonly DiscordShardedClient _client;
private readonly HttpClient _http;
private readonly object _lock;
private const string LogFile = "data/Volte.log"; private const string LogFile = "data/Volte.log";
private readonly object _lock = new object();
public LoggingService(DiscordShardedClient discordShardedClient,
HttpClient httpClient)
{
_client = discordShardedClient;
_http = httpClient;
_lock = new object();
}
public override Task DoAsync(EventArgs args) public override Task DoAsync(EventArgs args)
{ {
@ -97,7 +113,7 @@ namespace Volte.Services
/// </summary> /// </summary>
/// <param name="e">Exception to print.</param> /// <param name="e">Exception to print.</param>
public void LogException(Exception e) public void LogException(Exception e)
=> Log(LogSeverity.Error, LogSource.Volte, string.Empty, e); => Execute(LogSeverity.Error, LogSource.Volte, string.Empty, e);
private void Execute(LogSeverity s, LogSource src, string message, Exception e) private void Execute(LogSeverity s, LogSource src, string message, Exception e)
{ {
@ -122,6 +138,7 @@ namespace Volte.Services
var toWrite = $"{Environment.NewLine}{e.Message}{Environment.NewLine}{e.StackTrace}"; var toWrite = $"{Environment.NewLine}{e.Message}{Environment.NewLine}{e.StackTrace}";
Append(toWrite, Color.IndianRed); Append(toWrite, Color.IndianRed);
content.Append(toWrite); content.Append(toWrite);
LogExceptionInDiscord(e);
} }
Console.Write(Environment.NewLine); Console.Write(Environment.NewLine);
@ -163,5 +180,31 @@ namespace Volte.Services
LogSeverity.Debug => (Color.SandyBrown, "DEBG"), LogSeverity.Debug => (Color.SandyBrown, "DEBG"),
_ => throw new ArgumentNullException(nameof(severity), "severity cannot be null") _ => throw new ArgumentNullException(nameof(severity), "severity cannot be null")
}; };
private void LogExceptionInDiscord(Exception e)
{
if (!Config.GuildLogging.Enabled) return;
var guildLogging = Config.GuildLogging;
var channel = _client.GetGuild(guildLogging.GuildId)?.GetTextChannel(guildLogging.ChannelId);
if (channel is null)
{
Error(LogSource.Volte, "Invalid guild_logging.guild_id/guild_logging.channel_id configuration. Check your IDs and try again.");
return;
}
_ = Task.Run(async () =>
{
var response = await _http.PostAsync("https://paste.greemdev.net/documents", new StringContent(e.StackTrace, Encoding.UTF8, "text/plain"));
var respObj = JObject.Parse(await response.Content.ReadAsStringAsync());
var url = $"https://paste.greemdev.net/{respObj.GetValue("key")}.cs";
var embed = new EmbedBuilder()
.WithErrorColor()
.WithTitle($"Exception at {DateTimeOffset.UtcNow.FormatDate()}, {DateTimeOffset.UtcNow.FormatFullTime()} UTC")
.AddField("Exception Type", e.GetType(), true)
.AddField("Exception Message", e.Message, true)
.WithDescription($"View the full Stack Trace [here]({url}).");
await embed.SendToAsync(channel);
});
}
} }
} }