0
# Registry Management
1
2
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.
3
4
## Capabilities
5
6
### Registry Creation and Access
7
8
Access the default registry or create custom registries for specific use cases.
9
10
```java { .api }
11
/**
12
* Default registry singleton for most applications
13
*/
14
public static final CollectorRegistry defaultRegistry;
15
16
/**
17
* Create a new CollectorRegistry instance
18
*/
19
public CollectorRegistry();
20
21
/**
22
* Create a new CollectorRegistry with auto-describe option
23
* @param autoDescribe Whether to automatically describe collectors
24
*/
25
public CollectorRegistry(boolean autoDescribe);
26
```
27
28
**Usage Example:**
29
30
```java
31
import io.prometheus.client.CollectorRegistry;
32
import io.prometheus.client.Counter;
33
34
// Use default registry (most common)
35
Counter requests = Counter.build()
36
.name("requests_total")
37
.help("Total requests")
38
.register(); // Registers to defaultRegistry
39
40
// Create custom registry for testing
41
CollectorRegistry testRegistry = new CollectorRegistry();
42
Counter testCounter = Counter.build()
43
.name("test_counter")
44
.help("Test counter")
45
.register(testRegistry);
46
47
// Registry with auto-describe for development
48
CollectorRegistry devRegistry = new CollectorRegistry(true);
49
```
50
51
### Collector Registration
52
53
Register and unregister metric collectors with the registry.
54
55
```java { .api }
56
/**
57
* Register a collector with this registry
58
* @param collector Collector to register
59
* @throws IllegalArgumentException if collector names conflict
60
*/
61
public void register(Collector collector);
62
63
/**
64
* Unregister a collector from this registry
65
* @param collector Collector to unregister
66
*/
67
public void unregister(Collector collector);
68
69
/**
70
* Unregister all collectors from this registry
71
*/
72
public void clear();
73
```
74
75
**Usage Examples:**
76
77
```java
78
// Register collectors explicitly
79
CollectorRegistry customRegistry = new CollectorRegistry();
80
81
Counter requests = Counter.build()
82
.name("requests_total")
83
.help("Total requests")
84
.create(); // Create without registering
85
86
Gauge memory = Gauge.build()
87
.name("memory_usage_bytes")
88
.help("Memory usage")
89
.create();
90
91
// Register to custom registry
92
customRegistry.register(requests);
93
customRegistry.register(memory);
94
95
// Unregister when no longer needed
96
customRegistry.unregister(requests);
97
98
// Name conflict detection
99
Counter duplicate = Counter.build()
100
.name("requests_total") // Same name as existing
101
.help("Duplicate counter")
102
.create();
103
104
try {
105
customRegistry.register(duplicate); // Throws IllegalArgumentException
106
} catch (IllegalArgumentException e) {
107
System.err.println("Name conflict: " + e.getMessage());
108
}
109
```
110
111
### Metric Sample Collection
112
113
Collect metric samples from all registered collectors for export.
114
115
```java { .api }
116
/**
117
* Get all metric family samples from registered collectors
118
* @return Enumeration of MetricFamilySamples
119
*/
120
public Enumeration<MetricFamilySamples> metricFamilySamples();
121
122
/**
123
* Get filtered metric family samples
124
* @param sampleNameFilter Predicate to filter sample names
125
* @return Enumeration of filtered MetricFamilySamples
126
*/
127
public Enumeration<MetricFamilySamples> filteredMetricFamilySamples(Predicate<String> sampleNameFilter);
128
129
/**
130
* Get metric family samples for specific metric names
131
* @param includedNames Set of metric names to include
132
* @return Enumeration of MetricFamilySamples for specified names
133
*/
134
public Enumeration<MetricFamilySamples> filteredMetricFamilySamples(Set<String> includedNames);
135
```
136
137
**Usage Examples:**
138
139
```java
140
// Collect all metrics
141
Enumeration<MetricFamilySamples> allMetrics =
142
CollectorRegistry.defaultRegistry.metricFamilySamples();
143
144
while (allMetrics.hasMoreElements()) {
145
MetricFamilySamples family = allMetrics.nextElement();
146
System.out.println("Metric: " + family.name + " (" + family.type + ")");
147
148
for (MetricFamilySamples.Sample sample : family.samples) {
149
System.out.println(" " + sample.name + " = " + sample.value);
150
}
151
}
152
153
// Filter metrics by name pattern
154
Predicate<String> httpMetricsFilter = name -> name.startsWith("http_");
155
Enumeration<MetricFamilySamples> httpMetrics =
156
CollectorRegistry.defaultRegistry.metricFamilySamples(httpMetricsFilter);
157
158
// Get specific metrics by name
159
Set<String> requestMetrics = Set.of("requests_total", "request_duration_seconds");
160
Enumeration<MetricFamilySamples> specificMetrics =
161
CollectorRegistry.defaultRegistry.filteredMetricFamilySamples(requestMetrics);
162
```
163
164
### Single Sample Value Access
165
166
Retrieve individual metric values for specific use cases.
167
168
```java { .api }
169
/**
170
* Get sample value for metric without labels
171
* @param name Metric name
172
* @return Sample value or null if not found
173
*/
174
public Double getSampleValue(String name);
175
176
/**
177
* Get sample value for labeled metric
178
* @param name Metric name
179
* @param labelNames Array of label names
180
* @param labelValues Array of label values (must match labelNames)
181
* @return Sample value or null if not found
182
*/
183
public Double getSampleValue(String name, String[] labelNames, String[] labelValues);
184
```
185
186
**Usage Examples:**
187
188
```java
189
// Get simple metric value
190
Double totalRequests = CollectorRegistry.defaultRegistry
191
.getSampleValue("requests_total");
192
193
if (totalRequests != null) {
194
System.out.println("Total requests: " + totalRequests);
195
}
196
197
// Get labeled metric value
198
String[] labelNames = {"method", "status"};
199
String[] labelValues = {"GET", "200"};
200
Double getRequests = CollectorRegistry.defaultRegistry
201
.getSampleValue("http_requests_total", labelNames, labelValues);
202
203
// Null check for missing metrics
204
if (getRequests != null) {
205
System.out.println("GET 200 requests: " + getRequests);
206
} else {
207
System.out.println("Metric not found or no samples");
208
}
209
210
// Utility method for safe value retrieval
211
public double getMetricValueOrDefault(String name, double defaultValue) {
212
Double value = CollectorRegistry.defaultRegistry.getSampleValue(name);
213
return value != null ? value : defaultValue;
214
}
215
```
216
217
## Important Notes
218
219
### Default Registry Usage
220
221
Most applications should use the default registry:
222
223
```java
224
// Recommended approach for most applications
225
Counter requests = Counter.build()
226
.name("requests_total")
227
.help("Total requests")
228
.register(); // Uses defaultRegistry automatically
229
230
// Equivalent explicit registration
231
Counter requests2 = Counter.build()
232
.name("requests_total_2")
233
.help("Total requests")
234
.register(CollectorRegistry.defaultRegistry);
235
```
236
237
### Custom Registry Use Cases
238
239
Create custom registries for:
240
241
- **Unit Testing**: Isolated metrics for test cases
242
- **Subsystem Isolation**: Separate metrics for different components
243
- **Partial Export**: Export subset of metrics to different endpoints
244
- **Development/Debug**: Enhanced introspection with auto-describe
245
246
```java
247
// Testing with isolated registry
248
@Test
249
public void testMetrics() {
250
CollectorRegistry testRegistry = new CollectorRegistry();
251
Counter testCounter = Counter.build()
252
.name("test_operations")
253
.help("Test operations")
254
.register(testRegistry);
255
256
testCounter.inc();
257
258
Double value = testRegistry.getSampleValue("test_operations_total");
259
assertEquals(1.0, value, 0.001);
260
}
261
262
// Subsystem-specific registry
263
public class DatabaseMetrics {
264
private static final CollectorRegistry dbRegistry = new CollectorRegistry();
265
266
public static final Counter queries = Counter.build()
267
.name("db_queries_total")
268
.help("Database queries")
269
.register(dbRegistry);
270
271
public static Enumeration<MetricFamilySamples> getMetrics() {
272
return dbRegistry.metricFamilySamples();
273
}
274
}
275
```
276
277
### Name Conflict Resolution
278
279
The registry prevents duplicate metric names:
280
281
```java
282
CollectorRegistry registry = new CollectorRegistry();
283
284
// First registration succeeds
285
Counter counter1 = Counter.build()
286
.name("operations")
287
.help("First counter")
288
.create();
289
registry.register(counter1);
290
291
// Second registration with same name fails
292
Counter counter2 = Counter.build()
293
.name("operations") // Conflict!
294
.help("Second counter")
295
.create();
296
297
try {
298
registry.register(counter2);
299
} catch (IllegalArgumentException e) {
300
// Handle name conflict
301
System.err.println("Metric name already exists: " + e.getMessage());
302
}
303
304
// Solution: Use different names or unregister first
305
registry.unregister(counter1);
306
registry.register(counter2); // Now succeeds
307
```
308
309
### Thread Safety
310
311
All registry operations are thread-safe:
312
313
```java
314
// Safe concurrent registration
315
CollectorRegistry registry = new CollectorRegistry();
316
317
// Multiple threads can safely register different collectors
318
Thread t1 = new Thread(() -> {
319
Counter c1 = Counter.build().name("metric1").help("M1").create();
320
registry.register(c1);
321
});
322
323
Thread t2 = new Thread(() -> {
324
Gauge g1 = Gauge.build().name("metric2").help("M2").create();
325
registry.register(g1);
326
});
327
328
t1.start();
329
t2.start();
330
```
331
332
### Sample Name Filtering
333
334
Use filtering for performance and relevance:
335
336
```java
337
// Performance: Only collect metrics you need
338
Predicate<String> relevantMetrics = name ->
339
name.startsWith("app_") || name.startsWith("business_");
340
341
Enumeration<MetricFamilySamples> filtered =
342
registry.metricFamilySamples(relevantMetrics);
343
344
// Custom filter implementation
345
public class MetricNameFilter implements Predicate<String> {
346
private final Set<String> allowedPrefixes;
347
348
public MetricNameFilter(String... prefixes) {
349
this.allowedPrefixes = Set.of(prefixes);
350
}
351
352
@Override
353
public boolean test(String name) {
354
return allowedPrefixes.stream().anyMatch(name::startsWith);
355
}
356
}
357
358
// Usage
359
MetricNameFilter filter = new MetricNameFilter("http_", "db_", "cache_");
360
Enumeration<MetricFamilySamples> metrics = registry.metricFamilySamples(filter);
361
```
362
363
### Integration Patterns
364
365
```java
366
// Metrics exporter pattern
367
public class PrometheusExporter {
368
private final CollectorRegistry registry;
369
370
public PrometheusExporter(CollectorRegistry registry) {
371
this.registry = registry;
372
}
373
374
public String exportMetrics() {
375
StringBuilder output = new StringBuilder();
376
Enumeration<MetricFamilySamples> samples = registry.metricFamilySamples();
377
378
while (samples.hasMoreElements()) {
379
MetricFamilySamples family = samples.nextElement();
380
// Format for Prometheus text format
381
output.append(formatFamily(family));
382
}
383
384
return output.toString();
385
}
386
}
387
388
// Health check integration
389
public class MetricsHealthCheck {
390
public boolean isHealthy() {
391
Double errorRate = CollectorRegistry.defaultRegistry
392
.getSampleValue("error_rate");
393
394
return errorRate == null || errorRate < 0.05; // 5% threshold
395
}
396
397
public Map<String, Object> getHealthDetails() {
398
Map<String, Object> details = new HashMap<>();
399
400
details.put("total_requests",
401
CollectorRegistry.defaultRegistry.getSampleValue("requests_total"));
402
details.put("error_count",
403
CollectorRegistry.defaultRegistry.getSampleValue("errors_total"));
404
405
return details;
406
}
407
}
408
```