From b255e0b4c34fd3fa3781fb6c55a25d1e9ff71ee3 Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Wed, 13 May 2026 16:32:23 +0200 Subject: [PATCH] [codex] Expose structured log storage diagnostics (#7446) * Expose structured log storage diagnostics * Address structured log diagnostics review * Fix checked storage diagnostics aggregation --- .../quickstart.md | 1 + .../Contracts/IStructuredLogWriteBuffer.cs | 4 +--- ...ructuredLogsServiceCollectionExtensions.cs | 1 + .../README.md | 2 ++ .../IStructuredLogStorageDiagnostics.cs | 6 +++++ .../StructuredLogs/Storage/Endpoint.cs | 24 +++++++++++++++++++ .../Models/StructuredLogStorageDiagnostics.cs | 3 +++ .../Elsa.Diagnostics.StructuredLogs/README.md | 5 ++-- 8 files changed, 41 insertions(+), 5 deletions(-) create mode 100644 src/modules/Elsa.Diagnostics.StructuredLogs/Contracts/IStructuredLogStorageDiagnostics.cs create mode 100644 src/modules/Elsa.Diagnostics.StructuredLogs/Endpoints/StructuredLogs/Storage/Endpoint.cs create mode 100644 src/modules/Elsa.Diagnostics.StructuredLogs/Models/StructuredLogStorageDiagnostics.cs diff --git a/specs/005-structured-log-persistence/quickstart.md b/specs/005-structured-log-persistence/quickstart.md index 0ddbcb573..015dba342 100644 --- a/specs/005-structured-log-persistence/quickstart.md +++ b/specs/005-structured-log-persistence/quickstart.md @@ -46,6 +46,7 @@ Studio continues to use: - `/diagnostics/structured-logs/recent` - `/diagnostics/structured-logs/sources` +- `/diagnostics/structured-logs/storage` - `/elsa/hubs/diagnostics/structured-logs` ## Migrations diff --git a/src/modules/Elsa.Diagnostics.StructuredLogs.Persistence.Relational/Contracts/IStructuredLogWriteBuffer.cs b/src/modules/Elsa.Diagnostics.StructuredLogs.Persistence.Relational/Contracts/IStructuredLogWriteBuffer.cs index 791d2631e..671f66666 100644 --- a/src/modules/Elsa.Diagnostics.StructuredLogs.Persistence.Relational/Contracts/IStructuredLogWriteBuffer.cs +++ b/src/modules/Elsa.Diagnostics.StructuredLogs.Persistence.Relational/Contracts/IStructuredLogWriteBuffer.cs @@ -2,9 +2,7 @@ using Elsa.Diagnostics.StructuredLogs.Contracts; namespace Elsa.Diagnostics.StructuredLogs.Persistence.Relational.Contracts; -public interface IStructuredLogWriteBuffer : IStructuredLogSink +public interface IStructuredLogWriteBuffer : IStructuredLogSink, IStructuredLogStorageDiagnostics { - long DroppedWriteCount { get; } - ValueTask FlushAsync(CancellationToken cancellationToken = default); } diff --git a/src/modules/Elsa.Diagnostics.StructuredLogs.Persistence.Relational/Extensions/RelationalStructuredLogsServiceCollectionExtensions.cs b/src/modules/Elsa.Diagnostics.StructuredLogs.Persistence.Relational/Extensions/RelationalStructuredLogsServiceCollectionExtensions.cs index 6e9e90a9a..1cccfe199 100644 --- a/src/modules/Elsa.Diagnostics.StructuredLogs.Persistence.Relational/Extensions/RelationalStructuredLogsServiceCollectionExtensions.cs +++ b/src/modules/Elsa.Diagnostics.StructuredLogs.Persistence.Relational/Extensions/RelationalStructuredLogsServiceCollectionExtensions.cs @@ -23,6 +23,7 @@ public static class RelationalStructuredLogsServiceCollectionExtensions services.TryAddSingleton(); services.AddSingleton(sp => sp.GetRequiredService()); services.AddSingleton(sp => sp.GetRequiredService()); + services.AddSingleton(sp => sp.GetRequiredService()); services.AddHostedService(sp => sp.GetRequiredService()); return services; diff --git a/src/modules/Elsa.Diagnostics.StructuredLogs.Persistence.Relational/README.md b/src/modules/Elsa.Diagnostics.StructuredLogs.Persistence.Relational/README.md index c9673ab4d..62981e232 100644 --- a/src/modules/Elsa.Diagnostics.StructuredLogs.Persistence.Relational/README.md +++ b/src/modules/Elsa.Diagnostics.StructuredLogs.Persistence.Relational/README.md @@ -11,3 +11,5 @@ To add a new relational provider such as SQL Server or PostgreSQL: 5. Register those services and call `AddRelationalStructuredLogPersistence`. The core `Elsa.Diagnostics.StructuredLogs` package must remain unaware of provider packages. Provider-specific SQL and migration runner dependencies belong in provider packages. + +`StructuredLogWriteBuffer` reports dropped durable writes through the core `IStructuredLogStorageDiagnostics` contract. The core endpoint `GET /diagnostics/structured-logs/storage` returns that provider-neutral count for Studio and other diagnostics clients. diff --git a/src/modules/Elsa.Diagnostics.StructuredLogs/Contracts/IStructuredLogStorageDiagnostics.cs b/src/modules/Elsa.Diagnostics.StructuredLogs/Contracts/IStructuredLogStorageDiagnostics.cs new file mode 100644 index 000000000..4c9b16d51 --- /dev/null +++ b/src/modules/Elsa.Diagnostics.StructuredLogs/Contracts/IStructuredLogStorageDiagnostics.cs @@ -0,0 +1,6 @@ +namespace Elsa.Diagnostics.StructuredLogs.Contracts; + +public interface IStructuredLogStorageDiagnostics +{ + long DroppedWriteCount { get; } +} diff --git a/src/modules/Elsa.Diagnostics.StructuredLogs/Endpoints/StructuredLogs/Storage/Endpoint.cs b/src/modules/Elsa.Diagnostics.StructuredLogs/Endpoints/StructuredLogs/Storage/Endpoint.cs new file mode 100644 index 000000000..382d035b4 --- /dev/null +++ b/src/modules/Elsa.Diagnostics.StructuredLogs/Endpoints/StructuredLogs/Storage/Endpoint.cs @@ -0,0 +1,24 @@ +using Elsa.Abstractions; +using Elsa.Diagnostics.StructuredLogs.Contracts; +using Elsa.Diagnostics.StructuredLogs.Models; +using Elsa.Diagnostics.StructuredLogs.Permissions; +using JetBrains.Annotations; + +namespace Elsa.Diagnostics.StructuredLogs.Endpoints.StructuredLogs.Storage; + +[PublicAPI] +internal class Endpoint(IEnumerable storageDiagnostics) : ElsaEndpointWithoutRequest +{ + public override void Configure() + { + Get("/diagnostics/structured-logs/storage"); + ConfigurePermissions(StructuredLogsPermissions.Read); + } + + public override Task ExecuteAsync(CancellationToken cancellationToken) + { + var diagnostics = storageDiagnostics.ToList(); + var droppedWriteCount = diagnostics.Aggregate(0L, (acc, x) => checked(acc + x.DroppedWriteCount)); + return Task.FromResult(new StructuredLogStorageDiagnostics(droppedWriteCount, diagnostics.Count > 0)); + } +} diff --git a/src/modules/Elsa.Diagnostics.StructuredLogs/Models/StructuredLogStorageDiagnostics.cs b/src/modules/Elsa.Diagnostics.StructuredLogs/Models/StructuredLogStorageDiagnostics.cs new file mode 100644 index 000000000..80f45107b --- /dev/null +++ b/src/modules/Elsa.Diagnostics.StructuredLogs/Models/StructuredLogStorageDiagnostics.cs @@ -0,0 +1,3 @@ +namespace Elsa.Diagnostics.StructuredLogs.Models; + +public record StructuredLogStorageDiagnostics(long DroppedWriteCount, bool HasStorageDiagnosticsProvider); diff --git a/src/modules/Elsa.Diagnostics.StructuredLogs/README.md b/src/modules/Elsa.Diagnostics.StructuredLogs/README.md index 5b7b6193c..c6f735146 100644 --- a/src/modules/Elsa.Diagnostics.StructuredLogs/README.md +++ b/src/modules/Elsa.Diagnostics.StructuredLogs/README.md @@ -30,7 +30,7 @@ This maps the structured logs hub at `/elsa/hubs/diagnostics/structured-logs` an ## Authorization -The recent-log endpoint and source-list endpoint require the `read:diagnostics:structured-logs` permission. The SignalR hub requires an authenticated user, matching the existing Elsa workflow hub authorization pattern. Grant `read:diagnostics:structured-logs` only to operators and developers who are allowed to inspect backend logs. +The recent-log endpoint, source-list endpoint, and storage-diagnostics endpoint require the `read:diagnostics:structured-logs` permission. The SignalR hub requires an authenticated user, matching the existing Elsa workflow hub authorization pattern. Grant `read:diagnostics:structured-logs` only to operators and developers who are allowed to inspect backend logs. ## Studio Integration @@ -40,6 +40,7 @@ Elsa Studio can use this module to show: - Live log events as the server emits them. - Level, category, message, tenant, workflow, trace, correlation, source, and time filters. - Cluster/source metadata such as source ID, pod name, namespace, container name, node name, machine name, process ID, and source health. +- Storage pressure metadata such as dropped durable write counts and whether the active store reports storage diagnostics. ## Clustered Deployments @@ -57,7 +58,7 @@ services.AddElsa(elsa => }); ``` -The core module remains storage-provider neutral. Custom stores can replace `IStructuredLogStore` while live updates continue through `IStructuredLogLiveFeed`; Studio continues to use the same REST and SignalR contracts, including source filtering and source-change notifications. +The core module remains storage-provider neutral. Custom stores can replace `IStructuredLogStore` while live updates continue through `IStructuredLogLiveFeed`; Studio continues to use the same REST and SignalR contracts, including source filtering, source-change notifications, and storage diagnostics. ## Redaction