Skip to content
This repository was archived by the owner on Apr 14, 2022. It is now read-only.

Send telemetry on unhandled exceptions inside the AnalysisQueue #460

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion src/LanguageServer/Impl/LanguageServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -60,10 +61,11 @@ public CancellationToken Start(IServiceContainer services, JsonRpc rpc) {
_ui = services.GetService<IUIService>();
_rpc = rpc;
_jsonSerializer = services.GetService<JsonSerializer>();
_telemetry = services.GetService<ITelemetryService2>();

var progress = services.GetService<IProgressService>();

var rpcTraceListener = new TelemetryRpcTraceListener(services.GetService<ITelemetryService2>());
var rpcTraceListener = new TelemetryRpcTraceListener(_telemetry);
_rpc.TraceSource.Listeners.Add(rpcTraceListener);

_server.OnLogMessage += OnLogMessage;
Expand All @@ -72,6 +74,7 @@ public CancellationToken Start(IServiceContainer services, JsonRpc rpc) {
_server.OnApplyWorkspaceEdit += OnApplyWorkspaceEdit;
_server.OnRegisterCapability += OnRegisterCapability;
_server.OnUnregisterCapability += OnUnregisterCapability;
_server.AnalysisQueue.UnhandledException += OnAnalysisQueueUnhandledException;

_disposables
.Add(() => _server.OnLogMessage -= OnLogMessage)
Expand All @@ -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 -= OnAnalysisQueueUnhandledException)
.Add(() => _shutdownCts.Cancel())
.Add(_prioritizer)
.Add(() => _pathsWatcher?.Dispose())
Expand Down Expand Up @@ -454,6 +458,16 @@ private void HandlePathWatchChange(JToken section) {
_searchPaths = _initParams.initializationOptions.searchPaths;
}

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("analysis_queue.unhandled_exception", ex);
_telemetry.SendTelemetry(te).DoNotWait();
}

private class Prioritizer : IDisposable {
private const int InitializePriority = 0;
private const int ConfigurationPriority = 1;
Expand Down
24 changes: 21 additions & 3 deletions src/LanguageServer/Impl/Telemetry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,26 @@ 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);

if (e is AggregateException ae && ae.InnerException != null) {
te.Properties["outerName"] = e.GetType().Name;
te.Properties["outerStackTrace"] = e.StackTrace;

e = ae.Flatten();

while (e.InnerException != null) {
e = e.InnerException;
}
}

te.Properties["name"] = e.GetType().Name;
te.Properties["stackTrace"] = e.StackTrace;

return te;
}
}

internal class TelemetryRpcTraceListener : TraceListener {
Expand Down Expand Up @@ -72,10 +92,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();
}
Expand Down