From cefae9b82153107b0e75c5d1c7fe0d61d779ddc4 Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Mon, 4 Mar 2024 12:34:31 -0500 Subject: [PATCH 1/5] [debugproxy] Invoke CDP endpoint to report error to telemetry --- .../debugger/BrowserDebugProxy/MonoProxy.cs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/mono/browser/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/browser/debugger/BrowserDebugProxy/MonoProxy.cs index 4ae7fdd5e15de9..bdb8559b9a907d 100644 --- a/src/mono/browser/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/browser/debugger/BrowserDebugProxy/MonoProxy.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Threading; @@ -1519,17 +1520,30 @@ private async Task OnEvaluateOnCallFrame(MessageId msg_id, int scopeId, st catch (ReturnAsErrorException ree) { SendResponse(msg_id, AddCallStackInfoToException(ree.Error, context, scopeId), token); + SendExceptionToTelemetry(ree, msg_id, token); } catch (Exception e) { logger.LogDebug($"Error in EvaluateOnCallFrame for expression '{expression}' with '{e}."); - var exc = new ReturnAsErrorException(e.Message, e.GetType().Name); - SendResponse(msg_id, AddCallStackInfoToException(exc.Error, context, scopeId), token); + var ree = new ReturnAsErrorException(e.Message, e.GetType().Name); + SendResponse(msg_id, AddCallStackInfoToException(ree.Error, context, scopeId), token); + SendExceptionToTelemetry(ree, msg_id, token); } return true; } + private void SendExceptionToTelemetry(ReturnAsErrorException ree, SessionId msg_id, CancellationToken token) + { + var exceptionWithCallStackInfo = $"{ree.Error}\n{new StackTrace(1, true)}"; + JObject reportBlazorDebugError = JObject.FromObject(new + { + exceptionType = "uncaughtException", + error = $"{exceptionWithCallStackInfo}", + }); + SendEvent(msg_id, "DotnetDebugger.reportBlazorDebugError", reportBlazorDebugError, token); + } + internal async Task GetScopeProperties(SessionId msg_id, int scopeId, CancellationToken token) { try From 6642ef9638003241a1ea8063be0c17e619f995e7 Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Tue, 5 Mar 2024 10:18:21 -0500 Subject: [PATCH 2/5] [debugproxy] Report EvaluateCondition error to telemetry --- src/mono/browser/debugger/BrowserDebugProxy/MonoProxy.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/mono/browser/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/browser/debugger/BrowserDebugProxy/MonoProxy.cs index bdb8559b9a907d..e7725aa9c29cbb 100644 --- a/src/mono/browser/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/browser/debugger/BrowserDebugProxy/MonoProxy.cs @@ -912,16 +912,19 @@ protected async Task EvaluateCondition(SessionId sessionId, ExecutionConte return true; } } - catch (ReturnAsErrorException raee) + catch (ReturnAsErrorException ree) { - logger.LogDebug($"Unable to evaluate breakpoint condition '{condition}': {raee}"); - SendLog(sessionId, $"Unable to evaluate breakpoint condition '{condition}': {raee.Message}", token, type: "error"); + logger.LogDebug($"Unable to evaluate breakpoint condition '{condition}': {ree}"); + SendLog(sessionId, $"Unable to evaluate breakpoint condition '{condition}': {ree.Message}", token, type: "error"); bp.ConditionAlreadyEvaluatedWithError = true; + SendExceptionToTelemetry(ree, sessionId, token); } catch (Exception e) { Log("info", $"Unable to evaluate breakpoint condition '{condition}': {e}"); bp.ConditionAlreadyEvaluatedWithError = true; + var ree = new ReturnAsErrorException(e.Message, e.GetType().Name); + SendExceptionToTelemetry(ree, sessionId, token); } return false; } From 92e2697d8baa13a885013d440d29166527eaaf50 Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Tue, 5 Mar 2024 10:52:07 -0500 Subject: [PATCH 3/5] Capture message portion of ReturnAsErrorException --- .../browser/debugger/BrowserDebugProxy/MonoProxy.cs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/mono/browser/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/browser/debugger/BrowserDebugProxy/MonoProxy.cs index e7725aa9c29cbb..a8d80f9bc85527 100644 --- a/src/mono/browser/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/browser/debugger/BrowserDebugProxy/MonoProxy.cs @@ -917,14 +917,13 @@ protected async Task EvaluateCondition(SessionId sessionId, ExecutionConte logger.LogDebug($"Unable to evaluate breakpoint condition '{condition}': {ree}"); SendLog(sessionId, $"Unable to evaluate breakpoint condition '{condition}': {ree.Message}", token, type: "error"); bp.ConditionAlreadyEvaluatedWithError = true; - SendExceptionToTelemetry(ree, sessionId, token); + SendExceptionToTelemetry(ree.Message, sessionId, token); } catch (Exception e) { Log("info", $"Unable to evaluate breakpoint condition '{condition}': {e}"); bp.ConditionAlreadyEvaluatedWithError = true; - var ree = new ReturnAsErrorException(e.Message, e.GetType().Name); - SendExceptionToTelemetry(ree, sessionId, token); + SendExceptionToTelemetry(e.Message, sessionId, token); } return false; } @@ -1523,22 +1522,22 @@ private async Task OnEvaluateOnCallFrame(MessageId msg_id, int scopeId, st catch (ReturnAsErrorException ree) { SendResponse(msg_id, AddCallStackInfoToException(ree.Error, context, scopeId), token); - SendExceptionToTelemetry(ree, msg_id, token); + SendExceptionToTelemetry(ree.Message, msg_id, token); } catch (Exception e) { logger.LogDebug($"Error in EvaluateOnCallFrame for expression '{expression}' with '{e}."); var ree = new ReturnAsErrorException(e.Message, e.GetType().Name); SendResponse(msg_id, AddCallStackInfoToException(ree.Error, context, scopeId), token); - SendExceptionToTelemetry(ree, msg_id, token); + SendExceptionToTelemetry(e.Message, msg_id, token); } return true; } - private void SendExceptionToTelemetry(ReturnAsErrorException ree, SessionId msg_id, CancellationToken token) + private void SendExceptionToTelemetry(string message, SessionId msg_id, CancellationToken token) { - var exceptionWithCallStackInfo = $"{ree.Error}\n{new StackTrace(1, true)}"; + var exceptionWithCallStackInfo = $"{message}\n{new StackTrace(1, true)}"; JObject reportBlazorDebugError = JObject.FromObject(new { exceptionType = "uncaughtException", From 2eafa05b32d8bef7f1d1712f051e708aacaaff82 Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Tue, 5 Mar 2024 12:00:40 -0500 Subject: [PATCH 4/5] Capture top 5 frames of the thrown exception --- .../debugger/BrowserDebugProxy/MonoProxy.cs | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/mono/browser/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/browser/debugger/BrowserDebugProxy/MonoProxy.cs index a8d80f9bc85527..927974d52e6e52 100644 --- a/src/mono/browser/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/browser/debugger/BrowserDebugProxy/MonoProxy.cs @@ -17,6 +17,7 @@ using static System.Formats.Asn1.AsnWriter; using System.Reflection; using System.Collections.Concurrent; +using System.Text; namespace Microsoft.WebAssembly.Diagnostics { @@ -917,13 +918,13 @@ protected async Task EvaluateCondition(SessionId sessionId, ExecutionConte logger.LogDebug($"Unable to evaluate breakpoint condition '{condition}': {ree}"); SendLog(sessionId, $"Unable to evaluate breakpoint condition '{condition}': {ree.Message}", token, type: "error"); bp.ConditionAlreadyEvaluatedWithError = true; - SendExceptionToTelemetry(ree.Message, sessionId, token); + SendExceptionToTelemetry(ree, sessionId, token); } catch (Exception e) { Log("info", $"Unable to evaluate breakpoint condition '{condition}': {e}"); bp.ConditionAlreadyEvaluatedWithError = true; - SendExceptionToTelemetry(e.Message, sessionId, token); + SendExceptionToTelemetry(e, sessionId, token); } return false; } @@ -1522,22 +1523,30 @@ private async Task OnEvaluateOnCallFrame(MessageId msg_id, int scopeId, st catch (ReturnAsErrorException ree) { SendResponse(msg_id, AddCallStackInfoToException(ree.Error, context, scopeId), token); - SendExceptionToTelemetry(ree.Message, msg_id, token); + SendExceptionToTelemetry(ree, msg_id, token); } catch (Exception e) { logger.LogDebug($"Error in EvaluateOnCallFrame for expression '{expression}' with '{e}."); var ree = new ReturnAsErrorException(e.Message, e.GetType().Name); SendResponse(msg_id, AddCallStackInfoToException(ree.Error, context, scopeId), token); - SendExceptionToTelemetry(e.Message, msg_id, token); + SendExceptionToTelemetry(e, msg_id, token); } return true; } - private void SendExceptionToTelemetry(string message, SessionId msg_id, CancellationToken token) + private void SendExceptionToTelemetry(Exception exc, SessionId msg_id, CancellationToken token) { - var exceptionWithCallStackInfo = $"{message}\n{new StackTrace(1, true)}"; + var stackTrace = exc.StackTrace ?? new StackTrace(1, true).ToString(); + var stackTraceLines = stackTrace.Split(new[] { Environment.NewLine }, StringSplitOptions.None); + var exceptionWithCallStackInfo = new StringBuilder($"{exc.Message}"); + + for (int i = 0; i < 5 && i < stackTraceLines.Length; i++) + { + exceptionWithCallStackInfo.Append($"\n{stackTraceLines[i]}"); + } + JObject reportBlazorDebugError = JObject.FromObject(new { exceptionType = "uncaughtException", From edd83b04dc593cda81763769ca528494bc88ced8 Mon Sep 17 00:00:00 2001 From: mdh1418 Date: Tue, 5 Mar 2024 12:29:57 -0500 Subject: [PATCH 5/5] Simplify error message to expression plus calling function --- .../debugger/BrowserDebugProxy/MonoProxy.cs | 23 +++++-------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/src/mono/browser/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/browser/debugger/BrowserDebugProxy/MonoProxy.cs index 927974d52e6e52..503f196c17f058 100644 --- a/src/mono/browser/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/browser/debugger/BrowserDebugProxy/MonoProxy.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Linq; using System.Threading; @@ -17,7 +16,6 @@ using static System.Formats.Asn1.AsnWriter; using System.Reflection; using System.Collections.Concurrent; -using System.Text; namespace Microsoft.WebAssembly.Diagnostics { @@ -918,13 +916,13 @@ protected async Task EvaluateCondition(SessionId sessionId, ExecutionConte logger.LogDebug($"Unable to evaluate breakpoint condition '{condition}': {ree}"); SendLog(sessionId, $"Unable to evaluate breakpoint condition '{condition}': {ree.Message}", token, type: "error"); bp.ConditionAlreadyEvaluatedWithError = true; - SendExceptionToTelemetry(ree, sessionId, token); + SendExceptionToTelemetry(ree, "EvaluateCondition", sessionId, token); } catch (Exception e) { Log("info", $"Unable to evaluate breakpoint condition '{condition}': {e}"); bp.ConditionAlreadyEvaluatedWithError = true; - SendExceptionToTelemetry(e, sessionId, token); + SendExceptionToTelemetry(e, "EvaluateCondition", sessionId, token); } return false; } @@ -1523,34 +1521,25 @@ private async Task OnEvaluateOnCallFrame(MessageId msg_id, int scopeId, st catch (ReturnAsErrorException ree) { SendResponse(msg_id, AddCallStackInfoToException(ree.Error, context, scopeId), token); - SendExceptionToTelemetry(ree, msg_id, token); + SendExceptionToTelemetry(ree, "OnEvaluateOnCallFrame", msg_id, token); } catch (Exception e) { logger.LogDebug($"Error in EvaluateOnCallFrame for expression '{expression}' with '{e}."); var ree = new ReturnAsErrorException(e.Message, e.GetType().Name); SendResponse(msg_id, AddCallStackInfoToException(ree.Error, context, scopeId), token); - SendExceptionToTelemetry(e, msg_id, token); + SendExceptionToTelemetry(e, "OnEvaluateOnCallFrame", msg_id, token); } return true; } - private void SendExceptionToTelemetry(Exception exc, SessionId msg_id, CancellationToken token) + private void SendExceptionToTelemetry(Exception exc, string callingFunction, SessionId msg_id, CancellationToken token) { - var stackTrace = exc.StackTrace ?? new StackTrace(1, true).ToString(); - var stackTraceLines = stackTrace.Split(new[] { Environment.NewLine }, StringSplitOptions.None); - var exceptionWithCallStackInfo = new StringBuilder($"{exc.Message}"); - - for (int i = 0; i < 5 && i < stackTraceLines.Length; i++) - { - exceptionWithCallStackInfo.Append($"\n{stackTraceLines[i]}"); - } - JObject reportBlazorDebugError = JObject.FromObject(new { exceptionType = "uncaughtException", - error = $"{exceptionWithCallStackInfo}", + error = $"{exc.Message} at {callingFunction}", }); SendEvent(msg_id, "DotnetDebugger.reportBlazorDebugError", reportBlazorDebugError, token); }