Skip to content

[codex] Add Studio server logs module#810

Merged
sfmskywalker merged 16 commits into
mainfrom
003-live-server-logs
May 10, 2026
Merged

[codex] Add Studio server logs module#810
sfmskywalker merged 16 commits into
mainfrom
003-live-server-logs

Conversation

@sfmskywalker
Copy link
Copy Markdown
Member

Summary

Adds an Elsa.Studio.ServerLogs module that lets operators inspect backend server logs from Studio. The module loads recent logs through the backend API, opens an authenticated SignalR subscription for live updates, and provides a dense operational log viewer with filters, source selection, copy actions, and workflow-instance deep links.

Highlights

  • Adds the Server Logs module, feature registration, menu item, route, models, backend client, service, SignalR observer, and page UI.
  • Adds filters for level, text, category, workflow instance, tenant, trace/correlation, time, and source.
  • Supports merged clustered views plus source-specific focus for pods/processes/containers.
  • Adds source health indicators, source-change handling, local row caps, pause/resume, reconnect, clear, auto-scroll, wrapping, compact mode, and copy selected/visible rows.
  • Adds workflow instance viewer link to /server-logs?workflowInstanceId=....
  • Adds README and Spec Kit updates.

Validation

  • dotnet build src/modules/Elsa.Studio.ServerLogs/Elsa.Studio.ServerLogs.csproj --no-restore --nologo -v:minimal passed.
  • dotnet test src/modules/Elsa.Studio.ServerLogs.Tests/Elsa.Studio.ServerLogs.Tests.csproj --nologo -v:minimal passed, 5 tests.
  • Earlier full dotnet build Elsa.Studio.sln --no-restore passed after restore.

Existing framework warnings remain in shared Studio projects, including XML documentation, trim analyzer, nullable, and MudBlazor analyzer warnings.

Copy link
Copy Markdown
Member Author

Paired Core PR: elsa-workflows/elsa-core#7438

@sfmskywalker sfmskywalker requested a review from Copilot May 8, 2026 13:23
@sfmskywalker sfmskywalker marked this pull request as ready for review May 8, 2026 13:23
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 8, 2026

Greptile Summary

This PR adds a new Elsa.Studio.ServerLogs module that streams live backend log events into Studio via SignalR, with a rich filter bar, source selector, pause/resume, row-cap enforcement, and a deep-link from the workflow instance panel. The module is wired into both the Server and WASM hosts and ships with five unit tests for the filter mapper.

  • New module \u2014 feature registration, DI wiring, Refit API client, SignalR observer, Blazor page with toolbar/filters/log surface, and scoped CSS.
  • Workflow integration \u2014 WorkflowInstanceDetails gains a "Server Logs" panel entry that links to /server-logs?workflowInstanceId=\u2026.
  • Key defect \u2014 SignalRServerLogObserver.StartAsync catches UnauthorizedAccessException to detect 401 responses, but SignalR throws HttpRequestException (with StatusCode = Unauthorized) instead; the unauthorized state is therefore never reachable and a backend 401 surfaces as a generic error.

Confidence Score: 3/5

Safe to merge in environments where the hub never returns 401, but the unauthorized path is broken and will produce confusing error messages when auth is enforced.

The SignalR observer catches UnauthorizedAccessException to handle hub 401s, but SignalR raises HttpRequestException with Unauthorized status code instead. Any backend enforcing read:server-logs permission will surface a raw exception rather than the intended access-denied UI. This is the auth entry-point for the entire live-streaming feature.

src/modules/Elsa.Studio.ServerLogs/Services/SignalRServerLogObserver.cs — incorrect exception type for 401 handling in StartAsync.

Important Files Changed

