Chronolap 1.2.1

dotnet add package Chronolap --version 1.2.1
                    
NuGet\Install-Package Chronolap -Version 1.2.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Chronolap" Version="1.2.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Chronolap" Version="1.2.1" />
                    
Directory.Packages.props
<PackageReference Include="Chronolap" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Chronolap --version 1.2.1
                    
#r "nuget: Chronolap, 1.2.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Chronolap@1.2.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Chronolap&version=1.2.1
                    
Install as a Cake Addin
#tool nuget:?package=Chronolap&version=1.2.1
                    
Install as a Cake Tool

Chronolap

Advanced stopwatch library with lap tracking support for .NET developers.

Supported Frameworks

.NET Core 3.0+
.NET 5+
.NET 6+
.NET 7+
.NET Standard 2.1

Features

  • Lap tracking with configurable maximum lap count
  • Measurement time recording (synchronous and asynchronous)
  • Return value support in measurement methods
  • Exception handling support (measurements are recorded even when exceptions occur)
  • Pause / Resume functionality
  • Advanced statistics (Min, Max, Mean, Median, Standard Deviation, Variance, Percentiles)
  • Fastest/Slowest lap detection
  • ILogger logging support
  • OpenTelemetry Activity integration
  • Dependency Injection support (AddChronolap() extension method)
  • Configurable minimum lap count for statistics
  • Cached total lap time calculation for optimal performance
  • Thread-safe - Safe to use in multi-threaded environments

Installation

Install via NuGet:

dotnet add package Chronolap

Usage

Basic Usage

using Chronolap;
using System;
using System.Threading;

class Program
{
    static void Main()
    {
        var timer = new ChronolapTimer();

        timer.Start();
        Thread.Sleep(100);
        timer.Lap("First lap");
        Thread.Sleep(200);
        timer.Lap("Second lap");
        timer.Stop();

        foreach (var lap in timer.Laps)
        {
            Console.WriteLine(lap);
        }
    }
}

Measurement with Return Values

var timer = new ChronolapTimer();
timer.Start();

// Measure and get return value
int result = timer.MeasureExecutionTime(() => CalculateValue(), "Calculation");
Console.WriteLine($"Result: {result}");

// Async measurement with return value
var data = await timer.MeasureExecutionTimeAsync(async () => 
{
    return await FetchDataAsync();
}, "DataFetch");

Exception Handling

var timer = new ChronolapTimer();
timer.Start();

// Lap is recorded even if exception occurs
try
{
    timer.MeasureExecutionTimeWithExceptionHandling(() => 
    {
        RiskyOperation();
    }, "RiskyOperation");
}
catch (Exception ex)
{
    // Lap was still recorded
    Console.WriteLine($"Operation failed but timing was recorded");
}

// With return value
int? result = null;
try
{
    result = timer.MeasureExecutionTimeWithExceptionHandling(() => 
    {
        return RiskyOperationWithReturn();
    }, "RiskyOperation");
}
finally
{
    // Timing is always recorded
}

Advanced Statistics

var timer = new ChronolapTimer();
timer.Start();

// Record multiple laps
for (int i = 0; i < 50; i++)
{
    Thread.Sleep(10 + i);
    timer.Lap($"Lap{i}");
}

// Calculate statistics
var min = timer.CalculateLapStatistic(LapStatisticsType.Min);
var max = timer.CalculateLapStatistic(LapStatisticsType.Max);
var mean = timer.CalculateLapStatistic(LapStatisticsType.ArithmeticMean);
var median = timer.CalculateLapStatistic(LapStatisticsType.Median);
var stdDev = timer.CalculateLapStatistic(LapStatisticsType.StandardDeviation);
var variance = timer.CalculateLapStatistic(LapStatisticsType.Variance);

// Calculate percentiles
var p50 = timer.CalculatePercentile(50);  // Median
var p95 = timer.CalculatePercentile(95);  // 95th percentile
var p99 = timer.CalculatePercentile(99);  // 99th percentile

// Find fastest and slowest laps
var fastest = timer.GetFastestLap();
var slowest = timer.GetSlowestLap();

Console.WriteLine($"Fastest: {fastest?.Name} ({fastest?.Duration.TotalMilliseconds} ms)");
Console.WriteLine($"Slowest: {slowest?.Name} ({slowest?.Duration.TotalMilliseconds} ms)");

Configuration

// Configure maximum lap count and minimum lap count for statistics
var timer = new ChronolapTimer(
    maxLapCount: 5000, 
    minimumLapCountForStatistics: 50
);

// Or change minimum lap count at runtime
timer.MinimumLapCountForStatistics = 100;

// Access configuration
Console.WriteLine($"Max Lap Count: {timer.MaxLapCount}");
Console.WriteLine($"Min Lap Count for Stats: {timer.MinimumLapCountForStatistics}");

Pause and Resume

var timer = new ChronolapTimer();
timer.Start();

Thread.Sleep(100);
timer.Lap("Before pause");

timer.Pause();
// Timer is paused, elapsed time won't increase
Thread.Sleep(1000); // This won't be counted

timer.Resume();
Thread.Sleep(200);
timer.Lap("After resume");

timer.Stop();

Thread-Safe Usage

Chronolap is fully thread-safe and can be safely used in multi-threaded environments:

var timer = new ChronolapTimer();
timer.Start();

// Multiple threads can safely add laps concurrently
Parallel.For(0, 100, i =>
{
    Thread.Sleep(10);
    timer.Lap($"Lap{i}");
});

