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; _ = Task.Run(() => { var logman = LogManager.Instance; var i = 0; while (true) { logman.WriteAsync($"Logman test {++i}", ELogType.TRACE).ConfigureAwait(false); Task.Delay(10).ConfigureAwait(false); } }).ConfigureAwait(false); // 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", ApplicationVersion = "1.0.0", Environment = "Production", BatchSize = 50, FlushIntervalSeconds = 5 }; var logClient = new LogCentralClient(centralOptions); // 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); var jsonLogger = new JsonFileLoggerProvider().CreateLogger("MyCategory") as JsonFileLogger; jsonLogger?.SetContext("CorrelationId", "abc-123"); jsonLogger?.SetContext("UserId", "john.doe"); jsonLogger?.LogInformation("User logged in"); Console.WriteLine(DllInfo.EonaCatVersion); Console.Title = VersionHelper.GetInformationalVersion(); 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(); TcpLoggerOptions tcpLoggerOptions = new TcpLoggerOptions { Host = "192.168.1.1", Port = 12345, }; builder.Logging.AddEonaCatTcpLogger((tcpLoggerOptions) => { tcpLoggerOptions.Port = 12345; tcpLoggerOptions.Host = "192.168.1.1"; }); builder.Services.AddRazorPages(); //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; rateOptions.AddDefaultConfiguration(config => config.AddIpResolver().AddRule(3, TimeSpan.FromSeconds(10)) ); RateLimiterMiddleware.OnLimitResponseCreated += RateLimiterMiddlewareOnLimitResponseCreatedAsync; 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 => { // Configures the default rateLimitConfiguration rateOptions.AddDefaultConfiguration(rateLimitConfiguration => { // throttling is based on request ip rateLimitConfiguration.AddIpResolver() // add general rules for all ips .AddRule(3, TimeSpan.FromSeconds(10)) // 3 requests could be called every 10 seconds .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(); var app = builder.Build(); // 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"); //} //app.UseWebTracer(); app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthorization(); app.UseWebRateLimiter(); app.MapRazorPages().RateLimit(); void RunLoggingExceptionTests() { var loggerSettings = new LoggerSettings(); loggerSettings.FileLoggerOptions.UseLocalTime = true; loggerSettings.UseLocalTime = true; loggerSettings.Id = "TEST"; loggerSettings.TypesToLog.Add(ELogType.INFO); var logger = new LogManager(loggerSettings); for (var i = 0; i < 10; i++) { try { throw new Exception($"Normal Exception {i}"); } catch (Exception exception) { logger.WriteAsync(exception).ConfigureAwait(false); Console.WriteLine($"Normal ExceptionLogged: {i}"); } Task.Delay(1); } } //MemoryLeakTester.Start(logger); _ = Task.Run(RunMemoryReportTask).ConfigureAwait(false); _ = Task.Run(RunMaskTest).ConfigureAwait(false); _ = Task.Run(RunWebLoggerTestsAsync).ConfigureAwait(false); _ = Task.Run(RunWebLoggingTests).ConfigureAwait(false); _ = Task.Run(RunLoggingTestsAsync).ConfigureAwait(false); _ = Task.Run(RunLoggingExceptionTests).ConfigureAwait(false); _ = Task.Run(RunWebLoggingExceptionTests).ConfigureAwait(false); async Task RunMemoryReportTask() { while (true) { await MemoryGuard.PrintReportAsync().ConfigureAwait(false); await Task.Delay(60000).ConfigureAwait(false); Console.ReadKey(); } } void RunWebLoggingExceptionTests() { for (var i = 0; i < 10; i++) { try { throw new Exception($"WebException {i}"); } catch (Exception exception) { app.Logger.LogCritical(exception, "CRITICAL"); app.Logger.LogDebug(exception, "DEBUG"); app.Logger.LogError(exception, "ERROR"); app.Logger.LogTrace(exception, "TRACE"); app.Logger.LogWarning(exception, "WARNING"); app.Logger.LogInformation(exception, "INFORMATION"); Console.WriteLine($"WebExceptionLogged: {i}"); } Task.Delay(1); } } async Task RunWebLoggingTests() { if (!Directory.Exists(logger.LogFolder)) { Directory.CreateDirectory(logger.LogFolder); } for (var i = 0; i < 9000000; i++) { app.Logger.LogInformation($"web-test {i}"); using (var file = new StreamWriter(Path.Combine(logger.LogFolder, "test.log"), true)) { await file.WriteAsync($"WebLogged: {i}{Environment.NewLine}").ConfigureAwait(false); } Console.WriteLine($"WebLogged: {i}"); await Task.Delay(1); } } async Task RunMaskTest() { if (!Directory.Exists(logger.LogFolder)) { Directory.CreateDirectory(logger.LogFolder); } for (var i = 0; i < 9000000; i++) { var message = $"mask-test {i}"; app.Logger.LogInformation("password: test"); app.Logger.LogInformation("JWT Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"); app.Logger.LogInformation("JWT Token2: eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.iOeNU4dAFFeBwNj6qdhdvm-IvDQrTa6R22lQVJVuWJxorJfeQww5Nwsra0PjaOYhAMj9jNMO5YLmud8U7iQ5gJK2zYyepeSuXhfSi8yjFZfRiSkelqSkU19I-Ja8aQBDbqXf2SAWA8mHF8VS3F08rgEaLCyv98fLLH4vSvsJGf6ueZSLKDVXz24rZRXGWtYYk_OYYTVgR1cg0BLCsuCvqZvHleImJKiWmtS0-CymMO4MMjCy_FIl6I56NqLE9C87tUVpo1mT-kbg5cHDD8I7MjCW5Iii5dethB4Vid3mZ6emKjVYgXrtkOQ-JyGMh6fnQxEFN1ft33GX2eRHluK9eg"); using (var file = new StreamWriter(Path.Combine(logger.LogFolder, "testmask.log"), true)) { await file.WriteAsync(message); } Console.WriteLine($"Masked: {i}"); await Task.Delay(1); } } async Task RunLoggingTestsAsync() { var loggerSettings = new LoggerSettings(); loggerSettings.Id = "TEST"; loggerSettings.UseLocalTime = true; loggerSettings.FileLoggerOptions.UseLocalTime = true; loggerSettings.TypesToLog.Add(ELogType.INFO); loggerSettings.TypesToLog.Add(ELogType.WARNING); loggerSettings.TypesToLog.Add(ELogType.ERROR); loggerSettings.TypesToLog.Add(ELogType.TRAFFIC); loggerSettings.TypesToLog.Add(ELogType.DEBUG); loggerSettings.LogDebug(); loggerSettings.LogInfo(); loggerSettings.LogWarning(); loggerSettings.LogError(); loggerSettings.LogCritical(); loggerSettings.LogTrace(); loggerSettings.LogTraffic(); loggerSettings.FileLoggerOptions.FileSizeLimit = 1024 * 1024 * 1; loggerSettings.FileLoggerOptions.FileNamePrefix = "AllTypes"; loggerSettings.FileLoggerOptions.MaxRolloverFiles = 5; var logger = new LogManager(loggerSettings); for (var i = 0; i < 9000000; i++) { await logger.WriteAsync($"test to file {i} INFO").ConfigureAwait(false); await logger.WriteAsync($"test to file {i} CRITICAL", ELogType.CRITICAL).ConfigureAwait(false); await logger.WriteAsync($"test to file {i} DEBUG", ELogType.DEBUG).ConfigureAwait(false); await logger.WriteAsync($"test to file {i} ERROR", ELogType.ERROR).ConfigureAwait(false); await logger.WriteAsync($"test to file {i} TRACE", ELogType.TRACE).ConfigureAwait(false); await logger.WriteAsync($"test to file {i} TRAFFIC", ELogType.TRAFFIC).ConfigureAwait(false); await logger.WriteAsync($"test to file {i} WARNING", ELogType.WARNING).ConfigureAwait(false); await logger.WriteAsync($"test to file {i} NONE", ELogType.NONE).ConfigureAwait(false); Console.WriteLine($"Logged: {i}"); await Task.Delay(1).ConfigureAwait(false); } } async Task RunWebLoggerTestsAsync() { var i = 0; while (true) { i++; await Task.Run(async () => { await logger.LogAsync($"test via logger {i}").ConfigureAwait(false); await logger.LogAsync($"test via logger {i}", ELogType.CRITICAL).ConfigureAwait(false); await logger.LogAsync($"test via logger {i}", ELogType.DEBUG).ConfigureAwait(false); await logger.LogAsync($"test via logger {i}", ELogType.ERROR).ConfigureAwait(false); await logger.LogAsync($"test via logger {i}", ELogType.TRAFFIC).ConfigureAwait(false); await logger.LogAsync($"test via logger {i}", ELogType.WARNING).ConfigureAwait(false); await logger.LogAsync($"test via logger {i}", ELogType.NONE).ConfigureAwait(false); }).ConfigureAwait(false); await Task.Delay(1).ConfigureAwait(false); } } app.Run(); } private static void Instance_LeakDetected(object? sender, EonaCat.MemoryGuard.EventArguments.MemoryLeakDetectedEventArgs e) { // Leak detected } } static class MemoryLeakTester { // Rooted forever → GC can never collect private static readonly List _managedLeak = new(); private static readonly List _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); } }); } } }