Mostlylucid.Ephemeral.Patterns.SignalLogWatcher
2.3.2
dotnet add package Mostlylucid.Ephemeral.Patterns.SignalLogWatcher --version 2.3.2
NuGet\Install-Package Mostlylucid.Ephemeral.Patterns.SignalLogWatcher -Version 2.3.2
<PackageReference Include="Mostlylucid.Ephemeral.Patterns.SignalLogWatcher" Version="2.3.2" />
<PackageVersion Include="Mostlylucid.Ephemeral.Patterns.SignalLogWatcher" Version="2.3.2" />
<PackageReference Include="Mostlylucid.Ephemeral.Patterns.SignalLogWatcher" />
paket add Mostlylucid.Ephemeral.Patterns.SignalLogWatcher --version 2.3.2
#r "nuget: Mostlylucid.Ephemeral.Patterns.SignalLogWatcher, 2.3.2"
#:package Mostlylucid.Ephemeral.Patterns.SignalLogWatcher@2.3.2
#addin nuget:?package=Mostlylucid.Ephemeral.Patterns.SignalLogWatcher&version=2.3.2
#tool nuget:?package=Mostlylucid.Ephemeral.Patterns.SignalLogWatcher&version=2.3.2
Mostlylucid.Ephemeral.Patterns.SignalLogWatcher
Watches a SignalSink for matching signals and triggers callbacks. Useful for error monitoring and alerting.
dotnet add package mostlylucid.ephemeral.patterns.signallogwatcher
Quick Start
using Mostlylucid.Ephemeral.Patterns.SignalLogWatcher;
var sink = new SignalSink();
await using var watcher = new SignalLogWatcher(
sink,
evt => Console.WriteLine($"Error: {evt.Signal}"),
pattern: "error.*",
pollInterval: TimeSpan.FromMilliseconds(100));
// When any signal matching "error.*" appears, the callback fires
// Automatically deduplicates to avoid repeated callbacks for same signal
All Options
new SignalLogWatcher(
// Required: signal sink to watch
sink: signalSink,
// Required: callback when matching signal found
onMatch: evt => HandleSignal(evt),
// Glob pattern to match signals
// Default: "error.*"
pattern: "error.*",
// How often to poll the sink
// Default: 200ms
pollInterval: TimeSpan.FromMilliseconds(200)
)
API Reference
// Constructor starts watching immediately
var watcher = new SignalLogWatcher(sink, callback, pattern, pollInterval);
// Dispose to stop watching
await watcher.DisposeAsync();
How It Works
SignalSink: [error.db] [info.request] [error.api] [error.api] [warn.memory]
│ │ │
▼ ▼ │
Callback Callback │
▼
(deduplicated)
Poll every 200ms:
- Get all signals from sink
- Match against pattern "error.*"
- Fire callback for NEW matches only
- Track seen signals to prevent duplicates
Example: Error Alerting
var sink = new SignalSink();
await using var watcher = new SignalLogWatcher(
sink,
async evt =>
{
await alertService.SendSlackAlert(
$"Error detected: {evt.Signal}",
$"Operation: {evt.OperationId}, Time: {evt.Timestamp}");
},
pattern: "error.*",
pollInterval: TimeSpan.FromSeconds(1));
// All error signals trigger alerts
sink.Raise("error.database.connection");
sink.Raise("error.api.timeout");
Attribute-driven alert jobs
[EphemeralJobs(SignalPrefix = "error")]
public sealed class ErrorAlertJobs
{
private readonly IAlertService _alerts;
public ErrorAlertJobs(IAlertService alerts) => _alerts = alerts;
[EphemeralJob(".*", Lane = "alerts", MaxConcurrency = 2)]
public Task NotifyAsync(SignalEvent evt, CancellationToken ct)
{
return _alerts.SendAlertAsync(
$"Captured {evt.Signal}",
$"Op {evt.OperationId} @ {evt.Timestamp}",
ct);
}
}
var sink = new SignalSink();
await using var runner = new EphemeralSignalJobRunner(sink, new[] { new ErrorAlertJobs(alertService) });
sink.Raise("error.database.connection");
Handlers created from the attribute package see the same signal stream, but the wiring lives right next to the logic
that responds to error.* patterns.
Example: Multiple Watchers
var sink = new SignalSink();
// Watch for errors
await using var errorWatcher = new SignalLogWatcher(
sink,
evt => logger.LogError("Error signal: {Signal}", evt.Signal),
pattern: "error.*");
// Watch for performance issues
await using var perfWatcher = new SignalLogWatcher(
sink,
evt => metrics.RecordSlowOperation(evt.Signal),
pattern: "perf.slow.*");
// Watch for security events
await using var securityWatcher = new SignalLogWatcher(
sink,
evt => securityLog.Record(evt),
pattern: "security.*",
pollInterval: TimeSpan.FromMilliseconds(50)); // Fast polling for security
Example: With Coordinator
var sink = new SignalSink();
await using var coordinator = new EphemeralWorkCoordinator<Request>(
async (req, ct) =>
{
try
{
await ProcessRequest(req, ct);
}
catch (Exception ex)
{
sink.Raise($"error.request.{ex.GetType().Name}");
throw;
}
},
new EphemeralOptions { Signals = sink });
await using var watcher = new SignalLogWatcher(
sink,
evt => Console.WriteLine($"Request failed: {evt.Signal}"),
pattern: "error.request.*");
// Process requests - errors automatically logged
foreach (var req in requests)
await coordinator.EnqueueAsync(req);
Related Packages
| Package | Description |
|---|---|
| mostlylucid.ephemeral | Core library |
| mostlylucid.ephemeral.patterns.anomalydetector | Anomaly detection |
| mostlylucid.ephemeral.patterns.telemetry | Telemetry integration |
| mostlylucid.ephemeral.complete | All in one DLL |
License
Unlicense (public domain)
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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 is compatible. 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. |
-
net10.0
- mostlylucid.ephemeral (>= 2.3.2)
-
net8.0
- mostlylucid.ephemeral (>= 2.3.2)
-
net9.0
- mostlylucid.ephemeral (>= 2.3.2)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Mostlylucid.Ephemeral.Patterns.SignalLogWatcher:
| Package | Downloads |
|---|---|
|
mostlylucid.ephemeral.complete
Meta-package that references all Mostlylucid.Ephemeral packages - bounded async execution with signals, atoms, and patterns. Install this single package to get everything. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.3.2 | 87 | 1/9/2026 |
| 2.3.1 | 102 | 1/9/2026 |
| 2.3.1-alpha0 | 85 | 1/9/2026 |
| 2.3.0 | 285 | 1/8/2026 |
| 2.3.0-alpha1 | 86 | 1/8/2026 |
| 2.1.0 | 94 | 1/8/2026 |
| 2.1.0-preview | 87 | 1/8/2026 |
| 2.0.1 | 88 | 1/8/2026 |
| 2.0.0 | 124 | 1/8/2026 |
| 2.0.0-alpha1 | 83 | 1/8/2026 |
| 1.7.1 | 414 | 12/11/2025 |
| 1.6.8 | 429 | 12/9/2025 |
| 1.6.7 | 421 | 12/9/2025 |
| 1.6.6 | 427 | 12/9/2025 |
| 1.6.5 | 427 | 12/9/2025 |
| 1.6.0 | 412 | 12/8/2025 |
| 1.5.0 | 411 | 12/8/2025 |
| 1.3.0 | 291 | 12/7/2025 |
| 1.2.2 | 296 | 12/7/2025 |
| 1.1.0-preview2 | 201 | 12/7/2025 |
| 1.0.0-preview3 | 202 | 12/7/2025 |