diff --git a/CryptoExchange.Net/Clients/BaseClient.cs b/CryptoExchange.Net/Clients/BaseClient.cs index 362d4a0..360ba44 100644 --- a/CryptoExchange.Net/Clients/BaseClient.cs +++ b/CryptoExchange.Net/Clients/BaseClient.cs @@ -63,6 +63,7 @@ namespace CryptoExchange.Net log = new Log(name); log.UpdateWriters(options.LogWriters); log.Level = options.LogLevel; + options.OnLoggingChanged += HandleLogConfigChange; ClientOptions = options; @@ -282,12 +283,22 @@ namespace CryptoExchange.Net } } + /// + /// Handle a change in the client options log config + /// + private void HandleLogConfigChange() + { + log.UpdateWriters(ClientOptions.LogWriters); + log.Level = ClientOptions.LogLevel; + } + /// /// Dispose /// public virtual void Dispose() { log.Write(LogLevel.Debug, "Disposing client"); + ClientOptions.OnLoggingChanged -= HandleLogConfigChange; foreach (var client in ApiClients) client.Dispose(); } diff --git a/CryptoExchange.Net/Clients/BaseSocketClient.cs b/CryptoExchange.Net/Clients/BaseSocketClient.cs index 7979935..d4af631 100644 --- a/CryptoExchange.Net/Clients/BaseSocketClient.cs +++ b/CryptoExchange.Net/Clients/BaseSocketClient.cs @@ -36,10 +36,6 @@ namespace CryptoExchange.Net /// protected internal readonly SemaphoreSlim semaphoreSlim = new(1); /// - /// The max amount of concurrent socket connections - /// - protected int MaxSocketConnections { get; set; } = 9999; - /// /// Keep alive interval for websocket connection /// protected TimeSpan KeepAliveInterval { get; set; } = TimeSpan.FromSeconds(10); @@ -520,7 +516,7 @@ namespace CryptoExchange.Net var result = socketResult.Equals(default(KeyValuePair)) ? null : socketResult.Value; if (result != null) { - if (result.SubscriptionCount < ClientOptions.SocketSubscriptionsCombineTarget || (socketConnections.Count >= MaxSocketConnections && socketConnections.All(s => s.Value.SubscriptionCount >= ClientOptions.SocketSubscriptionsCombineTarget))) + if (result.SubscriptionCount < ClientOptions.SocketSubscriptionsCombineTarget || (socketConnections.Count >= ClientOptions.MaxSocketConnections && socketConnections.All(s => s.Value.SubscriptionCount >= ClientOptions.SocketSubscriptionsCombineTarget))) { // Use existing socket if it has less than target connections OR it has the least connections and we can't make new return result; diff --git a/CryptoExchange.Net/Logging/Log.cs b/CryptoExchange.Net/Logging/Log.cs index 1778343..745300a 100644 --- a/CryptoExchange.Net/Logging/Log.cs +++ b/CryptoExchange.Net/Logging/Log.cs @@ -26,6 +26,8 @@ namespace CryptoExchange.Net.Logging /// public string ClientName { get; set; } + private readonly object _lock = new object(); + /// /// ctor /// @@ -42,7 +44,8 @@ namespace CryptoExchange.Net.Logging /// public void UpdateWriters(List textWriters) { - writers = textWriters; + lock (_lock) + writers = textWriters; } /// @@ -56,16 +59,19 @@ namespace CryptoExchange.Net.Logging return; var logMessage = $"{ClientName,-10} | {message}"; - foreach (var writer in writers.ToList()) + lock (_lock) { - try + foreach (var writer in writers) { - writer.Log(logLevel, logMessage); - } - catch (Exception e) - { - // Can't write to the logging so where else to output.. - Trace.WriteLine($"{DateTime.Now:yyyy/MM/dd HH:mm:ss:fff} | Warning | Failed to write log to writer {writer.GetType()}: " + e.ToLogString()); + try + { + writer.Log(logLevel, logMessage); + } + catch (Exception e) + { + // Can't write to the logging so where else to output.. + Trace.WriteLine($"{DateTime.Now:yyyy/MM/dd HH:mm:ss:fff} | Warning | Failed to write log to writer {writer.GetType()}: " + e.ToLogString()); + } } } } diff --git a/CryptoExchange.Net/Objects/Options.cs b/CryptoExchange.Net/Objects/Options.cs index e9669ad..01cbfa3 100644 --- a/CryptoExchange.Net/Objects/Options.cs +++ b/CryptoExchange.Net/Objects/Options.cs @@ -14,15 +14,35 @@ namespace CryptoExchange.Net.Objects /// public class BaseOptions { + internal event Action OnLoggingChanged; + + private LogLevel _logLevel = LogLevel.Information; /// /// The minimum log level to output /// - public LogLevel LogLevel { get; set; } = LogLevel.Information; + public LogLevel LogLevel + { + get => _logLevel; + set + { + _logLevel = value; + OnLoggingChanged?.Invoke(); + } + } + private List _logWriters = new List { new DebugLogger() }; /// /// The log writers /// - public List LogWriters { get; set; } = new List { new DebugLogger() }; + public List LogWriters + { + get => _logWriters; + set + { + _logWriters = value; + OnLoggingChanged?.Invoke(); + } + } /// /// If true, the CallResult and DataEvent objects will also include the originally received json data in the OriginalData property @@ -189,6 +209,11 @@ namespace CryptoExchange.Net.Objects /// public int? SocketSubscriptionsCombineTarget { get; set; } + /// + /// The max amount of connections to make to the server. Can be used for API's which only allow a certain number of connections. Changing this to a high value might cause issues. + /// + public int? MaxSocketConnections { get; set; } + /// /// ctor /// @@ -213,12 +238,13 @@ namespace CryptoExchange.Net.Objects SocketResponseTimeout = baseOptions.SocketResponseTimeout; SocketNoDataTimeout = baseOptions.SocketNoDataTimeout; SocketSubscriptionsCombineTarget = baseOptions.SocketSubscriptionsCombineTarget; + MaxSocketConnections = baseOptions.MaxSocketConnections; } /// public override string ToString() { - return $"{base.ToString()}, AutoReconnect: {AutoReconnect}, ReconnectInterval: {ReconnectInterval}, MaxReconnectTries: {MaxReconnectTries}, MaxResubscribeTries: {MaxResubscribeTries}, MaxConcurrentResubscriptionsPerSocket: {MaxConcurrentResubscriptionsPerSocket}, SocketResponseTimeout: {SocketResponseTimeout:c}, SocketNoDataTimeout: {SocketNoDataTimeout}, SocketSubscriptionsCombineTarget: {SocketSubscriptionsCombineTarget}"; + return $"{base.ToString()}, AutoReconnect: {AutoReconnect}, ReconnectInterval: {ReconnectInterval}, MaxReconnectTries: {MaxReconnectTries}, MaxResubscribeTries: {MaxResubscribeTries}, MaxConcurrentResubscriptionsPerSocket: {MaxConcurrentResubscriptionsPerSocket}, SocketResponseTimeout: {SocketResponseTimeout:c}, SocketNoDataTimeout: {SocketNoDataTimeout}, SocketSubscriptionsCombineTarget: {SocketSubscriptionsCombineTarget}, MaxSocketConnections: {MaxSocketConnections}"; } }