From a2b12520b2839a6c67cc6aa07c54c7ef4124dabe Mon Sep 17 00:00:00 2001 From: RogueException Date: Sat, 18 Mar 2017 12:14:14 -0300 Subject: [PATCH] Added CommandService logging --- src/Discord.Net.Commands/CommandException.cs | 15 ++++++ src/Discord.Net.Commands/CommandService.cs | 17 +++++-- .../CommandServiceConfig.cs | 3 ++ src/Discord.Net.Commands/Info/CommandInfo.cs | 46 +++++++++++++++++-- .../Info/ParameterInfo.cs | 4 +- src/Discord.Net.Core/DiscordConfig.cs | 2 +- 6 files changed, 76 insertions(+), 11 deletions(-) create mode 100644 src/Discord.Net.Commands/CommandException.cs diff --git a/src/Discord.Net.Commands/CommandException.cs b/src/Discord.Net.Commands/CommandException.cs new file mode 100644 index 000000000..9a582d17b --- /dev/null +++ b/src/Discord.Net.Commands/CommandException.cs @@ -0,0 +1,15 @@ +using System; + +namespace Discord.Commands +{ + public class CommandException : Exception + { + public CommandInfo Command { get; } + public ICommandContext Content { get; } + + public CommandException(CommandInfo command, ICommandContext context, Exception ex) + : base($"Error occurred executing {command.GetLogText(context)}.", ex) + { + } + } +} diff --git a/src/Discord.Net.Commands/CommandService.cs b/src/Discord.Net.Commands/CommandService.cs index 5f4f2a504..e8db0100d 100644 --- a/src/Discord.Net.Commands/CommandService.cs +++ b/src/Discord.Net.Commands/CommandService.cs @@ -1,4 +1,6 @@ -using System; +using Discord.Commands.Builders; +using Discord.Logging; +using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; @@ -7,12 +9,13 @@ using System.Reflection; using System.Threading; using System.Threading.Tasks; -using Discord.Commands.Builders; - namespace Discord.Commands { public class CommandService { + public event Func Log { add { _logEvent.Add(value); } remove { _logEvent.Remove(value); } } + internal readonly AsyncEvent> _logEvent = new AsyncEvent>(); + private readonly SemaphoreSlim _moduleLock; private readonly ConcurrentDictionary _typedModuleDefs; private readonly ConcurrentDictionary> _typeReaders; @@ -24,6 +27,8 @@ namespace Discord.Commands internal readonly bool _caseSensitive; internal readonly char _separatorChar; internal readonly RunMode _defaultRunMode; + internal readonly Logger _cmdLogger; + internal readonly LogManager _logManager; public IEnumerable Modules => _moduleDefs.Select(x => x); public IEnumerable Commands => _moduleDefs.SelectMany(x => x.Commands); @@ -36,7 +41,11 @@ namespace Discord.Commands _separatorChar = config.SeparatorChar; _defaultRunMode = config.DefaultRunMode; if (_defaultRunMode == RunMode.Default) - throw new InvalidOperationException("The default run mode cannot be set to Default, it must be one of Sync, Mixed, or Async"); + throw new InvalidOperationException("The default run mode cannot be set to Default."); + + _logManager = new LogManager(config.LogLevel); + _logManager.Message += async msg => await _logEvent.InvokeAsync(msg).ConfigureAwait(false); + _cmdLogger = _logManager.CreateLogger("Command"); _moduleLock = new SemaphoreSlim(1, 1); _typedModuleDefs = new ConcurrentDictionary(); diff --git a/src/Discord.Net.Commands/CommandServiceConfig.cs b/src/Discord.Net.Commands/CommandServiceConfig.cs index 037e315c7..a94e433f5 100644 --- a/src/Discord.Net.Commands/CommandServiceConfig.cs +++ b/src/Discord.Net.Commands/CommandServiceConfig.cs @@ -8,5 +8,8 @@ public char SeparatorChar { get; set; } = ' '; /// Should commands be case-sensitive? public bool CaseSensitiveCommands { get; set; } = false; + + /// Gets or sets the minimum log level severity that will be sent to the Log event. + public LogSeverity LogLevel { get; set; } = LogSeverity.Info; } } diff --git a/src/Discord.Net.Commands/Info/CommandInfo.cs b/src/Discord.Net.Commands/Info/CommandInfo.cs index 63333f0d2..d953013ab 100644 --- a/src/Discord.Net.Commands/Info/CommandInfo.cs +++ b/src/Discord.Net.Commands/Info/CommandInfo.cs @@ -137,16 +137,48 @@ namespace Discord.Commands return ExecuteResult.FromError(result); } + await Module.Service._cmdLogger.DebugAsync($"Executing {GetLogText(context)}").ConfigureAwait(false); switch (RunMode) { case RunMode.Sync: //Always sync - await _action(context, args, map).ConfigureAwait(false); + try + { + await _action(context, args, map).ConfigureAwait(false); + } + catch (Exception ex) + { + ex = new CommandException(this, context, ex); + await Module.Service._cmdLogger.ErrorAsync(ex).ConfigureAwait(false); + throw; + } + await Module.Service._cmdLogger.VerboseAsync($"Executed {GetLogText(context)}").ConfigureAwait(false); break; case RunMode.Mixed: //Sync until first await statement - var t1 = _action(context, args, map); + var t1 = _action(context, args, map).ContinueWith(async t => + { + if (t.IsFaulted) + { + var ex = new CommandException(this, context, t.Exception); + await Module.Service._cmdLogger.ErrorAsync(ex).ConfigureAwait(false); + } + else + await Module.Service._cmdLogger.VerboseAsync($"Executed {GetLogText(context)}").ConfigureAwait(false); + }); break; case RunMode.Async: //Always async - var t2 = Task.Run(() => _action(context, args, map)); + var t2 = Task.Run(() => + { + var _ = _action(context, args, map).ContinueWith(async t => + { + if (t.IsFaulted) + { + var ex = new CommandException(this, context, t.Exception); + await Module.Service._cmdLogger.ErrorAsync(ex).ConfigureAwait(false); + } + else + await Module.Service._cmdLogger.VerboseAsync($"Executed {GetLogText(context)}").ConfigureAwait(false); + }); + }); break; } return ExecuteResult.FromSuccess(); @@ -189,5 +221,13 @@ namespace Discord.Commands private static T[] ConvertParamsList(IEnumerable paramsList) => paramsList.Cast().ToArray(); + + internal string GetLogText(ICommandContext context) + { + if (context.Guild != null) + return $"\"{Name}\" for {context.User} in {context.Guild}/{context.Channel}"; + else + return $"\"{Name}\" for {context.User} in {context.Channel}"; + } } } \ No newline at end of file diff --git a/src/Discord.Net.Commands/Info/ParameterInfo.cs b/src/Discord.Net.Commands/Info/ParameterInfo.cs index d49b84c7f..4ef145b9e 100644 --- a/src/Discord.Net.Commands/Info/ParameterInfo.cs +++ b/src/Discord.Net.Commands/Info/ParameterInfo.cs @@ -1,11 +1,9 @@ +using Discord.Commands.Builders; using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Threading.Tasks; -using Discord.Commands.Builders; -using System.Reflection; - namespace Discord.Commands { public class ParameterInfo diff --git a/src/Discord.Net.Core/DiscordConfig.cs b/src/Discord.Net.Core/DiscordConfig.cs index 78a5b0e1e..b1e075e5b 100644 --- a/src/Discord.Net.Core/DiscordConfig.cs +++ b/src/Discord.Net.Core/DiscordConfig.cs @@ -22,7 +22,7 @@ namespace Discord /// Gets or sets how a request should act in the case of an error, by default. public RetryMode DefaultRetryMode { get; set; } = RetryMode.AlwaysRetry; - /// Gets or sets the minimum log level severity that will be sent to the LogMessage event. + /// Gets or sets the minimum log level severity that will be sent to the Log event. public LogSeverity LogLevel { get; set; } = LogSeverity.Info; /// Gets or sets whether the initial log entry should be printed.