elsa-core/src/modules/Elsa.Diagnostics.ConsoleLogs/Extensions/ServiceCollectionExtensions.cs
Sipke Schoorstra 8e301d4e1e
[codex] Scope console logs to workflow instances (#7535)
* 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
2026-05-25 11:49:51 +02:00

96 lines
3.9 KiB
C#

using Elsa.Diagnostics.ConsoleLogs.Contracts;
using Elsa.Diagnostics.ConsoleLogs.RealTime;
using Elsa.Diagnostics.ConsoleLogs.Services;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace Elsa.Diagnostics.ConsoleLogs.Extensions;
public static class ServiceCollectionExtensions
{
/// <summary>
/// Registers shell-level console-log consumers (SignalR, subscription manager) and exposes the
/// process-wide capture pipeline owned by <see cref="ConsoleLogsHost"/> through DI. Configuration
/// supplied here applies only if the host has not yet been initialized (first-wins). Prefer calling
/// <c>AddConsoleLogsHost</c> from <c>Program.cs</c> for deterministic host-level configuration.
/// </summary>
public static IServiceCollection AddConsoleLogsServices(this IServiceCollection services, Action<ConsoleLogsOptions>? configureOptions = null)
{
ConsoleStreamHook.Install();
var defaultProviderDescriptor = ServiceDescriptor.Singleton<IConsoleLogProvider>(_ => ConsoleLogsHost.Provider);
if (configureOptions != null)
ConsoleLogsHost.Configure(configureOptions);
services.TryAdd(defaultProviderDescriptor);
services.TryAddSingleton(new ConsoleLogsProviderRegistration(services, defaultProviderDescriptor));
ConsoleLogsProviderRegistration GetRegistration(IServiceProvider serviceProvider) =>
serviceProvider.GetRequiredService<ConsoleLogsProviderRegistration>();
void ConfigureCustomProvider(IServiceProvider serviceProvider) =>
GetRegistration(serviceProvider).ConfigureProvider(serviceProvider);
services.AddSignalR();
// Every shell resolves the same process-wide singletons — console output is a shared OS resource.
services.TryAddSingleton<IOptions<ConsoleLogsOptions>>(sp =>
{
if (GetRegistration(sp).TryGetHostOptions(out var options))
return options;
ConfigureCustomProvider(sp);
return ConsoleLogsHost.Options;
});
services.TryAddSingleton<IConsoleLogSourceRegistry>(sp =>
{
if (GetRegistration(sp).TryGetHostSourceRegistry(out var sourceRegistry))
return sourceRegistry;
ConfigureCustomProvider(sp);
return ConsoleLogsHost.SourceRegistry;
});
services.TryAddSingleton<IConsoleLogRedactor>(sp =>
{
if (GetRegistration(sp).TryGetHostRedactor(out var redactor))
return redactor;
ConfigureCustomProvider(sp);
return ConsoleLogsHost.Redactor;
});
services.TryAddSingleton(sp =>
{
if (GetRegistration(sp).TryGetHostFormatter(out var formatter))
return formatter;
ConfigureCustomProvider(sp);
return ConsoleLogsHost.Formatter;
});
services.TryAddSingleton(sp =>
{
if (GetRegistration(sp).TryGetHostScopeAccessor(out var scopeAccessor))
return scopeAccessor;
ConfigureCustomProvider(sp);
return ConsoleLogsHost.ScopeAccessor;
});
services.AddSingleton<ILoggerProvider>(sp =>
{
ConfigureCustomProvider(sp);
return ConsoleLogsHost.ScopeAccessor;
});
#pragma warning disable CS0618
services.TryAddSingleton<IConsoleLogCapture, ConsoleLogCaptureAdapter>();
#pragma warning restore CS0618
// The subscription manager wraps a per-shell SignalR hub context, so it must be per-shell.
services.TryAddSingleton<ConsoleLogSubscriptionManager>();
services.TryAddEnumerable(ServiceDescriptor.Singleton<IHostedService, ConsoleLogsHostedService>());
return services;
}
}