Waystone.Monads.Extensions.Logging
7.1.0
dotnet add package Waystone.Monads.Extensions.Logging --version 7.1.0
NuGet\Install-Package Waystone.Monads.Extensions.Logging -Version 7.1.0
<PackageReference Include="Waystone.Monads.Extensions.Logging" Version="7.1.0" />
<PackageVersion Include="Waystone.Monads.Extensions.Logging" Version="7.1.0" />
<PackageReference Include="Waystone.Monads.Extensions.Logging" />
paket add Waystone.Monads.Extensions.Logging --version 7.1.0
#r "nuget: Waystone.Monads.Extensions.Logging, 7.1.0"
#:package Waystone.Monads.Extensions.Logging@7.1.0
#addin nuget:?package=Waystone.Monads.Extensions.Logging&version=7.1.0
#tool nuget:?package=Waystone.Monads.Extensions.Logging&version=7.1.0
Waystone.Monads.Extensions.Logging
Routes the exceptions Waystone.Monads swallows to a
Microsoft.Extensions.Logging ILogger.
Option.Try and Result.Try catch an exception and hand back a None or an
Err. The exception itself is gone from the caller's point of view — in the
Option case, gone entirely. This package makes it turn up in the logging you
already have, without a try/catch at any call site.
Install and configure
dotnet add package Waystone.Monads.Extensions.Logging
On a host, where a service provider exists:
var app = builder.Build();
MonadOptions.Configure(options => options.UseLoggerFactoryFrom(app.Services));
Without a container — a console application, a test, a worker built by hand:
using ILoggerFactory factory = LoggerFactory.Create(
builder => builder.AddConsole());
MonadOptions.Configure(options => options.UseLoggerFactory(factory));
LoggerFactory.Create is not in Microsoft.Extensions.Logging.Abstractions, which
is all this package brings with it. Add Microsoft.Extensions.Logging to build a
factory yourself, plus a provider package such as
Microsoft.Extensions.Logging.Console. An application with a host already has both.
Or hand over a logger you already hold, which then keeps its own category:
MonadOptions.Configure(options => options.UseLogger(logger));
UseLoggerFactoryFrom resolves through IServiceProvider.GetService and takes no
dependency-injection package, so any container that can produce a provider works.
It throws if no ILoggerFactory is registered, naming UseLoggerFactory as the
way round it.
What gets written
One entry per swallowed exception, carrying the exception itself plus the call site the compiler recorded:
| Property | Meaning |
|---|---|
ArgumentExpression |
The source text of the delegate that threw |
MemberName |
The member that called Try |
LineNumber |
The line the Try call is on |
The exception travels in ILogger.Log's exception parameter rather than as
properties of its own, so an OpenTelemetry logging bridge derives
exception.type, exception.message and exception.stacktrace from it without
double-reporting.
Properties are PascalCase rather than the dotted code.function.name form the
semantic conventions use. Serilog property names must match [A-Za-z0-9_]+, and a
dotted token in a message template is not parsed as a property at all — it renders
literally. The dotted form is used where it is safe, on the metric tags the core
package emits.
Level
LogLevel.Debug by default. A Try that produces a None or an Err is an
ordinary outcome, and warning on it is noise in the applications this library was
built for. Semantic conventions suggest WARN for a handled exception; pass it if
you would rather follow them:
MonadOptions.Configure(
options => options.UseLoggerFactoryFrom(app.Services, LogLevel.Warning));
Both the logger and the level are held on a MonadOptions satellite, so a scope
overrides them for one asynchronous flow and leaves the rest of the process alone:
using (MonadOptions.BeginScope(
options => options.UseLogger(logger, LogLevel.Warning)))
{
// Everything in here logs at Warning, to this logger.
}
A logger created by UseLoggerFactory or UseLoggerFactoryFrom is in the
Waystone.Monads category, so it can be filtered without touching the rest of
your application:
{ "Logging": { "LogLevel": { "Waystone.Monads": "Warning" } } }
Relationship to the rest of the library
This package replaces MonadOptions.UseExceptionLogger, which is obsolete and
removed in 7.0.0. Configuring both logs every handled exception twice.
Metrics need nothing from this package. Waystone.Monads emits them itself,
under a meter named after itself. Add Waystone.Monads to the meters your
OpenTelemetry pipeline collects and you have counts of handled exceptions with no
Waystone package installed beyond the core one:
builder.Services.AddOpenTelemetry()
.WithMetrics(metrics => metrics.AddMeter("Waystone.Monads"));
Logging is the signal that cannot work that way. Microsoft.Extensions.Logging
publishes no ambient logger to discover, so a configuration call is permanently
required — which is what this package exists to be.
How it works
Core writes a Waystone.Monads.ExceptionHandled event to a DiagnosticListener
named Waystone.Monads. This package subscribes to it once, on the first
configuration call, and writes what arrives to the configured logger. Until then
there is no subscriber, so core's IsEnabled check short-circuits and the event
payload is never built.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. 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 was computed. 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 was computed. 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. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.2)
- Waystone.Monads (>= 7.1.0)
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 |
|---|---|---|
| 7.1.0 | 37 | 9/4/2026 |
| 7.1.0-beta.2 | 34 | 9/3/2026 |
| 7.1.0-beta.1 | 42 | 9/2/2026 |
| 7.0.1 | 84 | 8/30/2026 |
| 7.0.0 | 75 | 8/30/2026 |
| 7.0.0-beta.3 | 49 | 8/29/2026 |
| 7.0.0-beta.2 | 51 | 8/27/2026 |
| 7.0.0-beta.1 | 55 | 8/27/2026 |
| 6.7.0 | 81 | 8/26/2026 |