From 508e5472772a9ae229aeacbb5722f1672e5b7416 Mon Sep 17 00:00:00 2001 From: Mariusz Kotas Date: Wed, 6 Sep 2023 18:09:31 +0200 Subject: [PATCH] Use Microsoft `ILogger` abstraction [breaking change] --- src/Websocket.Client/IWebsocketClient.cs | 7 +- .../Models/DisconnectionInfo.cs | 10 +- .../Models/DisconnectionType.cs | 2 +- .../Models/ReconnectionInfo.cs | 6 +- src/Websocket.Client/ResponseMessage.cs | 12 +- src/Websocket.Client/Websocket.Client.csproj | 8 +- .../WebsocketClient.Reconnecting.cs | 20 +-- .../WebsocketClient.Sending.cs | 35 ++--- src/Websocket.Client/WebsocketClient.cs | 122 +++++++++--------- .../Websocket.Client.Sample/Program.cs | 13 +- .../Websocket.Client.Sample.csproj | 1 + 11 files changed, 117 insertions(+), 119 deletions(-) diff --git a/src/Websocket.Client/IWebsocketClient.cs b/src/Websocket.Client/IWebsocketClient.cs index 932bb8d..0a2c0f8 100644 --- a/src/Websocket.Client/IWebsocketClient.cs +++ b/src/Websocket.Client/IWebsocketClient.cs @@ -2,7 +2,6 @@ using System.Net.WebSockets; using System.Text; using System.Threading.Tasks; -using Websocket.Client.Models; namespace Websocket.Client { @@ -56,7 +55,7 @@ public interface IWebsocketClient : IDisposable /// Get or set the name of the current websocket client instance. /// For logging purpose (in case you use more parallel websocket clients and want to distinguish between them) /// - string Name { get; set; } + string? Name { get; set; } /// /// Returns true if Start() method was called at least once. False if not started or disposed @@ -83,13 +82,13 @@ public interface IWebsocketClient : IDisposable /// Returns currently used native websocket client. /// Use with caution, on every reconnection there will be a new instance. /// - ClientWebSocket NativeClient { get; } + ClientWebSocket? NativeClient { get; } /// /// Sets used encoding for sending and receiving text messages. /// Default: UTF8 /// - Encoding MessageEncoding { get; set; } + Encoding? MessageEncoding { get; set; } /// /// Start listening to the websocket stream on the background thread. diff --git a/src/Websocket.Client/Models/DisconnectionInfo.cs b/src/Websocket.Client/Models/DisconnectionInfo.cs index a67f070..7806e8f 100644 --- a/src/Websocket.Client/Models/DisconnectionInfo.cs +++ b/src/Websocket.Client/Models/DisconnectionInfo.cs @@ -13,7 +13,7 @@ public class DisconnectionInfo /// Info about happened disconnection /// public DisconnectionInfo(DisconnectionType type, WebSocketCloseStatus? closeStatus, - string closeStatusDescription, string subProtocol, Exception exception) + string? closeStatusDescription, string? subProtocol, Exception? exception) { Type = type; CloseStatus = closeStatus; @@ -35,17 +35,17 @@ public DisconnectionInfo(DisconnectionType type, WebSocketCloseStatus? closeStat /// /// Allows the remote endpoint to describe the reason why the connection was closed /// - public string CloseStatusDescription { get; } + public string? CloseStatusDescription { get; } /// /// The subprotocol that was negotiated during the opening handshake /// - public string SubProtocol { get; } + public string? SubProtocol { get; } /// /// Exception that cause disconnection, can be null /// - public Exception Exception { get; } + public Exception? Exception { get; } /// @@ -62,7 +62,7 @@ public DisconnectionInfo(DisconnectionType type, WebSocketCloseStatus? closeStat /// /// Simple factory method /// - public static DisconnectionInfo Create(DisconnectionType type, WebSocket client, Exception exception) + public static DisconnectionInfo Create(DisconnectionType type, WebSocket? client, Exception? exception) { return new DisconnectionInfo(type, client?.CloseStatus, client?.CloseStatusDescription, client?.SubProtocol, exception); diff --git a/src/Websocket.Client/Models/DisconnectionType.cs b/src/Websocket.Client/Models/DisconnectionType.cs index a87ccf0..c6bfb2f 100644 --- a/src/Websocket.Client/Models/DisconnectionType.cs +++ b/src/Websocket.Client/Models/DisconnectionType.cs @@ -19,7 +19,7 @@ public enum DisconnectionType /// /// Type used when connection to websocket was lost by not receiving any message in given time-range /// - NoMessageReceived = 2, + NoMessageReceived = 2, /// /// Type used when connection or reconnection returned error diff --git a/src/Websocket.Client/Models/ReconnectionInfo.cs b/src/Websocket.Client/Models/ReconnectionInfo.cs index ceea9a6..c3a76ec 100644 --- a/src/Websocket.Client/Models/ReconnectionInfo.cs +++ b/src/Websocket.Client/Models/ReconnectionInfo.cs @@ -1,7 +1,5 @@ -using System; - -// ReSharper disable once CheckNamespace -namespace Websocket.Client.Models +// ReSharper disable once CheckNamespace +namespace Websocket.Client { /// /// Info about happened reconnection diff --git a/src/Websocket.Client/ResponseMessage.cs b/src/Websocket.Client/ResponseMessage.cs index c4ef4c0..c2eba25 100644 --- a/src/Websocket.Client/ResponseMessage.cs +++ b/src/Websocket.Client/ResponseMessage.cs @@ -7,7 +7,7 @@ namespace Websocket.Client /// public class ResponseMessage { - private ResponseMessage(byte[] binary, string text, WebSocketMessageType messageType) + private ResponseMessage(byte[]? binary, string? text, WebSocketMessageType messageType) { Binary = binary; Text = text; @@ -17,12 +17,12 @@ private ResponseMessage(byte[] binary, string text, WebSocketMessageType message /// /// Received text message (only if type = WebSocketMessageType.Text) /// - public string Text { get; } + public string? Text { get; } /// /// Received text message (only if type = WebSocketMessageType.Binary) /// - public byte[] Binary { get; } + public byte[]? Binary { get; } /// /// Current message type (Text or Binary) @@ -36,7 +36,7 @@ public override string ToString() { if (MessageType == WebSocketMessageType.Text) { - return Text; + return Text ?? string.Empty; } return $"Type binary, length: {Binary?.Length}"; @@ -45,7 +45,7 @@ public override string ToString() /// /// Create text response message /// - public static ResponseMessage TextMessage(string data) + public static ResponseMessage TextMessage(string? data) { return new ResponseMessage(null, data, WebSocketMessageType.Text); } @@ -53,7 +53,7 @@ public static ResponseMessage TextMessage(string data) /// /// Create binary response message /// - public static ResponseMessage BinaryMessage(byte[] data) + public static ResponseMessage BinaryMessage(byte[]? data) { return new ResponseMessage(data, null, WebSocketMessageType.Binary); } diff --git a/src/Websocket.Client/Websocket.Client.csproj b/src/Websocket.Client/Websocket.Client.csproj index 17eaae4..65834ff 100644 --- a/src/Websocket.Client/Websocket.Client.csproj +++ b/src/Websocket.Client/Websocket.Client.csproj @@ -1,7 +1,7 @@  - netstandard2.0;netstandard2.1;net6;net7 + netstandard2.1;net6;net7 Websocket.Client Mariusz Kotas Client for websocket API with built-in reconnection and error handling @@ -24,13 +24,11 @@ true snupkg + enable - - all - runtime; build; native; contentfiles; analyzers - + diff --git a/src/Websocket.Client/WebsocketClient.Reconnecting.cs b/src/Websocket.Client/WebsocketClient.Reconnecting.cs index fcc8730..60baa90 100644 --- a/src/Websocket.Client/WebsocketClient.Reconnecting.cs +++ b/src/Websocket.Client/WebsocketClient.Reconnecting.cs @@ -1,7 +1,7 @@ using System; using System.Threading; using System.Threading.Tasks; -using Websocket.Client.Logging; +using Microsoft.Extensions.Logging; namespace Websocket.Client { @@ -32,7 +32,7 @@ private async Task ReconnectInternal(bool failFast) { if (!IsStarted) { - Logger.Debug(L("Client not started, ignoring reconnection..")); + _logger.LogDebug(L("Client not started, ignoring reconnection.."), Name); return; } @@ -46,7 +46,7 @@ private async Task ReconnectInternal(bool failFast) } } - private async Task ReconnectSynchronized(ReconnectionType type, bool failFast, Exception causedException) + private async Task ReconnectSynchronized(ReconnectionType type, bool failFast, Exception? causedException) { using (await _locker.LockAsync()) { @@ -54,7 +54,7 @@ private async Task ReconnectSynchronized(ReconnectionType type, bool failFast, E } } - private async Task Reconnect(ReconnectionType type, bool failFast, Exception causedException) + private async Task Reconnect(ReconnectionType type, bool failFast, Exception? causedException) { IsRunning = false; if (_disposing || !IsStarted) @@ -73,18 +73,18 @@ private async Task Reconnect(ReconnectionType type, bool failFast, Exception cau if (disInfo.CancelReconnection) { // reconnection canceled by user, do nothing - Logger.Info(L($"Reconnecting canceled by user, exiting.")); + _logger.LogInformation(L("Reconnecting canceled by user, exiting."), Name); } } - _cancellation.Cancel(); + _cancellation?.Cancel(); try { _client?.Abort(); } catch (Exception e) { - Logger.Error(e, L($"Exception while aborting client. " + $"Error: '{e.Message}'")); + _logger.LogError(e, L("Exception while aborting client. Error: '{error}'"), Name, e.Message); } _client?.Dispose(); @@ -96,7 +96,7 @@ private async Task Reconnect(ReconnectionType type, bool failFast, Exception cau return; } - Logger.Debug(L("Reconnecting...")); + _logger.LogDebug(L("Reconnecting..."), Name); _cancellation = new CancellationTokenSource(); await StartClient(_url, _cancellation.Token, type, failFast).ConfigureAwait(false); _reconnecting = false; @@ -114,7 +114,7 @@ private void DeactivateLastChance() _lastChanceTimer = null; } - private void LastChance(object state) + private void LastChance(object? state) { if (!IsReconnectionEnabled || ReconnectTimeout == null) { @@ -127,7 +127,7 @@ private void LastChance(object state) var diffMs = Math.Abs(DateTime.UtcNow.Subtract(_lastReceivedMsg).TotalMilliseconds); if (diffMs > timeoutMs) { - Logger.Debug(L($"Last message received more than {timeoutMs:F} ms ago. Hard restart..")); + _logger.LogDebug(L("Last message received more than {timeoutMs} ms ago. Hard restart.."), Name, timeoutMs.ToString("F")); DeactivateLastChance(); _ = ReconnectSynchronized(ReconnectionType.NoMessageReceived, false, null); diff --git a/src/Websocket.Client/WebsocketClient.Sending.cs b/src/Websocket.Client/WebsocketClient.Sending.cs index 294a952..b8f5cb4 100644 --- a/src/Websocket.Client/WebsocketClient.Sending.cs +++ b/src/Websocket.Client/WebsocketClient.Sending.cs @@ -1,8 +1,9 @@ using System; using System.Net.WebSockets; +using System.Threading; using System.Threading.Channels; using System.Threading.Tasks; -using Websocket.Client.Logging; +using Microsoft.Extensions.Logging; namespace Websocket.Client { @@ -109,7 +110,7 @@ private async Task SendTextFromQueue() } catch (Exception e) { - Logger.Error(e, L($"Failed to send text message: '{message}'. Error: {e.Message}")); + _logger.LogError(e, L("Failed to send text message: '{message}'. Error: {error}"), Name, message, e.Message); } } } @@ -124,13 +125,13 @@ private async Task SendTextFromQueue() } catch (Exception e) { - if (_cancellationTotal.IsCancellationRequested || _disposing) + if (_cancellationTotal?.IsCancellationRequested == true || _disposing) { // disposing/canceling, do nothing and exit return; } - Logger.Trace(L($"Sending text thread failed, error: {e.Message}. Creating a new sending thread.")); + _logger.LogTrace(L("Sending text thread failed, error: {error}. Creating a new sending thread."), Name, e.Message); StartBackgroundThreadForSendingText(); } @@ -150,7 +151,7 @@ private async Task SendBinaryFromQueue() } catch (Exception e) { - Logger.Error(e, L($"Failed to send binary message: '{message}'. Error: {e.Message}")); + _logger.LogError(e, L("Failed to send binary message: '{message}'. Error: {error}"), Name, message, e.Message); } } } @@ -165,13 +166,13 @@ private async Task SendBinaryFromQueue() } catch (Exception e) { - if (_cancellationTotal.IsCancellationRequested || _disposing) + if (_cancellationTotal?.IsCancellationRequested == true || _disposing) { // disposing/canceling, do nothing and exit return; } - Logger.Trace(L($"Sending binary thread failed, error: {e.Message}. Creating a new sending thread.")); + _logger.LogTrace(L("Sending binary thread failed, error: {error}. Creating a new sending thread."), Name, e.Message); StartBackgroundThreadForSendingBinary(); } @@ -179,12 +180,12 @@ private async Task SendBinaryFromQueue() private void StartBackgroundThreadForSendingText() { - _ = Task.Factory.StartNew(_ => SendTextFromQueue(), TaskCreationOptions.LongRunning, _cancellationTotal.Token); + _ = Task.Factory.StartNew(_ => SendTextFromQueue(), TaskCreationOptions.LongRunning, _cancellationTotal?.Token ?? CancellationToken.None); } private void StartBackgroundThreadForSendingBinary() { - _ = Task.Factory.StartNew(_ => SendBinaryFromQueue(), TaskCreationOptions.LongRunning, _cancellationTotal.Token); + _ = Task.Factory.StartNew(_ => SendBinaryFromQueue(), TaskCreationOptions.LongRunning, _cancellationTotal?.Token ?? CancellationToken.None); } private async Task SendInternalSynchronized(string message) @@ -199,15 +200,15 @@ private async Task SendInternal(string message) { if (!IsClientConnected()) { - Logger.Debug(L($"Client is not connected to server, cannot send: {message}")); + _logger.LogDebug(L("Client is not connected to server, cannot send: {message}"), Name, message); return; } - Logger.Trace(L($"Sending: {message}")); + _logger.LogTrace(L("Sending: {message}"), Name, message); var buffer = GetEncoding().GetBytes(message); var messageSegment = new ArraySegment(buffer); - await _client - .SendAsync(messageSegment, WebSocketMessageType.Text, true, _cancellation.Token) + await _client! + .SendAsync(messageSegment, WebSocketMessageType.Text, true, _cancellation?.Token ?? CancellationToken.None) .ConfigureAwait(false); } @@ -223,14 +224,14 @@ private async Task SendInternal(ArraySegment message) { if (!IsClientConnected()) { - Logger.Debug(L($"Client is not connected to server, cannot send binary, length: {message.Count}")); + _logger.LogDebug(L("Client is not connected to server, cannot send binary, length: {length}"), Name, message.Count); return; } - Logger.Trace(L($"Sending binary, length: {message.Count}")); + _logger.LogTrace(L("Sending binary, length: {length}"), Name, message.Count); - await _client - .SendAsync(message, WebSocketMessageType.Binary, true, _cancellation.Token) + await _client! + .SendAsync(message, WebSocketMessageType.Binary, true, _cancellation?.Token ?? CancellationToken.None) .ConfigureAwait(false); } } diff --git a/src/Websocket.Client/WebsocketClient.cs b/src/Websocket.Client/WebsocketClient.cs index 6bed527..1e1fb3d 100644 --- a/src/Websocket.Client/WebsocketClient.cs +++ b/src/Websocket.Client/WebsocketClient.cs @@ -1,5 +1,5 @@ +using Microsoft.Extensions.Logging; using System; -using System.Diagnostics; using System.IO; using System.Linq; using System.Net.WebSockets; @@ -8,9 +8,8 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.Logging.Abstractions; using Websocket.Client.Exceptions; -using Websocket.Client.Logging; -using Websocket.Client.Models; using Websocket.Client.Threading; namespace Websocket.Client @@ -20,22 +19,21 @@ namespace Websocket.Client /// public partial class WebsocketClient : IWebsocketClient { - private static readonly ILog Logger = GetLogger(); - + private readonly ILogger _logger; private readonly WebsocketAsyncLock _locker = new WebsocketAsyncLock(); private readonly Func> _connectionFactory; private Uri _url; - private Timer _lastChanceTimer; + private Timer? _lastChanceTimer; private DateTime _lastReceivedMsg = DateTime.UtcNow; private bool _disposing; private bool _reconnecting; private bool _stopping; private bool _isReconnectionEnabled = true; - private WebSocket _client; - private CancellationTokenSource _cancellation; - private CancellationTokenSource _cancellationTotal; + private WebSocket? _client; + private CancellationTokenSource? _cancellation; + private CancellationTokenSource? _cancellationTotal; private readonly Subject _messageReceivedSubject = new Subject(); private readonly Subject _reconnectionSubject = new Subject(); @@ -46,8 +44,19 @@ public partial class WebsocketClient : IWebsocketClient /// /// Target websocket url (wss://) /// Optional factory for native ClientWebSocket, use it whenever you need some custom features (proxy, settings, etc) - public WebsocketClient(Uri url, Func clientFactory = null) - : this(url, GetClientFactory(clientFactory)) + public WebsocketClient(Uri url, Func? clientFactory = null) + : this(url, null, GetClientFactory(clientFactory)) + { + } + + /// + /// A simple websocket client with built-in reconnection and error handling + /// + /// Target websocket url (wss://) + /// Logger instance, can be null + /// Optional factory for native ClientWebSocket, use it whenever you need some custom features (proxy, settings, etc) + public WebsocketClient(Uri url, ILogger? logger, Func? clientFactory = null) + : this(url, logger, GetClientFactory(clientFactory)) { } @@ -55,11 +64,13 @@ public WebsocketClient(Uri url, Func clientFactory = null) /// A simple websocket client with built-in reconnection and error handling /// /// Target websocket url (wss://) + /// Logger instance, can be null /// Optional factory for native creating and connecting to a websocket. The method should return a which is connected. Use it whenever you need some custom features (proxy, settings, etc) - public WebsocketClient(Uri url, Func> connectionFactory) + public WebsocketClient(Uri url, ILogger? logger, Func>? connectionFactory) { Validations.Validations.ValidateInput(url, nameof(url)); + _logger = logger ?? NullLogger.Instance; _url = url; _connectionFactory = connectionFactory ?? (async (uri, token) => { @@ -148,7 +159,7 @@ public bool IsReconnectionEnabled /// Get or set the name of the current websocket client instance. /// For logging purpose (in case you use more parallel websocket clients and want to distinguish between them) /// - public string Name { get; set; } + public string? Name { get; set; } /// /// Returns true if Start() method was called at least once. False if not started or disposed @@ -167,10 +178,10 @@ public bool IsReconnectionEnabled public bool IsTextMessageConversionEnabled { get; set; } = true; /// - public Encoding MessageEncoding { get; set; } + public Encoding? MessageEncoding { get; set; } /// - public ClientWebSocket NativeClient => GetSpecificOrThrow(_client); + public ClientWebSocket? NativeClient => GetSpecificOrThrow(_client); /// /// Terminate the websocket connection and cleanup everything @@ -178,11 +189,11 @@ public bool IsReconnectionEnabled public void Dispose() { _disposing = true; - Logger.Debug(L("Disposing..")); + _logger.LogDebug(L("Disposing.."), Name); try { - _messagesTextToSendQueue?.Writer.Complete(); - _messagesBinaryToSendQueue?.Writer.Complete(); + _messagesTextToSendQueue.Writer.Complete(); + _messagesBinaryToSendQueue.Writer.Complete(); _lastChanceTimer?.Dispose(); _cancellation?.Cancel(); _cancellationTotal?.Cancel(); @@ -195,7 +206,7 @@ public void Dispose() } catch (Exception e) { - Logger.Error(e, L($"Failed to dispose client, error: {e.Message}")); + _logger.LogError(e, L("Failed to dispose client, error: {error}"), Name, e.Message); } if (IsRunning) @@ -264,7 +275,7 @@ public async Task StopOrFail(WebSocketCloseStatus status, string statusDes return result; } - private static Func> GetClientFactory(Func clientFactory) + private static Func>? GetClientFactory(Func? clientFactory) { if (clientFactory == null) return null; @@ -281,18 +292,18 @@ private async Task StartInternal(bool failFast) { if (_disposing) { - throw new WebsocketException(L("Client is already disposed, starting not possible")); + throw new WebsocketException($"Client {Name} is already disposed, starting not possible"); } if (IsStarted) { - Logger.Debug(L("Client already started, ignoring..")); + _logger.LogDebug(L("Client already started, ignoring.."), Name); return; } IsStarted = true; - Logger.Debug(L("Starting..")); + _logger.LogDebug(L("Starting.."), Name); _cancellation = new CancellationTokenSource(); _cancellationTotal = new CancellationTokenSource(); @@ -302,12 +313,12 @@ private async Task StartInternal(bool failFast) StartBackgroundThreadForSendingBinary(); } - private async Task StopInternal(WebSocket client, WebSocketCloseStatus status, string statusDescription, + private async Task StopInternal(WebSocket? client, WebSocketCloseStatus status, string statusDescription, CancellationToken? cancellation, bool failFast, bool byServer) { if (_disposing) { - throw new WebsocketException(L("Client is already disposed, stopping not possible")); + throw new WebsocketException($"Client {Name} is already disposed, stopping not possible"); } DeactivateLastChance(); @@ -321,7 +332,7 @@ private async Task StopInternal(WebSocket client, WebSocketCloseStatus sta if (!IsRunning) { - Logger.Info(L("Client is already stopped")); + _logger.LogInformation(L("Client is already stopped"), Name); IsStarted = false; return false; } @@ -339,12 +350,12 @@ private async Task StopInternal(WebSocket client, WebSocketCloseStatus sta } catch (Exception e) { - Logger.Error(e, L($"Error while stopping client, message: '{e.Message}'")); + _logger.LogError(e, L("Error while stopping client, message: '{error}'"), Name, e.Message); if (failFast) { // fail fast, propagate exception - throw new WebsocketException($"Failed to stop Websocket client, error: '{e.Message}'", e); + throw new WebsocketException($"Failed to stop Websocket client {Name}, error: '{e.Message}'", e); } } finally @@ -384,8 +395,8 @@ private async Task StartClient(Uri uri, CancellationToken token, ReconnectionTyp if (info.CancelReconnection) { // reconnection canceled by user, do nothing - Logger.Error(e, L($"Exception while connecting. " + - $"Reconnecting canceled by user, exiting. Error: '{e.Message}'")); + _logger.LogError(e, L("Exception while connecting. " + + "Reconnecting canceled by user, exiting. Error: '{error}'"), Name, e.Message); return; } @@ -393,19 +404,19 @@ private async Task StartClient(Uri uri, CancellationToken token, ReconnectionTyp { // fail fast, propagate exception // do not reconnect - throw new WebsocketException($"Failed to start Websocket client, error: '{e.Message}'", e); + throw new WebsocketException($"Failed to start Websocket client {Name}, error: '{e.Message}'", e); } if (ErrorReconnectTimeout == null) { - Logger.Error(e, L($"Exception while connecting. " + - $"Reconnecting disabled, exiting. Error: '{e.Message}'")); + _logger.LogError(e, L("Exception while connecting. " + + "Reconnecting disabled, exiting. Error: '{error}'"), Name, e.Message); return; } var timeout = ErrorReconnectTimeout.Value; - Logger.Error(e, L($"Exception while connecting. " + - $"Waiting {timeout.TotalSeconds} sec before next reconnection try. Error: '{e.Message}'")); + _logger.LogError(e, L("Exception while connecting. " + + "Waiting {timeout} sec before next reconnection try. Error: '{error}'"), Name, timeout.TotalSeconds, e.Message); await Task.Delay(timeout, token).ConfigureAwait(false); await Reconnect(ReconnectionType.Error, false, e).ConfigureAwait(false); } @@ -413,12 +424,12 @@ private async Task StartClient(Uri uri, CancellationToken token, ReconnectionTyp private bool IsClientConnected() { - return _client.State == WebSocketState.Open; + return _client?.State == WebSocketState.Open; } private async Task Listen(WebSocket client, CancellationToken token) { - Exception causedException = null; + Exception? causedException = null; try { // define buffer here and reuse, to avoid more allocation @@ -428,10 +439,10 @@ private async Task Listen(WebSocket client, CancellationToken token) do { WebSocketReceiveResult result; - byte[] resultArrayWithTrailing = null; + byte[]? resultArrayWithTrailing = null; var resultArraySize = 0; var isResultArrayCloned = false; - MemoryStream ms = null; + MemoryStream? ms = null; while (true) { @@ -458,7 +469,7 @@ private async Task Listen(WebSocket client, CancellationToken token) { // create memory stream and insert first chunk ms = new MemoryStream(); - ms.Write(resultArrayWithTrailing, 0, resultArraySize); + ms.Write(resultArrayWithTrailing!, 0, resultArraySize); } // insert current chunk @@ -493,7 +504,7 @@ private async Task Listen(WebSocket client, CancellationToken token) } else if (result.MessageType == WebSocketMessageType.Close) { - Logger.Trace(L($"Received close message")); + _logger.LogTrace(L("Received close message"), Name); if (!IsStarted || _stopping) { @@ -508,7 +519,7 @@ private async Task Listen(WebSocket client, CancellationToken token) // closing canceled, reconnect if enabled if (IsReconnectionEnabled) { - throw new OperationCanceledException("Websocket connection was closed by server"); + throw new OperationCanceledException($"Websocket connection was closed by server (client: {Name})"); } continue; @@ -540,7 +551,7 @@ await StopInternal(client, WebSocketCloseStatus.NormalClosure, "Closing", ms?.Dispose(); - Logger.Trace(L($"Received: {message}")); + _logger.LogTrace(L("Received: {message}"), Name, message); _lastReceivedMsg = DateTime.UtcNow; _messageReceivedSubject.OnNext(message); @@ -563,7 +574,7 @@ await StopInternal(client, WebSocketCloseStatus.NormalClosure, "Closing", } catch (Exception e) { - Logger.Error(e, L($"Error while listening to websocket stream, error: '{e.Message}'")); + _logger.LogError(e, L("Error while listening to websocket stream, error: '{error}'"), Name, e.Message); causedException = e; } @@ -576,8 +587,8 @@ await StopInternal(client, WebSocketCloseStatus.NormalClosure, "Closing", if (LostReconnectTimeout.HasValue) { var timeout = LostReconnectTimeout.Value; - Logger.Warn(L("Listening websocket stream is lost. " + - $"Waiting {timeout.TotalSeconds} sec before next reconnection try.")); + _logger.LogWarning(L("Listening websocket stream is lost. " + + "Waiting {timeout} sec before next reconnection try."), Name, timeout.TotalSeconds); await Task.Delay(timeout, token).ConfigureAwait(false); } @@ -603,7 +614,7 @@ private Encoding GetEncoding() return MessageEncoding; } - private ClientWebSocket GetSpecificOrThrow(WebSocket client) + private ClientWebSocket? GetSpecificOrThrow(WebSocket? client) { if (client == null) return null; @@ -616,22 +627,7 @@ private ClientWebSocket GetSpecificOrThrow(WebSocket client) private string L(string msg) { - var name = Name ?? "CLIENT"; - return $"[WEBSOCKET {name}] {msg}"; - } - - private static ILog GetLogger() - { - try - { - return LogProvider.GetCurrentClassLogger(); - } - catch (Exception e) - { - Trace.WriteLine($"[WEBSOCKET] Failed to initialize logger, disabling.. " + - $"Error: {e}"); - return LogProvider.NoOpLogger.Instance; - } + return $"[WEBSOCKET {{name}}] {msg}"; } private DisconnectionType TranslateTypeToDisconnection(ReconnectionType type) diff --git a/test_integration/Websocket.Client.Sample/Program.cs b/test_integration/Websocket.Client.Sample/Program.cs index d0a9229..be984e4 100644 --- a/test_integration/Websocket.Client.Sample/Program.cs +++ b/test_integration/Websocket.Client.Sample/Program.cs @@ -5,8 +5,10 @@ using System.Runtime.Loader; using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; using Serilog; using Serilog.Events; +using Serilog.Extensions.Logging; using Serilog.Sinks.SystemConsole.Themes; namespace Websocket.Client.Sample @@ -17,7 +19,7 @@ internal class Program private static void Main() { - InitLogging(); + var logFactory = InitLogging(); AppDomain.CurrentDomain.ProcessExit += CurrentDomainOnProcessExit; AssemblyLoadContext.Default.Unloading += DefaultOnUnloading; @@ -32,6 +34,7 @@ private static void Main() Log.Debug(" STARTING "); Log.Debug("===================================="); + var logger = logFactory.CreateLogger(); var factory = new Func(() => { var client = new ClientWebSocket @@ -49,7 +52,7 @@ private static void Main() var url = new Uri("wss://www.bitmex.com/realtime"); - using (IWebsocketClient client = new WebsocketClient(url, factory)) + using (IWebsocketClient client = new WebsocketClient(url, logger, factory)) { client.Name = "Bitmex"; client.ReconnectTimeout = TimeSpan.FromSeconds(30); @@ -110,17 +113,19 @@ private static async Task SwitchUrl(IWebsocketClient client) } } - private static void InitLogging() + private static SerilogLoggerFactory InitLogging() { var executingDir = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location); var logPath = Path.Combine(executingDir ?? string.Empty, "logs", "verbose.log"); - Log.Logger = new LoggerConfiguration() + var logger = new LoggerConfiguration() .MinimumLevel.Verbose() .WriteTo.File(logPath, rollingInterval: RollingInterval.Day) .WriteTo.Console(LogEventLevel.Verbose, theme: AnsiConsoleTheme.Literate, outputTemplate: "{Timestamp:HH:mm:ss} [{Level:u3}] {Message} {NewLine}{Exception}") .CreateLogger(); + Log.Logger = logger; + return new SerilogLoggerFactory(logger); } private static void CurrentDomainOnProcessExit(object sender, EventArgs eventArgs) diff --git a/test_integration/Websocket.Client.Sample/Websocket.Client.Sample.csproj b/test_integration/Websocket.Client.Sample/Websocket.Client.Sample.csproj index 7e023a1..e875d11 100644 --- a/test_integration/Websocket.Client.Sample/Websocket.Client.Sample.csproj +++ b/test_integration/Websocket.Client.Sample/Websocket.Client.Sample.csproj @@ -6,6 +6,7 @@ +