Core instrumentation library for the Prometheus Java client, providing fundamental metric types for application monitoring
—
The CollectorRegistry manages metric registration, collection, and provides access to metric samples for export to monitoring systems. It serves as the central hub for all metric collectors in an application.
Access the default registry or create custom registries for specific use cases.
/**
* Default registry singleton for most applications
*/
public static final CollectorRegistry defaultRegistry;
/**
* Create a new CollectorRegistry instance
*/
public CollectorRegistry();
/**
* Create a new CollectorRegistry with auto-describe option
* @param autoDescribe Whether to automatically describe collectors
*/
public CollectorRegistry(boolean autoDescribe);Usage Example:
import io.prometheus.client.CollectorRegistry;
import io.prometheus.client.Counter;
// Use default registry (most common)
Counter requests = Counter.build()
.name("requests_total")
.help("Total requests")
.register(); // Registers to defaultRegistry
// Create custom registry for testing
CollectorRegistry testRegistry = new CollectorRegistry();
Counter testCounter = Counter.build()
.name("test_counter")
.help("Test counter")
.register(testRegistry);
// Registry with auto-describe for development
CollectorRegistry devRegistry = new CollectorRegistry(true);Register and unregister metric collectors with the registry.
/**
* Register a collector with this registry
* @param collector Collector to register
* @throws IllegalArgumentException if collector names conflict
*/
public void register(Collector collector);
/**
* Unregister a collector from this registry
* @param collector Collector to unregister
*/
public void unregister(Collector collector);
/**
* Unregister all collectors from this registry
*/
public void clear();Usage Examples:
// Register collectors explicitly
CollectorRegistry customRegistry = new CollectorRegistry();
Counter requests = Counter.build()
.name("requests_total")
.help("Total requests")
.create(); // Create without registering
Gauge memory = Gauge.build()
.name("memory_usage_bytes")
.help("Memory usage")
.create();
// Register to custom registry
customRegistry.register(requests);
customRegistry.register(memory);
// Unregister when no longer needed
customRegistry.unregister(requests);
// Name conflict detection
Counter duplicate = Counter.build()
.name("requests_total") // Same name as existing
.help("Duplicate counter")
.create();
try {
customRegistry.register(duplicate); // Throws IllegalArgumentException
} catch (IllegalArgumentException e) {
System.err.println("Name conflict: " + e.getMessage());
}Collect metric samples from all registered collectors for export.
/**
* Get all metric family samples from registered collectors
* @return Enumeration of MetricFamilySamples
*/
public Enumeration<MetricFamilySamples> metricFamilySamples();
/**
* Get filtered metric family samples
* @param sampleNameFilter Predicate to filter sample names
* @return Enumeration of filtered MetricFamilySamples
*/
public Enumeration<MetricFamilySamples> filteredMetricFamilySamples(Predicate<String> sampleNameFilter);
/**
* Get metric family samples for specific metric names
* @param includedNames Set of metric names to include
* @return Enumeration of MetricFamilySamples for specified names
*/
public Enumeration<MetricFamilySamples> filteredMetricFamilySamples(Set<String> includedNames);Usage Examples:
// Collect all metrics
Enumeration<MetricFamilySamples> allMetrics =
CollectorRegistry.defaultRegistry.metricFamilySamples();
while (allMetrics.hasMoreElements()) {
MetricFamilySamples family = allMetrics.nextElement();
System.out.println("Metric: " + family.name + " (" + family.type + ")");
for (MetricFamilySamples.Sample sample : family.samples) {
System.out.println(" " + sample.name + " = " + sample.value);
}
}
// Filter metrics by name pattern
Predicate<String> httpMetricsFilter = name -> name.startsWith("http_");
Enumeration<MetricFamilySamples> httpMetrics =
CollectorRegistry.defaultRegistry.metricFamilySamples(httpMetricsFilter);
// Get specific metrics by name
Set<String> requestMetrics = Set.of("requests_total", "request_duration_seconds");
Enumeration<MetricFamilySamples> specificMetrics =
CollectorRegistry.defaultRegistry.filteredMetricFamilySamples(requestMetrics);Retrieve individual metric values for specific use cases.
/**
* Get sample value for metric without labels
* @param name Metric name
* @return Sample value or null if not found
*/
public Double getSampleValue(String name);
/**
* Get sample value for labeled metric
* @param name Metric name
* @param labelNames Array of label names
* @param labelValues Array of label values (must match labelNames)
* @return Sample value or null if not found
*/
public Double getSampleValue(String name, String[] labelNames, String[] labelValues);Usage Examples:
// Get simple metric value
Double totalRequests = CollectorRegistry.defaultRegistry
.getSampleValue("requests_total");
if (totalRequests != null) {
System.out.println("Total requests: " + totalRequests);
}
// Get labeled metric value
String[] labelNames = {"method", "status"};
String[] labelValues = {"GET", "200"};
Double getRequests = CollectorRegistry.defaultRegistry
.getSampleValue("http_requests_total", labelNames, labelValues);
// Null check for missing metrics
if (getRequests != null) {
System.out.println("GET 200 requests: " + getRequests);
} else {
System.out.println("Metric not found or no samples");
}
// Utility method for safe value retrieval
public double getMetricValueOrDefault(String name, double defaultValue) {
Double value = CollectorRegistry.defaultRegistry.getSampleValue(name);
return value != null ? value : defaultValue;
}Most applications should use the default registry:
// Recommended approach for most applications
Counter requests = Counter.build()
.name("requests_total")
.help("Total requests")
.register(); // Uses defaultRegistry automatically
// Equivalent explicit registration
Counter requests2 = Counter.build()
.name("requests_total_2")
.help("Total requests")
.register(CollectorRegistry.defaultRegistry);Create custom registries for:
// Testing with isolated registry
@Test
public void testMetrics() {
CollectorRegistry testRegistry = new CollectorRegistry();
Counter testCounter = Counter.build()
.name("test_operations")
.help("Test operations")
.register(testRegistry);
testCounter.inc();
Double value = testRegistry.getSampleValue("test_operations_total");
assertEquals(1.0, value, 0.001);
}
// Subsystem-specific registry
public class DatabaseMetrics {
private static final CollectorRegistry dbRegistry = new CollectorRegistry();
public static final Counter queries = Counter.build()
.name("db_queries_total")
.help("Database queries")
.register(dbRegistry);
public static Enumeration<MetricFamilySamples> getMetrics() {
return dbRegistry.metricFamilySamples();
}
}The registry prevents duplicate metric names:
CollectorRegistry registry = new CollectorRegistry();
// First registration succeeds
Counter counter1 = Counter.build()
.name("operations")
.help("First counter")
.create();
registry.register(counter1);
// Second registration with same name fails
Counter counter2 = Counter.build()
.name("operations") // Conflict!
.help("Second counter")
.create();
try {
registry.register(counter2);
} catch (IllegalArgumentException e) {
// Handle name conflict
System.err.println("Metric name already exists: " + e.getMessage());
}
// Solution: Use different names or unregister first
registry.unregister(counter1);
registry.register(counter2); // Now succeedsAll registry operations are thread-safe:
// Safe concurrent registration
CollectorRegistry registry = new CollectorRegistry();
// Multiple threads can safely register different collectors
Thread t1 = new Thread(() -> {
Counter c1 = Counter.build().name("metric1").help("M1").create();
registry.register(c1);
});
Thread t2 = new Thread(() -> {
Gauge g1 = Gauge.build().name("metric2").help("M2").create();
registry.register(g1);
});
t1.start();
t2.start();Use filtering for performance and relevance:
// Performance: Only collect metrics you need
Predicate<String> relevantMetrics = name ->
name.startsWith("app_") || name.startsWith("business_");
Enumeration<MetricFamilySamples> filtered =
registry.metricFamilySamples(relevantMetrics);
// Custom filter implementation
public class MetricNameFilter implements Predicate<String> {
private final Set<String> allowedPrefixes;
public MetricNameFilter(String... prefixes) {
this.allowedPrefixes = Set.of(prefixes);
}
@Override
public boolean test(String name) {
return allowedPrefixes.stream().anyMatch(name::startsWith);
}
}
// Usage
MetricNameFilter filter = new MetricNameFilter("http_", "db_", "cache_");
Enumeration<MetricFamilySamples> metrics = registry.metricFamilySamples(filter);// Metrics exporter pattern
public class PrometheusExporter {
private final CollectorRegistry registry;
public PrometheusExporter(CollectorRegistry registry) {
this.registry = registry;
}
public String exportMetrics() {
StringBuilder output = new StringBuilder();
Enumeration<MetricFamilySamples> samples = registry.metricFamilySamples();
while (samples.hasMoreElements()) {
MetricFamilySamples family = samples.nextElement();
// Format for Prometheus text format
output.append(formatFamily(family));
}
return output.toString();
}
}
// Health check integration
public class MetricsHealthCheck {
public boolean isHealthy() {
Double errorRate = CollectorRegistry.defaultRegistry
.getSampleValue("error_rate");
return errorRate == null || errorRate < 0.05; // 5% threshold
}
public Map<String, Object> getHealthDetails() {
Map<String, Object> details = new HashMap<>();
details.put("total_requests",
CollectorRegistry.defaultRegistry.getSampleValue("requests_total"));
details.put("error_count",
CollectorRegistry.defaultRegistry.getSampleValue("errors_total"));
return details;
}
}Install with Tessl CLI
npx tessl i tessl/maven-io-prometheus--simpleclient