This Gist is available under the https://choosealicense.com/licenses/mit/ license copyright 2022 the contributors
Last active
June 23, 2022 11:57
-
-
Save chrisfcarroll/f00944ecc100e7ffb0b070bb67d803ca to your computer and use it in GitHub Desktop.
Log.Assert
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#nullable enable | |
using Microsoft.Extensions.Logging; | |
using Microsoft.VisualBasic; | |
using System; | |
using System.Diagnostics; | |
using System.Diagnostics.CodeAnalysis; | |
using System.Linq; | |
namespace LogAssert | |
{ | |
/// <summary>Taken from https://gist.github.com/chrisfcarroll/f00944ecc100e7ffb0b070bb67d803ca</summary> | |
public static class LogAssert | |
{ | |
/// <summary> | |
/// If <paramref name="condition" /> evaluates true, | |
/// then call <see cref="ILogger.LogWarning(string,object[]" /><c>(message, args)</c>. | |
/// If <paramref name="@condition" /> evaluates false, do nothing. | |
/// If an exception is thrown during evaluation, then catch it and log that as an Error, | |
/// and continue. | |
/// </summary> | |
/// <param name="log">your Serilog logger</param> | |
/// <param name="condition">the condition</param> | |
/// <param name="message">message format</param> | |
/// <param name="args">args to message format</param> | |
/// <returns> | |
/// <paramref name="condition" /> | |
/// </returns> | |
public static bool WarnIf(this ILogger log, bool condition, string message, params object?[] args) | |
{ | |
return If(log, LogLevel.Warning, condition, message, args); | |
} | |
/// <summary> | |
/// If <paramref name="condition" /> evaluates true, | |
/// then call <see cref="ILogger.LogError(string,object[]" /><c>(message, args)</c>. | |
/// If <paramref name="@condition" /> evaluates false, do nothing. | |
/// If an exception is thrown during evaluation, then catch it and log that as an Error, | |
/// and continue. | |
/// </summary> | |
/// <param name="log">your Serilog logger</param> | |
/// <param name="condition">the condition</param> | |
/// <param name="message">message format</param> | |
/// <param name="args">args to message format</param> | |
/// <returns> | |
/// <paramref name="condition" /> | |
/// </returns> | |
public static bool ErrorIf(this ILogger log, bool condition, string message, params object?[] args) | |
{ | |
return If(log, LogLevel.Error, condition, message, args); | |
} | |
/// <summary> | |
/// If <paramref name="condition" /> evaluates true, | |
/// then call <see cref="Information" /><c>(message, args)</c>. | |
/// If <paramref name="condition" /> evaluates false, do nothing. | |
/// If an exception is thrown during evaluation, then catch it and log that as an Error, | |
/// and continue. | |
/// </summary> | |
/// <param name="log">your Serilog logger</param> | |
/// <param name="condition">the condition</param> | |
/// <param name="message">message format</param> | |
/// <param name="args">args to message format</param> | |
/// <returns> | |
/// <paramref name="condition" /> | |
/// </returns> | |
public static bool InformationIf(this ILogger log, bool condition, string message, params object?[] args) | |
{ | |
return If(log, LogLevel.Information, condition, message, args); | |
} | |
/// <summary> | |
/// If <paramref name="condition" /> evaluates true, | |
/// then call <see cref="Debug" /><c>(message, args)</c>. | |
/// If <paramref name="condition" /> evaluates false, do nothing. | |
/// If an exception is thrown during evaluation, then catch it and log that as an Error, | |
/// and continue. | |
/// </summary> | |
/// <param name="log">your Serilog logger</param> | |
/// <param name="condition">the condition</param> | |
/// <param name="message">message format</param> | |
/// <param name="args">args to message format</param> | |
/// <returns> | |
/// <paramref name="condition" /> | |
/// </returns> | |
public static bool DebugIf(this ILogger log, bool condition, string message, params object?[] args) | |
{ | |
return If(log, LogLevel.Debug, condition, message, args); | |
} | |
/// <summary> | |
/// If <paramref name="condition" /> evaluates true, | |
/// then call <see cref="ILogger.LogWarning(string,object[]" /><c>(message, args)</c>. | |
/// If <paramref name="@condition" /> evaluates false, do nothing. | |
/// If an exception is thrown during evaluation, then catch it and log that as an Error, | |
/// and continue. | |
/// </summary> | |
/// <param name="log">your Serilog logger</param> | |
/// <param name="LogLevel">The <see cref="LogLevel" /> at which to log</param> | |
/// <param name="condition">the condition</param> | |
/// <param name="message">message format</param> | |
/// <param name="args">args to message format</param> | |
/// <returns> | |
/// <paramref name="condition" /> | |
/// </returns> | |
private static bool If(ILogger log, LogLevel LogLevel, bool condition, string message, object?[] args) | |
{ | |
try | |
{ | |
if (condition) | |
{ | |
log.Log(LogLevel, message, args); | |
} | |
} | |
catch (Exception e) | |
{ | |
log.LogError(e, "({Message},{@args}) was true, but logging it threw an Exception", message, args); | |
} | |
return condition; | |
} | |
/// <summary> | |
/// If <paramref name="condition" /> evaluates true, | |
/// then call <see cref="ILogger.LogWarning(string,object[]" /><c>(message, args)</c>. | |
/// If <paramref name="@condition" /> evaluates false, do nothing. | |
/// If an exception is thrown during evaluation, then catch it and log that as an Error, | |
/// and continue. | |
/// </summary> | |
/// <param name="log"></param> | |
/// <param name="condition">the condition</param> | |
/// <param name="message">message format</param> | |
/// <param name="delayedArgs"> | |
/// if <paramref name="condition" /> is true then this function is | |
/// evaluated to generate args for the log. This allows logging of values that may be | |
/// expensive to compute, or may be invalid when <c>condition</c> is false. | |
/// </param> | |
/// <returns> | |
/// <paramref name="condition" /> | |
/// </returns> | |
public static bool WarnIf<T>(this ILogger log, bool condition, string message, Func<T> delayedArgs) | |
{ | |
return If(log, LogLevel.Warning, condition, message, delayedArgs); | |
} | |
/// <summary> | |
/// If <paramref name="condition" /> evaluates true, | |
/// then call <see cref="ILogger.LogError(string,object[]" /><c>(message, args)</c>. | |
/// If <paramref name="@condition" /> evaluates false, do nothing. | |
/// If an exception is thrown during evaluation, then catch it and log that as an Error, | |
/// and continue. | |
/// </summary> | |
/// <param name="log"></param> | |
/// <param name="condition">the condition</param> | |
/// <param name="message">message format</param> | |
/// <param name="delayedArgs"> | |
/// if <paramref name="condition" /> is true then this function is | |
/// evaluated to generate args for the log. This allows logging of values that may be | |
/// expensive to compute, or may be invalid when <c>condition</c> is false. | |
/// </param> | |
/// <returns> | |
/// <paramref name="condition" /> | |
/// </returns> | |
public static bool ErrorIf<T>(this ILogger log, bool condition, string message, Func<T> delayedArgs) | |
{ | |
return If(log, LogLevel.Error, condition, message, delayedArgs); | |
} | |
/// <summary> | |
/// If <paramref name="condition" /> evaluates true, | |
/// then call <see cref="Information" /><c>(message, args)</c>. | |
/// If <paramref name="condition" /> evaluates false, do nothing. | |
/// If an exception is thrown during evaluation, then catch it and log that as an Error, | |
/// and continue. | |
/// </summary> | |
/// <param name="log"></param> | |
/// <param name="condition">the condition</param> | |
/// <param name="message">message format</param> | |
/// <param name="delayedArgs"> | |
/// if <paramref name="condition" /> is true then this function is | |
/// evaluated to generate args for the log. This allows logging of values that may be | |
/// expensive to compute, or may be invalid when <c>condition</c> is false. | |
/// </param> | |
/// <returns> | |
/// <paramref name="condition" /> | |
/// </returns> | |
public static bool InformationIf<T>(this ILogger log, bool condition, string message, Func<T> delayedArgs) | |
{ | |
return If(log, LogLevel.Information, condition, message, delayedArgs); | |
} | |
/// <summary> | |
/// If <paramref name="condition" /> evaluates true, | |
/// then call <see cref="Debug" /><c>(message, args)</c>. | |
/// If <paramref name="condition" /> evaluates false, do nothing. | |
/// If an exception is thrown during evaluation, then catch it and log that as an Error, | |
/// and continue. | |
/// </summary> | |
/// <param name="log"></param> | |
/// <param name="condition">the condition</param> | |
/// <param name="message">message format</param> | |
/// <param name="delayedArgs"> | |
/// if <paramref name="condition" /> is true then this function is | |
/// evaluated to generate args for the log. This allows logging of values that may be | |
/// expensive to compute, or may be invalid when <c>condition</c> is false. | |
/// </param> | |
/// <returns> | |
/// <paramref name="condition" /> | |
/// </returns> | |
public static bool DebugIf<T>(this ILogger log, bool condition, string message, Func<T> delayedArgs) | |
{ | |
return If(log, LogLevel.Debug, condition, message, delayedArgs); | |
} | |
private static bool If<T>(ILogger log, LogLevel LogLevel, bool condition, string message, Func<T> delayedArgs) | |
{ | |
try | |
{ | |
if (condition) | |
{ | |
log.Log(LogLevel, message, delayedArgs()); | |
} | |
} | |
catch (Exception e) | |
{ | |
log.LogError(e, "({Message},{@delayedArgs}) was true, but logging it threw an Exception", | |
message, delayedArgs); | |
} | |
return condition; | |
} | |
/// <summary> | |
/// If <c>that(<paramref name="@this" />)</c> evaluates true, | |
/// then call <see cref="ILogger.LogWarning(string,object[]" /><c>(message, args)</c>. | |
/// If <c>that(<paramref name="@this" />)</c> evaluates false, do nothing. | |
/// If an exception is thrown during evaluation, then catch it and log that as an Error, | |
/// and continue. | |
/// </summary> | |
/// <param name="log"></param> | |
/// <param name="@this">the object to test with <paramref name="that" /></param> | |
/// <param name="that">the condition</param> | |
/// <param name="message">message format</param> | |
/// <param name="args">args to message format</param> | |
/// <returns> | |
/// <paramref name="that" />(<paramref name="@this" />). | |
/// If evaluation throws an exception, then null is returned. | |
/// </returns> | |
public static bool? WarnIf<T>(this ILogger log, T @this, Func<T, bool> that, string message, | |
params object[] args) | |
{ | |
bool outcome; | |
try | |
{ | |
outcome = that(@this); | |
if (outcome) | |
{ | |
log.LogWarning(message, args); | |
} | |
} | |
catch (Exception e) | |
{ | |
log.LogError(e, "({Message},{@args}) threw when evaluating it.", message, args); | |
return null; | |
} | |
return outcome; | |
} | |
/// <summary> | |
/// If <c>that(<paramref name="@this" />)</c> evaluates true, | |
/// then call <see cref="ILogger.LogWarning(string,object[]" /><c>(message, args)</c>. | |
/// If <c>that(<paramref name="@this" />)</c> evaluates false, do nothing. | |
/// If an exception is thrown during evaluation, then catch it and log that as an Error, | |
/// and continue. | |
/// </summary> | |
/// <param name="log"></param> | |
/// <param name="@this">the object to test with <paramref name="that" /></param> | |
/// <param name="that">the condition</param> | |
/// <param name="message">message format</param> | |
/// <param name="delayedArgs"> | |
/// if <c>that(<paramref name="@this" />)</c> is true then this function is | |
/// evaluated to generate args for the log. This allows logging of values that may be | |
/// expensive to compute, or may be invalid when <c>that(<paramref name="@this" />)</c> is false. | |
/// </param> | |
/// <returns> | |
/// <paramref name="condition" /> | |
/// </returns> | |
/// <returns> | |
/// <paramref name="that" />(<paramref name="@this" />). | |
/// If evaluation throws an exception, then null is returned. | |
/// </returns> | |
public static bool? WarnIf<T, Ta>(this ILogger log, T @this, Func<T, bool> that, string message, | |
Func<Ta> delayedArgs) | |
{ | |
bool outcome; | |
try | |
{ | |
outcome = that(@this); | |
if (outcome) | |
{ | |
log.LogWarning(message, delayedArgs()); | |
} | |
} | |
catch (Exception e) | |
{ | |
log.LogError(e, "({Message},{delayedArgs}) threw when evaluating it.", message, delayedArgs); | |
return null; | |
} | |
return outcome; | |
} | |
/// <summary> | |
/// If <paramref name="condition" /> is true, do nothing. | |
/// If <paramref name="condition" /> is false, then | |
/// call <see cref="ILogger.LogWarning(string,object[]" /><c>(message, args)</c> | |
/// If an exception is thrown during evaluation, then catch it and log that as an Error, | |
/// and continue. | |
/// </summary> | |
/// <param name="log"></param> | |
/// <param name="condition">the condition</param> | |
/// <param name="message">message format</param> | |
/// <param name="args">args to message format</param> | |
/// <returns> | |
/// <paramref name="condition" /> | |
/// </returns> | |
public static bool WarnIfNot(this ILogger log, bool condition, string message, params object[] args) | |
{ | |
return IfNot(log, LogLevel.Warning, condition, message, args); | |
} | |
/// <summary> | |
/// If <paramref name="condition" /> is true, do nothing. | |
/// If <paramref name="condition" /> is false, then | |
/// call <see cref="ILogger.LogError(string,object[]" /><c>(message, args)</c> | |
/// If an exception is thrown during evaluation, then catch it and log that as an Error, | |
/// and continue. | |
/// </summary> | |
/// <param name="log"></param> | |
/// <param name="condition">the condition</param> | |
/// <param name="message">message format</param> | |
/// <param name="args">args to message format</param> | |
/// <returns> | |
/// <paramref name="condition" /> | |
/// </returns> | |
public static bool ErrorIfNot(this ILogger log, bool condition, string message, params object[] args) | |
{ | |
return IfNot(log, LogLevel.Error, condition, message, args); | |
} | |
/// <summary> | |
/// If <paramref name="condition" /> is true, do nothing. | |
/// If <paramref name="condition" /> is false, then | |
/// call <see cref="Information" /><c>(message, args)</c> | |
/// If an exception is thrown during evaluation, then catch it and log that as an Error, | |
/// and continue. | |
/// </summary> | |
/// <param name="log"></param> | |
/// <param name="condition">the condition</param> | |
/// <param name="message">message format</param> | |
/// <param name="args">args to message format</param> | |
/// <returns> | |
/// <paramref name="condition" /> | |
/// </returns> | |
public static bool InformationIfNot(this ILogger log, bool condition, string message, params object[] args) | |
{ | |
return IfNot(log, LogLevel.Information, condition, message, args); | |
} | |
private static bool IfNot(ILogger log, LogLevel LogLevel, bool condition, string message, object[] args) | |
{ | |
try | |
{ | |
if (!condition) | |
{ | |
log.Log(LogLevel, message, args); | |
} | |
} | |
catch (Exception e) | |
{ | |
log.LogError(e, "({Message},{@args}) was false, but logging it threw an Exception", message, args); | |
} | |
return condition; | |
} | |
/// <summary> | |
/// If <c>that(<paramref name="@this" />)</c> evaluates true, do nothing. | |
/// if <c>that(<paramref name="@this" />)</c> evaluates false, | |
/// then call <see cref="ILogger.LogWarning(string,object[]" /><c>(message, args)</c> | |
/// If an exception is thrown during evaluation, then catch it and log that as an Error, | |
/// and continue. | |
/// </summary> | |
/// <param name="log"></param> | |
/// <param name="@this">the object to test with <paramref name="that" /></param> | |
/// <param name="that">the condition</param> | |
/// <param name="message">message format</param> | |
/// <param name="args">args to message format</param> | |
/// <returns> | |
/// <paramref name="that" />(<paramref name="@this" />). | |
/// If evaluation throws an exception, then null is returned. | |
/// </returns> | |
public static bool? WarnIfNot<T>(this ILogger log, T @this, Func<T, bool> that, string message, | |
params object[] args) | |
{ | |
bool outcome; | |
try | |
{ | |
outcome = that(@this); | |
if (!outcome) | |
{ | |
log.LogWarning(message, args); | |
} | |
} | |
catch (Exception e) | |
{ | |
log.LogError(e, "({Message},{@args}) threw when evaluating it.", message, args); | |
return null; | |
} | |
return outcome; | |
} | |
/// <summary> | |
/// AssertNotNull is a synonym for <see cref="ThrowIfNull{T}(Microsoft.Extensions.Logging.ILogger,T?,string,object[])" />(<c><paramref name="it" /> is null</c>) | |
/// If <paramref name="it" /> evaluates not null, do nothing. | |
/// If <paramref name="it" /> evaluates null,then call <see cref="ILogger.LogError(string,object[]" /> | |
/// <c>(message, args)</c> | |
/// If an exception is thrown during evaluation, then catch it and log that as an Error, | |
/// and continue. | |
/// </summary> | |
/// <param name="log"></param> | |
/// <param name="it">the object under test</param> | |
/// <param name="message">message format</param> | |
/// <param name="args">args to message format</param> | |
/// <returns> | |
/// <paramref name="that" /> | |
/// </returns> | |
[return: NotNull] | |
public static T AssertNotNull<T>(this ILogger log, T? it, string message, params object[] args) => ThrowIfNull(log, it, message, args); | |
/// <summary> | |
/// Log.Assert is a synonym for <see cref="ThrowIfNot" />. | |
/// If <paramref name="condition" /> is true, do nothing. | |
/// If <paramref name="condition" /> is false then call <see cref="ILogger.LogError(string,object[]" /> | |
/// <c>(message, args)</c> | |
/// If an exception is thrown during evaluation, then catch it and log that as an Error, | |
/// and continue. | |
/// </summary> | |
/// <param name="log"></param> | |
/// <param name="condition">the condition</param> | |
/// <param name="message">message format</param> | |
/// <param name="args">args to message format</param> | |
/// <returns> | |
/// <paramref name="condition" /> | |
/// </returns> | |
public static bool Assert(this ILogger log, bool condition, string message, params object[] args) => ThrowIfNot(log, condition, message, args); | |
/// <summary>Log <paramref name="exception" /> and return it, but don't throw it.</summary> | |
/// <param name="log"></param> | |
/// <param name="exception"></param> | |
/// <returns> | |
/// <paramref name="exception" /> | |
/// </returns> | |
[return: NotNullIfNotNull("exception")] | |
public static Exception? Exception(this ILogger log, Exception? exception, params object[] args) | |
{ | |
if (exception is null) | |
{ | |
log.LogError("Tried to log a null exception {args}", args); | |
return exception; | |
} | |
log.LogError(exception, exception.GetType().ToString(), args); | |
return exception; | |
} | |
/// <summary> | |
/// Log <paramref name="exception" /> and then throw it. | |
/// Note that <see cref="System.Exception" /> is usually | |
/// preferable, both because the compiler can understand it, and because the resulting stack | |
/// trace is more to the point. | |
/// </summary> | |
/// <param name="log"></param> | |
/// <param name="exception"></param> | |
/// <exception><paramref name="exception" /> is thrown immediately after logging.</exception> | |
/// <see cref="System.Exception" /> | |
/// <remarks> | |
/// Note that <see cref="System.Exception" /> is usually | |
/// preferable, both because the compiler can understand it, and because the resulting stack | |
/// trace is more to the point. | |
/// </remarks> | |
/// <returns>Never returns. The exception is thrown.</returns> | |
public static Exception ExceptionThenThrow(this ILogger log, Exception exception, params object[] args) | |
{ | |
exception ??= new Exception("Tried to log a null exception"); | |
log.LogError(exception, exception.GetType().ToString(), args); | |
throw exception; | |
} | |
/// <summary>Log <paramref name="exception" /> and then <see cref="Environment.Exit" />> the current Process</summary> | |
/// <param name="log"></param> | |
/// <param name="exception"></param> | |
/// <param name="exitCode">The exitCode to return to the operating system or calling process</param> | |
/// <returns>Nothing. The Process is halted.</returns> | |
public static void ExceptionThenSystemExitCurrentProcessWithExitCode(this ILogger log, Exception exception, | |
int exitCode, params object[] args) | |
{ | |
if (exception is null) { log.LogError("Tried to log a null exception {args}", args); } | |
else { log.LogError(exception, exception.GetType().ToString(), args); } | |
Environment.Exit(exitCode); | |
} | |
/// <summary> | |
/// Create a new <see cref="ApplicationException" /> with <paramref name="message" />, | |
/// log it with <paramref name="args" />, then return it. But don't throw it. | |
/// </summary> | |
/// <param name="log"></param> | |
/// <param name="message"></param> | |
/// <returns> | |
/// The new <see cref="ApplicationException" /> with <paramref name="message" /> | |
/// Returns null if there is no message and no arguments. | |
/// </returns> | |
public static ApplicationException? Exception(this ILogger log, string message, params object[] args) | |
{ | |
if (string.IsNullOrWhiteSpace(message) && args.Length == 0) | |
{ | |
log.LogError("Tried to log an empty exception"); | |
return null; | |
} | |
ApplicationException ex = new(message); | |
log.LogError(ex, message ?? "{args}", args); | |
return ex; | |
} | |
/// <summary> | |
/// If <paramref name="condition" /> is true do nothing. | |
/// Otherwise log it as Error and throw an InvalidOperationException containing <paramref name="message"/> and <paramref name="args"/> | |
/// If an exception is thrown during evaluation, then log that as an Error, | |
/// and throw that instead. | |
/// </summary> | |
/// <param name="log"></param> | |
/// <param name="condition">the condition</param> | |
/// <param name="message">The log message if <paramref name="condition" /> is false. | |
/// </param> | |
/// <param name="args">will be passed to <see cref="ILogger.LogError" /> if <paramref name="condition" /> is false</param> | |
/// <exception cref="System.Exception"> | |
/// <see cref="InvalidOperationException"/> will be thrown using <paramref name="message"/> and <paramref name="args"/> | |
/// if <paramref name="condition"/> is false. | |
/// </exception> | |
/// <returns><paramref name="condition" />.</returns> | |
public static bool ThrowIfNot(this ILogger log, bool condition, string message, params object[] args) | |
{ | |
try | |
{ | |
if (condition) { return condition; } | |
InvalidOperationException exception = new(PoorFormat(message, args)); | |
log.LogError(exception, message, args); | |
throw exception; | |
} | |
catch (Exception e) | |
{ | |
log.LogError(e, MessageThrew, args); | |
throw; | |
} | |
} | |
/// <summary> | |
/// If <paramref name="that" /> is true do nothing. | |
/// Otherwise log it as Error and throw the Exception generated by <paramref name="exception" /> | |
/// If an exception is thrown during evaluation, then log that as an Error, | |
/// and throw that instead. | |
/// </summary> | |
/// <param name="log"></param> | |
/// <param name="that">the condition</param> | |
/// <param name="exception">an exception to throw if <paramref name="that" /> is false.</param> | |
/// <param name="args">will be passed to <see cref="ILogger.LogError" /> if <paramref name="that" /> is false</param> | |
/// <exception cref="System.Exception"> | |
/// <paramref name="exception" /> | |
/// </exception> | |
/// <returns><paramref name="that" />.</returns> | |
public static bool ThrowIfNot(this ILogger log, bool that, Exception exception, params object[] args) | |
{ | |
try | |
{ | |
if (that) { return that; } | |
log.LogError(exception, MessageWasFalse, args); | |
throw exception; | |
} | |
catch (Exception e) | |
{ | |
log.LogError(e, MessageThrew, args); | |
throw; | |
} | |
} | |
/// <summary> | |
/// If <paramref name="that" /> is true do nothing. | |
/// Otherwise log it as Error and throw the Exception generated by <paramref name="exception" /> | |
/// If an exception is thrown during evaluation, then log that as an Error, | |
/// and throw that instead. | |
/// </summary> | |
/// <param name="log"></param> | |
/// <param name="that">the condition</param> | |
/// <param name="exception">a function that will generate the exception</param> | |
/// <param name="args"> | |
/// will be passed to <see cref="ILogger.LogError" /> as args, | |
/// if <paramref name="that" /> is false | |
/// </param> | |
/// <exception cref="System.Exception"> | |
/// <paramref name="exception" /> | |
/// </exception> | |
/// <returns> | |
/// <paramref name="that" /> | |
/// </returns> | |
public static bool ThrowIfNot(this ILogger log, bool that, Func<Exception> exception, params object[] args) | |
{ | |
try | |
{ | |
if (that) { return that; } | |
Exception ex = exception(); | |
log.LogError(ex, MessageWasFalse, args); | |
throw ex; | |
} | |
catch (Exception e) | |
{ | |
log.LogError(e, MessageThrew, args); | |
throw; | |
} | |
} | |
/// <summary> | |
/// If <paramref name="that" /> is true do nothing. | |
/// Otherwise log it as Error and throw the Exception generated by <paramref name="exception" /> | |
/// If an exception is thrown during evaluation, then log that as an Error, | |
/// and throw that instead. | |
/// </summary> | |
/// <param name="log"></param> | |
/// <param name="that">the condition</param> | |
/// <param name="exception">a function that will generate the exception</param> | |
/// <param name="delayedArgs"> | |
/// will be evaluated only if <paramref name="that" /> is false, | |
/// then passed as args to <see cref="ILogger.LogError" /> | |
/// </param> | |
/// <exception cref="System.Exception"> | |
/// <paramref name="exception" /> | |
/// </exception> | |
/// <returns> | |
/// <paramref name="that" /> | |
/// </returns> | |
public static bool ThrowIfNot(this ILogger log, bool that, Func<Exception> exception, | |
Func<object[]> delayedArgs) | |
{ | |
try | |
{ | |
if (that) { return that; } | |
Exception ex = exception(); | |
log.LogError(ex, MessageWasFalse, delayedArgs()); | |
throw ex; | |
} | |
catch (Exception e) | |
{ | |
log.LogError(e, MessageThrew, "(Func<object[]> delayedArgs not evaluated)"); | |
throw; | |
} | |
} | |
/// <summary> | |
/// If <paramref name="it" /> is not null, do nothing. | |
/// Otherwise log it as Error and throw and <see cref="ArgumentNullException"/> with <paramref name="message"/> and <paramref name="args"/> | |
/// If an exception is thrown during evaluation, then log that as an Error, | |
/// and throw that instead. | |
/// </summary> | |
/// <param name="log"></param> | |
/// <param name="it">the object which should not be null</param> | |
/// <param name="message">the message to log, and to put in the exception if <paramref name="it" /> is null.</param> | |
/// <param name="args">will be passed to <see cref="ILogger.LogError" /> if <paramref name="it" /> is null.</param> | |
/// <exception cref="System.Exception"> | |
/// <see cref="ArgumentNullException"/> | |
/// </exception> | |
/// <returns><paramref name="it" />.</returns> | |
[return: NotNull]public static T ThrowIfNull<T>(this ILogger log, T? it, string message, params object[] args) | |
{ | |
try | |
{ | |
if (it is not null) { return it; } | |
ArgumentNullException exception = new(PoorFormat(message, args)); | |
log.LogError(exception, message, args); | |
throw exception; | |
} | |
catch (Exception e) | |
{ | |
log.LogError(e, MessageThrew, args); | |
throw; | |
} | |
} | |
/// <summary> | |
/// If <paramref name="it" /> is not null, do nothing. | |
/// Otherwise log it as Error and throw the Exception generated by <paramref name="exception" /> | |
/// If an exception is thrown during evaluation, then log that as an Error, | |
/// and throw that instead. | |
/// </summary> | |
/// <param name="log"></param> | |
/// <param name="it">the object which should not be null</param> | |
/// <param name="exception">an exception to throw if <paramref name="that" /> is false.</param> | |
/// <param name="args">will be passed to <see cref="ILogger.LogError" /> if <paramref name="that" /> is false</param> | |
/// <exception cref="System.Exception"> | |
/// <paramref name="exception" /> | |
/// </exception> | |
/// <returns><paramref name="it" />.</returns> | |
[return: NotNullIfNotNull("it")] | |
public static T ThrowIfNull<T>(this ILogger log, T? it, Exception exception, params object[] args) | |
{ | |
try | |
{ | |
if (it is not null) | |
{ | |
return it; | |
} | |
log.LogError(exception, MessageWasFalse, args); | |
throw exception; | |
} | |
catch (Exception e) | |
{ | |
log.LogError(e, MessageThrew, args); | |
throw; | |
} | |
} | |
/// <summary> | |
/// If <paramref name="it" /> is true do nothing. | |
/// Otherwise log it as Error and throw the Exception generated by <paramref name="exception" /> | |
/// If an exception is thrown during evaluation, then log that as an Error, | |
/// and throw that instead. | |
/// </summary> | |
/// <param name="log"></param> | |
/// <param name="it">the object which should not be null</param> | |
/// <param name="exception">a function that will generate the exception</param> | |
/// <param name="args"> | |
/// will be passed to <see cref="ILogger.LogError" /> as args, | |
/// if <paramref name="it" /> is false | |
/// </param> | |
/// <exception cref="System.Exception"> | |
/// <paramref name="exception" /> | |
/// </exception> | |
/// <returns> | |
/// <paramref name="it" /> | |
/// </returns> | |
[return: NotNullIfNotNull("it")] | |
public static T ThrowIfNull<T>(this ILogger log, T? it, Func<Exception> exception, | |
params object[] args) | |
{ | |
try | |
{ | |
if (it is not null) | |
{ | |
return it!; | |
} | |
Exception ex = exception(); | |
log.LogError(ex, MessageWasFalse, args); | |
throw ex; | |
} | |
catch (Exception e) | |
{ | |
log.LogError(e, MessageThrew, args); | |
throw; | |
} | |
} | |
/// <summary> | |
/// If <paramref name="it" /> is not null do nothing. | |
/// Otherwise log it as Error and throw the Exception generated by <paramref name="exception" /> | |
/// If an exception is thrown during evaluation, then log that as an Error, | |
/// and throw that instead. | |
/// </summary> | |
/// <param name="log"></param> | |
/// <param name="it">the object which should not be null</param> | |
/// <param name="exception">a function that will generate the exception</param> | |
/// <param name="delayedArgs"> | |
/// will be evaluated only if <paramref name="it" /> is false, | |
/// then passed as args to <see cref="ILogger.LogError" /> | |
/// </param> | |
/// <exception cref="System.Exception"> | |
/// <paramref name="exception" /> | |
/// </exception> | |
/// <returns> | |
/// <paramref name="it" /> | |
/// </returns> | |
[return: NotNullIfNotNull("it")] | |
public static T ThrowIfNull<T>(this ILogger log, T it, Func<Exception> exception, | |
Func<object[]> delayedArgs) | |
{ | |
try | |
{ | |
if (it is not null) | |
{ | |
return it!; | |
} | |
Exception ex = exception(); | |
log.LogError(ex, MessageWasFalse, delayedArgs()); | |
throw ex; | |
} | |
catch (Exception e) | |
{ | |
log.LogError(e, MessageThrew, "(Func<object[]> delayedArgs not evaluated)"); | |
throw; | |
} | |
} | |
public static string PoorFormat(string message, object[] args) | |
{ | |
return (args != null) | |
? $"{message} args={string.Join(",", args.Select(a => a?.ToString()))}" | |
:message??""; | |
} | |
private const string MessageThisThrew = "EnsureElseLogAndThrow({@this},) threw during evaluation."; | |
private const string MessageThisWasFalse = "EnsureElseLogAndThrow({@this},) was false."; | |
private const string MessageThrew = "EnsureElseLogAndThrow threw during evaluation. {args}"; | |
private const string MessageWasFalse = "EnsureElseLogAndThrow was false. {args}"; | |
private static readonly string nl = Environment.NewLine; | |
private static readonly Exception FailedToEvaluateOrGetExceptionException | |
= new("Failed to evaluate an assertion and failed to evaluate the exception to describe it"); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Diagnostics.CodeAnalysis; | |
using Serilog; | |
using Serilog.Events; | |
namespace LogAssert | |
{ | |
/// <summary>Taken from https://gist.github.com/chrisfcarroll/f00944ecc100e7ffb0b070bb67d803ca</summary> | |
public static class LogAssert_v1 | |
{ | |
/// <summary>If <paramref name="condition"/> evaluates true, | |
/// then call <see cref="ILogger.Warning(string,object[]"/><c>(message, args)</c>. | |
/// If <paramref name="@condition"/> evaluates false, do nothing. | |
/// If an exception is thrown during evaluation, then catch it and log that as an Error, | |
/// and continue.</summary> | |
/// <param name="log">your Serilog logger</param> | |
/// <param name="condition">the condition</param> | |
/// <param name="message">message format</param> | |
/// <param name="args">args to message format</param> | |
/// <returns><paramref name="condition"/></returns> | |
public static bool WarnIf(this ILogger log, bool condition, string message, params object?[] args) | |
=> If(log, LogEventLevel.Warning, condition, message, args); | |
/// <summary>If <paramref name="condition"/> evaluates true, | |
/// then call <see cref="ILogger.Error(string,object[]"/><c>(message, args)</c>. | |
/// If <paramref name="@condition"/> evaluates false, do nothing. | |
/// If an exception is thrown during evaluation, then catch it and log that as an Error, | |
/// and continue.</summary> | |
/// <param name="log">your Serilog logger</param> | |
/// <param name="condition">the condition</param> | |
/// <param name="message">message format</param> | |
/// <param name="args">args to message format</param> | |
/// <returns><paramref name="condition"/></returns> | |
public static bool ErrorIf(this ILogger log, bool condition, string message, params object?[] args) | |
=> If(log, LogEventLevel.Error, condition, message, args); | |
/// <summary>If <paramref name="condition"/> evaluates true, | |
/// then call <see cref="ILogger.Information(string,object[]"/><c>(message, args)</c>. | |
/// If <paramref name="@condition"/> evaluates false, do nothing. | |
/// If an exception is thrown during evaluation, then catch it and log that as an Error, | |
/// and continue.</summary> | |
/// <param name="log">your Serilog logger</param> | |
/// <param name="condition">the condition</param> | |
/// <param name="message">message format</param> | |
/// <param name="args">args to message format</param> | |
/// <returns><paramref name="condition"/></returns> | |
public static bool InformationIf(this ILogger log, bool condition, string message, params object?[] args) | |
=> If(log, LogEventLevel.Information, condition, message, args); | |
/// <summary>If <paramref name="condition"/> evaluates true, | |
/// then call <see cref="ILogger.Debug(string,object[]"/><c>(message, args)</c>. | |
/// If <paramref name="@condition"/> evaluates false, do nothing. | |
/// If an exception is thrown during evaluation, then catch it and log that as an Error, | |
/// and continue.</summary> | |
/// <param name="log">your Serilog logger</param> | |
/// <param name="condition">the condition</param> | |
/// <param name="message">message format</param> | |
/// <param name="args">args to message format</param> | |
/// <returns><paramref name="condition"/></returns> | |
public static bool DebugIf(this ILogger log, bool condition, string message, params object?[] args) | |
=> If(log, LogEventLevel.Debug, condition, message, args); | |
/// <summary>If <paramref name="condition"/> evaluates true, | |
/// then call <see cref="ILogger.Warning(string,object[]"/><c>(message, args)</c>. | |
/// If <paramref name="@condition"/> evaluates false, do nothing. | |
/// If an exception is thrown during evaluation, then catch it and log that as an Error, | |
/// and continue.</summary> | |
/// <param name="log">your Serilog logger</param> | |
/// <param name="logEventLevel">The <see cref="LogEventLevel"/> at which to log</param> | |
/// <param name="condition">the condition</param> | |
/// <param name="message">message format</param> | |
/// <param name="args">args to message format</param> | |
/// <returns><paramref name="condition"/></returns> | |
static bool If(ILogger log, LogEventLevel logEventLevel, bool condition, string message, object?[] args) | |
{ | |
try { if (condition) log.Write(logEventLevel, message, args); } | |
catch (Exception e) | |
{ | |
log.Error(e, "({Message},{@args}) was true, but logging it threw an Exception", message, args); | |
} | |
return condition; | |
} | |
/// <summary>If <paramref name="condition"/> evaluates true, | |
/// then call <see cref="ILogger.Warning(string,object[]"/><c>(message, args)</c>. | |
/// If <paramref name="@condition"/> evaluates false, do nothing. | |
/// If an exception is thrown during evaluation, then catch it and log that as an Error, | |
/// and continue.</summary> | |
/// <param name="log"></param> | |
/// <param name="condition">the condition</param> | |
/// <param name="message">message format</param> | |
/// <param name="delayedArgs">if <paramref name="condition"/> is true then this function is | |
/// evaluated to generate args for the log. This allows logging of values that may be | |
/// expensive to compute, or may be invalid when <c>condition</c> is false.</param> | |
/// <returns><paramref name="condition"/></returns> | |
public static bool WarnIf<T>(this ILogger log, bool condition, string message, Func<T> delayedArgs) | |
=> If(log, LogEventLevel.Warning, condition, message, delayedArgs); | |
/// <summary>If <paramref name="condition"/> evaluates true, | |
/// then call <see cref="ILogger.Error(string,object[]"/><c>(message, args)</c>. | |
/// If <paramref name="@condition"/> evaluates false, do nothing. | |
/// If an exception is thrown during evaluation, then catch it and log that as an Error, | |
/// and continue.</summary> | |
/// <param name="log"></param> | |
/// <param name="condition">the condition</param> | |
/// <param name="message">message format</param> | |
/// <param name="delayedArgs">if <paramref name="condition"/> is true then this function is | |
/// evaluated to generate args for the log. This allows logging of values that may be | |
/// expensive to compute, or may be invalid when <c>condition</c> is false.</param> | |
/// <returns><paramref name="condition"/></returns> | |
public static bool ErrorIf<T>(this ILogger log, bool condition, string message, Func<T> delayedArgs) | |
=> If(log, LogEventLevel.Error, condition, message, delayedArgs); | |
/// <summary>If <paramref name="condition"/> evaluates true, | |
/// then call <see cref="ILogger.Information(string,object[]"/><c>(message, args)</c>. | |
/// If <paramref name="@condition"/> evaluates false, do nothing. | |
/// If an exception is thrown during evaluation, then catch it and log that as an Error, | |
/// and continue.</summary> | |
/// <param name="log"></param> | |
/// <param name="condition">the condition</param> | |
/// <param name="message">message format</param> | |
/// <param name="delayedArgs">if <paramref name="condition"/> is true then this function is | |
/// evaluated to generate args for the log. This allows logging of values that may be | |
/// expensive to compute, or may be invalid when <c>condition</c> is false.</param> | |
/// <returns><paramref name="condition"/></returns> | |
public static bool InformationIf<T>(this ILogger log, bool condition, string message, Func<T> delayedArgs) | |
=> If(log, LogEventLevel.Information, condition, message, delayedArgs); | |
/// <summary>If <paramref name="condition"/> evaluates true, | |
/// then call <see cref="ILogger.Debug(string,object[]"/><c>(message, args)</c>. | |
/// If <paramref name="@condition"/> evaluates false, do nothing. | |
/// If an exception is thrown during evaluation, then catch it and log that as an Error, | |
/// and continue.</summary> | |
/// <param name="log"></param> | |
/// <param name="condition">the condition</param> | |
/// <param name="message">message format</param> | |
/// <param name="delayedArgs">if <paramref name="condition"/> is true then this function is | |
/// evaluated to generate args for the log. This allows logging of values that may be | |
/// expensive to compute, or may be invalid when <c>condition</c> is false.</param> | |
/// <returns><paramref name="condition"/></returns> | |
public static bool DebugIf<T>(this ILogger log, bool condition, string message, Func<T> delayedArgs) | |
=> If(log, LogEventLevel.Debug, condition, message, delayedArgs); | |
static bool If<T>(ILogger log, LogEventLevel logEventLevel, bool condition, string message, Func<T> delayedArgs) | |
{ | |
try { if (condition) log.Write(logEventLevel, message, delayedArgs()); } | |
catch (Exception e) | |
{ | |
log.Error(e, "({Message},{@delayedArgs}) was true, but logging it threw an Exception", | |
message, delayedArgs); | |
} | |
return condition; | |
} | |
/// <summary>If <c>that(<paramref name="@this"/>)</c> evaluates true, | |
/// then call <see cref="ILogger.Warning(string,object[]"/><c>(message, args)</c>. | |
/// If <c>that(<paramref name="@this"/>)</c> evaluates false, do nothing. | |
/// If an exception is thrown during evaluation, then catch it and log that as an Error, | |
/// and continue.</summary> | |
/// <param name="log"></param> | |
/// <param name="@this">the object to test with <paramref name="that"/></param> | |
/// <param name="that">the condition</param> | |
/// <param name="message">message format</param> | |
/// <param name="args">args to message format</param> | |
/// <returns><paramref name="that"/>(<paramref name="@this"/>). | |
/// If evaluation throws an exception, then null is returned.</returns> | |
public static bool? WarnIf<T>(this ILogger log, T @this, Func<T,bool> that, string message, params object[] args) | |
{ | |
bool outcome; | |
try { outcome= that(@this); if (outcome)log.Warning(message, args); } | |
catch (Exception e) | |
{ | |
log.Error(e, "({Message},{@args}) threw when evaluating it.",message,args); | |
return null; | |
} | |
return outcome; | |
} | |
/// <summary>If <c>that(<paramref name="@this"/>)</c> evaluates true, | |
/// then call <see cref="ILogger.Warning(string,object[]"/><c>(message, args)</c>. | |
/// If <c>that(<paramref name="@this"/>)</c> evaluates false, do nothing. | |
/// If an exception is thrown during evaluation, then catch it and log that as an Error, | |
/// and continue.</summary> | |
/// <param name="log"></param> | |
/// <param name="@this">the object to test with <paramref name="that"/></param> | |
/// <param name="that">the condition</param> | |
/// <param name="message">message format</param> | |
/// <param name="delayedArgs">if <c>that(<paramref name="@this"/>)</c> is true then this function is | |
/// evaluated to generate args for the log. This allows logging of values that may be | |
/// expensive to compute, or may be invalid when <c>that(<paramref name="@this"/>)</c> is false.</param> | |
/// <returns><paramref name="condition"/></returns> | |
/// <returns><paramref name="that"/>(<paramref name="@this"/>). | |
/// If evaluation throws an exception, then null is returned.</returns> | |
public static bool? WarnIf<T,Ta>(this ILogger log, T @this, Func<T,bool> that, string message, Func<Ta> delayedArgs) | |
{ | |
bool outcome; | |
try { outcome= that(@this); if (outcome)log.Warning(message, delayedArgs()); } | |
catch (Exception e) | |
{ | |
log.Error(e, "({Message},{delayedArgs}) threw when evaluating it.",message,delayedArgs); | |
return null; | |
} | |
return outcome; | |
} | |
/// <summary>If <paramref name="condition"/> is true, do nothing. | |
/// If <paramref name="condition"/> is false, then | |
/// call <see cref="ILogger.Warning(string,object[]"/><c>(message, args)</c> | |
/// If an exception is thrown during evaluation, then catch it and log that as an Error, | |
/// and continue.</summary> | |
/// <param name="log"></param> | |
/// <param name="condition">the condition</param> | |
/// <param name="message">message format</param> | |
/// <param name="args">args to message format</param> | |
/// <returns><paramref name="condition"/></returns> | |
public static bool WarnIfNot(this ILogger log, bool condition, string message, params object[] args) | |
{ | |
return IfNot(log, LogEventLevel.Warning, condition, message, args); | |
} | |
/// <summary>If <paramref name="condition"/> is true, do nothing. | |
/// If <paramref name="condition"/> is false, then | |
/// call <see cref="ILogger.Error(string,object[]"/><c>(message, args)</c> | |
/// If an exception is thrown during evaluation, then catch it and log that as an Error, | |
/// and continue.</summary> | |
/// <param name="log"></param> | |
/// <param name="condition">the condition</param> | |
/// <param name="message">message format</param> | |
/// <param name="args">args to message format</param> | |
/// <returns><paramref name="condition"/></returns> | |
public static bool ErrorIfNot(this ILogger log, bool condition, string message, params object[] args) | |
{ | |
return IfNot(log, LogEventLevel.Error, condition, message, args); | |
} | |
/// <summary>If <paramref name="condition"/> is true, do nothing. | |
/// If <paramref name="condition"/> is false, then | |
/// call <see cref="ILogger.Information(string,object[]"/><c>(message, args)</c> | |
/// If an exception is thrown during evaluation, then catch it and log that as an Error, | |
/// and continue.</summary> | |
/// <param name="log"></param> | |
/// <param name="condition">the condition</param> | |
/// <param name="message">message format</param> | |
/// <param name="args">args to message format</param> | |
/// <returns><paramref name="condition"/></returns> | |
public static bool InformationIfNot(this ILogger log, bool condition, string message, params object[] args) | |
{ | |
return IfNot(log, LogEventLevel.Information, condition, message, args); | |
} | |
static bool IfNot(ILogger log, LogEventLevel logEventLevel, bool condition, string message, object[] args) | |
{ | |
try { if (!condition) log.Write(logEventLevel,message, args); } | |
catch (Exception e) | |
{ | |
log.Error(e, "({Message},{@args}) was false, but logging it threw an Exception", message, args); | |
} | |
return condition; | |
} | |
/// <summary>If <c>that(<paramref name="@this"/>)</c> evaluates true, do nothing. | |
/// if <c>that(<paramref name="@this"/>)</c> evaluates false, | |
/// then call <see cref="ILogger.Warning(string,object[]"/><c>(message, args)</c> | |
/// If an exception is thrown during evaluation, then catch it and log that as an Error, | |
/// and continue.</summary> | |
/// <param name="log"></param> | |
/// <param name="@this">the object to test with <paramref name="that"/></param> | |
/// <param name="that">the condition</param> | |
/// <param name="message">message format</param> | |
/// <param name="args">args to message format</param> | |
/// <returns><paramref name="that"/>(<paramref name="@this"/>). | |
/// If evaluation throws an exception, then null is returned.</returns> | |
public static bool? WarnIfNot<T>(this ILogger log, T @this, Func<T,bool> that, string message, params object[] args) | |
{ | |
bool outcome; | |
try { outcome= that(@this); if (!outcome)log.Warning(message, args); } | |
catch (Exception e) | |
{ | |
log.Error(e, "({Message},{@args}) threw when evaluating it.",message,args); | |
return null; | |
} | |
return outcome; | |
} | |
/// <summary>AssertNotNull is an abbreviation for <see cref="ErrorIf"/>(<c><paramref name="it"/> is null</c>) | |
/// If <paramref name="it"/> evaluates not null, do nothing. | |
/// If <paramref name="it"/> evaluates null,then call <see cref="ILogger.Error(string,object[]"/><c>(message, args)</c> | |
/// If an exception is thrown during evaluation, then catch it and log that as an Error, | |
/// and continue.</summary> | |
/// <param name="log"></param> | |
/// <param name="it">the object under test</param> | |
/// <param name="message">message format</param> | |
/// <param name="args">args to message format</param> | |
/// <returns><paramref name="that"/></returns> | |
[return:NotNull] | |
public static T AssertNotNull<T>(this ILogger log, T? it, string message, params object[] args) | |
{ | |
ErrorIf(log, it is null, message, args); | |
return it!; | |
} | |
/// <summary>Log.Assert is a synonym for <see cref="ErrorIfNot"/>. | |
/// If <paramref name="condition"/> is true, do nothing. | |
/// If <paramref name="condition"/> is false then call <see cref="ILogger.Error(string,object[]"/><c>(message, args)</c> | |
/// If an exception is thrown during evaluation, then catch it and log that as an Error, | |
/// and continue.</summary> | |
/// <param name="log"></param> | |
/// <param name="condition">the condition</param> | |
/// <param name="message">message format</param> | |
/// <param name="args">args to message format</param> | |
/// <returns><paramref name="condition"/></returns> | |
public static bool Assert(this ILogger log, bool condition, string message, params object[] args) | |
=> ErrorIfNot(log, condition, message, args); | |
/// <summary>Log <paramref name="exception"/> and return it, but don't throw it.</summary> | |
/// <param name="log"></param> | |
/// <param name="exception"></param> | |
/// <returns><paramref name="exception"/></returns> | |
public static Exception Exception(this ILogger log, Exception exception, params object[] args) | |
{ | |
if(exception is null){log.Error("Tried to log a null exception",args); return exception;} | |
log.Error(exception, exception.GetType().ToString(),args); | |
return exception; | |
} | |
/// <summary>Log <paramref name="exception"/> and then throw it. | |
/// Note that <see cref="Exception(Serilog.ILogger,System.Exception,object[])"/> is usually | |
/// preferable, both because the compiler can understand it, and because the resulting stack | |
/// trace is more to the point.</summary> | |
/// <param name="log"></param> | |
/// <param name="exception"></param> | |
/// <exception><paramref name="exception"/> is thrown immediately after logging.</exception> | |
/// <see cref="Exception(Serilog.ILogger,System.Exception,object[])"/> | |
/// <remarks>Note that <see cref="Exception(Serilog.ILogger,System.Exception,object[])"/> is usually | |
/// preferable, both because the compiler can understand it, and because the resulting stack | |
/// trace is more to the point.</remarks> | |
/// <returns>Never returns. The exception is thrown.</returns> | |
public static Exception ExceptionThenThrow(this ILogger log, Exception exception, params object[] args) | |
{ | |
exception ??= new Exception("Tried to log a null exception"); | |
log.Error(exception, exception.GetType().ToString(), args); | |
throw exception; | |
} | |
/// <summary>Log <paramref name="exception"/> and then <see cref="Environment.Exit"/>> the current Process</summary> | |
/// <param name="log"></param> | |
/// <param name="exception"></param> | |
/// <param name="exitCode">The exitCode to return to the operating system or calling process</param> | |
/// <returns>Nothing. The Process is halted.</returns> | |
public static void ExceptionThenSystemExitCurrentProcessWithExitCode(this ILogger log, Exception exception, int exitCode, params object[] args) | |
{ | |
if(exception is null){log.Error("Tried to log a null exception",args);} | |
else { log.Error(exception, exception.GetType().ToString(), args); } | |
System.Environment.Exit(exitCode); | |
} | |
/// <summary>Create a new <see cref="ApplicationException"/> with <paramref name="message"/>, | |
/// log it with <paramref name="args"/>, then return it. But don't throw it.</summary> | |
/// <param name="log"></param> | |
/// <param name="message"></param> | |
/// <returns>The new <see cref="ApplicationException"/> with <paramref name="message"/></returns> | |
public static ApplicationException Exception(this ILogger log, string message,params object[] args) | |
{ | |
if(string.IsNullOrWhiteSpace(message) && args.Length==0){log.Error("Tried to log an empty exception"); return null;} | |
var ex = new ApplicationException(message); | |
log.Error(ex, message,args); | |
return ex; | |
} | |
/// <summary>If <paramref name="that"/> is true do nothing. | |
/// Otherwise log it as Error and throw the Exception generated by <paramref name="exception"/> | |
/// If an exception is thrown during evaluation, then log that as an Error, | |
/// and throw that instead.</summary> | |
/// <param name="log"></param> | |
/// <param name="that">the condition</param> | |
/// <param name="exception">an exception to throw if <paramref name="that"/> is false.</param> | |
/// <param name="args">will be passed to <see cref="ILogger.Error"/> if <paramref name="that"/> is false</param> | |
/// <exception cref="System.Exception"><paramref name="exception"/></exception> | |
/// <returns><paramref name="that"/>.</returns> | |
public static bool EnsureElseThrow(this ILogger log, bool that, Exception exception, params object[] args) | |
{ | |
try { if (that) return that; log.Error(exception,messageWasFalse,args); throw exception;} | |
catch (Exception e) { log.Error(e,messageThrew); throw;} | |
} | |
/// <summary>If <paramref name="that"/> is true do nothing. | |
/// Otherwise log it as Error and throw the Exception generated by <paramref name="exception"/> | |
/// If an exception is thrown during evaluation, then log that as an Error, | |
/// and throw that instead.</summary> | |
/// <param name="log"></param> | |
/// <param name="that">the condition</param> | |
/// <param name="exception">a function that will generate the exception</param> | |
/// <param name="args">will be passed to <see cref="ILogger.Error"/> as args, | |
/// if <paramref name="that"/> is false</param> | |
/// <exception cref="System.Exception"><paramref name="exception"/></exception> | |
/// <returns><paramref name="that"/></returns> | |
public static bool EnsureElseThrow(this ILogger log, bool that, Func<Exception> exception, params object[] args) | |
{ | |
try { if (that) return that; var ex = exception(); log.Error(ex,messageWasFalse,args); throw ex;} | |
catch (Exception e) { log.Error(e,messageThrew); throw;} | |
} | |
/// <summary>If <paramref name="that"/> is true do nothing. | |
/// Otherwise log it as Error and throw the Exception generated by <paramref name="exception"/> | |
/// If an exception is thrown during evaluation, then log that as an Error, | |
/// and throw that instead.</summary> | |
/// <param name="log"></param> | |
/// <param name="that">the condition</param> | |
/// <param name="exception">a function that will generate the exception</param> | |
/// <param name="delayedArgs">will be evaluated only if <paramref name="that"/> is false, | |
/// then passed as args to <see cref="ILogger.Error"/></param> | |
/// <exception cref="System.Exception"><paramref name="exception"/></exception> | |
/// <returns><paramref name="that"/></returns> | |
public static bool EnsureElseThrow(this ILogger log, bool that, Func<Exception> exception, Func<object[]> delayedArgs) | |
{ | |
try { | |
if (that) return that; | |
var ex = exception(); | |
log.Error(ex,messageWasFalse,delayedArgs()); | |
throw ex; | |
} | |
catch (Exception e) { log.Error(e,messageThrew); throw;} | |
} | |
const string messageThisThrew = "EnsureElseLogAndThrow({@this},) threw during evaluation."; | |
const string messageThisWasFalse = "EnsureElseLogAndThrow({@this},) was false."; | |
const string messageThrew = "EnsureElseLogAndThrow threw during evaluation."; | |
const string messageWasFalse = "EnsureElseLogAndThrow was false."; | |
static readonly string nl = Environment.NewLine; | |
static readonly Exception FailedToEvaluateOrGetExceptionException | |
= new Exception("Failed to evaluate an assertion and failed to evaluate the exception to describe it"); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Xunit; | |
namespace LogAssert.Tests | |
{ | |
public class LogAssertExtensionTests | |
{ | |
[Theory] | |
[InlineData(null, null)] | |
[InlineData(null, 1, null)] | |
[InlineData("", 1, null)] | |
[InlineData("", "1", null)] | |
[InlineData("message", null)] | |
[InlineData("message", 1, null)] | |
[InlineData("message", "1", null)] | |
[InlineData(" ", null)] | |
public void LogAssertPoorFormatDoesntThrowButDoesIncludeMessage(string msg, params object[] args) | |
{ | |
var actual=LogAssert.PoorFormat(msg, args); | |
if(!string.IsNullOrEmpty(msg)) Assert.StartsWith(msg,actual); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment