Files
OpenRA/OpenRA.Game/Support/ExceptionHandler.cs
2018-07-01 11:08:32 +02:00

105 lines
3.3 KiB
C#

#region Copyright & License Information
/*
* Copyright 2007-2018 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version. For more
* information, see COPYING.
*/
#endregion
using System;
using System.Diagnostics;
using System.Globalization;
using System.Text;
namespace OpenRA
{
public static class ExceptionHandler
{
public static void HandleFatalError(Exception ex)
{
var exceptionName = "exception-" + DateTime.UtcNow.ToString("yyyy-MM-ddTHHmmssZ", CultureInfo.InvariantCulture) + ".log";
Log.AddChannel("exception", exceptionName);
if (Game.EngineVersion != null)
Log.Write("exception", "OpenRA engine version {0}", Game.EngineVersion);
if (Game.ModData != null)
{
var mod = Game.ModData.Manifest.Metadata;
Log.Write("exception", "{0} mod version {1}", mod.Title, mod.Version);
}
if (Game.OrderManager != null && Game.OrderManager.World != null && Game.OrderManager.World.Map != null)
{
var map = Game.OrderManager.World.Map;
Log.Write("exception", "on map {0} ({1} by {2}).", map.Uid, map.Title, map.Author);
}
Log.Write("exception", "Date: {0:u}", DateTime.UtcNow);
Log.Write("exception", "Operating System: {0} ({1})", Platform.CurrentPlatform, Environment.OSVersion);
Log.Write("exception", "Runtime Version: {0}", Platform.RuntimeVersion);
var rpt = BuildExceptionReport(ex).ToString();
Log.Write("exception", "{0}", rpt);
Console.Error.WriteLine(rpt);
}
static StringBuilder BuildExceptionReport(Exception ex)
{
return BuildExceptionReport(ex, new StringBuilder(), 0);
}
static StringBuilder AppendIndentedFormatLine(this StringBuilder sb, int indent, string format, params object[] args)
{
return sb.Append(new string(' ', indent * 2)).AppendFormat(format, args).AppendLine();
}
static StringBuilder BuildExceptionReport(Exception ex, StringBuilder sb, int indent)
{
if (ex == null)
return sb;
sb.AppendIndentedFormatLine(indent, "Exception of type `{0}`: {1}", ex.GetType().FullName, ex.Message);
var tle = ex as TypeLoadException;
var oom = ex as OutOfMemoryException;
if (tle != null)
{
sb.AppendIndentedFormatLine(indent, "TypeName=`{0}`", tle.TypeName);
}
else if (oom != null)
{
var gcMemoryBeforeCollect = GC.GetTotalMemory(false);
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
sb.AppendIndentedFormatLine(indent, "GC Memory (post-collect)={0:N0}", GC.GetTotalMemory(false));
sb.AppendIndentedFormatLine(indent, "GC Memory (pre-collect)={0:N0}", gcMemoryBeforeCollect);
using (var p = Process.GetCurrentProcess())
{
sb.AppendIndentedFormatLine(indent, "Working Set={0:N0}", p.WorkingSet64);
sb.AppendIndentedFormatLine(indent, "Private Memory={0:N0}", p.PrivateMemorySize64);
sb.AppendIndentedFormatLine(indent, "Virtual Memory={0:N0}", p.VirtualMemorySize64);
}
}
else
{
// TODO: more exception types
}
if (ex.InnerException != null)
{
sb.AppendIndentedFormatLine(indent, "Inner");
BuildExceptionReport(ex.InnerException, sb, indent + 1);
}
sb.AppendIndentedFormatLine(indent, "{0}", ex.StackTrace);
return sb;
}
}
}