提交 5bcacbaf 编写于 作者: H Heejae Chang

report more data on crash due to dispose

this is port of https://github.com/dotnet/roslyn/pull/20968 to dev15.3.x
上级 bb2767f5
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
namespace Microsoft.VisualStudio.LanguageServices.Implementation
{
/// <summary>
/// Mock to make test project build
/// </summary>
internal class WatsonReporter
{
public static void Report(string description, Exception exception, Func<IFaultUtility, int> callback)
{
// do nothing
}
public interface IFaultUtility
{
void AddProcessDump(int pid);
void AddFile(string fullpathname);
}
}
}
\ No newline at end of file
......@@ -246,6 +246,7 @@
<Compile Include="Preview\MockPreviewPaneService.cs" />
<Compile Include="QuickInfo\AbstractQuickInfoSourceTests.cs" />
<Compile Include="QuickInfo\AbstractSemanticQuickInfoSourceTests.cs" />
<Compile Include="Remote\WatsonReporter.cs" />
<Compile Include="RenameTracking\MockPreviewDialogService.cs" />
<Compile Include="RenameTracking\MockRefactorNotifyService.cs" />
<Compile Include="Semantics\SpeculationAnalyzerTestsBase.cs" />
......
......@@ -2,12 +2,15 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using StreamJsonRpc;
using Microsoft.CodeAnalysis.ErrorReporting;
using Microsoft.CodeAnalysis.Remote;
using Roslyn.Utilities;
using Microsoft.VisualStudio.LanguageServices.Implementation;
namespace Microsoft.VisualStudio.LanguageServices.Remote
{
......@@ -20,6 +23,9 @@ internal class JsonRpcClient : IDisposable
private readonly JsonRpc _rpc;
private readonly CancellationToken _cancellationToken;
private JsonRpcDisconnectedEventArgs _debuggingLastDisconnectReason;
private string _debuggingLastDisconnectCallstack;
public JsonRpcClient(
Stream stream, object callbackTarget, bool useThisAsCallback, CancellationToken cancellationToken)
{
......@@ -42,7 +48,7 @@ public async Task InvokeAsync(string targetName, params object[] arguments)
{
await _rpc.InvokeAsync(targetName, arguments).ConfigureAwait(false);
}
catch
catch (Exception ex) when (ReportUnlessCanceled(ex, _cancellationToken))
{
// any exception can be thrown from StreamJsonRpc if JsonRpc is disposed in the middle of read/write.
// until we move to newly added cancellation support in JsonRpc, we will catch exception and translate to
......@@ -61,7 +67,7 @@ public async Task<T> InvokeAsync<T>(string targetName, params object[] arguments
{
return await _rpc.InvokeAsync<T>(targetName, arguments).ConfigureAwait(false);
}
catch
catch (Exception ex) when (ReportUnlessCanceled(ex, _cancellationToken))
{
// any exception can be thrown from StreamJsonRpc if JsonRpc is disposed in the middle of read/write.
// until we move to newly added cancellation support in JsonRpc, we will catch exception and translate to
......@@ -82,6 +88,68 @@ public Task<T> InvokeAsync<T>(string targetName, IEnumerable<object> arguments,
return Extensions.InvokeAsync(_rpc, targetName, arguments, funcWithDirectStreamAsync, _cancellationToken);
}
private bool ReportUnlessCanceled(Exception ex, CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
{
return true;
}
// save extra info using NFW
ReportExtraInfoAsNFW(ex);
// make it to explicitly crash to get better info
FatalError.Report(ex);
GC.KeepAlive(_debuggingLastDisconnectReason);
GC.KeepAlive(_debuggingLastDisconnectCallstack);
return Contract.FailWithReturn<bool>("shouldn't be able to reach here");
}
private void ReportExtraInfoAsNFW(Exception ex)
{
WatsonReporter.Report("RemoteHost Failed", ex, u =>
{
try
{
// we will record dumps for all service hub processes
foreach (var p in Process.GetProcessesByName("ServiceHub.RoslynCodeAnalysisService32"))
{
// include all remote host processes
u.AddProcessDump(p.Id);
}
// include all service hub logs as well
var logPath = Path.Combine(Path.GetTempPath(), "servicehub", "logs");
if (Directory.Exists(logPath))
{
// attach all log files that are modified less than 1 day before.
var now = DateTime.UtcNow;
var oneDay = TimeSpan.FromDays(1);
foreach (var file in Directory.EnumerateFiles(logPath, "*.log"))
{
var lastWrite = File.GetLastWriteTimeUtc(file);
if (now - lastWrite > oneDay)
{
continue;
}
u.AddFile(file);
}
}
}
catch
{
// ignore issue
}
// 0 means send watson
return 0;
});
}
public void Dispose()
{
OnDisposed();
......@@ -104,6 +172,8 @@ protected virtual void OnDisposed()
protected virtual void OnDisconnected(object sender, JsonRpcDisconnectedEventArgs e)
{
// do nothing
_debuggingLastDisconnectReason = e;
_debuggingLastDisconnectCallstack = new StackTrace().ToString();
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册