diff --git a/Testers/EonaCat.Logger.Test.Web/EonaCat.Logger.Test.Web.csproj b/Testers/EonaCat.Logger.Test.Web/EonaCat.Logger.Test.Web.csproj index db0a879..16c3fa4 100644 --- a/Testers/EonaCat.Logger.Test.Web/EonaCat.Logger.Test.Web.csproj +++ b/Testers/EonaCat.Logger.Test.Web/EonaCat.Logger.Test.Web.csproj @@ -7,7 +7,12 @@ - + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + diff --git a/Testers/EonaCat.Logger.Test.Web/Program.cs b/Testers/EonaCat.Logger.Test.Web/Program.cs index ad98028..d0c0137 100644 --- a/Testers/EonaCat.Logger.Test.Web/Program.cs +++ b/Testers/EonaCat.Logger.Test.Web/Program.cs @@ -1,331 +1,406 @@ -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 { - ServerUrl = "https://localhost:7282", - ApiKey = "716a964de381979df4303bf93fc091d3", - ApplicationName = "MyApp", - ApplicationVersion = "1.0.0", - Environment = "Production", - BatchSize = 50, - FlushIntervalSeconds = 5 -}; + 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; -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); - -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) -{ - 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 => + public class Program { - // 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 + public static async Task Main(string[] args) { - throw new Exception($"Normal Exception {i}"); - } - catch (Exception exception) - { - logger.WriteAsync(exception).ConfigureAwait(false); - Console.WriteLine($"Normal ExceptionLogged: {i}"); + 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", + 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); + + Console.WriteLine(DllInfo.EonaCatVersion); + Console.WriteLine(VersionHelper.GetInformationalVersion()); + + + // 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(); + + 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); + 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() + { + 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 void 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 void 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(); } - 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); - -async void 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 + private static void Instance_LeakDetected(object? sender, EonaCat.MemoryGuard.EventArguments.MemoryLeakDetectedEventArgs e) { - throw new Exception($"WebException {i}"); + throw new NotImplementedException(); } - catch (Exception exception) + } + + 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) { - 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}"); + // 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(); } - Task.Delay(1); - } -} - -async void 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)) + private static void OnLogLeak(EonaCatLogMessage message) { - await file.WriteAsync($"WebLogged: {i}{Environment.NewLine}").ConfigureAwait(false); + // 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)); } - Console.WriteLine($"WebLogged: {i}"); - await Task.Delay(1); - } -} -async void 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)) + private static void StartUnmanagedLeak() { - await file.WriteAsync(message); + _ = Task.Run(async () => + { + while (true) + { + Marshal.AllocHGlobal(10_000_000); // 10 MB unmanaged + await Task.Delay(500).ConfigureAwait(false); + } + }); } - 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(); \ No newline at end of file +} \ No newline at end of file