Filename Overview
src/modules/Elsa.Studio.ServerLogs/Services/SignalRServerLogObserver.cs SignalR live log observer; catches the wrong exception type for 401 so the Unauthorized state is never set when the hub rejects the connection.
src/modules/Elsa.Studio.ServerLogs/UI/Pages/ServerLogs.razor.cs Main page code-behind; HasActiveFilter always true on load due to non-null default MinimumLevel, and scroll uses eval unnecessarily. Otherwise solid lifecycle and filter management.
src/modules/Elsa.Studio.ServerLogs/Services/RemoteServerLogService.cs HTTP client wrapper for recent logs and sources; gracefully handles 404 and delegates to filter mapper. Looks correct.
src/modules/Elsa.Studio.ServerLogs/Services/ServerLogFilterMapper.cs Stateless filter copier; correctly clamps Take and deep-copies the Levels collection to prevent aliasing.
src/modules/Elsa.Studio.ServerLogs/UI/Pages/ServerLogs.razor Razor template for the log viewer; toolbar, filters, row rendering, and exception display all look correct.
src/modules/Elsa.Studio.ServerLogs.Tests/ServerLogFilterMapperTests.cs Five unit tests covering field mapping, Take clamping, defaults, and Levels copy isolation — all correct.
src/modules/Elsa.Studio.Workflows/Components/WorkflowInstanceViewer/Components/WorkflowInstanceDetails.razor.cs Adds a deep-link from the workflow instance panel to the server logs page with the instance ID URL-encoded; straightforward and correct.
src/modules/Elsa.Studio.ServerLogs/Extensions/ServiceCollectionExtensions.cs DI registration for feature, menu, service, and observer — all scoped, no issues.

Sequence Diagram

sequenceDiagram
    participant Page as ServerLogs Page
    participant SLS as RemoteServerLogService
    participant Obs as SignalRServerLogObserver
    participant API as Backend REST API
    participant Hub as Backend SignalR Hub

    Page->>SLS: ListSourcesAsync()
    SLS->>API: GET /server-logs/sources
    API-->>SLS: sources list
    SLS-->>Page: sources

    Page->>SLS: GetRecentAsync(filter, rowCap)
    SLS->>API: POST /server-logs/recent
    API-->>SLS: RecentServerLogsResult
    SLS-->>Page: recent logs

    Page->>Obs: StartAsync(filter)
    Obs->>Hub: HubConnection.StartAsync()
    Obs->>Hub: SendAsync SubscribeAsync
    Hub-->>Obs: ReceiveLogEventAsync
    Obs-->>Page: LogReceived event
    Hub-->>Obs: ReceiveDroppedEventsAsync
    Obs-->>Page: DroppedEventsReceived event

    Page->>Obs: DisposeAsync()
    Obs->>Hub: SendAsync UnsubscribeAsync
    Obs->>Hub: StopAsync and DisposeAsync
Loading
Prompt To Fix All With AI
Fix the following 3 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 3
src/modules/Elsa.Studio.ServerLogs/Services/SignalRServerLogObserver.cs:55-58
**Wrong exception type for 401 Unauthorized**

SignalR's `HubConnection.StartAsync()` does not throw `UnauthorizedAccessException` on an HTTP 401 response — it throws `HttpRequestException` with `StatusCode = HttpStatusCode.Unauthorized`. This catch block will never fire, so a 401 from the hub endpoint will propagate as an unhandled exception and surface as a generic `ErrorMessage` on the page rather than setting the `Unauthorized` connection state. The fix is to match the existing 404 pattern and catch `HttpRequestException e when (e.StatusCode is HttpStatusCode.Unauthorized)`.

### Issue 2 of 3
src/modules/Elsa.Studio.ServerLogs/UI/Pages/ServerLogs.razor.cs:104
`HasActiveFilter` always true on initial load due to non-null default `MinimumLevel`

`ServerLogFilter.MinimumLevel` defaults to `ServerLogLevel.Information` (not `null`), so `HasActiveFilter` evaluates to `true` the moment the page opens. This means the empty-state message will always read "No server logs match the current filters" on first load, even before the user touches any filter — the intended message "No server logs received yet" is never shown.

```suggestion
    protected bool HasActiveFilter => !string.IsNullOrWhiteSpace(ViewState.Filter.SourceId) || (ViewState.Filter.MinimumLevel != null && ViewState.Filter.MinimumLevel != ServerLogLevel.Information) || !string.IsNullOrWhiteSpace(ViewState.Filter.Text) || !string.IsNullOrWhiteSpace(ViewState.Filter.WorkflowInstanceId);
```

### Issue 3 of 3
src/modules/Elsa.Studio.ServerLogs/UI/Pages/ServerLogs.razor.cs:380
`eval` used for scroll — unnecessary and fragile

