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 { /// /// Registers shell-level console-log consumers (SignalR, subscription manager) and exposes the /// process-wide capture pipeline owned by through DI. Configuration /// supplied here applies only if the host has not yet been initialized (first-wins). Prefer calling /// AddConsoleLogsHost from Program.cs for deterministic host-level configuration. /// public static IServiceCollection AddConsoleLogsServices(this IServiceCollection services, Action? configureOptions = null) { ConsoleStreamHook.Install(); var defaultProviderDescriptor = ServiceDescriptor.Singleton(_ => ConsoleLogsHost.Provider); if (configureOptions != null) ConsoleLogsHost.Configure(configureOptions); services.TryAdd(defaultProviderDescriptor); services.TryAddSingleton(new ConsoleLogsProviderRegistration(services, defaultProviderDescriptor)); ConsoleLogsProviderRegistration GetRegistration(IServiceProvider serviceProvider) => serviceProvider.GetRequiredService(); 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>(sp => { if (GetRegistration(sp).TryGetHostOptions(out var options)) return options; ConfigureCustomProvider(sp); return ConsoleLogsHost.Options; }); services.TryAddSingleton(sp => { if (GetRegistration(sp).TryGetHostSourceRegistry(out var sourceRegistry)) return sourceRegistry; ConfigureCustomProvider(sp); return ConsoleLogsHost.SourceRegistry; }); services.TryAddSingleton(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(sp => { ConfigureCustomProvider(sp); return ConsoleLogsHost.ScopeAccessor; }); #pragma warning disable CS0618 services.TryAddSingleton(); #pragma warning restore CS0618 // The subscription manager wraps a per-shell SignalR hub context, so it must be per-shell. services.TryAddSingleton(); services.TryAddEnumerable(ServiceDescriptor.Singleton()); return services; } }