Log.Assert 0.2.0-pre1

This is a prerelease version of Log.Assert.
There is a newer prerelease version of this package available.
See the version list below for details.
dotnet add package Log.Assert --version 0.2.0-pre1
                    
NuGet\Install-Package Log.Assert -Version 0.2.0-pre1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Log.Assert" Version="0.2.0-pre1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Log.Assert" Version="0.2.0-pre1" />
                    
Directory.Packages.props
<PackageReference Include="Log.Assert" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Log.Assert --version 0.2.0-pre1
                    
#r "nuget: Log.Assert, 0.2.0-pre1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Log.Assert@0.2.0-pre1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Log.Assert&version=0.2.0-pre1&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=Log.Assert&version=0.2.0-pre1&prerelease
                    
Install as a Cake Tool

Log.Assert( it is "A better style of application logging" )

Log.Assert and Serilog.Assert add assertion-style application logging to ILogger.

public string GoBang(string target, int guess)
{
    log.Me();
    log.PreconditionNotNull(target);

    var graphemes = new StringInfo(target??"");
    log.Assert(graphemes.LengthInTextElements > 0);
    log.Precondition(0 <= guess && guess <= graphemes.LengthInTextElements);

    log.ExceptionAndThrowIf(
        graphemes.SubstringByTextElements(guess,1) is "💥",
        new ApplicationException("bang!"));

    var remainder = Remove(graphemes,guess);
   
    log.DebugIf(remainder.Length == 0,"TBC:is this permitted?");
    log.If(graphemes.LengthInTextElements > 0,
              helpfulInformation: (target,guess,graphemes.LengthInTextElements),
              label: "Remaining after Removal");

    log.PreconditionNotNull(target);
    log.Postcondition(remainder.Length < target.Length);
    log.Me(remainder);
    return remainder;
}

What is Logged?

  • All methods log the current method or member name.
  • Assertions, Pre-, and Post-Conditions log nothing at all if they pass.
  • Assertions, Pre-, and Post-Conditions log the literal failed expression if they fail.
  • log.If() methods log nothing at all if the condition is false
  • log.If() methods log the literal condition expression if it is true
  • All methods can log additional information, either auto-labelled or explicitly labelled.

Do log.Assertions throw?

No, they log. Traditionally, assertions are stripped out for release, and take effect only when code is compiled in debug mode. Log.Assert strongly encourages you to instead keep the assertions and log the failures. (But there are also log.AssertElseThrow() methods, which do throw on failure).

Do I have to use pre- and post-conditions everywhere now?

No, you don't. Try a few and see what you learn.

Example output

Depending on your logger template configuration, something like:

INF] GoBang((target,guess)=(12🍾4💥, 1))
ERR] GoBang:Precondition Not Null Failed:target:
ERR] GoBang:Assertion Failed:graphemes.LengthInTextElements > 0:
ERR] GoBang:Precondition Failed:0 <= guess && guess <= graphemes.LengthInTextElements
INF] GoBang:graphemes.LengthInTextElements > 0:Remaining after Removal:(12🍾4💥, 1, 5)
ERR] GoBang:Postcondition Failed:0 <= guess && guess <= graphemes.LengthInTextElements
INF] GoBang(remainder=1🍾4💥)

Structured Logging Properties

The default properties sent to structured logging are:

  • All methods log the current method or member name as a string {Action}
  • Assertions, Pre-, and Post-Conditions log their {Assertion} as a literal code string
  • log.If() and log.IfNot() methods log their {Condition} as a literal code string
  • All methods log optional helpfulInformation as an object {@State} and a string {Label}
  • Exceptions log {Exception} just as the frameworks normally do.

{@State} is the only complex property, everything else is a string.

{Action} and {Label} values can be overridden inline:

log.Me(state, action:"Not the method name", label:"Not the auto-generated label")

Changing the Template Strings and Structured Property Names

To change the message templates, and the property names used for structured logging, set the properties of TemplateStrings static class to the template strings and property names you want.

For instance if you set

TemplateStrings.Me = "{MethodName}({Title}{Info})";

Then log.Me(param1) will result in structured logging properties:

