Chaturmind
LearnDSASystem DesignDevOpsEngineering GrowthBlog
Start learning
Chaturmind

Structured learning paths for engineers who want to go deep. Written by practitioners.

Learn

  • Java
  • DSA
  • System Design
  • Spring Boot
  • AI / ML
  • DevOps
  • Engineering Growth

Company

  • Blog
  • Contact

Legal

  • Privacy Policy
  • Terms of Service

© 2026 Chaturmind. All rights reserved.

Built for engineers who want to go deep.


← Low-Level Design & Design Patterns

OOP Fundamentals & SOLID Principles

  • Object-Oriented Design Refresher
  • Single Responsibility & Open/Closed
  • Liskov Substitution & Interface Segregation
  • Dependency Inversion

Creational Design Patterns

  • Singleton Pattern
  • Factory & Abstract Factory
  • Builder Pattern
  • Prototype Pattern

Structural Design Patterns

  • Adapter & Facade
  • Decorator Pattern
  • Composite & Proxy
  • Bridge & Flyweight

Behavioral Design Patterns

  • Strategy Pattern
  • Observer Pattern
  • Command Pattern
  • Template Method
  • State Pattern
  • Chain of Responsibility
  • Iterator & Mediator
  • Visitor Pattern

Machine Coding Exercises

  • Parking Lot — Requirements & Class Design
  • Parking Lot — Implementation
  • Elevator System — Requirements & Class Design
  • Elevator System — Implementation & Scheduling
  • Library Management System
  • Tic-Tac-Toe / Board Game Design
  • Chess Engine Design
  • Vending Machine Design
  • ATM System Design
  • In-Memory Rate Limiter
  • Thread-Safe LRU Cache
  • Connection Pool Design
  • Producer-Consumer Class Design
  • Movie Ticket Booking System
  • Hotel Reservation System
  • Airline Booking / Seat Selection System
  • Splitwise / Expense Sharing System
  • Design a Logging Framework
  • Design a Notification/Observer-Based Pub-Sub
  • Design a Cache with Pluggable Eviction Policy
  • Design Snake and Ladder
  • Design a Card Game Framework
  • Design an Inventory Management System
  • Restaurant Management System
  • Food Delivery Order Matching
  • Design a Shopping Cart & Checkout Flow
  • Design a Recommendation Engine
  • Design a Job Scheduler
  • Design a Circuit Breaker
  • Design a Distributed ID Generator
  • Design a Pub-Sub Message Broker
  • Design Twitter/X
  • Multi-Pattern Problem: Design a Ride Booking Class Model
  • Multi-Pattern Problem: Design a Food Ordering Class Model
  • Design an Authentication/Authorization Module
  • Design a Form/Survey Builder
  • Design a Meeting Room / Calendar Booking System
  • Design a Search/Filter Engine for an E-Commerce Catalog
  • Design a Voting/Polling System
  • Design a Retry Mechanism with Backoff
  • Design a Health Check Aggregator
  • Design a Feature Flag System
  • Design a Config Management Client
  • Design a Leader Election Algorithm
  • Design a Distributed Counter
  • Design a Bloom Filter
  • Design a Consistent Hashing Ring
  • Design a Distributed Tracing Library
  • Design a Metrics Collection Library
  • Design an Audit Logging Framework
  • Design a Plugin/Extension System
  • Design a Workflow Engine
  • Multi-Pattern Capstone: Design a Food Delivery App
Chaturmind
← Low-Level Design & Design Patterns

OOP Fundamentals & SOLID Principles

  • Object-Oriented Design Refresher
  • Single Responsibility & Open/Closed
  • Liskov Substitution & Interface Segregation
  • Dependency Inversion

Creational Design Patterns

  • Singleton Pattern
  • Factory & Abstract Factory
  • Builder Pattern
  • Prototype Pattern

Structural Design Patterns

  • Adapter & Facade
  • Decorator Pattern
  • Composite & Proxy
  • Bridge & Flyweight

Behavioral Design Patterns

  • Strategy Pattern
  • Observer Pattern
  • Command Pattern
  • Template Method
  • State Pattern
  • Chain of Responsibility
  • Iterator & Mediator
  • Visitor Pattern

Machine Coding Exercises

  • Parking Lot — Requirements & Class Design
  • Parking Lot — Implementation
  • Elevator System — Requirements & Class Design
  • Elevator System — Implementation & Scheduling
  • Library Management System
  • Tic-Tac-Toe / Board Game Design
  • Chess Engine Design
  • Vending Machine Design
  • ATM System Design
  • In-Memory Rate Limiter
  • Thread-Safe LRU Cache
  • Connection Pool Design
  • Producer-Consumer Class Design
  • Movie Ticket Booking System
  • Hotel Reservation System
  • Airline Booking / Seat Selection System
  • Splitwise / Expense Sharing System
  • Design a Logging Framework
  • Design a Notification/Observer-Based Pub-Sub
  • Design a Cache with Pluggable Eviction Policy
  • Design Snake and Ladder
  • Design a Card Game Framework
  • Design an Inventory Management System
  • Restaurant Management System
  • Food Delivery Order Matching
  • Design a Shopping Cart & Checkout Flow
  • Design a Recommendation Engine
  • Design a Job Scheduler
  • Design a Circuit Breaker
  • Design a Distributed ID Generator
  • Design a Pub-Sub Message Broker
  • Design Twitter/X
  • Multi-Pattern Problem: Design a Ride Booking Class Model
  • Multi-Pattern Problem: Design a Food Ordering Class Model
  • Design an Authentication/Authorization Module
  • Design a Form/Survey Builder
  • Design a Meeting Room / Calendar Booking System
  • Design a Search/Filter Engine for an E-Commerce Catalog
  • Design a Voting/Polling System
  • Design a Retry Mechanism with Backoff
  • Design a Health Check Aggregator
  • Design a Feature Flag System
  • Design a Config Management Client
  • Design a Leader Election Algorithm
  • Design a Distributed Counter
  • Design a Bloom Filter
  • Design a Consistent Hashing Ring
  • Design a Distributed Tracing Library
  • Design a Metrics Collection Library
  • Design an Audit Logging Framework
  • Design a Plugin/Extension System
  • Design a Workflow Engine
  • Multi-Pattern Capstone: Design a Food Delivery App
