Better exception report.

This commit is contained in:
qianlifeng 2015-01-16 23:42:12 +08:00
parent 32e0074f26
commit 9d39b616f9
12 changed files with 98 additions and 80 deletions

View File

@ -10,21 +10,19 @@ namespace Wox.Core.Exception
{ {
public class ExceptionFormatter public class ExceptionFormatter
{ {
public static string FormatExcpetion(object exception) public static string FormatExcpetion(System.Exception exception)
{ {
return CreateExceptionReport(exception); return CreateExceptionReport(exception);
} }
private static string CreateExceptionReport(object exceptionObject) private static string CreateExceptionReport(System.Exception ex)
{ {
var sb = new StringBuilder(); var sb = new StringBuilder();
sb.AppendLine();
sb.AppendLine("## Exception"); sb.AppendLine("## Exception");
sb.AppendLine(); sb.AppendLine();
sb.AppendLine("```"); sb.AppendLine("```");
var ex = exceptionObject as System.Exception;
if (ex != null)
{
var exlist = new List<StringBuilder>(); var exlist = new List<StringBuilder>();
while (ex != null) while (ex != null)
@ -59,14 +57,6 @@ namespace Wox.Core.Exception
} }
sb.AppendLine("```"); sb.AppendLine("```");
sb.AppendLine(); sb.AppendLine();
}
else
{
sb.AppendLine(exceptionObject.GetType().FullName);
sb.AppendLine(new StackTrace().ToString());
sb.AppendLine("```");
sb.AppendLine();
}
sb.AppendLine("## Environment"); sb.AppendLine("## Environment");
sb.AppendLine(); sb.AppendLine();
@ -88,9 +78,9 @@ namespace Wox.Core.Exception
} }
sb.AppendLine(); sb.AppendLine();
sb.AppendLine("## Assemblies - " + System.AppDomain.CurrentDomain.FriendlyName); sb.AppendLine("## Assemblies - " + AppDomain.CurrentDomain.FriendlyName);
sb.AppendLine(); sb.AppendLine();
foreach (var ass in System.AppDomain.CurrentDomain.GetAssemblies().OrderBy(o => o.GlobalAssemblyCache ? 100 : 0)) foreach (var ass in AppDomain.CurrentDomain.GetAssemblies().OrderBy(o => o.GlobalAssemblyCache ? 50 : 0))
{ {
sb.Append("* "); sb.Append("* ");
sb.Append(ass.FullName); sb.Append(ass.FullName);
@ -99,38 +89,6 @@ namespace Wox.Core.Exception
sb.AppendLine(")"); sb.AppendLine(")");
} }
var process = System.Diagnostics.Process.GetCurrentProcess();
sb.AppendLine();
sb.AppendLine("## Modules - " + process.ProcessName);
sb.AppendLine();
foreach (ProcessModule mod in process.Modules)
{
sb.Append("* ");
sb.Append(mod.FileName);
sb.Append(" (");
sb.Append(mod.FileVersionInfo.FileDescription);
sb.Append(", ");
sb.Append(mod.FileVersionInfo.FileVersion);
sb.Append(", ");
sb.Append(mod.FileVersionInfo.ProductName);
sb.Append(", ");
sb.Append(mod.FileVersionInfo.ProductVersion);
sb.Append(", ");
sb.Append(mod.FileVersionInfo.CompanyName);
sb.Append("), ");
sb.Append(string.Format("0x{0:X16}", mod.BaseAddress.ToInt64()));
sb.AppendLine();
}
sb.AppendLine();
sb.AppendLine("## Threads - " + process.Threads.Count);
sb.AppendLine();
foreach (ProcessThread th in process.Threads)
{
sb.Append("* ");
sb.AppendLine(string.Format("{0}, {1} {2}, Started: {3}, StartAddress: 0x{4:X16}", th.Id, th.ThreadState, th.PriorityLevel, th.StartTime, th.StartAddress.ToInt64()));
}
return sb.ToString(); return sb.ToString();
} }

View File

@ -10,5 +10,11 @@
{ {
} }
public WoxException(string msg, System.Exception innerException)
: base(msg, innerException)
{
}
} }
} }

View File

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Wox.Core.Exception
{
public class WoxPluginException : WoxException
{
public string PluginName { get; set; }
public WoxPluginException(string pluginName,System.Exception e)
: base(e.Message,e)
{
PluginName = pluginName;
}
}
}

View File

