CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-dropwizard-metrics--metrics-core

Comprehensive metrics collection and monitoring library providing counters, gauges, histograms, meters, and timers for Java applications.

Pending
Overview
Eval results
Files

core-metrics.mddocs/

Core Metrics Framework

The core metrics framework provides the fundamental building blocks for application monitoring: the central registry system and the five primary metric types. These components form the foundation for all metrics collection and are designed for high-performance, thread-safe operation in production environments.

MetricRegistry

The MetricRegistry is the central repository for all metrics in an application. It provides factory methods for creating metrics, manages metric lifecycles, and serves as the primary integration point for reporting systems.

public class MetricRegistry implements MetricSet {
    // Constructor
    public MetricRegistry();
    
    // Metric factory methods - primary API for creating metrics
    public Counter counter(String name);
    public Counter counter(String name, MetricSupplier<Counter> supplier);
    public Histogram histogram(String name);
    public Histogram histogram(String name, MetricSupplier<Histogram> supplier);
    public Meter meter(String name);
    public Meter meter(String name, MetricSupplier<Meter> supplier);
    public Timer timer(String name);
    public Timer timer(String name, MetricSupplier<Timer> supplier);
    public <T extends Gauge> T gauge(String name);
    public <T extends Gauge> T gauge(String name, MetricSupplier<T> supplier);
    
    // Generic registration and management
    public <T extends Metric> T register(String name, T metric) throws IllegalArgumentException;
    public <T> Gauge<T> registerGauge(String name, Gauge<T> metric) throws IllegalArgumentException;
    public void registerAll(MetricSet metrics) throws IllegalArgumentException;
    public void registerAll(String prefix, MetricSet metrics) throws IllegalArgumentException;
    public boolean remove(String name);
    public void removeMatching(MetricFilter filter);
    
    // Registry inspection
    public SortedSet<String> getNames();
    
    // Metric retrieval by type
    public SortedMap<String, Counter> getCounters();
    public SortedMap<String, Counter> getCounters(MetricFilter filter);
    public SortedMap<String, Gauge> getGauges();
    public SortedMap<String, Gauge> getGauges(MetricFilter filter);
    public SortedMap<String, Histogram> getHistograms();
    public SortedMap<String, Histogram> getHistograms(MetricFilter filter);
    public SortedMap<String, Meter> getMeters();
    public SortedMap<String, Meter> getMeters(MetricFilter filter);
    public SortedMap<String, Timer> getTimers();
    public SortedMap<String, Timer> getTimers(MetricFilter filter);
    public Map<String, Metric> getMetrics();
    
    // Listener management
    public void addListener(MetricRegistryListener listener);
    public void removeListener(MetricRegistryListener listener);
    
    // Utility methods for metric naming
    public static String name(String name, String... names);
    public static String name(Class<?> klass, String... names);
    
    // MetricSet implementation
    public Map<String, Metric> getMetrics();
}

Usage Examples

Basic Registry Setup:

MetricRegistry registry = new MetricRegistry();

// Create metrics using factory methods
Counter requestCount = registry.counter("requests");
Timer responseTime = registry.timer("response.time");
Histogram responseSizes = registry.histogram("response.sizes");

Hierarchical Metric Naming:

// Using static name() method for dot-separated hierarchical names
String timerName = MetricRegistry.name("http", "requests", "GET", "/api/users");
Timer timer = registry.timer(timerName); // Creates "http.requests.GET./api/users"

// Using class-based naming
Timer classTimer = registry.timer(MetricRegistry.name(UserService.class, "createUser"));
// Creates "com.example.UserService.createUser"

Registry Filtering:

// Get only counters with names starting with "http"
SortedMap<String, Counter> httpCounters = registry.getCounters(
    MetricFilter.startsWith("http"));

// Remove all metrics matching a pattern
registry.removeMatching(MetricFilter.contains("temp"));

Counter

Counters are the simplest metric type, providing thread-safe increment and decrement operations. They maintain a running total that can only be changed by specified amounts.

public class Counter implements Metric, Counting {
    // Constructor
    public Counter();
    
    // Increment operations
    public void inc();
    public void inc(long n);
    
    // Decrement operations
    public void dec();
    public void dec(long n);
    
    // Value access
    public long getCount();
}

Usage Examples

Counter requestCounter = registry.counter("requests.total");
Counter errorCounter = registry.counter("errors.total");

// Basic incrementing
requestCounter.inc();           // Increment by 1
requestCounter.inc(5);          // Increment by 5

