Files
hrynco-common/HrynCo.Common/Profiler.cs
T
agrynco 30538b7262 fix(common): classify request cancellation in profiler
Preserve legacy profiler contracts and record expected cancellation below error level.
2026-10-11 17:50:19 +03:00

89 lines
2.8 KiB
C#

namespace HrynCo.Common;
using System.Diagnostics;
using Serilog;
public interface IProfiler
{
Task<T> MeasureExecutionAsync<T>(Func<Task<T>> function, string blockName = "");
Task<T> MeasureExecutionAsync<T>(Func<Task<T>> function, string blockName, CancellationToken cancellationToken)
{
return MeasureExecutionAsync(function, blockName);
}
Task MeasureExecutionAsync(Func<Task> action, string blockName = "");
Task MeasureExecutionAsync(Func<Task> action, string blockName, CancellationToken cancellationToken)
{
return MeasureExecutionAsync(action, blockName);
}
}
public class Profiler(ILogger logger) : IProfiler
{
public Task<T> MeasureExecutionAsync<T>(Func<Task<T>> function, string blockName = "")
{
return MeasureExecutionAsync(function, blockName, CancellationToken.None);
}
public async Task<T> MeasureExecutionAsync<T>(Func<Task<T>> function, string blockName, CancellationToken cancellationToken)
{
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 (OperationCanceledException) when (cancellationToken.IsCancellationRequested)
{
logger
.ForContext("PerformanceLog", true)
.Debug("{BlockName} - Canceled", blockName);
throw;
}
catch (Exception ex) // NOSONAR
{
logger
.ForContext("PerformanceLog", true)
.Error(ex, "{BlockName} - An error occurred", blockName);
throw;
}
}
public Task MeasureExecutionAsync(Func<Task> action, string blockName = "")
{
return MeasureExecutionAsync(action, blockName, CancellationToken.None);
}
public async Task MeasureExecutionAsync(Func<Task> action, string blockName, CancellationToken cancellationToken)
{
await MeasureExecutionAsync<object?>(async () =>
{
await action();
return null;
}, blockName, cancellationToken);
}
}