@ -1,7 +1,9 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using Wox.Core.Exception;
using Wox.Core.UserSettings; using Wox.Core.UserSettings;
using Wox.Infrastructure.Logger;
using Wox.Plugin; using Wox.Plugin;
//using Wox.Plugin.SystemPlugins; //using Wox.Plugin.SystemPlugins;
@ -27,11 +29,18 @@ namespace Wox.Core.Plugin.QueryDispatcher
{ {
PluginPair pair1 = pair; PluginPair pair1 = pair;
ThreadPool.QueueUserWorkItem(state => ThreadPool.QueueUserWorkItem(state =>
{
try
{ {
List<Result> results = pair1.Plugin.Query(query); List<Result> results = pair1.Plugin.Query(query);
results.ForEach(o => { o.AutoAjustScore = true; }); results.ForEach(o => { o.AutoAjustScore = true; });
PluginManager.API.PushResults(query, pair1.Metadata, results); PluginManager.API.PushResults(query, pair1.Metadata, results);
}
catch (System.Exception e)
{
throw new WoxPluginException(pair1.Metadata.Name,e);
}
}); });
} }
} }

View File

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using Wox.Core.Exception;
using Wox.Core.UserSettings; using Wox.Core.UserSettings;
using Wox.Infrastructure.Logger; using Wox.Infrastructure.Logger;
using Wox.Plugin; using Wox.Plugin;
@ -30,15 +31,9 @@ namespace Wox.Core.Plugin.QueryDispatcher
List<Result> results = userPlugin.Plugin.Query(query) ?? new List<Result>(); List<Result> results = userPlugin.Plugin.Query(query) ?? new List<Result>();
PluginManager.API.PushResults(query,userPlugin.Metadata,results); PluginManager.API.PushResults(query,userPlugin.Metadata,results);
} }
catch (System.Exception queryException) catch (System.Exception e)
{ {
Log.Error(string.Format("Plugin {0} query failed: {1}", userPlugin.Metadata.Name, throw new WoxPluginException(userPlugin.Metadata.Name, e);
queryException.Message));
#if (DEBUG)
{
throw;
}
#endif
} }
}); });
} }

View File

@ -64,6 +64,7 @@
<Compile Include="Exception\WoxHttpException.cs" /> <Compile Include="Exception\WoxHttpException.cs" />
<Compile Include="Exception\WoxI18nException.cs" /> <Compile Include="Exception\WoxI18nException.cs" />
<Compile Include="Exception\WoxJsonRPCException.cs" /> <Compile Include="Exception\WoxJsonRPCException.cs" />
<Compile Include="Exception\WoxPluginException.cs" />
<Compile Include="UserSettings\HttpProxy.cs" /> <Compile Include="UserSettings\HttpProxy.cs" />
<Compile Include="i18n\AvailableLanguages.cs" /> <Compile Include="i18n\AvailableLanguages.cs" />
<Compile Include="i18n\IInternationalization.cs" /> <Compile Include="i18n\IInternationalization.cs" />

View File

@ -18,6 +18,10 @@ namespace Wox.CrashReporter
{ {
if (exception == null) return; if (exception == null) return;
if (exception.InnerException != null)
{
exception = exception.InnerException;
}
ReportWindow reportWindow = new ReportWindow(exception); ReportWindow reportWindow = new ReportWindow(exception);
reportWindow.Show(); reportWindow.Show();
} }

View File

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Data; using System.Windows.Data;
@ -47,6 +48,11 @@ namespace Wox.CrashReporter
string sendingMsg = InternationalizationManager.Internationalization.GetTranslation("reportWindow_sending"); string sendingMsg = InternationalizationManager.Internationalization.GetTranslation("reportWindow_sending");
tbSendReport.Content = sendingMsg; tbSendReport.Content = sendingMsg;
btnSend.IsEnabled = false; btnSend.IsEnabled = false;
ThreadPool.QueueUserWorkItem(o => SendReport());
}
private void SendReport()
{
string error = string.Format("{{\"data\":{0}}}", ExceptionFormatter.FormatExcpetion(exception)); string error = string.Format("{{\"data\":{0}}}", ExceptionFormatter.FormatExcpetion(exception));
string response = HttpRequest.Post(APIServer.ErrorReportURL, error, HttpProxy.Instance); string response = HttpRequest.Post(APIServer.ErrorReportURL, error, HttpProxy.Instance);
if (response.ToLower() == "ok") if (response.ToLower() == "ok")
@ -57,7 +63,7 @@ namespace Wox.CrashReporter
{ {
MessageBox.Show(InternationalizationManager.Internationalization.GetTranslation("reportWindow_report_failed")); MessageBox.Show(InternationalizationManager.Internationalization.GetTranslation("reportWindow_report_failed"));
} }
Close(); Dispatcher.Invoke(new Action(Close));
} }
private void btnCancel_Click(object sender, RoutedEventArgs e) private void btnCancel_Click(object sender, RoutedEventArgs e)

View File

