{"id":50259665,"url":"https://github.com/valence-works/console-log-streaming","last_synced_at":"2026-05-31T12:00:28.525Z","repository":{"id":360191646,"uuid":"1248688274","full_name":"valence-works/console-log-streaming","owner":"valence-works","description":"Reusable .NET libraries for capturing, redacting, buffering, streaming, and optionally persisting stdout/stderr console logs.","archived":false,"fork":false,"pushed_at":"2026-05-27T00:24:50.000Z","size":718,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-28T09:24:10.949Z","etag":null,"topics":["console","diagnostics","dotnet","signalr","sqlite","stderr","stdout"],"latest_commit_sha":null,"homepage":"https://www.consolelogstreaming.dev","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/valence-works.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-05-25T00:35:46.000Z","updated_at":"2026-05-27T08:48:04.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/valence-works/console-log-streaming","commit_stats":null,"previous_names":["valence-works/console-log-stream","valence-works/console-log-streaming"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/valence-works/console-log-streaming","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/valence-works%2Fconsole-log-streaming","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/valence-works%2Fconsole-log-streaming/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/valence-works%2Fconsole-log-streaming/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/valence-works%2Fconsole-log-streaming/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/valence-works","download_url":"https://codeload.github.com/valence-works/console-log-streaming/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/valence-works%2Fconsole-log-streaming/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33646428,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-29T02:00:06.066Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["console","diagnostics","dotnet","signalr","sqlite","stderr","stdout"],"created_at":"2026-05-27T08:31:25.416Z","updated_at":"2026-05-29T10:00:35.362Z","avatar_url":"https://github.com/valence-works.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Console Log Streaming\n\nConsole Log Streaming is a small .NET library family for capturing managed\n`Console.Out` and `Console.Error` output as redacted, line-oriented diagnostics\nevents. It gives applications a reusable foundation for recent console log\nbackfill, live streaming, and optional short-term SQLite persistence without\ncoupling the core package to ASP.NET Core, SignalR, SQLite, Elsa, or any one UI.\n\n## Why\n\nMany .NET apps need an admin-facing view of raw backend console output: worker\nprogress, boot diagnostics, library `Console.WriteLine` calls, stderr messages,\nand troubleshooting traces that are not always represented as structured\n`ILogger` events.\n\nThe usual choices are awkward:\n\n- SSH into the host or inspect container logs.\n- Build a one-off `Console.SetOut` wrapper per app.\n- Force everything through a logging framework and lose raw stdout/stderr\n  semantics.\n- Add a vendor log stack when all you need is short-term operational visibility.\n\nConsole Log Streaming packages the reusable middle layer: safe managed capture,\nredaction, bounded buffers, filters, live subscriptions, optional web transport,\nand optional local persistence.\n\n## Packages\n\n| Package | Purpose |\n|---------|---------|\n| `ConsoleLogStreaming.Core` | Framework-neutral capture, redaction, models, bounded in-memory provider, and async live subscriptions. |\n| `ConsoleLogStreaming.Contracts` | Shared HTTP and realtime DTOs plus core-to-DTO mapping seams. |\n| `ConsoleLogStreaming.Endpoints.MinimalApi` | Minimal API recent and sources endpoints. |\n| `ConsoleLogStreaming.Endpoints.FastEndpoints` | FastEndpoints recent and sources endpoints. |\n| `ConsoleLogStreaming.SignalR` | Optional SignalR realtime hub and subscription manager. |\n| `ConsoleLogStreaming.AspNetCore` | Convenience package that composes Minimal API endpoints and SignalR. |\n| `ConsoleLogStreaming.Persistence.Sqlite` | Optional durable store for redacted console lines with retention. |\n\n## Safety Model\n\nConsole output often contains sensitive data. The library is designed around a\nstrict boundary:\n\n1. Managed stdout/stderr writes are captured by a tee writer.\n2. Lines are normalized, optionally stripped of ANSI escapes, and redacted.\n3. Only redacted line events reach providers, live subscribers, web endpoints,\n   SignalR clients, or SQLite persistence.\n\nDefault redaction masks common bearer tokens, password/secret/token/API-key style\nvalues, cookies, authorization values, and connection string style values. Add\nyour own rules for application-specific secrets.\n\n## Important Limitations\n\nVersion 1 captures managed .NET `Console.Out` and `Console.Error` writes. It does\nnot guarantee capture of:\n\n- Native code writing directly to stdout/stderr file descriptors.\n- Libraries that cached `Console.Out` or `Console.Error` before capture started.\n- Output emitted by child processes unless the child output is redirected back\n  into the current process and written to managed console writers.\n\nUse platform/container logs for authoritative process-level log capture. Use this\nlibrary for reusable in-app diagnostics surfaces.\n\n## Core Usage\n\n```csharp\nusing ConsoleLogStreaming.Core;\nusing ConsoleLogStreaming.Core.DependencyInjection;\nusing ConsoleLogStreaming.Core.Models;\nusing Microsoft.Extensions.DependencyInjection;\n\nawait using var services = new ServiceCollection()\n    .AddConsoleLogStreaming(options =\u003e\n    {\n        options.SourceId = \"worker-1\";\n        options.RecentCapacity = 1000;\n        options.MaxLineLength = 16 * 1024;\n        options.RedactionRules.Add(new()\n        {\n            Name = \"Tenant token\",\n            Pattern = @\"tenant-token=[^\\s]+\",\n            Replacement = \"tenant-token=[redacted]\"\n        });\n    })\n    .BuildServiceProvider();\n\nvar capture = services.GetRequiredService\u003cIConsoleLogCapture\u003e();\nawait capture.StartAsync();\n\nConsole.WriteLine(\"Hello from stdout\");\nConsole.Error.WriteLine(\"Hello from stderr\");\n\nvar provider = services.GetRequiredService\u003cIConsoleLogProvider\u003e();\nvar recent = await provider.GetRecentAsync(new ConsoleLogFilter\n{\n    Stream = ConsoleStream.Stdout,\n    Limit = 50\n});\n\nvar sources = services.GetRequiredService\u003cIConsoleLogSourceRegistry\u003e();\nsources.SourceChanged += source =\u003e\n{\n    // Notify clients when sources appear or move between connected/stale states.\n};\n\nawait capture.StopAsync();\n```\n\nFor app hosts that want managed process-wide capture tied to `IHostedService`,\nuse the host registration. It exposes the same host-owned provider, source\nregistry, redaction pipeline, formatter, and capture service through DI:\n\n```csharp\nbuilder.Services.AddConsoleLogStreamingHost(options =\u003e\n{\n    options.ServiceName = \"orders-worker\";\n    options.RecentCapacity = 5000;\n});\n```\n\nRegister `IConsoleLogMetadataAccessor` before `AddConsoleLogStreamingHost` to add\nper-line metadata. Register a custom `IConsoleLogProvider` before it when you\nwant the process-wide host to write to your own backend.\n\nFor advanced hosts that need to build their own line formatter or metadata\nadapter, the core package also exposes the raw process-wide hook:\n\n```csharp\nusing ConsoleLogStreaming.Core.Capture;\n\nConsoleStreamHook.Install();\n\nusing var subscription = ConsoleStreamHook.Subscribe(chunk =\u003e\n{\n    ConsoleStreamHook.SuppressCapture = true;\n    try\n    {\n        // Forward chunk.Text to your own buffer, provider, or transport here.\n    }\n    finally\n    {\n        ConsoleStreamHook.SuppressCapture = false;\n    }\n});\n```\n\n## ASP.NET Core Usage\n\n```csharp\nusing ConsoleLogStreaming.AspNetCore.DependencyInjection;\nusing ConsoleLogStreaming.Core.DependencyInjection;\n\nvar builder = WebApplication.CreateBuilder(args);\n\nbuilder.Services.AddConsoleLogStreaming(options =\u003e\n{\n    options.ServiceName = \"orders-api\";\n});\n\nbuilder.Services.AddConsoleLogStreamingAspNetCore(options =\u003e\n{\n    options.AuthorizationPolicy = \"diagnostics.console\";\n    options.RecentPath = \"/diagnostics/console-logs/recent\";\n    options.SourcesPath = \"/diagnostics/console-logs/sources\";\n    options.HubPath = \"/hubs/console-logs\";\n});\n\nvar app = builder.Build();\napp.MapConsoleLogStreaming();\n\nawait app.Services.GetRequiredService\u003cIConsoleLogCapture\u003e().StartAsync();\nawait app.RunAsync();\n```\n\nEndpoints:\n\n- `POST /diagnostics/console-logs/recent`\n- `GET /diagnostics/console-logs/sources`\n- SignalR hub: `/hubs/console-logs`\n\nThe hub exposes a streaming method:\n\n```csharp\nvar channel = await connection.StreamAsChannelAsync\u003cConsoleLogStreamingItem\u003e(\n    \"StreamAsync\",\n    new ConsoleLogFilter { Query = \"startup\", Limit = 100 });\n```\n\nIt also supports push-style methods:\n\n- `SubscribeAsync(ConsoleLogFilter filter)`\n- `UpdateFilterAsync(ConsoleLogFilter filter)`\n- `UnsubscribeAsync()`\n\n## SQLite Persistence\n\nSQLite persistence is optional and intended for short-term troubleshooting, not\ncompliance audit logging.\n\n```csharp\nusing ConsoleLogStreaming.Persistence.Sqlite.DependencyInjection;\n\nbuilder.Services.AddConsoleLogStreaming();\nbuilder.Services.AddConsoleLogStreamingSqlite(options =\u003e\n{\n    options.ConnectionString = \"Data Source=console-logs.db\";\n    options.MaxAge = TimeSpan.FromDays(7);\n    options.MaxRows = 100_000;\n});\n```\n\nSQLite stores redacted line text and redacted source metadata only. Writes are\nqueued and batched so console writes do not wait on disk I/O. Configure retention\nfor production use.\n\n## Filtering\n\nRecent queries and live subscriptions use `ConsoleLogFilter`:\n\n- `SourceId`\n- `Stream`\n- `Query`\n- `From`\n- `To`\n- `Limit`\n- `Metadata`\n\nProviders clamp requested limits to configured maximums.\n\n## Build\n\n```sh\ndotnet build ConsoleLogStreaming.slnx\ndotnet test ConsoleLogStreaming.slnx\n```\n\n## Samples\n\nThe repository includes three runnable UI samples that all use the same backend\nconsole streaming surface. Each sample starts its own ASP.NET Core host,\ncaptures managed stdout/stderr, persists redacted lines to a local SQLite\ndatabase, backfills recent output, and streams live events through SignalR.\n\n| Sample | Best for | Project |\n|--------|----------|---------|\n| Blazor Server | A fully .NET diagnostics surface with Razor components and server-side interactivity. | `samples/ConsoleLogStreaming.Sample.Blazor` |\n| React | A static React frontend served by ASP.NET Core without requiring an npm install. | `samples/ConsoleLogStreaming.Sample.React` |\n| Vanilla HTML + JavaScript | The smallest browser integration using plain HTML, CSS, JavaScript, and the SignalR client. | `samples/ConsoleLogStreaming.Sample.Vanilla` |\n\n### Blazor Server\n\n![Blazor console stream sample](docs/sample-screenshots/blazor-console-stream.png)\n\nThe Blazor sample uses interactive server components for the dashboard and\nregular ASP.NET Core endpoints for the console stream API. It is useful when you\nwant the diagnostics UI to live inside an existing .NET admin app without adding\na separate frontend toolchain.\n\n```sh\ndotnet run --project samples/ConsoleLogStreaming.Sample.Blazor\n```\n\n### React\n\n![React console stream sample](docs/sample-screenshots/react-console-stream.png)\n\nThe React sample serves prebuilt static assets from `wwwroot` and connects to\nthe same SignalR hub from the browser. It demonstrates how a JavaScript frontend\ncan consume recent backfill, source metadata, and live stdout/stderr updates from\nthe shared ASP.NET Core package.\n\n```sh\ndotnet run --project samples/ConsoleLogStreaming.Sample.React\n```\n\n### Vanilla HTML + JavaScript\n\n![Vanilla HTML and JavaScript console stream sample](docs/sample-screenshots/vanilla-console-stream.png)\n\nThe vanilla sample keeps the browser side intentionally small: static HTML,\nCSS, and JavaScript call the diagnostics endpoints directly and subscribe to the\nSignalR stream. Use it as the clearest reference for integrating the API without\na framework.\n\n```sh\ndotnet run --project samples/ConsoleLogStreaming.Sample.Vanilla\n```\n\nAll three UI samples expose the same runtime behavior:\n\n- recent console line backfill on load and after filter changes\n- live stdout/stderr streaming through SignalR\n- connected/stale source status\n- query and stream filtering\n- demo write buttons for stdout, stderr, and mixed bursts\n\nThey also map the same backend routes:\n\n- `GET /diagnostics/console-logs/recent?limit=100`\n- `GET /diagnostics/console-logs/sources`\n- SignalR hub at `/hubs/console-logs`\n- demo write endpoints under `/demo/*`\n\nFor more sample notes, see [`samples/README.md`](samples/README.md). The\nscreenshot gallery is also available at\n[`docs/sample-screenshots.md`](docs/sample-screenshots.md).\n\nTo build all sample projects:\n\n```sh\ndotnet build samples/ConsoleLogStreaming.Sample.Blazor\ndotnet build samples/ConsoleLogStreaming.Sample.React\ndotnet build samples/ConsoleLogStreaming.Sample.Vanilla\n```\n\n## Package Publishing\n\nThe base package version is controlled by `VersionPrefix` in\n`Directory.Build.props`.\n\nGitHub Actions publishes packages from `.github/workflows/nuget.yml`:\n\n- Pushes to `main` publish preview packages using\n  `{VersionPrefix}-preview.{GITHUB_RUN_NUMBER}`.\n- Manual `workflow_dispatch` runs publish preview packages using the same\n  preview version format when run from `main`. Dispatches from other branches\n  build, test, pack, and upload artifacts without publishing to NuGet.org.\n- Published GitHub releases publish stable packages using `VersionPrefix`.\n- Release tags must match the `VersionPrefix` in `Directory.Build.props`, e.g.\n  `1.2.3` or `v1.2.3`.\n\nConfigure the repository secret `NUGET_API_KEY` with a NuGet.org API key before\npublishing. If the secret is not configured, the workflow still builds, tests,\npacks, and uploads artifacts, but skips the NuGet.org publish step.\n\n## Repository Layout\n\n```text\nsrc/\n├── ConsoleLogStreaming.Core/\n├── ConsoleLogStreaming.AspNetCore/\n└── ConsoleLogStreaming.Persistence.Sqlite/\n\ntest/\n└── ConsoleLogStreaming.Tests/\n\nsamples/\n├── ConsoleLogStreaming.Sample.AspNetCore/\n├── ConsoleLogStreaming.Sample.Blazor/\n├── ConsoleLogStreaming.Sample.React/\n└── ConsoleLogStreaming.Sample.Vanilla/\n```\n\n## License\n\nMIT.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvalence-works%2Fconsole-log-streaming","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvalence-works%2Fconsole-log-streaming","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvalence-works%2Fconsole-log-streaming/lists"}