* Avoid null endpoint DTO metadata in tests * Enforce console logs hub read permission * Remove unused console logs hub import * Support mapped endpoint metadata in auth tests * Reduce console log capture throughput impact * Address Copilot console logs review * Refactor task scheduling to support tenant-level background work and enhance logging functionality. * Introduce ConsoleStreamHook for stdout/stderr tee and enhance logging validation. Adjust test cases and startup warnings for distributed lock provider usage. * Refactor console logging pipeline with capture optimization and new ConsoleLogsHost; update tests accordingly. * Add Ansi SGR parser for console logs and associated unit tests * Remove ANSI color renderings and parsers; integrate ConsoleLogScopeAccessor for improved logging context with workflow instance ID support. * Address console logs code quality feedback * Address PR review feedback * Preserve console logs extension points * Stabilize console logs host lifecycle * Address final automated review comments * Tighten console log capture shutdown * Address console log review feedback * Address follow-up review feedback * Cover final review feedback * Avoid recursive console provider initialization * Guard console host lease shutdown * Preserve console log scope and provider lifetime * Correlate console log scope fallback * Tighten console scope correlation * Expose host services during provider construction * Redact ANSI-normalized console lines * Add OpenTelemetry diagnostics backend foundation * Add OTLP HTTP ingestion parsing * Document OpenTelemetry diagnostics setup * Enforce OpenTelemetry hub permissions * Remove `ConsoleCaptureTee` and related services and tests * Add OpenTelemetry HTTP ingestion integration test * Use pipeline contributors for console log context * Update CShells package versions to 0.0.24-preview.132 * Add OpenTelemetry ingestion security tests * Add OpenTelemetry API authorization tests * Filter live console logs by workflow instance * Add OpenTelemetry hub tests * Add OpenTelemetry gRPC metadata hook * Assert OpenTelemetry workflow tags survive ingestion * Mark OpenTelemetry core build verified * Enhance console logging with activity execution metadata and extend test coverage. * Address console logs stream consumption comment * Wire OpenTelemetry diagnostics into core sample * Address Core diagnostics review feedback * Address Core Copilot follow-up feedback * Add OpenTelemetry metric instrument names * Address Core Copilot provider feedback * Address Core Copilot diagnostics follow-up * Address Core Copilot live feed feedback * Address Core Copilot store feedback * Integrate OpenTelemetry for logging, tracing, and metrics in ModularServer and update launch settings and docker-compose configuration. * Refactor to replace `ConsoleLogStream.Core` with `ConsoleLogStreaming.Core` across codebase and update `ConsoleStreamHook` installation. * Add diagnostics OpenTelemetry backend * Fix OpenTelemetry live hub subscription * Fix modular OpenTelemetry exporter endpoints * Add CShells logging configuration in appsettings.json * Remove obsolete unit tests and helper classes * Restore default activity exception handling * Simplify type serialization and alias management This commit refactors the internal type serialization and alias management system to reduce boilerplate, improve robustness, and simplify the developer experience: - Removed numerous explicit `ExpressionOptions` type alias registrations across various modules. - Updated `TypeJsonConverter` and polymorphic serialization to reliably handle types using assembly-qualified names when a short alias is not explicitly registered. - Streamlined `ExcludeFromHashConverter` to strictly adhere to `ExcludeFromHashAttribute` for hash calculations, removing complex `JsonIgnoreCondition` logic. - Eliminated several helper classes (`WorkflowJsonTypeResolver`, `WorkflowTypeValidator`, `IWorkflowTypeRegistry`, `WorkflowFactoryDictionary`, `JavaScriptExceptionTypeAliasRegistrar`, `WorkflowRuntimeTypeAliasRegistrar`) and their associated unit tests, simplifying the codebase. Additionally, this commit introduces a comprehensive markdown document (`product-website-feature-source.md`) outlining Elsa's core features, Studio capabilities, extension ecosystem, and architectural selling points, intended as source material for the product website. * Refine type serialization for improved robustness and alias handling This commit further enhances the type serialization and deserialization mechanisms: * Centralizes type resolution and alias management through `IWellKnownTypeRegistry` and `WorkflowJsonTypeResolver`. * Prioritizes registered type aliases when serializing type metadata in `PolymorphicObjectConverter`, resulting in more concise JSON output. * Enhances deserialization in `PolymorphicObjectConverter` and `VariableMapper` to gracefully handle unknown or non-instantiable types, providing fallbacks and logging warnings. * Simplifies `TypeJsonConverter` by delegating complex type resolution logic to the `WorkflowJsonTypeResolver`. * Adds `JsonArray` to the well-known type aliases for direct recognition. * Fix console logs packaging and workflow type resolution * Fix console log metadata and type resolution * Address Copilot review feedback * Enhance type resolution, improve console log handling, and update tests - Streamlined `WorkflowDictionaryExtensions` for better workflow registration validation. - Refined `ConsoleLogsAuthorizationTests` with the new `SetJsonRequest` helper to improve test requests handling. - Updated `OrderDefinition` to ignore JSON serialization for `KeySelector`. - Enhanced `WorkflowRuntimeFeature` for improved workflow registration and type alias configuration. - Added tests to ensure `ConsoleLogProvider` metadata filtration in various scenarios. - Improved type serialization logic in `WorkflowJsonTypeResolver`. - Updated README to fix references related to diagnostics. - Optimized `ExcludeFromHashConverter` for property serialization conditions. - Modified `TriggerIndexer` for streamlined trigger management. - Tested payload checks in `PublishEventTests`. - Adjusted `Endpoint` in `ConsoleLogs` for automatic JSON request handling. - Ensured registration of workflow type aliases in `WorkflowsFeature`. * Restore CLR workflow registration compatibility * Align JSON island serialization fixtures * Add Console Logs Services and Enhance Endpoint Handling - Introduced `ActivityExecutionsEndpointTests` to validate route exposure. - Added `ConsoleLogCaptureHostedService` for console log streaming. - Implemented `ConsoleStreamJsonConverter` for JSON conversion of console streams. - Developed `ElsaConsoleLogRecentBuffer` to handle recent log buffering. - Updated `ConsoleLogsAuthorizationTests` with new test cases for stream filter mapping. - Consolidated console log provider dependencies and registration, including recent buffering. - Enhanced `ElsaConsoleLogProvider` to use recent buffer for filtering. - Adjusted `Program.cs` for streamlined logging service setup. * Enhance type resolution and test coverage; streamline console log integration - Added `ConsoleStreamHook` for streamlined log streaming. - Updated `WorkflowJsonTypeResolverTests` to improve type resolution and test new scenarios. - Simplified type resolution by removing trusted assembly checks. * Fix CI smoke and package restore failures * Fix Docker smoke image project paths * Fix Docker Python runtime packages * Fix Docker CA smoke teardown * Refresh Elsa roadmap * Implement background processors and mediation coordination - Added `BackgroundCommandProcessor`, `BackgroundJobProcessor`, and `BackgroundNotificationProcessor` classes for handling commands, jobs, and notifications, respectively. - Introduced `MediatorBackgroundProcessingCoordinator` to coordinate the execution of all background processors. - Implemented `MediatorBackgroundTask` for wrapping `MediatorBackgroundProcessingCoordinator` in `BackgroundTask`. - Added unit tests for `MediatorBackgroundTask` to ensure proper start and stop behavior. - Refactored `BackgroundCommandSenderHostedService` to utilize `BackgroundCommandProcessor`. - Introduced 'elsa-roadmap-refresh' skill configuration for roadmap updates. * Address workflow type resolution review feedback * Address follow-up review feedback * Restore recent console logs execute path * Address Copilot follow-up review * Decouple workflow JSON aliases from expressions * Fix workflow management unit test setup * Fix console logs recent endpoint handler shape * Respect workflow JSON strict type aliases * Remove unused console log contracts reference * Address Copilot review feedback * Address Copilot follow-up comments * Synchronize ring buffer dropped count * Address background processor strategy replay
14 KiB
Feature Specification: Diagnostics OpenTelemetry
Feature Branch: 008-diagnostics-otel
Created: 2026-05-25
Status: Draft
Input: Core-owned specification for the backend side of the OpenTelemetry diagnostics PRD coordinated with elsa-studio/specs/008-diagnostics-otel.
Clarifications
Session 2026-05-25
- Q: What default capacity and overflow policy should the Core in-memory OTEL store use? -> A: Configurable bounded defaults with drop-oldest per signal.
- Q: How should Core decide when OTLP ingestion requires an API key? -> A: Require the configured header for any non-loopback request or non-loopback collector binding.
- Q: How should live SignalR subscriptions behave under backpressure? -> A: Use bounded per-connection queues, drop oldest updates, and report dropped counts.
- Q: Which workflow attributes are canonical for Elsa trace correlation? -> A: Preserve existing
Elsa.Workflowssemantic tags; do not add producer middleware or mutate ambient activity context.
User Scenarios & Testing (mandatory)
User Story 1 - Collect OpenTelemetry from Elsa services (Priority: P1)
An operator enables OpenTelemetry diagnostics on an Elsa backend and receives workflow traces, activity spans, metrics, resources, and correlated OTLP logs through a first-party diagnostics backend.
Why this priority: Studio cannot visualize telemetry until Core can collect, normalize, secure, and expose it.
Independent Test: Enable the Core OpenTelemetry diagnostics feature, run a workflow with multiple activities, export telemetry to the local diagnostics collector, and verify recent resources, traces, spans, metrics, and logs through backend diagnostics APIs.
Acceptance Scenarios:
- Given the diagnostics OpenTelemetry feature is enabled, When workflow execution emits spans and metrics from
Elsa.Workflows, Then Core stores recent telemetry with resource identity, trace/span IDs, timing, status, and workflow metadata. - Given a standard OpenTelemetry SDK posts OTLP traces, metrics, or logs to the HTTP/protobuf collector endpoint, When the payload is accepted, Then Core normalizes the telemetry into queryable diagnostics models.
- Given telemetry contains sensitive attributes matching configured redaction rules, When Core stores or streams it, Then sensitive values are redacted before provider boundaries.
User Story 2 - Serve Trace Investigation APIs (Priority: P1)
Studio and other authenticated diagnostics clients can query recent traces and retrieve a trace detail model with ordered spans, resource metadata, OTLP logs, and storage diagnostics.
Why this priority: Trace investigation is the main workflow troubleshooting path and must be backend-filtered before Studio renders a waterfall.
Independent Test: Seed or ingest telemetry for a workflow trace and call the trace search/detail APIs with filters for service, resource, trace ID, workflow instance ID, status, text, and time range.
Acceptance Scenarios:
- Given a trace contains workflow and activity spans, When a diagnostics client requests trace detail, Then Core returns parent/child span data ordered for a waterfall view.
- Given filters include workflow instance ID or trace ID, When trace search is executed, Then only matching trace summaries are returned.
- Given the caller lacks the OpenTelemetry diagnostics view permission, When the caller requests trace APIs or live updates, Then Core denies the request without exposing telemetry.
User Story 3 - Serve Metrics and OTLP Logs (Priority: P2)
An authenticated diagnostics client can inspect recent OpenTelemetry metric instruments, bounded metric points, OTLP log records, and overflow diagnostics.
Why this priority: Metrics and OTLP logs complement traces and validate that all OpenTelemetry signals are flowing.
Independent Test: Ingest metrics and OTLP logs for multiple resources, query them by resource, instrument, severity, trace/span ID, text, and time range, and verify capacity diagnostics.
Acceptance Scenarios:
- Given metrics are emitted by multiple services, When a client filters by resource or instrument, Then Core returns only matching bounded series.
- Given a metric has high-cardinality attributes, When capacity is exceeded, Then Core drops according to configured policy and reports dropped point counts.
- Given OTLP logs include trace/span IDs, When logs are queried by trace/span, Then Core returns correlated OTLP log records without merging them into
Elsa.Diagnostics.StructuredLogs.
User Story 4 - Expose Collector Configuration and Secure Ingestion (Priority: P3)
A developer can discover active collector endpoints and configure .NET or non-.NET senders using standard OTEL environment variables, while Core protects non-loopback ingestion.
Why this priority: Elsa does not own an Aspire-style launcher, so Core must make active collector configuration discoverable and secure.
Independent Test: Request collector configuration, verify HTTP metadata and nullable/disabled gRPC metadata, configure a sample sender, and verify non-loopback ingestion requires the configured API key header.
Acceptance Scenarios:
- Given the collector is enabled, When a diagnostics client requests collector configuration, Then Core returns HTTP endpoint metadata, any enabled gRPC endpoint metadata, required header names, and recommended non-secret environment variables.
- Given gRPC ingestion is unavailable, When configuration is requested, Then Core marks gRPC disabled instead of returning a misleading endpoint.
- Given OTLP ingestion is exposed beyond loopback, When a sender omits the required API key header, Then Core rejects the request.
Edge Cases
- OTLP payloads include unsupported future fields or incomplete resource attributes.
- Multiple services share
service.namebut have differentservice.instance.idvalues. - A trace arrives out of span order.
- Metrics create more series or points than configured capacity allows.
- Backend restarts and loses in-memory telemetry.
- OTLP logs reference trace/span IDs for traces that have expired.
- gRPC support is not available in the hosting configuration.
- The caller has Studio access but not the OpenTelemetry diagnostics permission.
- A sender posts from loopback while the collector is configured for loopback-only development.
- A sender posts from a non-loopback address without the configured ingestion API key header.
- A live client subscribes with filters that receive more updates than its per-connection queue allows.
- The historical
Elsa.OpenTelemetryextension package is present in another repository but must not be ported into this module.
Requirements (mandatory)
Functional Requirements
- FR-001: Core MUST introduce an opt-in module under
src/modules/Elsa.Diagnostics.OpenTelemetry. - FR-002: The module MUST be separate from
Elsa.Diagnostics.StructuredLogsandElsa.Diagnostics.ConsoleLogs. - FR-003: The module MUST use existing
Elsa.WorkflowsActivitySourceandMeterinstrumentation as the producer of Elsa workflow telemetry. - FR-004: The module MUST NOT port the historical
Elsa.OpenTelemetryproducer-side middleware fromelsa-extensionsin v1. - FR-005: The module MUST accept OTLP HTTP/protobuf traces, metrics, and logs.
- FR-006: The module SHOULD support OTLP gRPC ingestion when the host has gRPC support enabled; collector metadata MUST represent gRPC as disabled or null when unavailable.
- FR-007: HTTP and gRPC ingestion, when both are enabled, MUST feed one shared ingestion contract for normalization, redaction, storage, and live publishing.
- FR-008: The module MUST normalize telemetry into bounded queryable models for resources, traces, spans, metrics, and OTLP log records.
- FR-009: The default store MUST be bounded in memory and MUST report dropped telemetry counts.
- FR-010: Redaction MUST run before telemetry reaches provider storage or live subscribers.
- FR-011: Resource identity MUST use OpenTelemetry resource attributes, including service name and service instance ID when present.
- FR-012: Workflow and activity telemetry MUST preserve the existing
Elsa.Workflowssemantic attributes when present, includingworkflow.instance.id,workflow.definition.id,workflow.definition.version,workflow.definition.version.id,workflow.status,workflow.substatus,workflow.faulted,workflow.parent.instance.id,workflow.correlation.id,workflow.activity.id,workflow.activity.name,workflow.activity.type,workflow.activity.version,workflow.activity.execution.id,workflow.activity.status,workflow.activity.outcome,workflow.activity.parent.execution.id,workflow.activity.scheduled.by.execution.id,workflow.activity.faulted,elsa.tenant.id, andexception.type. - FR-013: The module MUST expose authenticated diagnostics APIs for resources, trace search, trace detail, metrics, OTLP logs, storage diagnostics, and collector configuration.
- FR-014: The module MUST expose live updates through an authenticated SignalR hub.
- FR-015: The module MUST enforce an OpenTelemetry diagnostics view permission for all diagnostics APIs and live connections.
- FR-016: Loopback-only development ingestion MAY run without an API key only for loopback requests while the collector is bound to loopback; any non-loopback request or non-loopback collector binding MUST require an explicit API key header or equivalent configured protection.
- FR-017: Collector configuration MUST expose standard OTEL environment variable metadata without exposing secret values.
- FR-018: The module MUST document that production deployments should generally export to an external OpenTelemetry Collector or observability backend unless Elsa collector capacity and security are deliberately configured.
- FR-019: OTLP logs MUST remain separate from
Elsa.Diagnostics.StructuredLogs; correlation uses trace/span IDs rather than shared storage. - FR-020: The module MUST include tests for ingestion, normalization, redaction, bounded storage, permissions, live updates, collector configuration, and end-to-end workflow export-to-collector timing.
- FR-021: In-memory storage defaults MUST be configurable and MUST start with bounded development defaults of at least 500 resources, 2,000 traces, 10,000 spans, 20,000 metric points, 10,000 OTLP log records, and 1,000 queued live updates per subscriber; when a capacity is exceeded, the oldest item in that signal-specific buffer is dropped and the relevant dropped count is incremented.
- FR-022: Search APIs MUST return deterministic, bounded result sets with caller-specified limits capped by server options; default ordering is newest receive time first for searches and parent/child chronological ordering for trace detail spans.
- FR-023: Live SignalR subscriptions MUST use bounded per-connection queues, update filters in place, drop oldest queued updates on overflow, and publish dropped-update diagnostics without disconnecting healthy subscribers.
- FR-024: The diagnostics module MUST NOT start new workflow or activity spans itself and MUST NOT mutate
Activity.Current; trace production remains owned by existingElsa.Workflows.Coreinstrumentation.
Key Entities
- Telemetry Resource: Resource/service identity derived from OTEL resource attributes.
- Telemetry Trace: Trace summary grouped by trace ID.
- Telemetry Span: Timed operation inside a trace with attributes, events, links, and status.
- Metric Instrument: Metric name, unit, description, type, resource, and bounded series.
- Metric Point: Recent data point for a metric series.
- OTLP Log Record: Log record received through OTLP and correlated by trace/span IDs.
- Collector Configuration: Active endpoint, protocol, security, and environment-variable metadata.
- Storage Diagnostics: Capacity and dropped telemetry counters.
- Telemetry Subscription: Live SignalR subscription with filters and connection state.
- Storage Capacity Policy: Configurable per-signal limits and drop-oldest overflow behavior for in-memory telemetry.
Success Criteria (mandatory)
Measurable Outcomes
- SC-001: A local Core host with OpenTelemetry diagnostics enabled receives workflow trace spans and exposes them through diagnostics APIs within 2 seconds of workflow execution.
- SC-002: Core accepts representative OTLP HTTP/protobuf traces, metrics, and logs from standard SDK payloads and returns normalized diagnostics models.
- SC-003: Trace detail APIs return at least 100 ordered spans for one trace without unbounded memory growth.
- SC-004: Metric APIs return at least 20 instruments and 1,000 recent points while honoring configured capacity.
- SC-005: Unauthorized API and hub calls are denied without exposing telemetry.
- SC-006: Sensitive configured attribute names and text patterns are redacted before stored telemetry is returned.
- SC-007: Collector configuration reports HTTP metadata, nullable/disabled gRPC metadata, and required header names accurately.
- SC-008: Capacity tests prove each signal-specific buffer drops oldest telemetry, increments dropped counts, and keeps queries bounded when defaults are exceeded.
- SC-009: SignalR tests prove subscriber overflow drops oldest queued live updates, reports dropped-update counts, and keeps the connection usable.
Assumptions
Elsa.Workflows.Corekeeps first-party workflow tracing and metrics instrumentation.- Durable OpenTelemetry persistence is a later provider feature.
- The Studio feature has its own spec in
elsa-studio/specs/008-diagnostics-otel. - Core and Studio contracts should remain aligned, but Core is the source of truth for ingestion, permissions, normalization, and API behavior.
- Default in-memory capacities are development-friendly starting points, not production sizing guidance.