From 5a282139e2f47c49f5ffc5854fe782b030082cdc Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Wed, 5 Dec 2018 12:18:52 -0800 Subject: [PATCH 1/4] Telemetrize unhandled AnalysisQueue exceptions --- src/LanguageServer/Impl/LanguageServer.cs | 18 +++++++++++++++- src/LanguageServer/Impl/Telemetry.cs | 26 ++++++++++++++++++++--- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/src/LanguageServer/Impl/LanguageServer.cs b/src/LanguageServer/Impl/LanguageServer.cs index 7c09d1cd2..5ae9ece72 100644 --- a/src/LanguageServer/Impl/LanguageServer.cs +++ b/src/LanguageServer/Impl/LanguageServer.cs @@ -45,6 +45,7 @@ public sealed partial class LanguageServer : IDisposable { private IServiceContainer _services; private IUIService _ui; + private ITelemetryService2 _telemetry; private JsonRpc _rpc; private JsonSerializer _jsonSerializer; @@ -60,10 +61,11 @@ public CancellationToken Start(IServiceContainer services, JsonRpc rpc) { _ui = services.GetService(); _rpc = rpc; _jsonSerializer = services.GetService(); + _telemetry = services.GetService(); var progress = services.GetService(); - var rpcTraceListener = new TelemetryRpcTraceListener(services.GetService()); + var rpcTraceListener = new TelemetryRpcTraceListener(_telemetry); _rpc.TraceSource.Listeners.Add(rpcTraceListener); _server.OnLogMessage += OnLogMessage; @@ -72,6 +74,7 @@ public CancellationToken Start(IServiceContainer services, JsonRpc rpc) { _server.OnApplyWorkspaceEdit += OnApplyWorkspaceEdit; _server.OnRegisterCapability += OnRegisterCapability; _server.OnUnregisterCapability += OnUnregisterCapability; + _server.AnalysisQueue.UnhandledException += OnAnalyzerUnhandledException; _disposables .Add(() => _server.OnLogMessage -= OnLogMessage) @@ -80,6 +83,7 @@ public CancellationToken Start(IServiceContainer services, JsonRpc rpc) { .Add(() => _server.OnApplyWorkspaceEdit -= OnApplyWorkspaceEdit) .Add(() => _server.OnRegisterCapability -= OnRegisterCapability) .Add(() => _server.OnUnregisterCapability -= OnUnregisterCapability) + .Add(() => _server.AnalysisQueue.UnhandledException -= OnAnalyzerUnhandledException) .Add(() => _shutdownCts.Cancel()) .Add(_prioritizer) .Add(() => _pathsWatcher?.Dispose()) @@ -454,6 +458,18 @@ private void HandlePathWatchChange(JToken section) { _searchPaths = _initParams.initializationOptions.searchPaths; } + private void OnAnalyzerUnhandledException(object sender, UnhandledExceptionEventArgs e) { + if (!(e.ExceptionObject is Exception ex)) { + Debug.Fail($"ExceptionObject was {e.ExceptionObject.GetType()}, not Exception"); + return; + } + + var te = Telemetry.CreateEventWithException("analyzer.unhandledException", ex); + te.Properties["isTerminating"] = e.IsTerminating.ToString(); + + _telemetry.SendTelemetry(te).DoNotWait(); + } + private class Prioritizer : IDisposable { private const int InitializePriority = 0; private const int ConfigurationPriority = 1; diff --git a/src/LanguageServer/Impl/Telemetry.cs b/src/LanguageServer/Impl/Telemetry.cs index d59da4df0..43ed02d7a 100644 --- a/src/LanguageServer/Impl/Telemetry.cs +++ b/src/LanguageServer/Impl/Telemetry.cs @@ -27,6 +27,28 @@ internal class Telemetry { public static TelemetryEvent CreateEvent(string eventName) => new TelemetryEvent { EventName = EventPrefix + eventName, }; + + public static TelemetryEvent CreateEventWithException(string eventName, Exception e) { + var te = CreateEvent(eventName); + te.Properties["name"] = e.GetType().Name; + te.Properties["stackTrace"] = e.StackTrace; + + var inner = e.InnerException; + if (inner != null) { + if (inner is AggregateException ae) { + inner = ae.Flatten(); + } + + while (inner.InnerException != null) { + inner = inner.InnerException; + } + + te.Properties["innerName"] = inner.GetType().Name; + te.Properties["innerStackTrace"] = inner.StackTrace; + } + + return te; + } } internal class TelemetryRpcTraceListener : TraceListener { @@ -72,10 +94,8 @@ public override void TraceData(TraceEventCache eventCache, string source, TraceE return; } - var e = Telemetry.CreateEvent("rpc.exception"); + var e = Telemetry.CreateEventWithException("rpc.exception", exception); e.Properties["method"] = method; - e.Properties["name"] = exception.GetType().Name; - e.Properties["stackTrace"] = exception.StackTrace; _telemetryService.SendTelemetry(e).DoNotWait(); } From c444ab1bf909909df3eb4e2ced24d5828a62525f Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Wed, 5 Dec 2018 12:48:33 -0800 Subject: [PATCH 2/4] make the main exception the inner one instead --- src/LanguageServer/Impl/Telemetry.cs | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/LanguageServer/Impl/Telemetry.cs b/src/LanguageServer/Impl/Telemetry.cs index 43ed02d7a..ee0592c70 100644 --- a/src/LanguageServer/Impl/Telemetry.cs +++ b/src/LanguageServer/Impl/Telemetry.cs @@ -30,23 +30,21 @@ internal class Telemetry { public static TelemetryEvent CreateEventWithException(string eventName, Exception e) { var te = CreateEvent(eventName); - te.Properties["name"] = e.GetType().Name; - te.Properties["stackTrace"] = e.StackTrace; - var inner = e.InnerException; - if (inner != null) { - if (inner is AggregateException ae) { - inner = ae.Flatten(); - } + if (e is AggregateException ae && ae.InnerException != null) { + te.Properties["outerName"] = e.GetType().Name; + te.Properties["outerStackTrace"] = e.StackTrace; - while (inner.InnerException != null) { - inner = inner.InnerException; - } + e = ae.Flatten(); - te.Properties["innerName"] = inner.GetType().Name; - te.Properties["innerStackTrace"] = inner.StackTrace; + while (e.InnerException != null) { + e = e.InnerException; + } } + te.Properties["name"] = e.GetType().Name; + te.Properties["stackTrace"] = e.StackTrace; + return te; } } From 7651e895cdb388716a115724fa1458965b1699fd Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Wed, 5 Dec 2018 14:05:32 -0800 Subject: [PATCH 3/4] don't bother sending isTerminating, we always send false --- src/LanguageServer/Impl/LanguageServer.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/LanguageServer/Impl/LanguageServer.cs b/src/LanguageServer/Impl/LanguageServer.cs index 5ae9ece72..6bb230f66 100644 --- a/src/LanguageServer/Impl/LanguageServer.cs +++ b/src/LanguageServer/Impl/LanguageServer.cs @@ -465,8 +465,6 @@ private void OnAnalyzerUnhandledException(object sender, UnhandledExceptionEvent } var te = Telemetry.CreateEventWithException("analyzer.unhandledException", ex); - te.Properties["isTerminating"] = e.IsTerminating.ToString(); - _telemetry.SendTelemetry(te).DoNotWait(); } From 5ac089a8a119411cd184664999bc0e63d7f8a983 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Thu, 6 Dec 2018 10:48:56 -0800 Subject: [PATCH 4/4] rename function, event name --- src/LanguageServer/Impl/LanguageServer.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/LanguageServer/Impl/LanguageServer.cs b/src/LanguageServer/Impl/LanguageServer.cs index 6bb230f66..001a9595a 100644 --- a/src/LanguageServer/Impl/LanguageServer.cs +++ b/src/LanguageServer/Impl/LanguageServer.cs @@ -74,7 +74,7 @@ public CancellationToken Start(IServiceContainer services, JsonRpc rpc) { _server.OnApplyWorkspaceEdit += OnApplyWorkspaceEdit; _server.OnRegisterCapability += OnRegisterCapability; _server.OnUnregisterCapability += OnUnregisterCapability; - _server.AnalysisQueue.UnhandledException += OnAnalyzerUnhandledException; + _server.AnalysisQueue.UnhandledException += OnAnalysisQueueUnhandledException; _disposables .Add(() => _server.OnLogMessage -= OnLogMessage) @@ -83,7 +83,7 @@ public CancellationToken Start(IServiceContainer services, JsonRpc rpc) { .Add(() => _server.OnApplyWorkspaceEdit -= OnApplyWorkspaceEdit) .Add(() => _server.OnRegisterCapability -= OnRegisterCapability) .Add(() => _server.OnUnregisterCapability -= OnUnregisterCapability) - .Add(() => _server.AnalysisQueue.UnhandledException -= OnAnalyzerUnhandledException) + .Add(() => _server.AnalysisQueue.UnhandledException -= OnAnalysisQueueUnhandledException) .Add(() => _shutdownCts.Cancel()) .Add(_prioritizer) .Add(() => _pathsWatcher?.Dispose()) @@ -458,13 +458,13 @@ private void HandlePathWatchChange(JToken section) { _searchPaths = _initParams.initializationOptions.searchPaths; } - private void OnAnalyzerUnhandledException(object sender, UnhandledExceptionEventArgs e) { + private void OnAnalysisQueueUnhandledException(object sender, UnhandledExceptionEventArgs e) { if (!(e.ExceptionObject is Exception ex)) { Debug.Fail($"ExceptionObject was {e.ExceptionObject.GetType()}, not Exception"); return; } - var te = Telemetry.CreateEventWithException("analyzer.unhandledException", ex); + var te = Telemetry.CreateEventWithException("analysis_queue.unhandled_exception", ex); _telemetry.SendTelemetry(te).DoNotWait(); }