namespace HrynCo.Common; using System.Diagnostics; using Serilog; public interface IProfiler { Task MeasureExecutionAsync(Func> function, string blockName = ""); Task MeasureExecutionAsync(Func action, string blockName = ""); } public class Profiler(ILogger logger) : IProfiler { public async Task MeasureExecutionAsync(Func> function, string blockName = "") { logger.ForContext("PerformanceLog", true).Information("{BlockName} - Start", blockName); var stopwatch = new Stopwatch(); var process = Process.GetCurrentProcess(); long memoryBefore = process.PrivateMemorySize64; try { stopwatch.Start(); T result = await function().ConfigureAwait(false); stopwatch.Stop(); long memoryAfter = process.PrivateMemorySize64; long memoryUsed = memoryAfter - memoryBefore; long stopwatchElapsedMilliseconds = stopwatch.ElapsedMilliseconds; logger .ForContext("PerformanceLog", true) .ForContext("Measurements", true) .Information( "{BlockName} - End. Duration: {Duration} ms. Memory used: {MemoryUsed} bytes", blockName, stopwatchElapsedMilliseconds, memoryUsed); return result; } catch (Exception ex) // NOSONAR { logger .ForContext("PerformanceLog", true) .Error(ex, "{BlockName} - An error occurred", blockName); throw; } } public async Task MeasureExecutionAsync(Func action, string blockName = "") { await MeasureExecutionAsync(async () => { await action(); return null; }, blockName); } }