// Error tracking
if (errorOccurred) {
    errorCounter.inc();
}

// Batch processing
int batchSize = processedItems.size();
requestCounter.inc(batchSize);

// Current value
long totalRequests = requestCounter.getCount();

Gauge

Gauges provide instantaneous readings of arbitrary values. They are functional interfaces that you implement to return current values, making them ideal for measuring things like queue sizes, memory usage, or any other fluctuating values.

@FunctionalInterface
public interface Gauge<T> extends Metric {
    T getValue();
}

Usage Examples

import java.util.concurrent.ConcurrentLinkedQueue;

Queue<String> processingQueue = new ConcurrentLinkedQueue<>();

// Lambda gauge for queue size
Gauge<Integer> queueSize = processingQueue::size;
registry.gauge("queue.size", queueSize);

// Anonymous class gauge
registry.gauge("memory.usage", new Gauge<Long>() {
    @Override
    public Long getValue() {
        Runtime runtime = Runtime.getRuntime();
        return runtime.totalMemory() - runtime.freeMemory();
    }
});

// Method reference gauge  
registry.gauge("active.threads", Thread::activeCount);

// Custom calculation gauge
registry.gauge("cpu.utilization", () -> {
    return managementFactory.getOperatingSystemMXBean().getProcessCpuLoad();
});

Meter

Meters measure the rate of events over time, providing mean throughput and exponentially-weighted moving averages over 1, 5, and 15-minute windows. They're similar to Unix load averages but for arbitrary events.

public class Meter implements Metered {
    // Constructors
    public Meter();
    public Meter(MovingAverages movingAverages);
    public Meter(Clock clock);
    public Meter(MovingAverages movingAverages, Clock clock);
    
    // Event marking
    public void mark();
    public void mark(long n);
    
    // Rate access (from Metered interface)
    public long getCount();
    public double getMeanRate();
    public double getOneMinuteRate();
    public double getFiveMinuteRate();
    public double getFifteenMinuteRate();
}

Usage Examples

Meter requestMeter = registry.meter("requests.rate");
Meter errorMeter = registry.meter("errors.rate");

// Mark single events
requestMeter.mark();

// Mark multiple events
int batchSize = 10;
requestMeter.mark(batchSize);

// Error rate tracking
try {
    processRequest();
    requestMeter.mark();
} catch (Exception e) {
    errorMeter.mark();
    throw e;
}

// Accessing rates
double avgRequestsPerSecond = requestMeter.getMeanRate();
double recentRequestsPerSecond = requestMeter.getOneMinuteRate();

System.out.printf("Requests: %.2f/sec (1min: %.2f/sec)%n", 
    avgRequestsPerSecond, recentRequestsPerSecond);

Histogram

Histograms measure the statistical distribution of values in a stream of data. They provide statistical summaries including minimum, maximum, mean, standard deviation, and various percentiles, while using configurable sampling strategies to manage memory usage.

public class Histogram implements Metric, Sampling, Counting {
    // Constructor
    public Histogram(Reservoir reservoir);
    
    // Value recording
    public void update(int value);
    public void update(long value);
    
    // Statistical access
    public long getCount();
    public Snapshot getSnapshot();
}

Usage Examples

// Using default exponentially decaying reservoir
Histogram responseSizes = registry.histogram("response.sizes");

// Using custom reservoir
Histogram customHistogram = new Histogram(new UniformReservoir(1000));
registry.register("custom.distribution", customHistogram);

// Recording values
responseSizes.update(1024);         // Response size in bytes
responseSizes.update(2048);
responseSizes.update(512);

// Getting statistics
Snapshot snapshot = responseSizes.getSnapshot();
System.out.printf("Response sizes - Count: %d, Mean: %.2f, Median: %.2f, 95th: %.2f%n",
    responseSizes.getCount(),
    snapshot.getMean(),
    snapshot.getMedian(),
    snapshot.get95thPercentile());

// Batch processing statistics
List<Integer> responseTimes = getResponseTimes();
for (int time : responseTimes) {
    responseSizes.update(time);
}

Timer

Timers are essentially histograms of duration measurements that also track the rate of events. They provide comprehensive timing statistics including duration distributions and throughput metrics, making them ideal for measuring method execution times, request processing times, and other time-based operations.

public class Timer implements Metered, Sampling {
    // Constructors
    public Timer();
    public Timer(Reservoir reservoir);
    public Timer(Reservoir reservoir, Clock clock);
    
    // Duration recording
    public void update(long duration, TimeUnit unit);
    public void update(Duration duration);
    