@ -26,7 +26,12 @@
</root> </root>
</log4net> </log4net>
<runtime> <runtime>
<!--http://stackoverflow.com/questions/186854/how-to-prevent-an-exception-in-a-background-thread-from-terminating-an-applicati--> <!--http://stackoverflow.com/questions/186854/how-to-prevent-an-exception-in-a-background-thread-from-terminating-an-application-->
<!--prevent non-ui exception crash wox-->
<legacyUnhandledExceptionPolicy enabled="1"/> <legacyUnhandledExceptionPolicy enabled="1"/>
</runtime> </runtime>
<startup><supportedRuntime version="v2.0.50727"/></startup></configuration> <startup>
<supportedRuntime version="v2.0.50727"/>
<supportedRuntime version="v4.0"/>
</startup>
</configuration>

View File

@ -33,7 +33,6 @@ namespace Wox
base.OnStartup(e); base.OnStartup(e);
DispatcherUnhandledException += ErrorReporting.DispatcherUnhandledException; DispatcherUnhandledException += ErrorReporting.DispatcherUnhandledException;
AppDomain.CurrentDomain.UnhandledException += ErrorReporting.UnhandledExceptionHandle; AppDomain.CurrentDomain.UnhandledException += ErrorReporting.UnhandledExceptionHandle;
System.Windows.Forms.Application.ThreadException += ErrorReporting.ThreadException;
Window = new MainWindow(); Window = new MainWindow();
CommandArgsFactory.Execute(e.Args.ToList()); CommandArgsFactory.Execute(e.Args.ToList());

View File

@ -5,31 +5,38 @@ using System.Windows.Forms;
using System.Windows.Threading; using System.Windows.Threading;
using Wox.Core.Exception; using Wox.Core.Exception;
using Wox.Infrastructure.Logger; using Wox.Infrastructure.Logger;
using MessageBox = System.Windows.MessageBox;
namespace Wox.Helper namespace Wox.Helper
{ {
public static class ErrorReporting public static class ErrorReporting
{ {
private static void Report(Exception e) public static void Report(Exception e)
{ {
//if (Debugger.IsAttached) return; if (Debugger.IsAttached) return;
Log.Error(ExceptionFormatter.FormatExcpetion(e)); Log.Error(ExceptionFormatter.FormatExcpetion(e));
new CrashReporter.CrashReporter(e).Show(); new CrashReporter.CrashReporter(e).Show();
} }
public static void UnhandledExceptionHandle(object sender, UnhandledExceptionEventArgs e) public static void UnhandledExceptionHandle(object sender, UnhandledExceptionEventArgs e)
{
//handle non-ui thread exceptions
App.Window.Dispatcher.Invoke(new Action(() =>
{ {
Report((Exception)e.ExceptionObject); Report((Exception)e.ExceptionObject);
if (!(e.ExceptionObject is WoxException))
{
Environment.Exit(0);
}
}));
} }
public static void DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) public static void DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{ {
//handle ui thread exceptions
Report(e.Exception); Report(e.Exception);
} //prevent crash
e.Handled = true;
public static void ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
{
Report(e.Exception);
} }
} }
} }

View File

@ -353,28 +353,38 @@ namespace Wox
Dispatcher.DelayInvoke("ClearResults", i => Dispatcher.DelayInvoke("ClearResults", i =>
{ {
// first try to use clear method inside pnlResult, which is more closer to the add new results // first try to use clear method inside pnlResult, which is more closer to the add new results
// and this will not bring splash issues.After waiting 30ms, if there still no results added, we // and this will not bring splash issues.After waiting 100ms, if there still no results added, we
// must clear the result. otherwise, it will be confused why the query changed, but the results // must clear the result. otherwise, it will be confused why the query changed, but the results
// didn't. // didn't.
if (pnlResult.Dirty) pnlResult.Clear(); if (pnlResult.Dirty) pnlResult.Clear();
}, TimeSpan.FromMilliseconds(100), null); }, TimeSpan.FromMilliseconds(100), null);
queryHasReturn = false; queryHasReturn = false;
var q = new Query(lastQuery); var q = new Query(lastQuery);
PluginManager.Query(q); Query(q);
BackToResultMode(); BackToResultMode();
if (PluginManager.IsUserPluginQuery(q))
{
Dispatcher.DelayInvoke("ShowProgressbar", originQuery => Dispatcher.DelayInvoke("ShowProgressbar", originQuery =>
{ {
if (!queryHasReturn && originQuery == lastQuery) if (!queryHasReturn && originQuery == lastQuery)
{ {
StartProgress(); StartProgress();
} }
}, TimeSpan.FromSeconds(0), lastQuery); }, TimeSpan.FromMilliseconds(150), lastQuery);
}
}, TimeSpan.FromMilliseconds(ShouldNotDelayQuery ? 0 : 200)); }, TimeSpan.FromMilliseconds(ShouldNotDelayQuery ? 0 : 200));
} }
private void Query(Query q)
{
try
{
PluginManager.Query(q);
}
catch (Exception e)
{
StopProgress();
ErrorReporting.Report(e);
}
}
private void BackToResultMode() private void BackToResultMode()
{ {
pnlResult.Visibility = Visibility.Visible; pnlResult.Visibility = Visibility.Visible;