Calling `eval` via JS interop is unnecessary; `scrollTo` can be invoked directly on the element via a lambda. While `LogSurfaceId` is a compile-time constant so there is no injection risk today, using `eval` conflicts with strict CSP policies and makes JS calls harder to audit.

```suggestion
            await JS.InvokeVoidAsync("(id) => { const el = document.getElementById(id); if (el) el.scrollTo({ top: el.scrollHeight }); }", LogSurfaceId);
```

Reviews (1): Last reviewed commit: "Merge branch 'main' into 003-live-server..." | Re-trigger Greptile

Comment thread src/modules/Elsa.Studio.ServerLogs/Services/SignalRServerLogObserver.cs Outdated
Comment thread src/modules/Elsa.Studio.ServerLogs/UI/Pages/ServerLogs.razor.cs Outdated
Comment thread src/modules/Elsa.Studio.ServerLogs/UI/Pages/ServerLogs.razor.cs Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new Elsa.Studio.ServerLogs module to Elsa Studio, enabling operators to view recent backend log events and subscribe to live log updates via SignalR, with filtering and basic operational controls. The PR also introduces accompanying specifications/Spec Kit workflow assets and wires the module into the bundled/hosted Studio applications.

Changes:

  • Introduce Elsa.Studio.ServerLogs module (models, API client, services, SignalR observer, UI page, menu integration, DI registration).
  • Add workflow-instance deep link to open Server Logs pre-filtered by workflowInstanceId.
  • Add Spec Kit specs/tasks/templates/scripts and include new test packages + a small xUnit test project for filter mapping.

Reviewed changes

