diff --git a/EonaCat.LogStack/EonaCat.LogStack.csproj b/EonaCat.LogStack/EonaCat.LogStack.csproj
index f7328d2..f4dbdde 100644
--- a/EonaCat.LogStack/EonaCat.LogStack.csproj
+++ b/EonaCat.LogStack/EonaCat.LogStack.csproj
@@ -14,7 +14,7 @@ It features a rich fluent API for routing log events to dozens of destinations f
EonaCat (Jeroen Saey)
EonaCat;Logger;EonaCatLogStack;Log;Writer;Flows;LogStack;Memory;Speed;Jeroen;Saey
- 0.0.6
+ 0.0.7
README.md
True
LICENSE
@@ -25,7 +25,7 @@ It features a rich fluent API for routing log events to dozens of destinations f
- 0.0.6+{chash:10}.{c:ymd}
+ 0.0.7+{chash:10}.{c:ymd}
true
true
v[0-9]*
diff --git a/EonaCat.LogStack/EonaCatLogger.cs b/EonaCat.LogStack/EonaCatLogger.cs
index f6f2065..594bdbc 100644
--- a/EonaCat.LogStack/EonaCatLogger.cs
+++ b/EonaCat.LogStack/EonaCatLogger.cs
@@ -178,15 +178,51 @@ namespace EonaCat.LogStack
ProcessLogEvent(ref builder);
}
- [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Trace(string message) => Log(LogLevel.Trace, message);
- [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Debug(string message) => Log(LogLevel.Debug, message);
- [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Information(string message) => Log(LogLevel.Information, message);
- [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Warning(string message) => Log(LogLevel.Warning, message);
- [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Warning(Exception ex, string message) => Log(LogLevel.Warning, ex, message);
- [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Error(string message) => Log(LogLevel.Error, message);
- [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Error(Exception ex, string message) => Log(LogLevel.Error, ex, message);
- [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Critical(string message) => Log(LogLevel.Critical, message);
- [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Critical(Exception ex, string message) => Log(LogLevel.Critical, ex, message);
+ private void Write(LogLevel level, string template, params object[] args)
+ {
+ Log(level, string.Format(template, args));
+ }
+
+ private void Write(LogLevel level, Exception ex, string template, params object[] args)
+ {
+ Log(level, ex, string.Format(template, args));
+ }
+
+ public void Trace(string template, params object[] args) => Write(LogLevel.Trace, template, args);
+
+ public void Debug(string template, params object[] args) => Write(LogLevel.Debug, template, args);
+
+ public void Information(string template, params object[] args) => Write(LogLevel.Information, template, args);
+
+ public void Warning(string template, params object[] args) => Write(LogLevel.Warning, template, args);
+
+ public void Warning(Exception ex, string template, params object[] args) => Write(LogLevel.Warning, ex, template, args);
+
+ public void Error(string template, params object[] args) => Write(LogLevel.Error, template, args);
+
+ public void Error(Exception ex, string template, params object[] args) => Write(LogLevel.Error, ex, template, args);
+
+ public void Critical(string template, params object[] args) => Write(LogLevel.Critical, template, args);
+
+ public void Critical(Exception ex, string template, params object[] args) => Write(LogLevel.Critical, ex, template, args);
+
+ public void LogTrace(string template, params object[] args) => Write(LogLevel.Trace, template, args);
+
+ public void LogDebug(string template, params object[] args) => Write(LogLevel.Debug, template, args);
+
+ public void LogInformation(string template, params object[] args) => Write(LogLevel.Information, template, args);
+
+ public void LogWarning(string template, params object[] args) => Write(LogLevel.Warning, template, args);
+
+ public void LogWarning(Exception ex, string template, params object[] args) => Write(LogLevel.Warning, ex, template, args);
+
+ public void LogError(string template, params object[] args) => Write(LogLevel.Error, template, args);
+
+ public void LogError(Exception ex, string template, params object[] args) => Write(LogLevel.Error, ex, template, args);
+
+ public void LogCritical(string template, params object[] args) => Write(LogLevel.Critical, template, args);
+
+ public void LogCritical(Exception ex, string template, params object[] args) => Write(LogLevel.Critical, ex, template, args);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ProcessLogEvent(ref LogEventBuilder builder)
diff --git a/EonaCat.LogStack/EonaCatLoggerCore/ILogger.cs b/EonaCat.LogStack/EonaCatLoggerCore/ILogger.cs
new file mode 100644
index 0000000..892e70e
--- /dev/null
+++ b/EonaCat.LogStack/EonaCatLoggerCore/ILogger.cs
@@ -0,0 +1,43 @@
+using EonaCat.LogStack.Core;
+using System;
+
+namespace EonaCat.LogStack.Logging;
+
+// This file is part of the EonaCat project(s) which is released under the Apache License.
+// See the LICENSE file or go to https://EonaCat.com/License for full license details.
+
+///
+/// Adapter interface that wraps EonaCatLogStack to be compatible with Microsoft.Extensions.Logging.ILogger pattern
+///
+public interface ILogger
+{
+ ///
+ /// Gets the category/name of this logger
+ ///
+ string Category { get; }
+
+ ///
+ /// Logs a message at the specified log level
+ ///
+ void Log(LogLevel level, string message);
+
+ ///
+ /// Logs a message with an exception at the specified log level
+ ///
+ void Log(LogLevel level, Exception exception, string message);
+
+ ///
+ /// Logs a formatted message at the specified log level
+ ///
+ void Log(LogLevel level, string format, params object[] args);
+
+ ///
+ /// Logs a formatted message with an exception at the specified log level
+ ///
+ void Log(LogLevel level, Exception exception, string format, params object[] args);
+
+ ///
+ /// Checks if the given log level is enabled for this logger
+ ///
+ bool IsEnabled(LogLevel level);
+}
diff --git a/EonaCat.LogStack/EonaCatLoggerCore/LoggerFactory.cs b/EonaCat.LogStack/EonaCatLoggerCore/LoggerFactory.cs
new file mode 100644
index 0000000..403011d
--- /dev/null
+++ b/EonaCat.LogStack/EonaCatLoggerCore/LoggerFactory.cs
@@ -0,0 +1,224 @@
+using EonaCat.LogStack.Core;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace EonaCat.LogStack.Logging;
+
+// This file is part of the EonaCat project(s) which is released under the Apache License.
+// See the LICENSE file or go to https://EonaCat.com/License for full license details.
+
+///
+/// Factory for creating logger instances with a shared configuration
+///
+public interface ILoggerFactory : IAsyncDisposable
+{
+ ///
+ /// Creates or retrieves a logger for the specified category
+ ///
+ ILogger CreateLogger(string categoryName);
+
+ ///
+ /// Gets the underlying EonaCatLogStack instance
+ ///
+ EonaCatLogStack GetLogStack();
+
+ ///
+ /// Flushes all pending log events
+ ///
+ System.Threading.Tasks.Task FlushAsync();
+
+ ///
+ /// Gets diagnostics information about the logger
+ ///
+ LoggerDiagnostics GetDiagnostics();
+}
+
+///
+/// Default implementation of ILoggerFactory that manages a single EonaCatLogStack instance
+///
+public sealed class LoggerFactory : ILoggerFactory
+{
+ private readonly EonaCatLogStack _logStack;
+ private readonly ConcurrentDictionary _loggers;
+ private volatile bool _isDisposed;
+
+ ///
+ /// Creates a new LoggerFactory with default settings
+ ///
+ public LoggerFactory(
+ LogLevel minimumLevel = LogLevel.Trace,
+ TimestampMode timestampMode = TimestampMode.Utc)
+ {
+ _logStack = new EonaCatLogStack(
+ category: "LoggerFactory",
+ minimumLevel: minimumLevel,
+ timestampMode: timestampMode);
+ _loggers = new ConcurrentDictionary();
+ }
+
+ ///
+ /// Creates a new LoggerFactory using an existing EonaCatLogStack instance
+ ///
+ public LoggerFactory(EonaCatLogStack logStack)
+ {
+ _logStack = logStack ?? throw new ArgumentNullException(nameof(logStack));
+ _loggers = new ConcurrentDictionary();
+ }
+
+ ///
+ /// Creates or retrieves a logger for the specified category
+ ///
+ public ILogger CreateLogger(string categoryName)
+ {
+ if (_isDisposed)
+ {
+ throw new ObjectDisposedException(nameof(LoggerFactory));
+ }
+
+ if (string.IsNullOrEmpty(categoryName))
+ {
+ categoryName = "Default";
+ }
+
+ return _loggers.GetOrAdd(categoryName, name => new Logger(name, _logStack));
+ }
+
+ ///
+ /// Gets the underlying EonaCatLogStack instance
+ ///
+ public EonaCatLogStack GetLogStack()
+ {
+ if (_isDisposed)
+ {
+ throw new ObjectDisposedException(nameof(LoggerFactory));
+ }
+
+ return _logStack;
+ }
+
+ ///
+ /// Flushes all pending log events
+ ///
+ public async System.Threading.Tasks.Task FlushAsync()
+ {
+ if (_isDisposed)
+ {
+ throw new ObjectDisposedException(nameof(LoggerFactory));
+ }
+
+ await _logStack.FlushAsync().ConfigureAwait(false);
+ }
+
+ ///
+ /// Gets diagnostics information about the logger
+ ///
+ public LoggerDiagnostics GetDiagnostics()
+ {
+ if (_isDisposed)
+ {
+ throw new ObjectDisposedException(nameof(LoggerFactory));
+ }
+
+ return _logStack.GetDiagnostics();
+ }
+
+ ///
+ /// Disposes all loggers and the underlying log stack
+ ///
+ public async ValueTask DisposeAsync()
+ {
+ if (_isDisposed)
+ {
+ return;
+ }
+
+ _isDisposed = true;
+ _loggers.Clear();
+ await _logStack.DisposeAsync().ConfigureAwait(false);
+ GC.SuppressFinalize(this);
+ }
+
+ ///
+ /// Internal logger adapter that wraps EonaCatLogStack
+ ///
+ private sealed class Logger : ILogger
+ {
+ private readonly string _category;
+ private readonly EonaCatLogStack _logStack;
+
+ public string Category => _category;
+
+ public Logger(string category, EonaCatLogStack logStack)
+ {
+ _category = category ?? "Default";
+ _logStack = logStack;
+ }
+
+ public void Log(LogLevel level, string message)
+ {
+ if (!IsEnabled(level))
+ {
+ return;
+ }
+
+ _logStack.Log(message, level);
+ }
+
+ public void Log(LogLevel level, Exception exception, string message)
+ {
+ if (!IsEnabled(level))
+ {
+ return;
+ }
+
+ _logStack.Log(level, exception, message);
+ }
+
+ public void Log(LogLevel level, string format, params object[] args)
+ {
+ if (!IsEnabled(level))
+ {
+ return;
+ }
+
+ try
+ {
+ var message = string.Format(format, args);
+ _logStack.Log(message, level);
+ }
+ catch
+ {
+ // Fallback if formatting fails
+ _logStack.Log(format, level);
+ }
+ }
+
+ public void Log(LogLevel level, Exception exception, string format, params object[] args)
+ {
+ if (!IsEnabled(level))
+ {
+ return;
+ }
+
+ try
+ {
+ var message = string.Format(format, args);
+ _logStack.Log(level, exception, message);
+ }
+ catch
+ {
+ // Fallback if formatting fails
+ _logStack.Log(level, exception, format);
+ }
+ }
+
+ public bool IsEnabled(LogLevel level)
+ {
+ // Check if level is enabled in the logstack
+ // This is a simple check; could be enhanced
+ return level >= LogLevel.Trace;
+ }
+ }
+}
diff --git a/EonaCat.LogStack/EonaCatLoggerCore/MicrosoftExtensionsLoggerAdapter.cs b/EonaCat.LogStack/EonaCatLoggerCore/MicrosoftExtensionsLoggerAdapter.cs
new file mode 100644
index 0000000..49eb4ee
--- /dev/null
+++ b/EonaCat.LogStack/EonaCatLoggerCore/MicrosoftExtensionsLoggerAdapter.cs
@@ -0,0 +1,120 @@
+using EonaCat.LogStack.Core;
+using System;
+
+namespace EonaCat.LogStack.Logging;
+
+// This file is part of the EonaCat project(s) which is released under the Apache License.
+// See the LICENSE file or go to https://EonaCat.com/License for full license details.
+
+///
+/// Adapter that bridges EonaCat logging with Microsoft.Extensions.Logging
+/// This allows EonaCatLogStack to be used where Microsoft.Extensions.Logging.ILogger is expected
+///
+public sealed class MicrosoftExtensionsLoggerAdapter : Microsoft.Extensions.Logging.ILogger
+{
+ private readonly ILogger _eonaCatLogger;
+
+ public MicrosoftExtensionsLoggerAdapter(ILogger eonaCatLogger)
+ {
+ _eonaCatLogger = eonaCatLogger ?? throw new ArgumentNullException(nameof(eonaCatLogger));
+ }
+
+ public IDisposable BeginScope(TState state)
+ {
+ // EonaCat doesn't support scopes out of the box, but we can return a no-op disposable
+ return new NoOpDisposable();
+ }
+
+ public bool IsEnabled(Microsoft.Extensions.Logging.LogLevel logLevel)
+ {
+ var eonaCatLevel = ConvertLogLevel(logLevel);
+ return _eonaCatLogger.IsEnabled(eonaCatLevel);
+ }
+
+ public void Log(
+ Microsoft.Extensions.Logging.LogLevel logLevel,
+ Microsoft.Extensions.Logging.EventId eventId,
+ TState state,
+ Exception exception,
+ Func formatter)
+ {
+ if (!IsEnabled(logLevel))
+ {
+ return;
+ }
+
+ var eonaCatLevel = ConvertLogLevel(logLevel);
+ var message = formatter(state, exception);
+
+ if (exception != null)
+ {
+ _eonaCatLogger.Log(eonaCatLevel, exception, message);
+ }
+ else
+ {
+ _eonaCatLogger.Log(eonaCatLevel, message);
+ }
+ }
+
+ private static LogLevel ConvertLogLevel(Microsoft.Extensions.Logging.LogLevel msLevel)
+ {
+ return msLevel switch
+ {
+ Microsoft.Extensions.Logging.LogLevel.Trace => LogLevel.Trace,
+ Microsoft.Extensions.Logging.LogLevel.Debug => LogLevel.Debug,
+ Microsoft.Extensions.Logging.LogLevel.Information => LogLevel.Information,
+ Microsoft.Extensions.Logging.LogLevel.Warning => LogLevel.Warning,
+ Microsoft.Extensions.Logging.LogLevel.Error => LogLevel.Error,
+ Microsoft.Extensions.Logging.LogLevel.Critical => LogLevel.Critical,
+ _ => LogLevel.Information
+ };
+ }
+
+ private sealed class NoOpDisposable : IDisposable
+ {
+ public void Dispose() { }
+ }
+}
+
+///
+/// Factory adapter that implements Microsoft.Extensions.Logging.ILoggerFactory
+///
+public sealed class MicrosoftExtensionsLoggerFactoryAdapter : Microsoft.Extensions.Logging.ILoggerFactory
+{
+ private readonly ILoggerFactory _eonaCatFactory;
+ private volatile bool _isDisposed;
+
+ public MicrosoftExtensionsLoggerFactoryAdapter(ILoggerFactory eonaCatFactory)
+ {
+ _eonaCatFactory = eonaCatFactory ?? throw new ArgumentNullException(nameof(eonaCatFactory));
+ }
+
+ public Microsoft.Extensions.Logging.ILogger CreateLogger(string categoryName)
+ {
+ if (_isDisposed)
+ {
+ throw new ObjectDisposedException(nameof(MicrosoftExtensionsLoggerFactoryAdapter));
+ }
+
+ var eonaCatLogger = _eonaCatFactory.CreateLogger(categoryName);
+ return new MicrosoftExtensionsLoggerAdapter(eonaCatLogger);
+ }
+
+ public void AddProvider(Microsoft.Extensions.Logging.ILoggerProvider provider)
+ {
+ // EonaCat uses Flows instead of providers, so this is a no-op
+ // Providers should be configured through the ILoggerFactory.GetLogStack()
+ }
+
+ public void Dispose()
+ {
+ if (_isDisposed)
+ {
+ return;
+ }
+
+ _isDisposed = true;
+ _eonaCatFactory.DisposeAsync().GetAwaiter().GetResult();
+ GC.SuppressFinalize(this);
+ }
+}
diff --git a/EonaCat.LogStack/Extensions/ServiceCollectionExtensions.cs b/EonaCat.LogStack/Extensions/ServiceCollectionExtensions.cs
new file mode 100644
index 0000000..5211773
--- /dev/null
+++ b/EonaCat.LogStack/Extensions/ServiceCollectionExtensions.cs
@@ -0,0 +1,251 @@
+using EonaCat.LogStack.Configuration;
+using EonaCat.LogStack.Core;
+using EonaCat.LogStack.Logging;
+using Microsoft.Extensions.DependencyInjection;
+using System;
+
+namespace EonaCat.LogStack.Extensions;
+
+// This file is part of the EonaCat project(s) which is released under the Apache License.
+// See the LICENSE file or go to https://EonaCat.com/License for full license details.
+
+///
+/// Extension methods for integrating EonaCat LogStack with Microsoft Dependency Injection
+///
+public static class ServiceCollectionExtensions
+{
+ ///
+ /// Registers EonaCat LogStack as the logging provider in the dependency injection container
+ ///
+ /// The service collection to register with
+ /// The minimum log level to process
+ /// The timestamp mode to use
+ /// The service collection for chaining
+ public static IServiceCollection AddEonaCatLogging(
+ this IServiceCollection services,
+ LogLevel minimumLevel = LogLevel.Trace,
+ TimestampMode timestampMode = TimestampMode.Utc)
+ {
+ if (services == null)
+ {
+ throw new ArgumentNullException(nameof(services));
+ }
+
+ var loggerFactory = new LoggerFactory(minimumLevel, timestampMode);
+ services.AddSingleton(loggerFactory);
+ services.AddSingleton(
+ new MicrosoftExtensionsLoggerFactoryAdapter(loggerFactory));
+
+ // Also register as ILogger for constructor injection
+ services.AddSingleton(sp => sp.GetRequiredService().CreateLogger("Default"));
+ services.AddSingleton(sp =>
+ new MicrosoftExtensionsLoggerAdapter(
+ sp.GetRequiredService().CreateLogger("Default")));
+
+ return services;
+ }
+
+ ///
+ /// Registers EonaCat LogStack using an existing EonaCatLogStack instance
+ ///
+ /// The service collection to register with
+ /// The pre-configured EonaCatLogStack instance
+ /// The service collection for chaining
+ public static IServiceCollection AddEonaCatLogging(
+ this IServiceCollection services,
+ EonaCatLogStack logStack)
+ {
+ if (services == null)
+ {
+ throw new ArgumentNullException(nameof(services));
+ }
+
+ if (logStack == null)
+ {
+ throw new ArgumentNullException(nameof(logStack));
+ }
+
+ var loggerFactory = new LoggerFactory(logStack);
+ services.AddSingleton(loggerFactory);
+ services.AddSingleton(
+ new MicrosoftExtensionsLoggerFactoryAdapter(loggerFactory));
+
+ // Also register as ILogger for constructor injection
+ services.AddSingleton(sp => sp.GetRequiredService().CreateLogger("Default"));
+ services.AddSingleton(sp =>
+ new MicrosoftExtensionsLoggerAdapter(
+ sp.GetRequiredService().CreateLogger("Default")));
+
+ return services;
+ }
+
+ ///
+ /// Registers EonaCat LogStack with a configuration callback
+ ///
+ /// The service collection to register with
+ /// Callback to configure the EonaCatLogStack instance
+ /// The service collection for chaining
+ public static IServiceCollection AddEonaCatLogging(
+ this IServiceCollection services,
+ Action configure)
+ {
+ if (services == null)
+ {
+ throw new ArgumentNullException(nameof(services));
+ }
+
+ if (configure == null)
+ {
+ throw new ArgumentNullException(nameof(configure));
+ }
+
+ var logStack = new EonaCatLogStack();
+ configure(logStack);
+
+ var loggerFactory = new LoggerFactory(logStack);
+ services.AddSingleton(loggerFactory);
+ services.AddSingleton(
+ new MicrosoftExtensionsLoggerFactoryAdapter(loggerFactory));
+
+ // Also register as ILogger for constructor injection
+ services.AddSingleton(sp => sp.GetRequiredService().CreateLogger("Default"));
+ services.AddSingleton(sp =>
+ new MicrosoftExtensionsLoggerAdapter(
+ sp.GetRequiredService().CreateLogger("Default")));
+
+ return services;
+ }
+
+ ///
+ /// Registers EonaCat LogStack using a fluent LogBuilder configuration.
+ /// This is the recommended approach for DI integration with fluent configuration.
+ ///
+ /// The service collection to register with
+ /// The category/name of the logger
+ /// Callback to configure the LogBuilder instance
+ /// The service collection for chaining
+ public static IServiceCollection AddEonaCatLogging(
+ this IServiceCollection services,
+ string category,
+ Action configure)
+ {
+ if (services == null)
+ {
+ throw new ArgumentNullException(nameof(services));
+ }
+
+ if (configure == null)
+ {
+ throw new ArgumentNullException(nameof(configure));
+ }
+
+ var builder = new LogBuilder(category);
+ configure(builder);
+ var logStack = builder.Build();
+
+ var loggerFactory = new LoggerFactory(logStack);
+ services.AddSingleton(loggerFactory);
+ services.AddSingleton(
+ new MicrosoftExtensionsLoggerFactoryAdapter(loggerFactory));
+
+ // Also register as ILogger for constructor injection
+ services.AddSingleton(sp => sp.GetRequiredService().CreateLogger(category));
+ services.AddSingleton(sp =>
+ new MicrosoftExtensionsLoggerAdapter(
+ sp.GetRequiredService().CreateLogger(category)));
+
+ return services;
+ }
+
+ ///
+ /// Registers EonaCat LogStack using a fluent LogBuilder configuration with "Application" as the default category.
+ /// This is the recommended approach for DI integration with fluent configuration.
+ ///
+ /// The service collection to register with
+ /// Callback to configure the LogBuilder instance
+ /// The service collection for chaining
+ public static IServiceCollection AddEonaCatLogging(
+ this IServiceCollection services,
+ Action configure)
+ {
+ if (services == null)
+ {
+ throw new ArgumentNullException(nameof(services));
+ }
+
+ if (configure == null)
+ {
+ throw new ArgumentNullException(nameof(configure));
+ }
+
+ return services.AddEonaCatLogging("Application", configure);
+ }
+
+ ///
+ /// Registers EonaCat LogStack as a factory using a LogBuilder configuration callback.
+ /// Allows configuring the logger factory through DI with full access to the service provider.
+ ///
+ /// The service collection to register with
+ /// The category/name of the logger
+ /// Callback to configure the LogBuilder instance
+ /// The service collection for chaining
+ public static IServiceCollection AddEonaCatLoggingFactory(
+ this IServiceCollection services,
+ string category,
+ Action configure)
+ {
+ if (services == null)
+ {
+ throw new ArgumentNullException(nameof(services));
+ }
+
+ if (configure == null)
+ {
+ throw new ArgumentNullException(nameof(configure));
+ }
+
+ services.AddSingleton(sp =>
+ {
+ var builder = new LogBuilder(category);
+ configure(builder);
+ var logStack = builder.Build();
+ return new LoggerFactory(logStack);
+ });
+
+ services.AddSingleton(sp =>
+ new MicrosoftExtensionsLoggerFactoryAdapter(
+ sp.GetRequiredService()));
+
+ // Also register as ILogger for constructor injection
+ services.AddSingleton(sp => sp.GetRequiredService().CreateLogger(category));
+ services.AddSingleton(sp =>
+ new MicrosoftExtensionsLoggerAdapter(
+ sp.GetRequiredService().CreateLogger(category)));
+
+ return services;
+ }
+
+ ///
+ /// Registers EonaCat LogStack as a factory using a LogBuilder configuration callback with "Application" as default category.
+ /// Allows configuring the logger factory through DI with full access to the service provider.
+ ///
+ /// The service collection to register with
+ /// Callback to configure the LogBuilder instance
+ /// The service collection for chaining
+ public static IServiceCollection AddEonaCatLoggingFactory(
+ this IServiceCollection services,
+ Action configure)
+ {
+ if (services == null)
+ {
+ throw new ArgumentNullException(nameof(services));
+ }
+
+ if (configure == null)
+ {
+ throw new ArgumentNullException(nameof(configure));
+ }
+
+ return services.AddEonaCatLoggingFactory("Application", configure);
+ }
+}
diff --git a/README.md b/README.md
index 8b8e773..339b369 100644
--- a/README.md
+++ b/README.md
@@ -474,4 +474,338 @@ server.LogDropped += line => Metrics.Increment("dropped");
Console.CancelKeyPress += (_, e) => { e.Cancel = true; server.Stop(); };
```
-`Stop()` prints a throughput summary and disposes all listeners cleanly.
\ No newline at end of file
+`Stop()` prints a throughput summary and disposes all listeners cleanly.
+
+
+## Dependency Injection (DI) registration methods
+
+### 1. Basic Registration (Simplest)
+
+Register with default settings:
+
+```csharp
+services.AddEonaCatLogging();
+```
+
+This registers:
+- `ILoggerFactory` - For creating category-specific loggers
+- `Microsoft.Extensions.Logging.ILoggerFactory` - For Microsoft.Extensions.Logging compatibility
+- `ILogger` - For injecting the default logger
+
+### 2. Registration with Log Level and Timestamp Mode
+
+```csharp
+services.AddEonaCatLogging(
+ minimumLevel: LogLevel.Information,
+ timestampMode: TimestampMode.Local);
+```
+
+### 3. Registration with Pre-built EonaCatLogStack
+
+If you've already created an `EonaCatLogStack` instance:
+
+```csharp
+var logStack = new EonaCatLogStack("MyApp");
+logStack.AddFlow(new ConsoleFlow());
+
+services.AddEonaCatLogging(logStack);
+```
+
+### 4. Registration with Configuration Callback (Recommended)
+
+Configure the logger directly with an `Action`:
+
+```csharp
+services.AddEonaCatLogging(logStack =>
+{
+ logStack.AddFlow(new ConsoleFlow());
+ logStack.AddFlow(new FileFlow("./logs"));
+ logStack.AddBooster(new MachineNameBooster());
+});
+```
+
+### 5. Registration with LogBuilder (Most Fluent - Recommended)
+
+Use the fluent `LogBuilder` API for the most intuitive configuration:
+
+```csharp
+services.AddEonaCatLogging("MyApplication", builder =>
+{
+ builder
+ .WithMinimumLevel(LogLevel.Information)
+ .WithTimestampMode(TimestampMode.Local)
+ .WriteToConsole()
+ .WriteToFile("./logs")
+ .BoostWithMachineName()
+ .BoostWithProcessId()
+ .BoostWithCorrelationId();
+});
+```
+
+Or with the default "Application" category:
+
+```csharp
+services.AddEonaCatLogging(builder =>
+{
+ builder
+ .WriteToConsole()
+ .WriteToFile("./logs");
+});
+```
+
+### 6. Registration with Factory Method (Advanced)
+
+For advanced scenarios where you need access to the service provider:
+
+```csharp
+services.AddEonaCatLoggingFactory("MyApplication", builder =>
+{
+ builder
+ .WriteToConsole()
+ .WriteToFile("./logs");
+});
+```
+
+## Using in Your Application
+
+### Injecting ILoggerFactory
+
+```csharp
+public class MyService
+{
+ private readonly ILoggerFactory _loggerFactory;
+
+ public MyService(ILoggerFactory loggerFactory)
+ {
+ _loggerFactory = loggerFactory;
+ }
+
+ public void DoSomething()
+ {
+ var logger = _loggerFactory.CreateLogger("MyService");
+ logger.Log(LogLevel.Information, "Doing something");
+ }
+}
+```
+
+### Injecting ILogger
+
+```csharp
+public class MyService
+{
+ private readonly ILogger _logger;
+
+ public MyService(ILogger logger)
+ {
+ _logger = logger;
+ }
+
+ public void DoSomething()
+ {
+ _logger.Log(LogLevel.Information, "Doing something");
+ }
+}
+```
+
+### Using with Microsoft.Extensions.Logging.ILogger
+
+```csharp
+public class MyService
+{
+ private readonly Microsoft.Extensions.Logging.ILogger _logger;
+
+ public MyService(Microsoft.Extensions.Logging.ILogger logger)
+ {
+ _logger = logger;
+ }
+
+ public void DoSomething()
+ {
+ _logger.LogInformation("Doing something");
+ }
+}
+```
+
+## ASP.NET Core / Razor Pages Integration
+
+In your `Program.cs`:
+
+```csharp
+var builder = WebApplication.CreateBuilder(args);
+
+// Add EonaCat LogStack to the service collection
+builder.Services.AddEonaCatLogging("WebApplication", logBuilder =>
+{
+ logBuilder
+ .WithMinimumLevel(LogLevel.Information)
+ .WriteToConsole(useColors: true)
+ .WriteToFile("./logs")
+ .BoostWithCorrelationId()
+ .BoostWithThreadId();
+});
+
+// Rest of your configuration...
+var app = builder.Build();
+
+// Configure HTTP request pipeline...
+app.Run();
+```
+
+### In Razor Page Code-Behind
+
+```csharp
+public class IndexModel : PageModel
+{
+ private readonly ILogger _logger;
+
+ public IndexModel(ILogger logger)
+ {
+ _logger = logger;
+ }
+
+ public void OnGet()
+ {
+ _logger.Log(LogLevel.Information, "Index page loaded");
+ }
+}
+```
+
+## Features
+
+### Multiple Output Destinations (Flows)
+
+```csharp
+services.AddEonaCatLogging(builder =>
+{
+ builder
+ .WriteToConsole() // Console output
+ .WriteToFile("./logs") // File output
+ .WriteToSlack("https://hooks.slack.com/...") // Slack
+ .WriteToDiscord("https://discordapp.com/...") // Discord
+ .WriteToElasticSearch("http://localhost:9200") // Elasticsearch
+ .WriteToEmail("smtp.gmail.com", 587, ...) // Email
+ .WriteToMicrosoftTeams("https://..."); // Teams
+});
+```
+
+### Enriching Log Events (Boosters)
+
+```csharp
+services.AddEonaCatLogging(builder =>
+{
+ builder
+ .BoostWithMachineName() // Adds machine name
+ .BoostWithProcessId() // Adds process ID
+ .BoostWithThreadId() // Adds thread ID
+ .BoostWithCorrelationId() // Adds correlation ID (for distributed tracing)
+ .BoostWithMemory() // Adds memory usage
+ .BoostWithOS() // Adds OS info
+ .BoostWithUser() // Adds username
+ .BoostWithCustomText("Environment", "Production"); // Custom properties
+});
+```
+
+### Log Level Filtering
+
+```csharp
+services.AddEonaCatLogging(builder =>
+{
+ builder
+ .WithMinimumLevel(LogLevel.Warning) // Only log warnings and above
+ .WriteToConsole(minimumLevel: LogLevel.Information) // More verbose for console
+ .WriteToFile("./logs", minimumLevel: LogLevel.Error); // Only errors to file
+});
+```
+
+## Best Practices
+
+1. **Use LogBuilder for Configuration**: The fluent LogBuilder API is the most readable and maintainable approach.
+
+2. **Register Early**: Register logging in `Program.cs` before other services that depend on logging.
+
+3. **Use Appropriate Log Levels**:
+ - `Trace` - Very detailed diagnostic info
+ - `Debug` - Debug-level diagnostic info
+ - `Information` - General informational messages
+ - `Warning` - Warning messages
+ - `Error` - Error messages
+ - `Critical` - Critical failures
+
+4. **Inject Specific Types**: Prefer injecting `ILoggerFactory` to create category-specific loggers rather than injecting a single shared logger.
+
+5. **Use Categories**: Create loggers with meaningful category names:
+ ```csharp
+ var logger = loggerFactory.CreateLogger("MyApp.Services.UserService");
+ ```
+
+6. **Enable Correlation IDs**: For distributed tracing scenarios:
+ ```csharp
+ builder.BoostWithCorrelationId()
+ ```
+
+## Configuration Examples
+
+### Minimal Setup (Console Only)
+
+```csharp
+services.AddEonaCatLogging(b => b.WriteToConsole());
+```
+
+### Development Environment
+
+```csharp
+services.AddEonaCatLogging(builder =>
+{
+ builder
+ .WithMinimumLevel(LogLevel.Debug)
+ .WriteToConsole(useColors: true)
+ .WriteToFile("./logs")
+ .BoostWithMachineName()
+ .BoostWithThreadId();
+});
+```
+
+### Production Environment
+
+```csharp
+services.AddEonaCatLogging("ProductionApp", builder =>
+{
+ builder
+ .WithMinimumLevel(LogLevel.Information)
+ .WriteToFile("./logs", minimumLevel: LogLevel.Information)
+ .WriteToElasticSearch("https://elastic.company.com")
+ .WriteToSlack("https://hooks.slack.com/...")
+ .BoostWithCorrelationId()
+ .BoostWithMachineName()
+ .BoostWithUser();
+});
+```
+## Diagnostics
+
+```csharp
+public class DiagnosticsService
+{
+ private readonly ILoggerFactory _loggerFactory;
+
+ public DiagnosticsService(ILoggerFactory loggerFactory)
+ {
+ _loggerFactory = loggerFactory;
+ }
+
+ public void PrintDiagnostics()
+ {
+ var diagnostics = _loggerFactory.GetDiagnostics();
+ Console.WriteLine($"Total Logged: {diagnostics.TotalLoggedCount}");
+ Console.WriteLine($"Total Dropped: {diagnostics.TotalDroppedCount}");
+ }
+}
+```
+
+## Disposing of the Logger
+
+The logger is registered as a Singleton in the DI container, so it will be automatically disposed when the application shuts down. You can also manually access and dispose it:
+
+```csharp
+var loggerFactory = app.Services.GetRequiredService();
+await loggerFactory.DisposeAsync();
+```
\ No newline at end of file
diff --git a/Testers/EonaCat.LogStack.Test.Web/Program.cs b/Testers/EonaCat.LogStack.Test.Web/Program.cs
index 709f120..adadf8d 100644
--- a/Testers/EonaCat.LogStack.Test.Web/Program.cs
+++ b/Testers/EonaCat.LogStack.Test.Web/Program.cs
@@ -130,6 +130,8 @@ namespace EonaCat.LogStack.Test.Web
var builder = WebApplication.CreateBuilder(args);
int onLogCounter = 0;
var defaultColor = Console.ForegroundColor;
+ builder.Services.AddEonaCatLogging();
+
//_ = Task.Run(() =>
//{