2026-05-25 09:49:51 +00:00
|
|
|
using Elsa.Diagnostics.ConsoleLogs.Contracts;
|
2026-05-18 00:16:46 +00:00
|
|
|
using Elsa.Diagnostics.ConsoleLogs.RealTime;
|
|
|
|
|
using Elsa.Diagnostics.ConsoleLogs.Services;
|
|
|
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
|
|
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
2026-05-25 09:49:51 +00:00
|
|
|
using Microsoft.Extensions.Hosting;
|
|
|
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
|
using Microsoft.Extensions.Options;
|
2026-05-18 00:16:46 +00:00
|
|
|
|
|
|
|
|
namespace Elsa.Diagnostics.ConsoleLogs.Extensions;
|
|
|
|
|
|
|
|
|
|
public static class ServiceCollectionExtensions
|
|
|
|
|
{
|
2026-05-25 09:49:51 +00:00
|
|
|
/// <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>
|
2026-05-18 00:16:46 +00:00
|
|
|
public static IServiceCollection AddConsoleLogsServices(this IServiceCollection services, Action<ConsoleLogsOptions>? configureOptions = null)
|
|
|
|
|
{
|
2026-05-25 09:49:51 +00:00
|
|
|
ConsoleStreamHook.Install();
|
|
|
|
|
var defaultProviderDescriptor = ServiceDescriptor.Singleton<IConsoleLogProvider>(_ => ConsoleLogsHost.Provider);
|
|
|
|
|
|
2026-05-18 00:16:46 +00:00
|
|
|
if (configureOptions != null)
|
2026-05-25 09:49:51 +00:00
|
|
|
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);
|
2026-05-18 00:16:46 +00:00
|
|
|
|
|
|
|
|
services.AddSignalR();
|
2026-05-25 09:49:51 +00:00
|
|
|
|
|
|
|
|
// 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.
|
2026-05-18 00:16:46 +00:00
|
|
|
services.TryAddSingleton<ConsoleLogSubscriptionManager>();
|
2026-05-25 09:49:51 +00:00
|
|
|
services.TryAddEnumerable(ServiceDescriptor.Singleton<IHostedService, ConsoleLogsHostedService>());
|
2026-05-18 00:16:46 +00:00
|
|
|
|
|
|
|
|
return services;
|
|
|
|
|
}
|
|
|
|
|
}
|