This commit is contained in:
2026-01-09 19:43:09 +01:00
parent 38512f9d6a
commit 39056fd16d
2 changed files with 394 additions and 314 deletions

View File

@@ -7,7 +7,12 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="EonaCat.MemoryGuard" Version="1.0.0" />
<PackageReference Include="EonaCat.MemoryGuard" Version="1.2.4" />
<PackageReference Include="EonaCat.Versioning" Version="1.2.6">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="EonaCat.Versioning.Helpers" Version="1.0.2" />
<PackageReference Include="EonaCat.Web.RateLimiter" Version="1.0.3" />
<PackageReference Include="EonaCat.Web.Tracer" Version="2.0.2" />
</ItemGroup>

View File

@@ -1,40 +1,62 @@
using EonaCat.Logger;
using EonaCat.Logger.EonaCatCoreLogger;
using EonaCat.Logger.EonaCatCoreLogger.Extensions;
using EonaCat.Logger.EonaCatCoreLogger.Models;
using EonaCat.Logger.LogClient;
using EonaCat.Logger.Managers;
using EonaCat.Logger.Test.Web;
using EonaCat.MemoryGuard;
using EonaCat.Versioning.Helpers;
using EonaCat.Web.RateLimiter;
using EonaCat.Web.RateLimiter.Endpoints.Extensions;
using Logger = EonaCat.Logger.Logger;
using LogLevel = EonaCat.Logger.LogClient.LogLevel;
MemoryGuard.StartDevelopment();
var builder = WebApplication.CreateBuilder(args);
int onLogCounter = 0;
var defaultColor = Console.ForegroundColor;
// Add services to the container.
Logger logger = new Logger();
logger.UseLocalTime = true;
logger.LoggerSettings.Id = "TEST";
logger.LoggerSettings.LogInfo();
logger.LoggerSettings.LogWarning();
logger.LoggerSettings.LogError();
logger.LoggerSettings.LogCritical();
logger.LoggerSettings.LogDebug();
logger.LoggerSettings.LogTrace();
logger.LoggerSettings.LogTraffic();
logger.LoggerSettings.OnLog += LoggerSettings_OnLog;
logger.LoggerSettings.UseMask = true;
// Configure the client
var centralOptions = new LogCentralOptions
namespace EonaCat.Logger.Test.Web
{
using EonaCat.Logger;
using EonaCat.Logger.EonaCatCoreLogger;
using EonaCat.Logger.EonaCatCoreLogger.Extensions;
using EonaCat.Logger.EonaCatCoreLogger.Models;
using EonaCat.Logger.LogClient;
using EonaCat.Logger.Managers;
using EonaCat.Logger.Test.Web;
using EonaCat.MemoryGuard;
using EonaCat.Versioning.Helpers;
using EonaCat.Web.RateLimiter;
using EonaCat.Web.RateLimiter.Endpoints.Extensions;
using System.Runtime.InteropServices;
public class Program
{
public static async Task Main(string[] args)
{
var _config = new MemoryGuardConfiguration
{
MonitoringInterval = TimeSpan.FromSeconds(5),
AnalysisInterval = TimeSpan.FromSeconds(10),
PredictionInterval = TimeSpan.FromSeconds(15),
LeakDetectionThreshold = TimeSpan.FromSeconds(5),
SuspiciousObjectThreshold = TimeSpan.FromSeconds(3),
CaptureStackTraces = true,
EnableAutoRemediation = true,
AutoSaveReports = true,
MemoryPressureThreshold = 500 * 1024 * 1024, // 500MB
BackgroundAnalysisInterval = TimeSpan.FromMinutes(1),
OptimizationInterval = TimeSpan.FromMinutes(10),
PatternDetectionInterval = TimeSpan.FromMinutes(3)
};
MemoryGuard.Initialize(_config);
AllocationInterceptor.Initialize(MemoryGuard.Instance);
var builder = WebApplication.CreateBuilder(args);
int onLogCounter = 0;
var defaultColor = Console.ForegroundColor;
// Add services to the container.
Logger logger = new Logger();
logger.UseLocalTime = true;
logger.LoggerSettings.Id = "TEST";
logger.LoggerSettings.LogInfo();
logger.LoggerSettings.LogWarning();
logger.LoggerSettings.LogError();
logger.LoggerSettings.LogCritical();
logger.LoggerSettings.LogDebug();
logger.LoggerSettings.LogTrace();
logger.LoggerSettings.LogTraffic();
logger.LoggerSettings.OnLog += LoggerSettings_OnLog;
logger.LoggerSettings.UseMask = true;
// Configure the client
var centralOptions = new LogCentralOptions
{
ServerUrl = "https://localhost:7282",
ApiKey = "716a964de381979df4303bf93fc091d3",
ApplicationName = "MyApp",
@@ -42,80 +64,82 @@ var centralOptions = new LogCentralOptions
Environment = "Production",
BatchSize = 50,
FlushIntervalSeconds = 5
};
};
var logClient = new LogCentralClient(centralOptions);
var logClient = new LogCentralClient(centralOptions);
// Create the adapter
var adapter = new LogCentralEonaCatAdapter(logger.LoggerSettings, logClient);
// Create the adapter
var adapter = new LogCentralEonaCatAdapter(logger.LoggerSettings, logClient);
// Now all EonaCat.Logger logs will be sent to LogCentral automatically
await logger.LogAsync("This is a test log message sent to LogCentral!", ELogType.INFO).ConfigureAwait(false);
// Now all EonaCat.Logger logs will be sent to LogCentral automatically
await logger.LogAsync("This is a test log message sent to LogCentral!", ELogType.INFO).ConfigureAwait(false);
Console.WriteLine(DllInfo.EonaCatVersion);
Console.WriteLine(VersionHelper.GetInformationalVersion());
Console.WriteLine(DllInfo.EonaCatVersion);
Console.WriteLine(VersionHelper.GetInformationalVersion());
var jsonLogger = new JsonFileLoggerProvider().CreateLogger("MyCategory") as JsonFileLogger;
jsonLogger?.SetContext("CorrelationId", "abc-123");
jsonLogger?.SetContext("UserId", "john.doe");
jsonLogger?.LogInformation("User logged in");
void LoggerSettings_OnLog(EonaCatLogMessage message)
{
// Generate a memory leak for testing
var jsonLogger = new JsonFileLoggerProvider().CreateLogger("MyCategory") as JsonFileLogger;
jsonLogger?.SetContext("CorrelationId", "abc-123");
jsonLogger?.SetContext("UserId", "john.doe");
jsonLogger?.LogInformation("User logged in");
void LoggerSettings_OnLog(EonaCatLogMessage message)
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine($"LogCounter: {++onLogCounter} {message}");
Console.ForegroundColor = defaultColor;
}
}
var options = new FileLoggerOptions();
options.MaxRolloverFiles = 5;
//options.FileSizeLimit = 1 * 1024 * 1024 / 4;
options.UseLocalTime = true;
options.UseMask = true;
builder.Logging.AddEonaCatFileLogger(fileLoggerOptions: options, filenamePrefix: "web");
builder.Logging.AddEonaCatConsoleLogger();
var options = new FileLoggerOptions();
options.MaxRolloverFiles = 5;
//options.FileSizeLimit = 1 * 1024 * 1024 / 4;
options.UseLocalTime = true;
options.UseMask = true;
builder.Logging.AddEonaCatFileLogger(fileLoggerOptions: options, filenamePrefix: "web");
builder.Logging.AddEonaCatConsoleLogger();
TcpLoggerOptions tcpLoggerOptions = new TcpLoggerOptions
{
TcpLoggerOptions tcpLoggerOptions = new TcpLoggerOptions
{
Host = "192.168.1.1",
Port = 12345,
};
};
builder.Logging.AddEonaCatTcpLogger((tcpLoggerOptions) =>
{
builder.Logging.AddEonaCatTcpLogger((tcpLoggerOptions) =>
{
tcpLoggerOptions.Port = 12345;
tcpLoggerOptions.Host = "192.168.1.1";
});
});
builder.Services.AddRazorPages();
builder.Services.AddRazorPages();
//var rateLimitOptions = new RateLimitOptions
//{
// Capacity = 10,
// Duration = TimeSpan.FromMinutes(1)
//};
//var rateLimitOptions = new RateLimitOptions
//{
// Capacity = 10,
// Duration = TimeSpan.FromMinutes(1)
//};
//builder.Services.AddRateLimiting(rateLimitOptions);
var rateOptions = new RateLimiterOptions();
rateOptions.OutputLimitMessageAsHtml = false;
rateOptions.OutputLimitMessageAsXml = false;
rateOptions.OutputLimitMessageAsJson = true;
//builder.Services.AddRateLimiting(rateLimitOptions);
var rateOptions = new RateLimiterOptions();
rateOptions.OutputLimitMessageAsHtml = false;
rateOptions.OutputLimitMessageAsXml = false;
rateOptions.OutputLimitMessageAsJson = true;
rateOptions.AddDefaultConfiguration(config =>
rateOptions.AddDefaultConfiguration(config =>
config.AddIpResolver().AddRule(3, TimeSpan.FromSeconds(10))
);
);
RateLimiterMiddleware.OnLimitResponseCreated += RateLimiterMiddlewareOnLimitResponseCreatedAsync;
RateLimiterMiddleware.OnLimitResponseCreated += RateLimiterMiddlewareOnLimitResponseCreatedAsync;
async void RateLimiterMiddlewareOnLimitResponseCreatedAsync(object? sender, HttpContext httpContext)
{
async void RateLimiterMiddlewareOnLimitResponseCreatedAsync(object? sender, HttpContext httpContext)
{
await httpContext.Response.WriteAsync(" THIS IS MY CUSTOM RATE LIMIT MESSAGE").ConfigureAwait(false);
}
}
//builder.Services.UseWebRateLimiter(rateOptions);
builder.Services.UseWebRateLimiter(rateOptions);
builder.Services.UseWebRateLimiter(rateOptions =>
{
//builder.Services.UseWebRateLimiter(rateOptions);
builder.Services.UseWebRateLimiter(rateOptions);
builder.Services.UseWebRateLimiter(rateOptions =>
{
// Configures the default rateLimitConfiguration
rateOptions.AddDefaultConfiguration(rateLimitConfiguration =>
{
@@ -126,44 +150,44 @@ builder.Services.UseWebRateLimiter(rateOptions =>
.AddRule(30, TimeSpan.FromMinutes(1)) // 30 requests could be called every 1 minute
.AddRule(500, TimeSpan.FromHours(1)); // 500 requests could be called every 1 hour
});
});
builder.Services.AddMemoryCache();
});
builder.Services.AddMemoryCache();
var app = builder.Build();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
}
//EonaCat.Web.RateLimiter.RateLimiterOptions options = new EonaCat.Web.RateLimiter.RateLimiterOptions();
//options.LimitMessage = "FUCKING NOOB!";
//options.WriteLimitMessageToResponse = true;
//options.WriteLimitMessageStatusCodeToResponse = true;
//app.UseRateLimiter(options);
//RateLimiterMiddleware.OnLimitResponseCreated += RateLimiterMiddleware_OnLimitResponseCreatedAsync;
//async void RateLimiterMiddleware_OnLimitResponseCreatedAsync(object? sender, HttpContext httpContext)
//{
// await httpContext.Response.WriteAsync("THIS IS MY CUSTOM RATE LIMIT MESSAGE");
//}
//EonaCat.Web.RateLimiter.RateLimiterOptions options = new EonaCat.Web.RateLimiter.RateLimiterOptions();
//options.LimitMessage = "FUCKING NOOB!";
//options.WriteLimitMessageToResponse = true;
//options.WriteLimitMessageStatusCodeToResponse = true;
//app.UseRateLimiter(options);
//RateLimiterMiddleware.OnLimitResponseCreated += RateLimiterMiddleware_OnLimitResponseCreatedAsync;
//async void RateLimiterMiddleware_OnLimitResponseCreatedAsync(object? sender, HttpContext httpContext)
//{
// await httpContext.Response.WriteAsync("THIS IS MY CUSTOM RATE LIMIT MESSAGE");
//}
//app.UseWebTracer();
//app.UseWebTracer();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseWebRateLimiter();
app.UseRouting();
app.UseAuthorization();
app.UseWebRateLimiter();
app.MapRazorPages().RateLimit();
app.MapRazorPages().RateLimit();
void RunLoggingExceptionTests()
{
void RunLoggingExceptionTests()
{
var loggerSettings = new LoggerSettings();
loggerSettings.FileLoggerOptions.UseLocalTime = true;
loggerSettings.UseLocalTime = true;
@@ -185,28 +209,29 @@ void RunLoggingExceptionTests()
Task.Delay(1);
}
}
}
await Task.Run(RunMemoryReportTask).ConfigureAwait(false);
await Task.Run(RunMaskTest).ConfigureAwait(false);
await Task.Run(RunWebLoggerTestsAsync).ConfigureAwait(false);
await Task.Run(RunWebLoggingTests).ConfigureAwait(false);
await Task.Run(RunLoggingTestsAsync).ConfigureAwait(false);
await Task.Run(RunLoggingExceptionTests).ConfigureAwait(false);
await Task.Run(RunWebLoggingExceptionTests).ConfigureAwait(false);
MemoryLeakTester.Start(logger);
await Task.Run(RunMemoryReportTask).ConfigureAwait(false);
await Task.Run(RunMaskTest).ConfigureAwait(false);
await Task.Run(RunWebLoggerTestsAsync).ConfigureAwait(false);
await Task.Run(RunWebLoggingTests).ConfigureAwait(false);
await Task.Run(RunLoggingTestsAsync).ConfigureAwait(false);
await Task.Run(RunLoggingExceptionTests).ConfigureAwait(false);
await Task.Run(RunWebLoggingExceptionTests).ConfigureAwait(false);
async void RunMemoryReportTask()
{
async void RunMemoryReportTask()
{
while (true)
{
await MemoryGuard.PrintReportAsync().ConfigureAwait(false);
await Task.Delay(60000).ConfigureAwait(false);
Console.ReadKey();
}
}
}
void RunWebLoggingExceptionTests()
{
void RunWebLoggingExceptionTests()
{
for (var i = 0; i < 10; i++)
{
try
@@ -226,10 +251,10 @@ void RunWebLoggingExceptionTests()
Task.Delay(1);
}
}
}
async void RunWebLoggingTests()
{
async void RunWebLoggingTests()
{
if (!Directory.Exists(logger.LogFolder))
{
Directory.CreateDirectory(logger.LogFolder);
@@ -245,10 +270,10 @@ async void RunWebLoggingTests()
Console.WriteLine($"WebLogged: {i}");
await Task.Delay(1);
}
}
}
async void RunMaskTest()
{
async void RunMaskTest()
{
if (!Directory.Exists(logger.LogFolder))
{
Directory.CreateDirectory(logger.LogFolder);
@@ -268,10 +293,10 @@ async void RunMaskTest()
Console.WriteLine($"Masked: {i}");
await Task.Delay(1);
}
}
}
async Task RunLoggingTestsAsync()
{
async Task RunLoggingTestsAsync()
{
var loggerSettings = new LoggerSettings();
loggerSettings.Id = "TEST";
loggerSettings.UseLocalTime = true;
@@ -306,10 +331,10 @@ async Task RunLoggingTestsAsync()
Console.WriteLine($"Logged: {i}");
await Task.Delay(1).ConfigureAwait(false);
}
}
}
async Task RunWebLoggerTestsAsync()
{
async Task RunWebLoggerTestsAsync()
{
var i = 0;
while (true)
{
@@ -326,6 +351,56 @@ async Task RunWebLoggerTestsAsync()
}).ConfigureAwait(false);
await Task.Delay(1).ConfigureAwait(false);
}
}
}
app.Run();
}
app.Run();
private static void Instance_LeakDetected(object? sender, EonaCat.MemoryGuard.EventArguments.MemoryLeakDetectedEventArgs e)
{
throw new NotImplementedException();
}
}
static class MemoryLeakTester
{
// Rooted forever → GC can never collect
private static readonly List<byte[]> _managedLeak = new();
private static readonly List<GCHandle> _handles = new();
public static void Start(Logger logger)
{
// Leak triggered via logging (very realistic)
logger.LoggerSettings.OnLog += OnLogLeak;
// Optional background unmanaged leak
StartUnmanagedLeak();
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("⚠ MEMORY LEAK TEST ENABLED");
Console.ResetColor();
}
private static void OnLogLeak(EonaCatLogMessage message)
{
// 5 MB per log
var data = new byte[5_000_000];
_managedLeak.Add(data);
// GCHandle leak (advanced / nasty)
_handles.Add(GCHandle.Alloc(data, GCHandleType.Normal));
}
private static void StartUnmanagedLeak()
{
_ = Task.Run(async () =>
{
while (true)
{
Marshal.AllocHGlobal(10_000_000); // 10 MB unmanaged
await Task.Delay(500).ConfigureAwait(false);
}
});
}
}
}