Metric instruments

Learn about the different types of metric instruments available in OpenTelemetry .NET

This guide explains the different types of metric instruments available in OpenTelemetry .NET and how to use them effectively.

Understanding metric instruments

OpenTelemetry provides several types of instruments to measure different kinds of data:

Instrument TypeBehaviorTypical Use Cases
CounterMonotonically increasing valueRequest counts, error counts
UpDownCounterValue that can increase or decreaseQueue size, active connections
HistogramDistribution of recorded valuesRequest durations, response sizes
GaugeObservation of a value at a specific point in timeCPU usage, memory usage

Counter

A Counter records a value that is summed over time and never decreases. It’s ideal for metrics that only increase, such as request counts, completed operations, or error counts.

Creating a counter

using System.Diagnostics.Metrics; // Create a meter var meter = new Meter("MyCompany.MyProduct", "1.0.0"); // Create a counter var requestCounter = meter.CreateCounter<long>("request_counter", "requests", "Counts the number of requests");

Recording measurements

// Increment by 1 requestCounter.Add(1); // Increment with attributes requestCounter.Add(1, new("endpoint", "/api/users"), new("method", "GET"));

UpDownCounter

An UpDownCounter records a value that can both increase and decrease, representing a current value at a given time. It’s useful for tracking values like queue sizes, active connections, or resource pool usage.

Creating an UpDownCounter

// Create an up-down counter var activeConnectionsCounter = meter.CreateUpDownCounter<int>("active_connections", "connections", "Number of active connections");

Recording UpDownCounter measurements

// Increment by 1 activeConnectionsCounter.Add(1); // Decrement by 1 activeConnectionsCounter.Add(-1); // With attributes activeConnectionsCounter.Add(1, new("pool", "worker"), new("region", "west"));

Histogram

A Histogram records a distribution of values, capturing statistics like count, sum, min, max, and percentiles. It’s ideal for measuring durations, sizes, and other distributed values.

Creating a histogram

// Create a histogram var requestDurationHistogram = meter.CreateHistogram<double>("request_duration", "ms", "Request duration in milliseconds");

Recording histogram measurements

// Record a duration requestDurationHistogram.Record(213.5); // With attributes requestDurationHistogram.Record(42.3, new("endpoint", "/api/users"), new("method", "GET"));

Observable instruments

Observable instruments allow you to collect measurements on-demand when metrics are collected rather than recording them directly in your code. This is useful for metrics that are better sampled periodically.

Observable counter

// Create an observable counter meter.CreateObservableCounter("processed_items_total", () => { // Return the current count from some internal state return new Measurement<long>(GetCurrentProcessedCount(), new("queue", "default")); }, "items", "Total number of processed items");

Observable UpDownCounter

// Create an observable up-down counter meter.CreateObservableUpDownCounter("active_tasks", () => { // Return current values from internal state return new[] { new Measurement<int>(GetHighPriorityTaskCount(), new("priority", "high")), new Measurement<int>(GetLowPriorityTaskCount(), new("priority", "low")) }; }, "tasks", "Current number of active tasks");

Observable gauge

// Create an observable gauge meter.CreateObservableGauge("cpu_usage", () => { // Get current CPU usage percentage return new Measurement<double>(GetCurrentCpuUsage()); }, "%", "Current CPU usage percentage");

Batching observable measurements

You can also register a callback that returns multiple measurements for multiple instruments:

// Register a single callback for multiple observable instruments var observableCounter = meter.CreateObservableCounter<long>("my_observable_counter", "items"); var observableGauge = meter.CreateObservableGauge<double>("my_observable_gauge", "%"); meter.RegisterObservableCallback(observableInstruments => { // Record a value for the counter observableInstruments.Observe(observableCounter, 42, new("type", "product_a")); // Record a value for the gauge observableInstruments.Observe(observableGauge, 12.3, new("resource", "cpu")); }, observableCounter, observableGauge);

Unit and description

When creating instruments, it’s a good practice to specify the unit and description:

// Specify unit and description var requestSizeHistogram = meter.CreateHistogram<long>( name: "http.request.size", unit: "By", // bytes description: "Size of HTTP request in bytes" );

Common units include:

  • Time: ms (milliseconds), s (seconds), min (minutes)
  • Bytes: By (bytes), KiBy (kibibytes), MiBy (mebibytes)
  • Count: Typically unitless, or use specific units like requests

Best practices

  1. Choose the right instrument - Select the instrument type that best matches the behavior of the metric you’re measuring
  2. Use meaningful names - Follow semantic conventions for metric names
  3. Add descriptive attributes - Use attributes to distinguish between different aspects of what you’re measuring
  4. Be mindful of cardinality - Too many unique attribute combinations can cause performance issues
  5. Reuse instruments - Create instruments once and reuse them throughout your application
  6. Provide units and descriptions - Always specify units and descriptions for better observability

Learn more