Observe the machine
in real-time.
Reusable .NET libraries for capturing, redacting, buffering, streaming, and optionally persisting stdout/stderr console logs — without external agents.
Three modules. One pipeline.
Add only what you need. The Core engine is required; ASP.NET Core and SQLite modules are opt-in.
ConsoleLogStream.Core
The engine. Captures managed Console.Out/Error via a tee writer, normalizes lines, strips ANSI, and applies the redaction pipeline.
dotnet add package ConsoleLogStream.CoreConsoleLogStream.AspNetCore
ASP.NET Core integration. Exposes recent/sources REST endpoints and a SignalR hub for live, filterable log streaming.
dotnet add package ConsoleLogStream.AspNetCoreConsoleLogStream.Persistence.Sqlite
Optional SQLite sink. Batched, queued writes of redacted lines for short-term troubleshooting with configurable retention.
dotnet add package ConsoleLogStream.Persistence.SqliteHow a log line travels.
Only redacted line events reach providers, live subscribers, web endpoints, SignalR clients, or SQLite persistence.
Built for diagnostics surfaces.
Tee capture
Wraps Console.Out and Console.Error so existing Console.WriteLine calls still print — and are also captured.
Built-in redaction
Masks bearer tokens, passwords, API keys, cookies, authorization values and connection strings out of the box.
Custom rules
Add named regex rules with replacements for application-specific secrets like tenant tokens or internal IDs.
In-memory buffer
Bounded recent buffer with configurable capacity, per-line length cap and clamp on requested query limits.
SignalR streaming
Channel-based Stream method plus Subscribe / UpdateFilter / Unsubscribe for push-style live dashboards.
SQLite persistence
Optional durable sink storing only redacted text, with MaxAge and MaxRows retention controls.
Wire it up in minutes.
Register services, start capture, and expose endpoints or persistence as needed.
using ConsoleLogStream.Core;
using ConsoleLogStream.Core.DependencyInjection;
using ConsoleLogStream.Core.Models;
using Microsoft.Extensions.DependencyInjection;
await using var services = new ServiceCollection()
.AddConsoleLogStream(options =>
{
options.SourceId = "worker-1";
options.RecentCapacity = 1000;
options.MaxLineLength = 16 * 1024;
options.RedactionRules.Add(new()
{
Name = "Tenant token",
Pattern = @"tenant-token=[^\s]+",
Replacement = "tenant-token=[redacted]"
});
})
.BuildServiceProvider();
var capture = services.GetRequiredService<IConsoleLogCapture>();
await capture.StartAsync();
Console.WriteLine("Hello from stdout");
Console.Error.WriteLine("Hello from stderr");
var provider = services.GetRequiredService<IConsoleLogProvider>();
var recent = await provider.GetRecentAsync(new ConsoleLogFilter
{
Stream = ConsoleStream.Stdout,
Limit = 50
});
await capture.StopAsync();using ConsoleLogStream.AspNetCore.DependencyInjection;
using ConsoleLogStream.Core.DependencyInjection;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddConsoleLogStream(options =>
{
options.ServiceName = "orders-api";
});
builder.Services.AddConsoleLogStreamAspNetCore(options =>
{
options.AuthorizationPolicy = "diagnostics.console";
options.RecentPath = "/diagnostics/console-logs/recent";
options.SourcesPath = "/diagnostics/console-logs/sources";
options.HubPath = "/hubs/console-logs";
});
var app = builder.Build();
app.MapConsoleLogStream();
await app.Services.GetRequiredService<IConsoleLogCapture>().StartAsync();
await app.RunAsync();using ConsoleLogStream.Persistence.Sqlite.DependencyInjection;
builder.Services.AddConsoleLogStream();
builder.Services.AddConsoleLogStreamSqlite(options =>
{
options.ConnectionString = "Data Source=console-logs.db";
options.MaxAge = TimeSpan.FromDays(7);
options.MaxRows = 100_000;
});- GET /diagnostics/console-logs/recent
- GET /diagnostics/console-logs/sources
- HUB /hubs/console-logs
v1 captures managed .NET Console writes.
- ›Native code writing directly to stdout/stderr file descriptors is not guaranteed to be captured.
- ›Libraries that cached Console.Out / Console.Error before capture started bypass the tee writer.
- ›Child process output is only captured when redirected back into the current process and written to managed writers.
Use platform/container logs for authoritative process-level capture. Use this library for reusable in-app diagnostics surfaces.