@@ -1,3 +1,4 @@ | |||||
using System; | |||||
using Discord.Rest; | using Discord.Rest; | ||||
using Discord.Socket; | using Discord.Socket; | ||||
@@ -9,14 +10,24 @@ namespace Discord | |||||
public DiscordGatewayApi Gateway { get; } | public DiscordGatewayApi Gateway { get; } | ||||
private readonly DiscordConfig _config; | private readonly DiscordConfig _config; | ||||
private readonly Logger _logger; | |||||
public DiscordClient(DiscordConfig config, DiscordRestApi restApi, DiscordGatewayApi gatewayApi) | public DiscordClient(DiscordConfig config, DiscordRestApi restApi, DiscordGatewayApi gatewayApi) | ||||
{ | { | ||||
_config = config; | _config = config; | ||||
_logger = new Logger("Client", config.MinClientSeverity); | |||||
Rest = restApi; | Rest = restApi; | ||||
Gateway = gatewayApi; | 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<LogMessage> Log; | |||||
public void Dispose() | public void Dispose() | ||||
{ | { | ||||
Rest.Dispose(); | Rest.Dispose(); | ||||
@@ -35,5 +35,17 @@ namespace Discord | |||||
/// SocketFactory gets or sets how a WebSocket will be created. | /// SocketFactory gets or sets how a WebSocket will be created. | ||||
/// </summary> | /// </summary> | ||||
public SocketFactory SocketFactory { get; set; } = DefaultSocketFactory.Create; | public SocketFactory SocketFactory { get; set; } = DefaultSocketFactory.Create; | ||||
/// <summary> | |||||
/// Minimum Log Severity for the Rest API. | |||||
/// </summary> | |||||
public LogSeverity MinRestSeverity { get; set; } = LogSeverity.Info; | |||||
/// <summary> | |||||
/// Minimum Log Severity for the Gateway API. | |||||
/// </summary> | |||||
public LogSeverity MinGatewaySeverity { get; set; } = LogSeverity.Info; | |||||
/// <summary> | |||||
/// Minimum Log Severity for the Client. | |||||
/// </summary> | |||||
public LogSeverity MinClientSeverity { get; set; } = LogSeverity.Info; | |||||
} | } | ||||
} | } |
@@ -22,5 +22,7 @@ namespace Discord | |||||
DiscordRestApi Rest { get; } | DiscordRestApi Rest { get; } | ||||
DiscordGatewayApi Gateway { get; } | DiscordGatewayApi Gateway { get; } | ||||
event Action<LogMessage> Log; | |||||
} | } | ||||
} | } |
@@ -14,8 +14,12 @@ namespace Discord.Rest | |||||
private readonly IDiscordRestApi _api; | private readonly IDiscordRestApi _api; | ||||
private readonly HttpClient _http; | private readonly HttpClient _http; | ||||
internal Logger Logger { get; private set; } | |||||
public DiscordRestApi(DiscordConfig config, AuthenticationHeaderValue token) | public DiscordRestApi(DiscordConfig config, AuthenticationHeaderValue token) | ||||
{ | { | ||||
Logger = new Logger("Rest", config.MinRestSeverity); | |||||
_http = new HttpClient(new DiscordHttpClientHandler(token), true) | _http = new HttpClient(new DiscordHttpClientHandler(token), true) | ||||
{ | { | ||||
BaseAddress = config.RestUri ?? DiscordConfig.DefaultRestUri, | BaseAddress = config.RestUri ?? DiscordConfig.DefaultRestUri, | ||||
@@ -9,10 +9,13 @@ namespace Discord.Socket | |||||
private readonly DiscordConfig _config; | private readonly DiscordConfig _config; | ||||
private readonly string _token; | private readonly string _token; | ||||
internal Logger Logger { get; private set; } | |||||
public ISocket Socket { get; set; } | public ISocket Socket { get; set; } | ||||
public DiscordGatewayApi(DiscordConfig config, string token) | public DiscordGatewayApi(DiscordConfig config, string token) | ||||
{ | { | ||||
Logger = new Logger("Gateway", config.MinGatewaySeverity); | |||||
_config = config; | _config = config; | ||||
_token = token; | _token = token; | ||||
@@ -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<LogMessage>? 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); | |||||
} | |||||
} |