Added dependency injection
This commit is contained in:
@@ -14,7 +14,7 @@ It features a rich fluent API for routing log events to dozens of destinations f
|
|||||||
<Copyright>EonaCat (Jeroen Saey)</Copyright>
|
<Copyright>EonaCat (Jeroen Saey)</Copyright>
|
||||||
<PackageTags>EonaCat;Logger;EonaCatLogStack;Log;Writer;Flows;LogStack;Memory;Speed;Jeroen;Saey</PackageTags>
|
<PackageTags>EonaCat;Logger;EonaCatLogStack;Log;Writer;Flows;LogStack;Memory;Speed;Jeroen;Saey</PackageTags>
|
||||||
<PackageIconUrl />
|
<PackageIconUrl />
|
||||||
<FileVersion>0.0.6</FileVersion>
|
<FileVersion>0.0.7</FileVersion>
|
||||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||||
@@ -25,7 +25,7 @@ It features a rich fluent API for routing log events to dozens of destinations f
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<EVRevisionFormat>0.0.6+{chash:10}.{c:ymd}</EVRevisionFormat>
|
<EVRevisionFormat>0.0.7+{chash:10}.{c:ymd}</EVRevisionFormat>
|
||||||
<EVDefault>true</EVDefault>
|
<EVDefault>true</EVDefault>
|
||||||
<EVInfo>true</EVInfo>
|
<EVInfo>true</EVInfo>
|
||||||
<EVTagMatch>v[0-9]*</EVTagMatch>
|
<EVTagMatch>v[0-9]*</EVTagMatch>
|
||||||
|
|||||||
@@ -178,15 +178,51 @@ namespace EonaCat.LogStack
|
|||||||
ProcessLogEvent(ref builder);
|
ProcessLogEvent(ref builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public void Trace(string message) => Log(LogLevel.Trace, message);
|
private void Write(LogLevel level, string template, params object[] args)
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public void Debug(string message) => Log(LogLevel.Debug, message);
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public void Information(string message) => Log(LogLevel.Information, message);
|
Log(level, string.Format(template, args));
|
||||||
[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);
|
private void Write(LogLevel level, Exception ex, string template, params object[] args)
|
||||||
[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);
|
Log(level, ex, string.Format(template, args));
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public void Critical(Exception ex, string message) => Log(LogLevel.Critical, ex, message);
|
}
|
||||||
|
|
||||||
|
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)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private void ProcessLogEvent(ref LogEventBuilder builder)
|
private void ProcessLogEvent(ref LogEventBuilder builder)
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adapter interface that wraps EonaCatLogStack to be compatible with Microsoft.Extensions.Logging.ILogger pattern
|
||||||
|
/// </summary>
|
||||||
|
public interface ILogger
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the category/name of this logger
|
||||||
|
/// </summary>
|
||||||
|
string Category { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Logs a message at the specified log level
|
||||||
|
/// </summary>
|
||||||
|
void Log(LogLevel level, string message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Logs a message with an exception at the specified log level
|
||||||
|
/// </summary>
|
||||||
|
void Log(LogLevel level, Exception exception, string message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Logs a formatted message at the specified log level
|
||||||
|
/// </summary>
|
||||||
|
void Log(LogLevel level, string format, params object[] args);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Logs a formatted message with an exception at the specified log level
|
||||||
|
/// </summary>
|
||||||
|
void Log(LogLevel level, Exception exception, string format, params object[] args);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the given log level is enabled for this logger
|
||||||
|
/// </summary>
|
||||||
|
bool IsEnabled(LogLevel level);
|
||||||
|
}
|
||||||
@@ -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.
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Factory for creating logger instances with a shared configuration
|
||||||
|
/// </summary>
|
||||||
|
public interface ILoggerFactory : IAsyncDisposable
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates or retrieves a logger for the specified category
|
||||||
|
/// </summary>
|
||||||
|
ILogger CreateLogger(string categoryName);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the underlying EonaCatLogStack instance
|
||||||
|
/// </summary>
|
||||||
|
EonaCatLogStack GetLogStack();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Flushes all pending log events
|
||||||
|
/// </summary>
|
||||||
|
System.Threading.Tasks.Task FlushAsync();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets diagnostics information about the logger
|
||||||
|
/// </summary>
|
||||||
|
LoggerDiagnostics GetDiagnostics();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Default implementation of ILoggerFactory that manages a single EonaCatLogStack instance
|
||||||
|
/// </summary>
|
||||||
|
public sealed class LoggerFactory : ILoggerFactory
|
||||||
|
{
|
||||||
|
private readonly EonaCatLogStack _logStack;
|
||||||
|
private readonly ConcurrentDictionary<string, Logger> _loggers;
|
||||||
|
private volatile bool _isDisposed;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new LoggerFactory with default settings
|
||||||
|
/// </summary>
|
||||||
|
public LoggerFactory(
|
||||||
|
LogLevel minimumLevel = LogLevel.Trace,
|
||||||
|
TimestampMode timestampMode = TimestampMode.Utc)
|
||||||
|
{
|
||||||
|
_logStack = new EonaCatLogStack(
|
||||||
|
category: "LoggerFactory",
|
||||||
|
minimumLevel: minimumLevel,
|
||||||
|
timestampMode: timestampMode);
|
||||||
|
_loggers = new ConcurrentDictionary<string, Logger>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new LoggerFactory using an existing EonaCatLogStack instance
|
||||||
|
/// </summary>
|
||||||
|
public LoggerFactory(EonaCatLogStack logStack)
|
||||||
|
{
|
||||||
|
_logStack = logStack ?? throw new ArgumentNullException(nameof(logStack));
|
||||||
|
_loggers = new ConcurrentDictionary<string, Logger>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates or retrieves a logger for the specified category
|
||||||
|
/// </summary>
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the underlying EonaCatLogStack instance
|
||||||
|
/// </summary>
|
||||||
|
public EonaCatLogStack GetLogStack()
|
||||||
|
{
|
||||||
|
if (_isDisposed)
|
||||||
|
{
|
||||||
|
throw new ObjectDisposedException(nameof(LoggerFactory));
|
||||||
|
}
|
||||||
|
|
||||||
|
return _logStack;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Flushes all pending log events
|
||||||
|
/// </summary>
|
||||||
|
public async System.Threading.Tasks.Task FlushAsync()
|
||||||
|
{
|
||||||
|
if (_isDisposed)
|
||||||
|
{
|
||||||
|
throw new ObjectDisposedException(nameof(LoggerFactory));
|
||||||
|
}
|
||||||
|
|
||||||
|
await _logStack.FlushAsync().ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets diagnostics information about the logger
|
||||||
|
/// </summary>
|
||||||
|
public LoggerDiagnostics GetDiagnostics()
|
||||||
|
{
|
||||||
|
if (_isDisposed)
|
||||||
|
{
|
||||||
|
throw new ObjectDisposedException(nameof(LoggerFactory));
|
||||||
|
}
|
||||||
|
|
||||||
|
return _logStack.GetDiagnostics();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Disposes all loggers and the underlying log stack
|
||||||
|
/// </summary>
|
||||||
|
public async ValueTask DisposeAsync()
|
||||||
|
{
|
||||||
|
if (_isDisposed)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_isDisposed = true;
|
||||||
|
_loggers.Clear();
|
||||||
|
await _logStack.DisposeAsync().ConfigureAwait(false);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Internal logger adapter that wraps EonaCatLogStack
|
||||||
|
/// </summary>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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.
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adapter that bridges EonaCat logging with Microsoft.Extensions.Logging
|
||||||
|
/// This allows EonaCatLogStack to be used where Microsoft.Extensions.Logging.ILogger is expected
|
||||||
|
/// </summary>
|
||||||
|
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>(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<TState>(
|
||||||
|
Microsoft.Extensions.Logging.LogLevel logLevel,
|
||||||
|
Microsoft.Extensions.Logging.EventId eventId,
|
||||||
|
TState state,
|
||||||
|
Exception exception,
|
||||||
|
Func<TState, Exception, string> 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() { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Factory adapter that implements Microsoft.Extensions.Logging.ILoggerFactory
|
||||||
|
/// </summary>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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.
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extension methods for integrating EonaCat LogStack with Microsoft Dependency Injection
|
||||||
|
/// </summary>
|
||||||
|
public static class ServiceCollectionExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Registers EonaCat LogStack as the logging provider in the dependency injection container
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="services">The service collection to register with</param>
|
||||||
|
/// <param name="minimumLevel">The minimum log level to process</param>
|
||||||
|
/// <param name="timestampMode">The timestamp mode to use</param>
|
||||||
|
/// <returns>The service collection for chaining</returns>
|
||||||
|
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<ILoggerFactory>(loggerFactory);
|
||||||
|
services.AddSingleton<Microsoft.Extensions.Logging.ILoggerFactory>(
|
||||||
|
new MicrosoftExtensionsLoggerFactoryAdapter(loggerFactory));
|
||||||
|
|
||||||
|
// Also register as ILogger for constructor injection
|
||||||
|
services.AddSingleton(sp => sp.GetRequiredService<ILoggerFactory>().CreateLogger("Default"));
|
||||||
|
services.AddSingleton(sp =>
|
||||||
|
new MicrosoftExtensionsLoggerAdapter(
|
||||||
|
sp.GetRequiredService<ILoggerFactory>().CreateLogger("Default")));
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Registers EonaCat LogStack using an existing EonaCatLogStack instance
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="services">The service collection to register with</param>
|
||||||
|
/// <param name="logStack">The pre-configured EonaCatLogStack instance</param>
|
||||||
|
/// <returns>The service collection for chaining</returns>
|
||||||
|
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<ILoggerFactory>(loggerFactory);
|
||||||
|
services.AddSingleton<Microsoft.Extensions.Logging.ILoggerFactory>(
|
||||||
|
new MicrosoftExtensionsLoggerFactoryAdapter(loggerFactory));
|
||||||
|
|
||||||
|
// Also register as ILogger for constructor injection
|
||||||
|
services.AddSingleton(sp => sp.GetRequiredService<ILoggerFactory>().CreateLogger("Default"));
|
||||||
|
services.AddSingleton(sp =>
|
||||||
|
new MicrosoftExtensionsLoggerAdapter(
|
||||||
|
sp.GetRequiredService<ILoggerFactory>().CreateLogger("Default")));
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Registers EonaCat LogStack with a configuration callback
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="services">The service collection to register with</param>
|
||||||
|
/// <param name="configure">Callback to configure the EonaCatLogStack instance</param>
|
||||||
|
/// <returns>The service collection for chaining</returns>
|
||||||
|
public static IServiceCollection AddEonaCatLogging(
|
||||||
|
this IServiceCollection services,
|
||||||
|
Action<EonaCatLogStack> 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<ILoggerFactory>(loggerFactory);
|
||||||
|
services.AddSingleton<Microsoft.Extensions.Logging.ILoggerFactory>(
|
||||||
|
new MicrosoftExtensionsLoggerFactoryAdapter(loggerFactory));
|
||||||
|
|
||||||
|
// Also register as ILogger for constructor injection
|
||||||
|
services.AddSingleton(sp => sp.GetRequiredService<ILoggerFactory>().CreateLogger("Default"));
|
||||||
|
services.AddSingleton(sp =>
|
||||||
|
new MicrosoftExtensionsLoggerAdapter(
|
||||||
|
sp.GetRequiredService<ILoggerFactory>().CreateLogger("Default")));
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Registers EonaCat LogStack using a fluent LogBuilder configuration.
|
||||||
|
/// This is the recommended approach for DI integration with fluent configuration.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="services">The service collection to register with</param>
|
||||||
|
/// <param name="category">The category/name of the logger</param>
|
||||||
|
/// <param name="configure">Callback to configure the LogBuilder instance</param>
|
||||||
|
/// <returns>The service collection for chaining</returns>
|
||||||
|
public static IServiceCollection AddEonaCatLogging(
|
||||||
|
this IServiceCollection services,
|
||||||
|
string category,
|
||||||
|
Action<LogBuilder> 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<ILoggerFactory>(loggerFactory);
|
||||||
|
services.AddSingleton<Microsoft.Extensions.Logging.ILoggerFactory>(
|
||||||
|
new MicrosoftExtensionsLoggerFactoryAdapter(loggerFactory));
|
||||||
|
|
||||||
|
// Also register as ILogger for constructor injection
|
||||||
|
services.AddSingleton(sp => sp.GetRequiredService<ILoggerFactory>().CreateLogger(category));
|
||||||
|
services.AddSingleton(sp =>
|
||||||
|
new MicrosoftExtensionsLoggerAdapter(
|
||||||
|
sp.GetRequiredService<ILoggerFactory>().CreateLogger(category)));
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="services">The service collection to register with</param>
|
||||||
|
/// <param name="configure">Callback to configure the LogBuilder instance</param>
|
||||||
|
/// <returns>The service collection for chaining</returns>
|
||||||
|
public static IServiceCollection AddEonaCatLogging(
|
||||||
|
this IServiceCollection services,
|
||||||
|
Action<LogBuilder> configure)
|
||||||
|
{
|
||||||
|
if (services == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(services));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configure == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(configure));
|
||||||
|
}
|
||||||
|
|
||||||
|
return services.AddEonaCatLogging("Application", configure);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="services">The service collection to register with</param>
|
||||||
|
/// <param name="category">The category/name of the logger</param>
|
||||||
|
/// <param name="configure">Callback to configure the LogBuilder instance</param>
|
||||||
|
/// <returns>The service collection for chaining</returns>
|
||||||
|
public static IServiceCollection AddEonaCatLoggingFactory(
|
||||||
|
this IServiceCollection services,
|
||||||
|
string category,
|
||||||
|
Action<LogBuilder> configure)
|
||||||
|
{
|
||||||
|
if (services == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(services));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configure == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(configure));
|
||||||
|
}
|
||||||
|
|
||||||
|
services.AddSingleton<ILoggerFactory>(sp =>
|
||||||
|
{
|
||||||
|
var builder = new LogBuilder(category);
|
||||||
|
configure(builder);
|
||||||
|
var logStack = builder.Build();
|
||||||
|
return new LoggerFactory(logStack);
|
||||||
|
});
|
||||||
|
|
||||||
|
services.AddSingleton<Microsoft.Extensions.Logging.ILoggerFactory>(sp =>
|
||||||
|
new MicrosoftExtensionsLoggerFactoryAdapter(
|
||||||
|
sp.GetRequiredService<ILoggerFactory>()));
|
||||||
|
|
||||||
|
// Also register as ILogger for constructor injection
|
||||||
|
services.AddSingleton(sp => sp.GetRequiredService<ILoggerFactory>().CreateLogger(category));
|
||||||
|
services.AddSingleton(sp =>
|
||||||
|
new MicrosoftExtensionsLoggerAdapter(
|
||||||
|
sp.GetRequiredService<ILoggerFactory>().CreateLogger(category)));
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="services">The service collection to register with</param>
|
||||||
|
/// <param name="configure">Callback to configure the LogBuilder instance</param>
|
||||||
|
/// <returns>The service collection for chaining</returns>
|
||||||
|
public static IServiceCollection AddEonaCatLoggingFactory(
|
||||||
|
this IServiceCollection services,
|
||||||
|
Action<LogBuilder> configure)
|
||||||
|
{
|
||||||
|
if (services == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(services));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configure == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(configure));
|
||||||
|
}
|
||||||
|
|
||||||
|
return services.AddEonaCatLoggingFactory("Application", configure);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -474,4 +474,338 @@ server.LogDropped += line => Metrics.Increment("dropped");
|
|||||||
Console.CancelKeyPress += (_, e) => { e.Cancel = true; server.Stop(); };
|
Console.CancelKeyPress += (_, e) => { e.Cancel = true; server.Stop(); };
|
||||||
```
|
```
|
||||||
|
|
||||||
`Stop()` prints a throughput summary and disposes all listeners cleanly.
|
`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<EonaCatLogStack>`:
|
||||||
|
|
||||||
|
```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<ILoggerFactory>();
|
||||||
|
await loggerFactory.DisposeAsync();
|
||||||
|
```
|
||||||
@@ -130,6 +130,8 @@ namespace EonaCat.LogStack.Test.Web
|
|||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
int onLogCounter = 0;
|
int onLogCounter = 0;
|
||||||
var defaultColor = Console.ForegroundColor;
|
var defaultColor = Console.ForegroundColor;
|
||||||
|
builder.Services.AddEonaCatLogging();
|
||||||
|
|
||||||
|
|
||||||
//_ = Task.Run(() =>
|
//_ = Task.Run(() =>
|
||||||
//{
|
//{
|
||||||
|
|||||||
Reference in New Issue
Block a user