* feat: add diagnostics console logs * test: avoid secret-like redaction fixtures * fix: address console logs review feedback * fix: harden console log capture lifecycle * fix: report console log drop summaries * fix: address diagnostics review cleanups
15 KiB
Feature Specification: Diagnostics Console Logs
Feature Branch: 006-diagnostics-console-logs
Created: 2026-05-18
Status: Draft
Input: User description: "Create a Core feature spec for diagnostics console streaming based on the existing roadmap at specs/diagnostics-console-streaming-roadmap.md and the surrounding context from specs/003-live-server-logs, specs/004-diagnostics-structured-logs, and specs/005-structured-log-persistence. Include requirements for backend capture, buffering, endpoints, SignalR hub, permissions, source identity, redaction, and provider boundaries. Avoid implementation code changes."
Clarifications
Session 2026-05-18
- Q: How should Core expose partial stdout/stderr writes that have not ended with a newline? -> A: Buffer until complete.
- Q: How should Core handle console lines longer than the configured maximum line length? -> A: Truncate oversized lines.
- Q: What should Core do with ANSI escape sequences by default? -> A: Strip ANSI by default.
- Q: What permission boundary should Core use for source listings? -> A: Same dedicated permission.
- Q: What content should console log providers receive and retain? -> A: Redacted content only.
User Scenarios & Testing (mandatory)
User Story 1 - Tail raw backend console output (Priority: P1)
An administrator or developer enables the Core console logs feature and watches recent plus live stdout and stderr lines from the backend process without using shell access.
Why this priority: Raw process console output is the core capability and is intentionally separate from structured log records.
Independent Test: Enable the console logs feature, write distinct lines to stdout and stderr, request recent lines, subscribe to the live stream, and verify callers receive ordered, source-aware console line events while the original console output still reaches its normal destination.
Acceptance Scenarios:
- Given diagnostics console logs are enabled and the caller is authorized, When the backend writes complete lines to stdout and stderr, Then the caller receives console line events with stream identity, text, timestamps, sequence, and source identity.
- Given console capture is enabled, When the backend writes to stdout or stderr, Then existing console behavior is preserved and output remains visible to the host environment.
- Given the caller requests recent console lines before subscribing live, When recent matching lines exist, Then the server returns a bounded ordered backfill before the caller receives new live lines.
User Story 2 - Filter, secure, and redact console output (Priority: P2)
An operator narrows noisy console output by source, stream, text, and time while the backend enforces a dedicated diagnostics permission and redacts sensitive data before data leaves the backend.
Why this priority: Console output can contain secrets and high-volume operational noise. The feature is not safe for real hosts without authorization, filtering, and redaction.
Independent Test: Connect authorized and unauthorized callers, write console lines containing secret-like values, apply filters, and verify unauthorized access is rejected while authorized callers only receive redacted lines matching their filters.
Acceptance Scenarios:
- Given an unauthenticated or unauthorized caller, When the caller requests recent console lines, source listings, or a live subscription, Then access is rejected.
- Given redaction rules are configured, When stdout or stderr contains matching sensitive values, Then recent and live events replace those values with a redaction marker before exposure.
- Given the caller filters by source, stream, text, or time, When matching and non-matching console lines are available, Then only matching redacted lines are returned or streamed.
User Story 3 - Identify console sources in clustered deployments (Priority: P3)
An operator diagnosing a clustered Elsa deployment can view a merged stream across known backend sources and filter to one source such as a process, pod, or container.
Why this priority: Source identity must be part of the first contract so the console viewer does not become single-process-only and can later use shared providers without changing Studio-facing behavior.
Independent Test: Simulate multiple console log sources through the provider boundary, request sources, subscribe to a merged stream, and then filter to one source while preserving source health and dropped-line metadata.
Acceptance Scenarios:
- Given multiple sources publish console lines through the configured provider, When the caller subscribes without a source filter, Then the server streams a merged ordered view with each line's source identity.
- Given the caller filters by a source ID, When lines arrive from multiple sources, Then only lines from the selected source are returned or streamed.
- Given a source stops sending heartbeats or lines, When the caller lists sources, Then the source is marked stale or disconnected without immediately losing its recent history.
Edge Cases
- Console writes arrive as partial lines or without a trailing newline.
- A console line exceeds the configured maximum line length.
- Output arrives faster than the recent buffer or subscriber queues can handle.
- A subscriber disconnects while console lines continue to arrive.
- A caller changes filters while subscribed.
- Console output contains ANSI escape sequences.
- Console output contains secrets in raw text or source metadata.
- Multiple sources have clock skew or overlapping sequence values.
- The console logs feature writes its own diagnostics messages and risks feeding them back into the captured console stream.
- The configured provider is unavailable at startup or becomes unavailable during streaming.
Requirements (mandatory)
Functional Requirements
Module boundary and feature identity
- FR-001: The backend MUST provide an opt-in Core diagnostics module named
Elsa.Diagnostics.ConsoleLogsor an equivalent diagnostics console logs name confirmed before implementation. - FR-002: The console logs module MUST be separate from
Elsa.Diagnostics.StructuredLogsand MUST NOT replace, rename, or parse structured log records. - FR-003: The module MUST advertise a diagnostics console logs remote feature so Studio can detect whether the backend supports console streaming.
- FR-004: The feature MUST document that raw stdout/stderr console streaming is distinct from structured logs, structured log persistence, trace waterfalls, metrics, and OpenTelemetry exploration.
Backend capture and line behavior
- FR-005: The feature MUST capture writes to stdout and stderr as raw console output while preserving the host's existing console output behavior.
- FR-006: Captured output MUST be emitted as line-oriented console events with stream identity of
stdoutorstderr. - FR-007: Captured console events MUST include ID, timestamp, received timestamp, source-local sequence, stream, text, source identity, truncation indicator, and dropped-line metadata when available.
- FR-008: Partial writes MUST be buffered and MUST NOT be exposed as separate fragment events; Core completes and emits a line only on newline, maximum line length, or configurable idle flush timeout.
- FR-009: Lines longer than the configured maximum line length MUST be truncated to the configured maximum, emitted as a single console line event, and marked with a truncation indicator.
- FR-010: ANSI escape sequences MUST be stripped by default before exposure, and hosts MUST be able to configure preservation of terminal formatting when needed.
- FR-011: The feature MUST avoid recursively capturing console diagnostics generated by the console logs feature itself unless explicitly enabled for troubleshooting.
Buffering and backpressure
- FR-012: The feature MUST keep a bounded recent-history buffer for initial backfill and MUST never grow memory without bound.
- FR-013: The feature MUST use bounded live subscriber behavior and MUST track dropped-line counts when buffers or subscriber queues overflow.
- FR-014: Recent-line requests MUST enforce a server-side maximum result count regardless of caller input.
- FR-015: Dropped-line summaries MUST identify the affected source and reason when that information is known.
Endpoints and live transport
- FR-016: The backend MUST expose an authenticated recent console lines endpoint for initial backfill, for example
/diagnostics/console-logs/recent. - FR-017: The backend MUST expose an authenticated console sources endpoint, for example
/diagnostics/console-logs/sources. - FR-018: The backend MUST expose an authenticated live console logs SignalR hub, for example
/elsa/hubs/diagnostics/console-logs. - FR-019: Recent queries and live subscriptions MUST support filters for source ID, stream, free-text query, time range, and maximum result count.
- FR-020: The live hub MUST allow a caller to subscribe, update filters without reconnecting, and unsubscribe.
- FR-021: The live hub MUST send console line events, dropped-line summaries, and source status changes to subscribed callers.
Authorization and redaction
- FR-022: Recent-line endpoints, source-listing endpoints, and live console log hubs MUST all require the same dedicated permission such as
read:diagnostics:console-logs. - FR-023: The feature MUST use Elsa's existing authentication, authorization, and cross-origin access patterns.
- FR-024: Redaction MUST run before console lines or source metadata are stored in recent buffers, streamed live, or returned by endpoints.
- FR-025: Default redaction MUST mask common secret indicators such as authorization, bearer tokens, passwords, secrets, API keys, cookies, connection strings, and similarly named values.
- FR-026: Hosts MUST be able to configure additional redaction rules and replacement text.
- FR-027: Redaction MUST apply to raw line text and to sensitive source metadata fields before data leaves the backend.
- FR-027a: Console log providers MUST receive, store, stream, and list only redacted console line text and redacted source metadata; raw unredacted console content MUST remain inside the capture/redaction boundary.
Source identity and provider boundaries
- FR-028: Every console line MUST include a source descriptor with source ID, display name, service name, process ID, machine name, and, when available, pod name, container name, namespace, and node name.
- FR-029: Sources MUST expose last-seen time and health such as connected, stale, or disconnected.
- FR-030: The default provider MUST support in-process capture for local development, tests, and single-node hosts.
- FR-031: The provider boundary MUST allow future shared or external providers to aggregate console lines across multiple Core instances without changing Studio-facing contracts.
- FR-032: Direct Kubernetes, Docker, orchestrator log API, vendor sink, and OpenTelemetry integrations MUST remain out of scope for this feature unless added by later specs.
- FR-033: Merged streams MUST provide deterministic ordering when source timestamps overlap or clocks differ, using received order or another stable tiebreaker.
Configuration and operations
- FR-034: The feature MUST provide host options for recent buffer capacity, subscriber/channel capacity, maximum recent query size, maximum line length, idle flush timeout, ANSI handling, source heartbeat timeout, redaction rules, and provider selection.
- FR-035: Provider failures MUST be surfaced to recent queries or live subscriptions with safe error information and without exposing unredacted console content.
- FR-036: The feature MUST include validation coverage for capture, stream identity, filtering, buffering, dropped counts, authorization, redaction, source health, provider boundaries, and feedback-loop prevention.
Key Entities (include if feature involves data)
- Console Log Line: A redacted raw stdout or stderr line with sequence, timestamps, stream identity, text, truncation state, source identity, and dropped-line context.
- Console Log Source: The process, pod, container, machine, or external provider source that produced console output.
- Console Log Filter: Criteria used for recent queries and live subscriptions, including source, stream, text, time range, and take limit.
- Console Log Provider: Replaceable provider that stores recent console lines, streams future lines, lists sources, and reports dropped-line/source status.
- Console Capture Tee: Capture boundary that observes stdout/stderr while preserving the original console destination.
- Console Redaction Rule: Configured matching rule that masks sensitive raw line text or source metadata before exposure.
- Console Log Subscription: Live connection with active filters, bounded queue behavior, and dropped-line summaries.
Success Criteria (mandatory)
Measurable Outcomes
- SC-001: In single-process validation, authorized subscribers receive 100% of complete stdout and stderr test lines up to configured subscriber capacity within 1 second of capture.
- SC-002: Recent-line queries never return more than the configured maximum number of lines.
- SC-003: Unauthorized callers are rejected for 100% of recent-line, source-list, and live hub access attempts.
- SC-004: Default redaction masks common secret patterns in raw console line text and sensitive source metadata in validation tests.
- SC-005: Under sustained overload, memory remains bounded and dropped-line counts are visible through recent results or live summaries.
- SC-006: In simulated multi-source validation, merged results include lines from all active sources and source filtering returns only the selected source.
- SC-007: A source that stops sending lines or heartbeats is marked stale within the configured heartbeat timeout.
- SC-008: Console writes continue reaching the host's original stdout/stderr destination while capture is enabled.
- SC-009: Documentation or feature metadata clearly separates console logs from structured logs, structured log persistence, and future OpenTelemetry diagnostics.
Assumptions
- Studio will implement a paired feature spec in the
elsa-studiorepository and is owned by another worker. - The Core route names, hub route, remote feature name, and permission use diagnostics console logs naming unless later renamed consistently before implementation.
- In-process capture is the first slice; cluster-ready behavior is provided through source identity and provider boundaries rather than direct orchestrator APIs.
- Recent console history is operational troubleshooting data, not durable audit logging.
- Redacted console lines are the only form exposed by providers, endpoints, hubs, and buffers.
- Hosts that need long-term log retention should continue using their existing observability or platform log systems.