// Statistics can be calculated while other threads are adding laps
var mean = timer.CalculateLapStatistic(LapStatisticsType.ArithmeticMean);
var fastest = timer.GetFastestLap();

timer.Stop();

All public methods and properties are thread-safe, ensuring safe concurrent access from multiple threads.

OpenTelemetry Activity Extensions Usage

You can easily integrate Chronolap lap timings with OpenTelemetry Activity by using the provided extension methods. These allow you to add lap duration tags directly to your active tracing activities.

Example

using System.Diagnostics;
using Chronolap;
using Chronolap.OpenTelemetry;

var activitySource = new ActivitySource("MyCompany.MyProduct.MyLibrary");
var timer = new ChronolapTimer();

using (var activity = activitySource.StartActivity("ExampleOperation"))
{
    timer.Start();

    // Perform some operations
    // ...

    timer.Lap("Initialization");
    // Lap after initialization

    timer.Lap("Processing");
    // Lap after processing

    timer.Stop();

    // Add last lap duration as tag
    activity.Lap("Processing", timer);

    // Or export all lap durations as tags at once
    activity.ExportAllLaps(timer);
}

Dependency Injection Support

Chronolap provides built-in support for Dependency Injection through the AddChronolap() extension method. This allows you to easily register ChronolapTimer in your service collection and inject it into your classes.

Basic Usage

using Chronolap;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

var builder = Host.CreateApplicationBuilder(args);

// Register Chronolap with default settings
builder.Services.AddChronolap();

// Or configure options
builder.Services.AddChronolap(options =>
{
    options.MaxLapCount = 5000;
    options.MinimumLapCountForStatistics = 50;
});

var app = builder.Build();

Using in Your Classes

using Chronolap;
using Microsoft.Extensions.Logging;

public class MyService
{
    private readonly ChronolapTimer _timer;
    private readonly ILogger<MyService> _logger;

    public MyService(ChronolapTimer timer, ILogger<MyService> logger)
    {
        _timer = timer;
        _logger = logger;
    }

    public void DoWork()
    {
        _timer.Start();
        
        // Your operations here
        Thread.Sleep(100);
        _timer.Lap("Operation 1");
        
        Thread.Sleep(200);
        _timer.Lap("Operation 2");
        
        _timer.Stop();
        
        // Log results using extension method
        _logger.LogLaps(_timer, LogLevel.Information);
    }
}

Configuration Options

The AddChronolap() method supports configuration through ChronolapOptions:

  • MaxLapCount: Maximum number of laps to store (default: 1000)
  • MinimumLapCountForStatistics: Minimum lap count required for statistics calculation (default: 30)

If ILogger<ChronolapTimer> is registered in your DI container, ChronolapTimer will automatically use it for logging lap information.

Contributing

Contributions are welcome! Please open issues or pull requests.

What's New

v1.2.1 - Thread-Safe Support

Thread Safety:

  • Full thread-safe implementation using lock mechanism
  • Safe concurrent access from multiple threads
  • All public methods and properties are thread-safe
  • Thread-safe lap recording, statistics calculation, and state management

v1.2.0 - Advanced Statistics, Performance Improvements & New Features

New Statistics Features:

  • Min, Max, Variance statistics support
  • Percentile calculation (P50, P95, P99, etc.)
  • GetFastestLap() and GetSlowestLap() methods
  • Configurable minimum lap count for statistics

Performance Improvements:

  • Cached TotalLapTime calculation (O(1) instead of O(n))
  • Configurable maximum lap count

New Measurement Features:

  • Return value support in measurement methods
  • Exception handling support (measurements recorded even when exceptions occur)
  • Both synchronous and asynchronous variants

Configuration:

  • MaxLapCount constructor parameter
  • MinimumLapCountForStatistics property

ILogger Integration:

  • Chronolap can now log lap results directly through ILogger
  • Batch Logging: All laps can be logged at once in a clean format
  • Customizable Formatting: Use the default format or provide your own custom formatter
  • Log Level Support: Log laps at Debug, Information, Warning, or any other log level

Example - Logging Extension

var loggerFactory = LoggerFactory.Create(builder => builder.AddConsole());
var logger = loggerFactory.CreateLogger<Program>();

var chrono = new ChronolapTimer();
chrono.Start();

Thread.Sleep(500);
chrono.Lap("First operation");

Thread.Sleep(700);
chrono.Lap("Second operation");

chrono.Stop();

logger.LogLaps(chrono, LogLevel.Information);

Output will looks like this;

info: Program[0]
      Chronolap Results:
      Lap 1: 00:00:00.5000000
      Lap 2: 00:00:01.2000000

Support

If you find this project useful, consider supporting me:

Buy Me a Coffee

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.1 is compatible. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (3)

Showing the top 3 NuGet packages that depend on Chronolap:

Package Downloads
Chronolap.OpenTelemetry

Advanced Stopwatch with Lap Tracking support for .NET developers With OpenTelemetry Extensions

Chronolap.Extensions.Logging

Advanced Stopwatch with Lap Tracking support for .NET developers

Chronolap.Profiler

Automatic method profiling with AOP (Castle.DynamicProxy) support for Chronolap. Profile methods using simple attributes.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.2.1 246 11/22/2025
1.2.0 487 11/20/2025
1.1.0 275 7/1/2025
1.0.0 218 6/30/2025