diff --git a/CHANGELOG.md b/CHANGELOG.md index ef47bc7ec2..f23f1f5fa4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ ``` (Issue [#2579](https://github.com/realm/realm-dotnet/issues/2579)) * The Realm source generator will now error out in case a collection in the model classes is assigned to a non-null value either in a property initializer or in a constructor. Realm collections are initialized internally and assigning non-null values to the property is not supported, where the `null!` assignment is only useful to silence nullable reference type warnings, in reality the collection will never be null. (Issue [#3455](https://github.com/realm/realm-dotnet/issues/3455)) +* Made WebSocket error logging more verbose when using `AppConfiguration.UseManagedWebSockets = true`. [#3459](https://github.com/realm/realm-dotnet/pull/3459) ### Fixed * None diff --git a/Realm/Realm/Native/SyncSocketProvider.WebSocket.cs b/Realm/Realm/Native/SyncSocketProvider.WebSocket.cs index 723b5f84d7..21ae8afa95 100644 --- a/Realm/Realm/Native/SyncSocketProvider.WebSocket.cs +++ b/Realm/Realm/Native/SyncSocketProvider.WebSocket.cs @@ -66,14 +66,9 @@ private async Task ReadThread() } catch (Exception e) { - if (e.InnerException is not null) - { - Logger.LogDefault(LogLevel.Error, $"Error establishing WebSocket connection: {e.InnerException.Message}"); - if (!string.IsNullOrEmpty(e.InnerException.StackTrace)) - { - Logger.LogDefault(LogLevel.Trace, e.InnerException.StackTrace); - } - } + var builder = new StringBuilder(); + FormatExceptionForLogging(e, builder); + Logger.LogDefault(LogLevel.Error, "Error establishing WebSocket connection " + builder.ToString()); await _workQueue.WriteAsync(new WebSocketClosedWork(false, (WebSocketCloseStatus)RLM_ERR_WEBSOCKET_CONNECTION_FAILED, e.Message, _observer, _cancellationToken)); return; @@ -108,11 +103,9 @@ private async Task ReadThread() } catch (Exception e) { - Logger.LogDefault(LogLevel.Error, $"Error reading from WebSocket: {e.Message}"); - if (!string.IsNullOrEmpty(e.StackTrace)) - { - Logger.LogDefault(LogLevel.Trace, e.StackTrace); - } + var builder = new StringBuilder(); + FormatExceptionForLogging(e, builder); + Logger.LogDefault(LogLevel.Error, "Error reading from WebSocket " + builder.ToString()); await _workQueue.WriteAsync(new WebSocketClosedWork(false, (WebSocketCloseStatus)RLM_ERR_WEBSOCKET_READ_ERROR, e.Message, _observer, _cancellationToken)); return; @@ -137,11 +130,9 @@ public async void Write(BinaryValue data, IntPtr native_callback) } catch (Exception e) { - Logger.LogDefault(LogLevel.Error, $"Error writing to WebSocket {e.GetType().FullName}: {e.Message}"); - if (!string.IsNullOrEmpty(e.StackTrace)) - { - Logger.LogDefault(LogLevel.Trace, e.StackTrace); - } + var builder = new StringBuilder(); + FormatExceptionForLogging(e, builder); + Logger.LogDefault(LogLevel.Error, "Error writing to WebSocket " + builder.ToString()); // in case of errors notify the websocket observer and just dispose the callback await _workQueue.WriteAsync(new WebSocketClosedWork(false, (WebSocketCloseStatus)RLM_ERR_WEBSOCKET_WRITE_ERROR, e.Message, _observer, _cancellationToken)); @@ -188,6 +179,33 @@ public async void Dispose() { } } + + private static void FormatExceptionForLogging(Exception ex, StringBuilder builder, int nesting = 0) + { + var indentation = new string('\t', nesting); + builder.Append(indentation); + + builder.AppendFormat("{0}: {1}", ex.GetType().FullName, ex.Message); + builder.AppendLine(); + if (Logger.LogLevel >= LogLevel.Trace && !string.IsNullOrEmpty(ex.StackTrace)) + { + builder.Append(indentation); + var indentedTrace = ex.StackTrace.Replace(Environment.NewLine, Environment.NewLine + indentation); + builder.AppendLine(indentedTrace); + } + + if (ex is AggregateException aggregateException) + { + foreach (var inner in aggregateException.InnerExceptions) + { + FormatExceptionForLogging(inner, builder, nesting + 1); + } + } + else if (ex.InnerException is Exception inner) + { + FormatExceptionForLogging(inner, builder, nesting + 1); + } + } } private abstract class WebSocketWork : IWork