Diagnostics and timing

TimingScope

Pineapple.Diagnostics.TimingScope logs the elapsed time of a using block through Microsoft.Extensions.Logging.ILogger at Debug level. It records the calling member automatically and opens a logging scope Caller=[member]. When Debug is disabled, it does nothing — no stopwatch, no allocation of a log message.

using Pineapple.Diagnostics;

public async Task<IReadOnlyList<Customer>> LoadAsync()
{
    using (new TimingScope("LoadCustomers", _logger))
    {
        return await _db.Customers.ToListAsync();
    }
}
// dbug: Operation [LoadCustomers] called from [LoadAsync] took 42.17ms

MeasureScope

Counts successful calls made through Count(Action) and writes the total to Debug.WriteLine on dispose.

using (var scope = new MeasureScope())
{
    foreach (var item in items)
        scope.Count(() => Process(item));
}

CallsPerMinute

A thread-safe rolling calls-per-minute counter over the last 60 seconds.

var cpm = new CallsPerMinute();
cpm.Add();                       // call on every request
double rate = cpm.Value;

ConsoleColorScope

Temporarily changes Console.ForegroundColor and restores it on dispose.

using (new ConsoleColorScope(ConsoleColor.Red))
{
    Console.WriteLine("Build failed");
}

Last reviewed October 13, 2026 · Pineapple 2.0.0