HomeLearnSystem DesignLow-Level Design & Design PatternsMachine Coding Exercises
✓ FreeIntermediate· 7 min read

Design a Metrics Collection Library

Counter, Gauge, and Histogram metric types behind a common MetricsRegistry, sampling strategies for high-volume histograms, and the direct mapping to Micrometer's own design.

Published September 23, 2026


Design a Metrics Collection Library

Three metric types, one registry

interface Metric { String name(); }

class Counter implements Metric {
    AtomicLong value = new AtomicLong(0);
    void increment() { value.incrementAndGet(); } // only ever goes UP
}

class Gauge implements Metric {
    Supplier<Double> valueSupplier; // reads a CURRENT value on demand, can go up or down
    double value() { return valueSupplier.get(); }
}

class Histogram implements Metric {
    List<Double> samples = new CopyOnWriteArrayList<>(); // or a more compact summary structure at scale
    void record(double value) { samples.add(value); }
    double percentile(double p) { /* sorted samples, interpolate at percentile p */ }
}

class MetricsRegistry {
    Map<String, Metric> metrics = new ConcurrentHashMap<>();
    void register(Metric metric) { metrics.put(metric.name(), metric); }
}

These three types map directly onto real metric semantics from Metrics & Monitoring: Counter (monotonically increasing — a request count, never decrements), Gauge (a current point-in-time value that can go up or down — active connection count, queue depth), Histogram (a DISTRIBUTION of observed values — request LATENCY specifically, where you care about the shape, not just an average, directly connecting to Metrics & Monitoring's percentile-vs-average discussion).

Sampling for histograms at high volume

class ReservoirSamplingHistogram implements Metric {
    double[] reservoir = new double[1000]; // fixed-size sample, NOT every single value
    int count = 0;

    void record(double value) {
        count++;
        if (count <= reservoir.length) {
            reservoir[count - 1] = value;
        } else {
            int j = ThreadLocalRandom.current().nextInt(count);
            if (j < reservoir.length) reservoir[j] = value; // reservoir sampling: replace with decreasing probability
        }
    }
}

Recording EVERY single value for a high-volume histogram (millions of requests/sec) is both a memory problem (storing every value) and a computation problem (percentile calculation over an ever-growing list). Reservoir sampling maintains a FIXED-SIZE representative sample — new values replace existing reservoir entries with DECREASING probability as more values arrive, which is what keeps the sample statistically representative of the full stream's distribution even though only a small, bounded subset is actually stored. This is the practical answer to "discuss sampling for histograms at high volume vs recording every single value" — a small, well-chosen sample gives a statistically sound percentile estimate at a fraction of the memory/compute cost of tracking everything.

Mapping directly onto Micrometer's actual design

Spring Boot's Micrometer (already introduced in Metrics & Monitoring) exposes exactly this same three-type model — Counter, Gauge, and Timer/DistributionSummary (Micrometer's histogram-equivalents) — registered against a MeterRegistry that plays the identical role as this exercise's MetricsRegistry. Building this from scratch is what turns @Timed and meterRegistry.counter(...) from magic annotations into a concrete, understood mechanism.

Follow-up questions this topic invites — and their answers

Q: Why can't a Gauge simply be implemented the same way as a Counter, with increment/decrement methods? A: It COULD be, but the Supplier<Double>-based approach shown (reading a current value ON DEMAND rather than maintaining running state) is often preferable for values that are already tracked elsewhere (e.g. connectionPool.getActiveCount()) — it avoids DUPLICATING state that already exists in the thing being measured, reading it fresh each time the metric is scraped instead.

Q: Does reservoir sampling bias the percentile estimate in any way? A: A correctly-implemented reservoir sampling algorithm (as shown, with the replacement probability decreasing appropriately as count grows) gives an UNBIASED uniform random sample of the full stream — the key correctness property is that every value seen so far has an EQUAL probability of being in the final reservoir, which the specific replace-with-probability-length/count formula guarantees.

Q: How would you export these in-memory metrics to an external system like Prometheus? A: A separate EXPORTER component would periodically read all registered metrics' current state (iterating the MetricsRegistry) and format them per Prometheus's expected text exposition format at a scrape endpoint (/actuator/prometheus, from Metrics & Monitoring) — the collection/storage layer (this exercise) and the export/format layer are cleanly separable concerns.

Q: Should Counter use a plain long with synchronization, or AtomicLong as shown? A: AtomicLong is the correct choice for a counter incremented from many concurrent threads — it provides lock-free, thread-safe increments via compare-and-swap (the same underlying mechanism discussed in this course's concurrency-focused lessons), meaningfully cheaper under contention than a synchronized block around a plain long.

Previous

Design a Distributed Tracing Library

Next

Design an Audit Logging Framework

AI Tutor

Lesson: Design a Metrics Collection Library

Quick actions

AI responses can be inaccurate. Verify critical information.