0
# Summary Metrics
1
2
Summary metrics track quantiles and distributions with configurable sliding time windows and precise quantile calculations. They provide count, sum, and quantile values without requiring predefined buckets like histograms.
3
4
## Capabilities
5
6
### Summary Creation
7
8
Create summary metrics using the builder pattern with optional quantile configuration.
9
10
```java { .api }
11
/**
12
* Create a new Summary builder
13
* @return Builder instance for configuration
14
*/
15
public static Summary.Builder build();
16
17
/**
18
* Create a new Summary builder with required fields
19
* @param name The metric name (without _count/_sum suffixes)
20
* @param help The help text describing the metric
21
* @return Builder instance for configuration
22
*/
23
public static Summary.Builder build(String name, String help);
24
```
25
26
**Usage Example:**
27
28
```java
29
import io.prometheus.client.Summary;
30
31
// Basic summary (count and sum only)
32
Summary requestLatency = Summary.build()
33
.name("request_latency_seconds")
34
.help("Request latency in seconds")
35
.register();
36
37
// Summary with quantiles
38
Summary responseTime = Summary.build()
39
.name("response_time_seconds")
40
.help("Response time distribution")
41
.quantile(0.5, 0.01) // 50th percentile ±1%
42
.quantile(0.95, 0.005) // 95th percentile ±0.5%
43
.quantile(0.99, 0.001) // 99th percentile ±0.1%
44
.register();
45
```
46
47
### Summary Builder Configuration
48
49
Configure summary quantiles, time windows, and sampling parameters.
50
51
```java { .api }
52
public static class Builder extends SimpleCollector.Builder<Builder, Summary> {
53
/**
54
* Add a quantile to track with specified error tolerance
55
* @param quantile Quantile to track (0.0 to 1.0)
56
* @param error Allowed error for quantile calculation
57
* @return Builder for method chaining
58
* @throws IllegalArgumentException if quantile not in [0,1] or error negative
59
*/
60
public Builder quantile(double quantile, double error);
61
62
/**
63
* Set the maximum age of observations in seconds
64
* @param ageSeconds Age in seconds (default: 600)
65
* @return Builder for method chaining
66
*/
67
public Builder maxAgeSeconds(long ageSeconds);
68
69
/**
70
* Set number of age buckets for sliding time window
71
* @param ageBuckets Number of buckets (default: 5)
72
* @return Builder for method chaining
73
*/
74
public Builder ageBuckets(int ageBuckets);
75
}
76
```
77
78
**Usage Examples:**
79
80
```java
81
// High-precision summary with custom time window
82
Summary preciseLatency = Summary.build()
83
.name("precise_latency_seconds")
84
.help("High precision latency tracking")
85
.quantile(0.50, 0.01) // Median ±1%
86
.quantile(0.90, 0.005) // 90th percentile ±0.5%
87
.quantile(0.95, 0.005) // 95th percentile ±0.5%
88
.quantile(0.99, 0.001) // 99th percentile ±0.1%
89
.maxAgeSeconds(300) // 5-minute window
90
.ageBuckets(5) // 5 buckets = 1 minute each
91
.register();
92
93
// Min/max tracking (special cases with zero error)
94
Summary minMax = Summary.build()
95
.name("processing_duration_seconds")
96
.help("Processing duration with min/max")
97
.quantile(0.0, 0.0) // Minimum (no extra memory)
98
.quantile(1.0, 0.0) // Maximum (no extra memory)
99
.quantile(0.5, 0.01) // Median ±1%
100
.register();
101
```
102
103
### Summary Observations
104
105
Record values in summary metrics for quantile and statistical calculations.
106
107
```java { .api }
108
/**
109
* Record an observation in the summary
110
* @param amt Value to observe
111
*/
112
public void observe(double amt);
113
```
114
115
**Usage Examples:**
116
117
```java
118
// Basic observations
119
requestLatency.observe(0.123); // 123ms request
120
responseTime.observe(0.045); // 45ms response
121
responseTime.observe(1.234); // 1.234s slower response
122
123
// Processing different types of operations
124
Summary operationDuration = Summary.build()
125
.name("operation_duration_seconds")
126
.help("Operation processing time")
127
.labelNames("operation_type")
128
.quantile(0.5, 0.01)
129
.quantile(0.95, 0.005)
130
.register();
131
132
operationDuration.labels("database_query").observe(0.025);
133
operationDuration.labels("file_write").observe(0.150);
134
operationDuration.labels("network_call").observe(0.300);
135
```
136
137
### Timer Operations
138
139
Use summaries for automatic duration measurement and timing operations.
140
141
```java { .api }
142
/**
143
* Start a timer for duration measurement
144
* @return Timer instance for duration tracking
145
*/
146
public Timer startTimer();
147
148
/**
149
* Time a Runnable execution and observe duration
150
* @param timeable Code to time
151
* @return Duration in seconds
152
*/
153
public double time(Runnable timeable);
154
155
/**
156
* Time a Callable execution and observe duration
157
* @param timeable Code to time
158
* @return Result from callable
159
* @throws RuntimeException if callable throws exception
160
*/
161
public <E> E time(Callable<E> timeable);
162
```
163
164
### Summary Timer Class
165
166
Timer provides duration measurement capabilities for summary metrics.
167
168
```java { .api }
169
public static class Timer implements Closeable {
170
/**
171
* Observe elapsed duration since timer start
172
* @return Elapsed duration in seconds
173
*/
174
public double observeDuration();
175
176
/**
177
* Equivalent to observeDuration() - implements Closeable
178
*/
179
public void close();
180
}
181
```
182
183
**Usage Examples:**
184
185
```java
186
// Manual timer usage
187
Summary.Timer timer = requestLatency.startTimer();
188
try {
189
processRequest();
190
} finally {
191
double duration = timer.observeDuration();
192
System.out.println("Request took: " + duration + " seconds");
193
}
194
195
// Try-with-resources timer
196
try (Summary.Timer timer = requestLatency.startTimer()) {
197
processRequest(); // Automatically observes duration on close
198
}
199
200
// Lambda timing
201
double duration = requestLatency.time(() -> {
202
processRequest();
203
});
204
205
// Timing with return value
206
String result = requestLatency.time(() -> {
207
return generateResponse();
208
});
209
210
// Batch processing timing
211
Summary batchProcessing = Summary.build()
212
.name("batch_processing_seconds")
213
.help("Batch processing duration")
214
.quantile(0.5, 0.01)
215
.quantile(0.95, 0.005)
216
.register();
217
218
List<String> results = batchProcessing.time(() -> {
219
return processBatch();
220
});
221
```
222
223
### Labeled Summary Operations
224
225
Work with multi-dimensional summaries using label values.
226
227
```java { .api }
228
/**
229
* Get summary child for specific label values
230
* @param labelValues Values for each label name (must match count)
231
* @return Summary.Child instance for the label combination
232
* @throws IllegalArgumentException if wrong number of labels
233
*/
234
public Summary.Child labels(String... labelValues);
235
236
/**
237
* Remove summary child for specific label values
238
* @param labelValues Values identifying the child to remove
239
*/
240
public void remove(String... labelValues);
241
242
/**
243
* Remove all summary children
244
*/
245
public void clear();
246
```
247
248
### Summary Child Operations
249
250
Summary.Child provides the same observation and timing operations for labeled instances.
251
252
```java { .api }
253
public static class Child {
254
/** Record observation in child summary */
255
public void observe(double amt);
256
257
/** Start timer for child summary */
258
public Timer startTimer();
259
260
/** Time operations for child summary */
261
public double time(Runnable timeable);
262
public <E> E time(Callable<E> timeable);
263
264
/** Get summary data snapshot */
265
public Value get();
266
}
267
```
268
269
### Summary Value Data
270
271
Access summary count, sum, and quantile data.
272
273
```java { .api }
274
public static class Value {
275
/** Total number of observations */
276
public final long count;
277
278
/** Sum of all observed values */
279
public final double sum;
280
281
/** Map of quantile values (quantile -> value) */
282
public final SortedMap<Double, Double> quantiles;
283
}
284
```
285
286
**Usage Example:**
287
288
```java
289
// API endpoint monitoring
290
Summary apiLatency = Summary.build()
291
.name("api_endpoint_duration_seconds")
292
.help("API endpoint response time")
293
.labelNames("endpoint", "method", "status")
294
.quantile(0.5, 0.01) // Median
295
.quantile(0.95, 0.005) // 95th percentile
296
.quantile(0.99, 0.001) // 99th percentile
297
.register();
298
299
// Track different endpoints
300
Summary.Child getUserLatency = apiLatency.labels("/users", "GET", "200");
301
Summary.Child postUserLatency = apiLatency.labels("/users", "POST", "201");
302
303
// Time requests
304
getUserLatency.time(() -> handleGetUser());
305
postUserLatency.observe(0.156); // Manual observation
306
307
// Access summary statistics
308
Summary.Child.Value stats = getUserLatency.get();
309
System.out.println("Total requests: " + stats.count);
310
System.out.println("Average latency: " + (stats.sum / stats.count));
311
System.out.println("95th percentile: " + stats.quantiles.get(0.95));
312
```
313
314
## Important Notes
315
316
### Quantile Configuration
317
318
**Quantile Range**: Must be between 0.0 and 1.0
319
- `0.0` = minimum value (special case, no extra memory)
320
- `0.5` = median (50th percentile)
321
- `0.95` = 95th percentile
322
- `0.99` = 99th percentile
323
- `1.0` = maximum value (special case, no extra memory)
324
325
**Error Tolerance**: Controls precision vs memory usage
326
- `0.01` = ±1% error (good for most use cases)
327
- `0.005` = ±0.5% error (higher precision)
328
- `0.001` = ±0.1% error (very high precision)
329
- `0.0` = exact tracking (uses more memory)
330
331
### Time Window Behavior
332
333
Summary uses a sliding time window:
334
- **maxAgeSeconds**: Total window duration (default: 10 minutes)
335
- **ageBuckets**: Number of sub-windows (default: 5 buckets)
336
- Window slides forward every `maxAgeSeconds / ageBuckets` interval
337
- Old observations are automatically discarded
338
339
Example with defaults:
340
- 10-minute total window
341
- 5 buckets = 2-minute intervals
342
- Window slides every 2 minutes
343
344
### Memory Usage
345
346
- Count and sum use minimal memory
347
- Each quantile uses approximately 100 samples regardless of observation count
348
- Min (0.0) and max (1.0) quantiles are memory-optimized special cases
349
- Choose error tolerance based on precision needs vs memory constraints
350
351
### Summary vs Histogram
352
353
**Use Summary when**:
354
- You need precise quantiles (e.g., SLA monitoring)
355
- You don't know the distribution shape in advance
356
- You want automatic memory management
357
- You need client-side quantile calculation
358
359
**Use Histogram when**:
360
- You need server-side quantile calculation
361
- You want to aggregate across multiple instances
362
- You know appropriate bucket boundaries
363
- You need Prometheus alerting on buckets
364
365
### Common Patterns
366
367
```java
368
// SLA monitoring
369
Summary slaLatency = Summary.build()
370
.name("sla_response_time_seconds")
371
.help("Response time for SLA monitoring")
372
.quantile(0.95, 0.01) // 95% of requests under X seconds
373
.quantile(0.99, 0.005) // 99% of requests under Y seconds
374
.maxAgeSeconds(300) // 5-minute sliding window
375
.register();
376
377
// Database query performance
378
Summary dbQueries = Summary.build()
379
.name("database_query_duration_seconds")
380
.help("Database query performance")
381
.labelNames("query_type", "table")
382
.quantile(0.5, 0.01) // Median
383
.quantile(0.9, 0.005) // 90th percentile
384
.quantile(0.99, 0.001) // 99th percentile
385
.register();
386
387
// Batch processing monitoring
388
Summary batchJobs = Summary.build()
389
.name("batch_job_duration_seconds")
390
.help("Batch job processing time")
391
.labelNames("job_type")
392
.quantile(0.0, 0.0) // Minimum (free)
393
.quantile(0.5, 0.01) // Median
394
.quantile(1.0, 0.0) // Maximum (free)
395
.register();
396
```