Copilot reviewed 103 out of 103 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
src/modules/Elsa.Studio.Workflows/Components/WorkflowInstanceViewer/Components/WorkflowInstanceDetails.razor.cs Adds a Server Logs deep link from workflow instance details.
src/modules/Elsa.Studio.ServerLogs/UI/Pages/ServerLogs.razor.css Styles for the dense log viewer surface and rows.
src/modules/Elsa.Studio.ServerLogs/UI/Pages/ServerLogs.razor Server Logs page markup (toolbar, filters, rows, empty/error states).
src/modules/Elsa.Studio.ServerLogs/UI/Pages/ServerLogs.razor.cs Page state management, REST backfill, live subscription handling, URL syncing, copy/scroll behaviors.
src/modules/Elsa.Studio.ServerLogs/Services/SignalRServerLogObserver.cs SignalR client connection lifecycle + event dispatch for live logs.
src/modules/Elsa.Studio.ServerLogs/Services/ServerLogFilterMapper.cs Maps UI filter state to REST/live subscription filters; clamps take for backfill.
src/modules/Elsa.Studio.ServerLogs/Services/RemoteServerLogService.cs Refit-backed service for recent logs and source listing.
src/modules/Elsa.Studio.ServerLogs/README.md Module setup + backend requirements + operator workflow docs.
src/modules/Elsa.Studio.ServerLogs/Models/ServerLogViewState.cs Stores local UI state (filter, caps, toggles, connection status).
src/modules/Elsa.Studio.ServerLogs/Models/ServerLogSourceStatus.cs Source health enum.
src/modules/Elsa.Studio.ServerLogs/Models/ServerLogSource.cs Source metadata model.
src/modules/Elsa.Studio.ServerLogs/Models/ServerLogLevel.cs Log level enum used by UI/API.
src/modules/Elsa.Studio.ServerLogs/Models/ServerLogFilter.cs Filter model for REST and live subscriptions.
src/modules/Elsa.Studio.ServerLogs/Models/ServerLogException.cs Exception payload model for log events.
src/modules/Elsa.Studio.ServerLogs/Models/ServerLogEvent.cs Log event model including source + workflow/tenant metadata.
src/modules/Elsa.Studio.ServerLogs/Models/ServerLogDroppedEventSummary.cs Model for backpressure/dropped event summaries.
src/modules/Elsa.Studio.ServerLogs/Models/ServerLogConnectionStatus.cs Connection state enum for UI messaging.
src/modules/Elsa.Studio.ServerLogs/Models/RecentServerLogsResult.cs DTO for backfill results + dropped count.
src/modules/Elsa.Studio.ServerLogs/Menu/ServerLogsMenu.cs Adds Server Logs menu entry.
src/modules/Elsa.Studio.ServerLogs/Feature.cs Declares a remote-feature-gated module feature (Elsa.ServerLogStreaming).
src/modules/Elsa.Studio.ServerLogs/Extensions/ServiceCollectionExtensions.cs Registers module services (feature, menu, service, observer).
src/modules/Elsa.Studio.ServerLogs/Elsa.Studio.ServerLogs.csproj New Razor SDK module project + SignalR/WebUtilities refs.
src/modules/Elsa.Studio.ServerLogs/Contracts/IServerLogService.cs Contract for backfill + source list.
src/modules/Elsa.Studio.ServerLogs/Contracts/IServerLogObserver.cs Contract for live observer (start/update/reconnect + events).
src/modules/Elsa.Studio.ServerLogs/Client/IServerLogsApi.cs Refit API contract for /server-logs/* endpoints.
src/modules/Elsa.Studio.ServerLogs/_Imports.razor Razor imports for the new module.
src/modules/Elsa.Studio.ServerLogs.Tests/ServerLogFilterMapperTests.cs Unit tests for filter mapping/clamping behavior.
src/modules/Elsa.Studio.ServerLogs.Tests/Elsa.Studio.ServerLogs.Tests.csproj New xUnit test project referencing the module.
src/hosts/Elsa.Studio.Host.Wasm/Program.cs Registers the Server Logs module in the WASM host.
src/hosts/Elsa.Studio.Host.Server/Program.cs Registers the Server Logs module in the Server host.
src/bundles/Elsa.Studio/Elsa.Studio.csproj Bundles the Server Logs module by default.
specs/003-live-server-logs/tasks.md Feature task breakdown for the Server Logs module.
specs/003-live-server-logs/spec.md Feature specification (stories, FRs/SCs, edge cases).
specs/003-live-server-logs/research.md Design decisions and rationale.
specs/003-live-server-logs/quickstart.md Quickstart validation steps.
specs/003-live-server-logs/plan.md Implementation plan + constitution check evidence.
specs/003-live-server-logs/data-model.md Data model definitions and invariants.
specs/003-live-server-logs/contracts/signalr-client.md SignalR client contract documentation.
specs/003-live-server-logs/contracts/backend-client.md REST client contract documentation.
specs/003-live-server-logs/checklists/requirements.md Requirements checklist for the feature.
Elsa.Studio.sln Adds the new module + test project to the solution; adjusts VS version line.
Directory.Packages.props Adds central package versions for xUnit + test SDK.
AGENTS.md Adds Spec Kit marker block for agent context.
.specify/workflows/workflow-registry.json Registers bundled workflow metadata.
.specify/workflows/speckit/workflow.yml Adds the Speckit workflow definition (gates + steps).
.specify/templates/tasks-template.md Adds/updates tasks template.
.specify/templates/spec-template.md Adds/updates spec template.
.specify/templates/plan-template.md Adds/updates plan template.
.specify/templates/constitution-template.md Adds constitution template.
.specify/templates/checklist-template.md Adds checklist template.
.specify/scripts/bash/setup-tasks.sh Adds tasks setup helper script.
.specify/scripts/bash/setup-plan.sh Adds plan setup helper script.
.specify/scripts/bash/check-prerequisites.sh Adds consolidated prerequisites checker script.
.specify/memory/constitution.md Adds Elsa Studio constitution used by Spec Kit.
.specify/integrations/speckit.manifest.json Records speckit integration manifest/version.
.specify/integrations/codex.manifest.json Records codex integration manifest/version.
.specify/integration.json Configures the default Spec Kit integration.
.specify/init-options.json Records Spec Kit init options.
.specify/extensions/git/scripts/powershell/initialize-repo.ps1 Git extension script (PowerShell) for repo init.
.specify/extensions/git/scripts/powershell/git-common.ps1 Git extension shared utilities (PowerShell).
.specify/extensions/git/scripts/powershell/auto-commit.ps1 Git extension auto-commit hook (PowerShell).
.specify/extensions/git/scripts/bash/initialize-repo.sh Git extension script (Bash) for repo init.
.specify/extensions/git/scripts/bash/git-common.sh Git extension shared utilities (Bash).
.specify/extensions/git/scripts/bash/auto-commit.sh Git extension auto-commit hook (Bash).
.specify/extensions/git/README.md Documentation for the git extension behavior/config.
.specify/extensions/git/git-config.yml Default git extension configuration.
.specify/extensions/git/extension.yml Git extension manifest (hooks/commands).
.specify/extensions/git/config-template.yml Git extension config template.
.specify/extensions/git/commands/speckit.git.validate.md Command doc: validate feature branch naming.
.specify/extensions/git/commands/speckit.git.remote.md Command doc: detect git remote.
.specify/extensions/git/commands/speckit.git.initialize.md Command doc: initialize git repo.
.specify/extensions/git/commands/speckit.git.feature.md Command doc: create feature branch.
.specify/extensions/git/commands/speckit.git.commit.md Command doc: auto-commit hook behavior.
.specify/extensions/.registry Registers extensions and their command bindings.
.specify/extensions.yml Enables git extension hooks in Spec Kit.
.github/prompts/speckit.git.validate.prompt.md Prompt stub for git validate agent.
.github/prompts/speckit.git.remote.prompt.md Prompt stub for git remote agent.
.github/prompts/speckit.git.initialize.prompt.md Prompt stub for git initialize agent.
.github/prompts/speckit.git.feature.prompt.md Prompt stub for git feature agent.
.github/prompts/speckit.git.commit.prompt.md Prompt stub for git commit agent.
.github/agents/speckit.git.validate.agent.md Agent definition for git validate.
.github/agents/speckit.git.remote.agent.md Agent definition for git remote.
.github/agents/speckit.git.initialize.agent.md Agent definition for git initialize.
.github/agents/speckit.git.feature.agent.md Agent definition for git feature.
.github/agents/speckit.git.commit.agent.md Agent definition for git commit.
.agents/skills/speckit-taskstoissues/SKILL.md Skill: convert tasks into GitHub issues.
.agents/skills/speckit-tasks/SKILL.md Skill: generate tasks.md from spec/plan artifacts.
.agents/skills/speckit-plan/SKILL.md Skill: create plan/research/contracts artifacts.
.agents/skills/speckit-implement/SKILL.md Skill: implement tasks.md step-by-step.
.agents/skills/speckit-git-validate/SKILL.md Skill wrapper for git validate command doc.
.agents/skills/speckit-git-remote/SKILL.md Skill wrapper for git remote command doc.
.agents/skills/speckit-git-initialize/SKILL.md Skill wrapper for git initialize command doc.
.agents/skills/speckit-git-feature/SKILL.md Skill wrapper for git feature command doc.
.agents/skills/speckit-git-commit/SKILL.md Skill wrapper for git commit command doc.
.agents/skills/speckit-constitution/SKILL.md Skill: update constitution + propagate into templates.
.agents/skills/speckit-clarify/SKILL.md Skill: ask/record targeted spec clarifications.
.agents/skills/speckit-analyze/SKILL.md Skill: read-only cross-artifact consistency analysis.

Comment thread src/modules/Elsa.Studio.ServerLogs/UI/Pages/ServerLogs.razor Outdated
Comment thread src/modules/Elsa.Studio.ServerLogs/UI/Pages/ServerLogs.razor Outdated
Comment thread src/modules/Elsa.Studio.ServerLogs/UI/Pages/ServerLogs.razor.cs Outdated
Comment thread src/modules/Elsa.Studio.ServerLogs/UI/Pages/ServerLogs.razor.cs Outdated
Comment thread src/modules/Elsa.Studio.ServerLogs/UI/Pages/ServerLogs.razor.cs Outdated
Comment thread src/modules/Elsa.Studio.ServerLogs/Menu/ServerLogsMenu.cs Outdated
Comment thread src/modules/Elsa.Studio.ServerLogs/Services/SignalRServerLogObserver.cs Outdated
* Specify diagnostics structured logs Studio module

* Clarify diagnostics structured logs spec

* Plan diagnostics structured logs refactor

* Create diagnostics structured logs tasks

* Refactor Studio server logs to structured diagnostics

* Record diagnostics structured logs verification

* Update Studio branding version to 3.8

* Update RemoteFeature name and simplify StructuredLogsMenu logic

* Fix structured logs response contract
@sfmskywalker sfmskywalker merged commit 310fa9e into main May 10, 2026
6 checks passed
@sfmskywalker sfmskywalker deleted the 003-live-server-logs branch May 10, 2026 22:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants