From 18438e2dda41ae3e1aeddba16c371907b27016c8 Mon Sep 17 00:00:00 2001 From: Christopher Felegy Date: Sun, 5 Jan 2020 23:29:48 -0500 Subject: [PATCH] util: add logging --- src/Discord.Net/DiscordClient.cs | 11 ++ src/Discord.Net/DiscordConfig.cs | 12 +++ src/Discord.Net/IDiscordClient.cs | 2 + src/Discord.Net/Rest/DiscordRestApi.cs | 4 + src/Discord.Net/Socket/DiscordGatewayApi.cs | 3 + src/Discord.Net/Utilities/Logging.cs | 159 ++++++++++++++++++++++++++++ 6 files changed, 191 insertions(+) create mode 100644 src/Discord.Net/Utilities/Logging.cs diff --git a/src/Discord.Net/DiscordClient.cs b/src/Discord.Net/DiscordClient.cs index c2498985c..5c651d88d 100644 --- a/src/Discord.Net/DiscordClient.cs +++ b/src/Discord.Net/DiscordClient.cs @@ -1,3 +1,4 @@ +using System; using Discord.Rest; using Discord.Socket; @@ -9,14 +10,24 @@ namespace Discord public DiscordGatewayApi Gateway { get; } private readonly DiscordConfig _config; + private readonly Logger _logger; public DiscordClient(DiscordConfig config, DiscordRestApi restApi, DiscordGatewayApi gatewayApi) { _config = config; + _logger = new Logger("Client", config.MinClientSeverity); + Rest = restApi; Gateway = gatewayApi; + + Log += _ => { }; // initialize log method + Rest.Logger.Message += m => Log(m); + Gateway.Logger.Message += m => Log(m); + _logger.Message += m => Log(m); } + public event Action Log; + public void Dispose() { Rest.Dispose(); diff --git a/src/Discord.Net/DiscordConfig.cs b/src/Discord.Net/DiscordConfig.cs index e8ba2407b..c752c27c3 100644 --- a/src/Discord.Net/DiscordConfig.cs +++ b/src/Discord.Net/DiscordConfig.cs @@ -35,5 +35,17 @@ namespace Discord /// SocketFactory gets or sets how a WebSocket will be created. /// public SocketFactory SocketFactory { get; set; } = DefaultSocketFactory.Create; + /// + /// Minimum Log Severity for the Rest API. + /// + public LogSeverity MinRestSeverity { get; set; } = LogSeverity.Info; + /// + /// Minimum Log Severity for the Gateway API. + /// + public LogSeverity MinGatewaySeverity { get; set; } = LogSeverity.Info; + /// + /// Minimum Log Severity for the Client. + /// + public LogSeverity MinClientSeverity { get; set; } = LogSeverity.Info; } } diff --git a/src/Discord.Net/IDiscordClient.cs b/src/Discord.Net/IDiscordClient.cs index 3a5c424fa..03e122425 100644 --- a/src/Discord.Net/IDiscordClient.cs +++ b/src/Discord.Net/IDiscordClient.cs @@ -22,5 +22,7 @@ namespace Discord DiscordRestApi Rest { get; } DiscordGatewayApi Gateway { get; } + + event Action Log; } } diff --git a/src/Discord.Net/Rest/DiscordRestApi.cs b/src/Discord.Net/Rest/DiscordRestApi.cs index b70c757f0..146b8025b 100644 --- a/src/Discord.Net/Rest/DiscordRestApi.cs +++ b/src/Discord.Net/Rest/DiscordRestApi.cs @@ -14,8 +14,12 @@ namespace Discord.Rest private readonly IDiscordRestApi _api; private readonly HttpClient _http; + internal Logger Logger { get; private set; } + public DiscordRestApi(DiscordConfig config, AuthenticationHeaderValue token) { + Logger = new Logger("Rest", config.MinRestSeverity); + _http = new HttpClient(new DiscordHttpClientHandler(token), true) { BaseAddress = config.RestUri ?? DiscordConfig.DefaultRestUri, diff --git a/src/Discord.Net/Socket/DiscordGatewayApi.cs b/src/Discord.Net/Socket/DiscordGatewayApi.cs index 705bba536..9e098ff5c 100644 --- a/src/Discord.Net/Socket/DiscordGatewayApi.cs +++ b/src/Discord.Net/Socket/DiscordGatewayApi.cs @@ -9,10 +9,13 @@ namespace Discord.Socket private readonly DiscordConfig _config; private readonly string _token; + internal Logger Logger { get; private set; } public ISocket Socket { get; set; } public DiscordGatewayApi(DiscordConfig config, string token) { + Logger = new Logger("Gateway", config.MinGatewaySeverity); + _config = config; _token = token; diff --git a/src/Discord.Net/Utilities/Logging.cs b/src/Discord.Net/Utilities/Logging.cs new file mode 100644 index 000000000..9cf6ebcff --- /dev/null +++ b/src/Discord.Net/Utilities/Logging.cs @@ -0,0 +1,159 @@ +using System; +using System.Text; + +namespace Discord +{ + public enum LogSeverity + { + Trace, + Debug, + Info, + Warn, + Error + } + + public struct LogMessage + { + public LogSeverity Level { get; } + public string Source { get; } + public string Message { get; } + public Exception? Exception { get; } + + public LogMessage(LogSeverity level, string source, string message, Exception? exception = null) + { + Level = level; + Source = source; + Message = message; + Exception = exception; + } + + public override string ToString() => ToString(); + public string ToString(StringBuilder? builder = null, + bool fullException = true, + bool prependTimestamp = true, + DateTimeKind timestampKind = DateTimeKind.Local, + int? padSource = 11) + { + string? exMessage = fullException ? Exception?.ToString() : Exception?.Message; + int maxLength = 1 + + (prependTimestamp ? 8 : 0) + 1 + + (padSource.HasValue ? padSource.Value : Source?.Length ?? 0) + 1 + + (Message?.Length ?? 0) + + (exMessage?.Length ?? 0) + 3; + + if (builder == null) + builder = new StringBuilder(maxLength); + else + { + builder.Clear(); + builder.EnsureCapacity(maxLength); + } + + if (prependTimestamp) + { + DateTime now; + if (timestampKind == DateTimeKind.Utc) + now = DateTime.UtcNow; + else + now = DateTime.Now; + if (now.Hour < 10) + builder.Append('0'); + builder.Append(now.Hour); + builder.Append(':'); + if (now.Minute < 10) + builder.Append('0'); + builder.Append(now.Minute); + builder.Append(':'); + if (now.Second < 10) + builder.Append('0'); + builder.Append(now.Second); + builder.Append(' '); + } + if (Source != null) + { + if (padSource.HasValue) + { + if (Source.Length < padSource.Value) + { + builder.Append(Source); + builder.Append(' ', padSource.Value - Source.Length); + } + else if (Source.Length > padSource.Value) + builder.Append(Source.Substring(0, padSource.Value)); + else + builder.Append(Source); + } + else + builder.Append(Source); + builder.Append(' '); + } + if (!string.IsNullOrEmpty(Message)) + { + char c; + for (int i = 0; i < Message.Length; i++) + { + c = Message[i]; + if (!char.IsControl(c)) + builder.Append(c); + } + } + if (exMessage != null) + { + if (!string.IsNullOrEmpty(Message)) + { + builder.Append(':'); + builder.AppendLine(); + } + builder.Append(exMessage); + } + + return builder.ToString(); + } + } + + public class Logger + { + public event Action? Message; + public string Name { get; set; } + public LogSeverity MinSeverity { get; set; } + + public Logger(string source, LogSeverity minSeverity) + { + Name = source; + MinSeverity = minSeverity; + } + + public void Log(LogMessage message) + { + if (message.Level < MinSeverity) + return; + Message?.Invoke(message); + } + + public void Log(LogSeverity severity, string message, Exception? err = null) + => Log(new LogMessage(severity, Name, message, err)); + + public void Trace(string message, Exception? err = null) + => Log(LogSeverity.Trace, message, err); + public void Debug(string message, Exception? err = null) + => Log(LogSeverity.Debug, message, err); + public void Info(string message, Exception? err = null) + => Log(LogSeverity.Info, message, err); + public void Warn(string message, Exception? err = null) + => Log(LogSeverity.Warn, message, err); + public void Error(string message, Exception? err = null) + => Log(LogSeverity.Error, message, err); + + public void Trace(Exception err) + => Log(LogSeverity.Trace, null!, err); + public void Debug(Exception err) + => Log(LogSeverity.Debug, null!, err); + public void Info(Exception err) + => Log(LogSeverity.Info, null!, err); + public void Warn(Exception err) + => Log(LogSeverity.Warn, null!, err); + public void Error(Exception err) + => Log(LogSeverity.Error, null!, err); + + } +}