{MethodName} = "<Method or member name>"
{Title} = "param1"
{Info} = <value of param1>

instead of the default {Action},{Label},{State}.

The default template strings are stored as constants in TemplateStrings.Defaults.

Log Level

  • Assertions, Pre-, and Post-Conditions log at level Error.
  • Other methods default to logging at level Information, with named methods for other log levels (see the full list below).
  • Exceptions log at level Error by default.

All Methods

All methods accept an optional additonal helpfulInformation parameter, and an optional label for it.

log.Me()
log.MeDebug()
log.MeTrace()   //Log.Assert
log.MeVerbose() //Serilog.Assert
log.MeWarning()
log.MeError()

log.Assert()
log.AssertNotNull()
log.AssertNotNullOrEmpty()
log.AssertNotNullOrWhitespace()

log.Precondition()
log.PreconditionNotNull()
log.PreconditionNotNullOrEmpty()
log.PreconditionNotNullOrWhitespace()

log.Postcondition()
log.PostconditionNotNull()
log.PostconditionNotNullOrEmpty()
log.PostconditionNotNullOrWhitespace()

log.AssertElseThrow()
log.AssertNotNullElseThrow()

log.PreconditionElseThrow()
log.PreconditionNotNullElseThrow()

log.PostconditionElseThrow()
log.PostconditionNotNullElseThrow()

log.If()
log.InformationIf()
log.DebugIf()
log.TraceIf()   //Log.Assert
log.VerboseIf() //Serilog.Assert
log.WarnIf()
log.ErrorIf()
log.CriticalIf() //Log.Assert
log.FatalIf()    //Serilog.Assert

log.IfNot()
log.InformationIfNot()
log.DebugIfNot()
log.TraceIfNot()    //Log.Assert
log.VerboseIfNot()  //Serilog.Assert
log.WarnIfNot()
log.ErrorIfNot()
log.CriticalIfNot() //Log.Assert
log.FatalIfNot()    //Serilog.Assert

log.Exception()
log.ExceptionIf()
log.ExceptionAndThrow()
log.ExceptionAndThrowIf()
log.CriticalThenThrow()                       //Log.Assert
log.CriticalExceptionThenExitProcessWithCode() //Log.Assert
log.FatalThenThrow()                          //Serilog.Assert
log.FatalExceptionThenExitProcessWithCode()   //Serilog.Assert

Logging additional helpfulInformation

//Use a ValueTuple or anonymous object to log multiple items of additional state 
log.Me( (this,that,other) );

// By default the log line will auto-label the state:
"MethodName:(this,that,other)=(value1,value2,value3)"

// You can explicitly label the state:
log.Me( (this,that,other), "Checkpoints 1 to 3")
"MethodName:Checkpoints 1 to 3=(value1,value2,value3)"

// additional state can be just a comment:
log.Me("Comment ...")
"MethodName:Comment ..."

What about performance?

For applications where the billionths of a second it takes to compute an assertion success are more critical than visibility of assertion failures, then you will not want to use logging assertions, you can use traditional assertions instead. Programs running on shared virtual infrastructure or making a network call do not fall into this category.

Billionth of a second?

I reckon a typical boolean assertion in a hotspot in a running program won't go beyond your processor's L2 cache, so we're talking clock cycles — nanoseconds, not milliseconds.

Reference and Inspiration

Logging production assertion failures can be an eye-opener. Jim Coplien made this point some years ago in his paper, Most Unit Testing is Waste. Why would you test only in a unit test run? Test in production too, it's what the pros do. (I offer no opinion on whether his title is statistically true. Obviously none of my unit tests are waste, because I deleted the pointless ones).

Proofs of program correctness have not been as fashionable as automated testing for the past thirty years. Now is your chance to join the trendsetters before everyone is doing it.

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.5.0-pre1 36 5/26/2026
0.4.0-pre1 50 5/25/2026
0.3.0-pre1 48 5/25/2026
0.2.0-pre1 59 5/22/2026
0.1.0-pre1 49 5/21/2026

ChangeLog
     ---------
     0.2    Downgrade dependencies (Serilog 2.10, Extensions.Logging..Abstraction fx.0.0)
     0.1    First release