2019-01-02 00:55:51 -05:00
// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
2018-01-02 15:30:26 -05:00
using System ;
2017-07-21 12:42:36 -04:00
using System.Collections.Generic ;
using System.Linq ;
using System.Text ;
using System.Threading.Tasks ;
2018-05-20 18:49:37 -04:00
using Tools.DotNETCommon ;
2017-07-21 12:42:36 -04:00
2018-05-21 09:26:21 -04:00
namespace Tools.DotNETCommon
2017-07-21 12:42:36 -04:00
{
/// <summary>
/// Methods for adding context information to exceptions
/// </summary>
public static class ExceptionUtils
{
/// <summary>
/// Unique key name for adding context to exceptions thrown inside Epic apps
/// </summary>
const string ContextEntryName = "EpicGames.Context" ;
/// <summary>
/// Adds a context message to a list stored on the given exception. Intended to be used in situations where supplying additional context
/// for an exception is valuable, but wrapping it would remove information.
/// </summary>
/// <param name="Ex">The exception that was thrown</param>
/// <param name="Message">Message to append to the context list</param>
public static void AddContext ( Exception Ex , string Message )
{
List < string > Messages = Ex . Data [ ContextEntryName ] as List < string > ;
if ( Messages = = null )
{
Messages = new List < string > ( ) ;
Ex . Data [ ContextEntryName ] = Messages ;
}
Messages . Add ( Message ) ;
}
/// <summary>
/// Adds a context message to a list stored on the given exception. Intended to be used in situations where supplying additional context
/// for an exception is valuable, but wrapping it would remove information.
/// </summary>
/// <param name="Ex">The exception that was thrown</param>
/// <param name="Format">Formatting string for </param>
/// <param name="Args">Message to append to the context list</param>
public static void AddContext ( Exception Ex , string Format , params object [ ] Args )
{
AddContext ( Ex , String . Format ( Format , Args ) ) ;
}
/// <summary>
/// Enumerates the context lines from the given exception
/// </summary>
/// <param name="Ex">The exception to retrieve context from</param>
/// <returns>Sequence of context lines</returns>
public static IEnumerable < string > GetContext ( Exception Ex )
{
List < string > Messages = Ex . Data [ ContextEntryName ] as List < string > ;
if ( Messages ! = null )
{
foreach ( string Message in Messages )
{
yield return Message ;
}
}
}
/// <summary>
2018-05-21 11:31:16 -04:00
/// Formats an exception for display in the log, including additional lines of context that were attached to it.
2017-07-21 12:42:36 -04:00
/// </summary>
2018-05-21 11:31:16 -04:00
/// <param name="Ex">The exception to format</param>
/// <returns>String containing the exception information. May be multiple lines.</returns>
public static string FormatException ( Exception Ex )
2017-07-21 12:42:36 -04:00
{
StringBuilder ErrorMessage = new StringBuilder ( ) ;
if ( Ex is AggregateException )
{
Exception InnerException = ( ( AggregateException ) Ex ) . InnerException ;
ErrorMessage . Append ( InnerException . ToString ( ) ) ;
foreach ( string Line in GetContext ( InnerException ) )
{
ErrorMessage . AppendFormat ( "\n {0}" , Line ) ;
}
}
else
{
ErrorMessage . Append ( Ex . ToString ( ) ) ;
}
foreach ( string Line in GetContext ( Ex ) )
{
ErrorMessage . AppendFormat ( "\n{0}" , Line ) ;
}
2018-05-21 11:31:16 -04:00
return ErrorMessage . ToString ( ) ;
}
2017-07-21 12:42:36 -04:00
2018-05-21 11:31:16 -04:00
/// <summary>
/// Formats a detailed information about where an exception occurs, including any inner exceptions
/// </summary>
/// <param name="Ex">The exception to format</param>
/// <returns>String containing the exception information. May be multiple lines.</returns>
public static string FormatExceptionDetails ( Exception Ex )
{
2017-07-21 12:42:36 -04:00
List < Exception > ExceptionStack = new List < Exception > ( ) ;
for ( Exception CurrentEx = Ex ; CurrentEx ! = null ; CurrentEx = CurrentEx . InnerException )
{
ExceptionStack . Add ( CurrentEx ) ;
}
2018-05-21 11:31:16 -04:00
StringBuilder Message = new StringBuilder ( ) ;
2017-07-21 12:42:36 -04:00
for ( int Idx = ExceptionStack . Count - 1 ; Idx > = 0 ; Idx - - )
{
Exception CurrentEx = ExceptionStack [ Idx ] ;
2018-05-21 11:31:16 -04:00
Message . AppendFormat ( "{0}{1}: {2}\n{3}" , ( Idx = = ExceptionStack . Count - 1 ) ? "" : "Wrapped by " , CurrentEx . GetType ( ) . Name , CurrentEx . Message , CurrentEx . StackTrace ) ;
2017-07-21 12:42:36 -04:00
if ( CurrentEx . Data . Count > 0 )
{
foreach ( object Key in CurrentEx . Data . Keys )
{
2018-04-26 14:11:04 -04:00
object Value = CurrentEx . Data [ Key ] ;
string ValueString ;
if ( Value is List < string > )
{
ValueString = String . Format ( "({0})" , String . Join ( ", " , ( ( List < string > ) Value ) . Select ( x = > String . Format ( "\"{0}\"" , x ) ) ) ) ;
}
else
{
ValueString = Value . ToString ( ) ;
}
2018-05-21 11:31:16 -04:00
Message . AppendFormat ( " data: {0} = {1}" , Key , ValueString ) ;
2017-07-21 12:42:36 -04:00
}
}
}
2018-05-21 11:31:16 -04:00
return Message . ToString ( ) ;
2017-07-21 12:42:36 -04:00
}
}
}