30538b7262
Preserve legacy profiler contracts and record expected cancellation below error level.
89 lines
2.8 KiB
C#
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);
|
|
}
|
|
}
|