.NET · stdout · stderr

Observe the machine
in real-time.

Reusable .NET libraries for capturing, redacting, buffering, streaming, and optionally persisting stdout/stderr console logs — without external agents.

Get Started
$dotnet add package ConsoleLogStream.Core
diagnostic_stream.log
10:24:01[INF]Capture started · source=orders-api
10:24:03[TRC]Mapping /diagnostics/console-logs/*
10:24:05[WRN]Secret detected · [redacted]
10:24:08[STR]SignalR push · 42 subscribers_
10:24:10[INF]Sqlite flush · 128 rows · 12ms
10:24:12[INF]Filter applied · query="startup"
Packages

Three modules. One pipeline.

Add only what you need. The Core engine is required; ASP.NET Core and SQLite modules are opt-in.

NuGet · .Core

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.Core
NuGet · .AspNetCore

ConsoleLogStream.AspNetCore

ASP.NET Core integration. Exposes recent/sources REST endpoints and a SignalR hub for live, filterable log streaming.

dotnet add package ConsoleLogStream.AspNetCore
NuGet · .Persistence.Sqlite

ConsoleLogStream.Persistence.Sqlite

Optional SQLite sink. Batched, queued writes of redacted lines for short-term troubleshooting with configurable retention.

dotnet add package ConsoleLogStream.Persistence.Sqlite
Pipeline

How a log line travels.

Stdout / Stderr
Tee & Normalize
Redact Secrets
Providers · SignalR · SQLite

Only redacted line events reach providers, live subscribers, web endpoints, SignalR clients, or SQLite persistence.

Features

Built for diagnostics surfaces.

01

Tee capture

Wraps Console.Out and Console.Error so existing Console.WriteLine calls still print — and are also captured.

02

Built-in redaction

Masks bearer tokens, passwords, API keys, cookies, authorization values and connection strings out of the box.

03

Custom rules

Add named regex rules with replacements for application-specific secrets like tenant tokens or internal IDs.

04

In-memory buffer

Bounded recent buffer with configurable capacity, per-line length cap and clamp on requested query limits.

05

SignalR streaming

Channel-based Stream method plus Subscribe / UpdateFilter / Unsubscribe for push-style live dashboards.

06

SQLite persistence

Optional durable sink storing only redacted text, with MaxAge and MaxRows retention controls.

Usage

Wire it up in minutes.

Register services, start capture, and expose endpoints or persistence as needed.

Core
Console.WriteLine → buffered, redacted.
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();
ASP.NET Core
REST endpoints + SignalR hub.
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();
SQLite
Optional batched persistence.
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;
});
Endpoints
  • GET /diagnostics/console-logs/recent
  • GET /diagnostics/console-logs/sources
  • HUB /hubs/console-logs
Important limitations

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.