    // Timing convenience methods
    public <T> T time(Callable<T> event) throws Exception;
    public void time(Runnable event);
    public <T> T timeSupplier(Supplier<T> event);
    public Context time();
    
    // Statistical access (from Sampling)
    public Snapshot getSnapshot();
    
    // Rate access (from Metered) 
    public long getCount();
    public double getMeanRate();
    public double getOneMinuteRate(); 
    public double getFiveMinuteRate();
    public double getFifteenMinuteRate();
    
    // Nested Context class for manual timing
    public static class Context implements AutoCloseable {
        public long stop();
        public void close();
    }
}

Usage Examples

Manual Timing with Context:

Timer requestTimer = registry.timer("request.duration");

// Manual timing with try-with-resources
try (Timer.Context context = requestTimer.time()) {
    processRequest();
    // Timing stops automatically when context closes
}

// Manual timing with explicit stop
Timer.Context context = requestTimer.time();
try {
    processRequest();
} finally {
    long elapsed = context.stop(); // Returns elapsed time in nanoseconds
    System.out.println("Request took " + elapsed + " nanoseconds");
}

Timing Callables and Runnables:

Timer dbTimer = registry.timer("database.query.time");

// Time a Callable (with return value)
String result = dbTimer.time(() -> {
    return database.executeQuery("SELECT * FROM users");
});

// Time a Runnable (no return value)  
dbTimer.time(() -> {
    database.executeUpdate("UPDATE users SET last_login = NOW()");
});

// Time a Supplier
List<User> users = dbTimer.timeSupplier(() -> userService.getAllUsers());

Direct Duration Recording:

Timer responseTimer = registry.timer("response.time");

long startTime = System.nanoTime();
processRequest();
long endTime = System.nanoTime();

// Record duration directly
responseTimer.update(endTime - startTime, TimeUnit.NANOSECONDS);

// Record using Duration (Java 8+)
Instant start = Instant.now();
processRequest();
Duration elapsed = Duration.between(start, Instant.now());
responseTimer.update(elapsed);

Accessing Timer Statistics:

Timer timer = registry.timer("api.request.time");

// Get duration statistics
Snapshot snapshot = timer.getSnapshot();
System.out.printf("Request timing - Count: %d, Mean: %.2fms, 99th: %.2fms%n",
    timer.getCount(),
    snapshot.getMean() / 1_000_000.0,  // Convert nanoseconds to milliseconds
    snapshot.get99thPercentile() / 1_000_000.0);

// Get rate statistics  
System.out.printf("Request rate - Mean: %.2f/sec, 1min: %.2f/sec%n",
    timer.getMeanRate(),
    timer.getOneMinuteRate());

Core Interfaces

The core metrics implement several key interfaces that provide common functionality:

Counting Interface

public interface Counting {
    long getCount();
}

Implemented by: Counter, Histogram, Meter, Timer

Metered Interface

public interface Metered extends Metric, Counting {
    long getCount();
    double getFifteenMinuteRate();
    double getFiveMinuteRate(); 
    double getMeanRate();
    double getOneMinuteRate();
}

Implemented by: Meter, Timer

Sampling Interface

public interface Sampling {
    Snapshot getSnapshot();
}

Implemented by: Histogram, Timer

Metric Interface

public interface Metric {
    // Tag interface - no methods
}

Base interface implemented by all metric types.

Best Practices

Metric Naming

  • Use hierarchical dot-separated names: "http.requests.GET.api.users"
  • Be consistent with naming conventions across your application
  • Use MetricRegistry.name() utility methods for consistent naming
  • Consider using class names as prefixes for method-level metrics

Registry Management

  • Create one MetricRegistry per application (use SharedMetricRegistries for global access)
  • Register metrics early in application lifecycle, ideally during initialization
  • Use meaningful metric names that clearly indicate what is being measured

Performance Considerations

  • Metric operations are designed to be very fast (nanoseconds) and thread-safe
  • Prefer instance variables for frequently-accessed metrics rather than registry lookups
  • Consider the overhead of string concatenation in hot paths when building metric names

Error Handling

  • Metric operations should never throw exceptions in normal operation
  • Metrics are designed to degrade gracefully under memory pressure
  • Failed metric registrations throw IllegalArgumentException for duplicate names

Install with Tessl CLI

npx tessl i tessl/maven-io-dropwizard-metrics--metrics-core

docs

advanced-gauges.md

core-metrics.md

index.md

reporting.md

reservoirs-sampling.md

utilities.md

tile.json