Skip to content

Commit 482656c

Browse files
authored
docs: add API reference for CollectorRegistry and custom collector classes (prometheus#1169)
Closes prometheus#1163 collector/custom.md: Collector protocol section (collect/describe), value vs labels mutual exclusivity note, full constructor and add_metric tables for GaugeMetricFamily, CounterMetricFamily, SummaryMetricFamily, HistogramMetricFamily, and InfoMetricFamily, plus a runnable real-world example. collector/_index.md: constructor parameter tables for ProcessCollector, PlatformCollector, and GCCollector, with exported metrics listed for each. registry/_index.md (new): CollectorRegistry constructor and all public methods (register, unregister, collect, restricted_registry, get_sample_value, set_target_info, get_target_info), the global REGISTRY instance, and examples for isolated registry usage and registry=None. All code examples verified by running them in Python. Signed-off-by: k1chik <107162115+k1chik@users.noreply.github.com>
1 parent e75a74f commit 482656c

3 files changed

Lines changed: 464 additions & 4 deletions

File tree

docs/content/collector/_index.md

Lines changed: 74 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ ProcessCollector(namespace='mydaemon', pid=lambda: open('/var/run/daemon.pid').r
1818
# Platform Collector
1919

2020
The client also automatically exports some metadata about Python. If using Jython,
21-
metadata about the JVM in use is also included. This information is available as
22-
labels on the `python_info` metric. The value of the metric is 1, since it is the
21+
metadata about the JVM in use is also included. This information is available as
22+
labels on the `python_info` metric. The value of the metric is 1, since it is the
2323
labels that carry information.
2424

2525
# Disabling Default Collector metrics
@@ -33,4 +33,75 @@ import prometheus_client
3333
prometheus_client.REGISTRY.unregister(prometheus_client.GC_COLLECTOR)
3434
prometheus_client.REGISTRY.unregister(prometheus_client.PLATFORM_COLLECTOR)
3535
prometheus_client.REGISTRY.unregister(prometheus_client.PROCESS_COLLECTOR)
36-
```
36+
```
37+
38+
## API Reference
39+
40+
### ProcessCollector
41+
42+
```python
43+
ProcessCollector(namespace='', pid=lambda: 'self', proc='/proc', registry=REGISTRY)
44+
```
45+
46+
Collects process metrics from `/proc`. Only available on Linux.
47+
48+
| Parameter | Type | Default | Description |
49+
|-----------|------|---------|-------------|
50+
| `namespace` | `str` | `''` | Prefix added to all metric names, e.g. `'mydaemon'` produces `mydaemon_process_cpu_seconds_total`. |
51+
| `pid` | `Callable[[], int or str]` | `lambda: 'self'` | Callable that returns the PID to monitor. `'self'` monitors the current process. |
52+
| `proc` | `str` | `'/proc'` | Path to the proc filesystem. Useful for testing or containerised environments with a non-standard mount point. |
53+
| `registry` | `CollectorRegistry` | `REGISTRY` | Registry to register with. Pass `None` to skip registration. |
54+
55+
Metrics exported:
56+
57+
| Metric | Description |
58+
|--------|-------------|
59+
| `process_cpu_seconds_total` | Total user and system CPU time in seconds. |
60+
| `process_virtual_memory_bytes` | Virtual memory size in bytes. |
61+
| `process_resident_memory_bytes` | Resident memory size in bytes. |
62+
| `process_start_time_seconds` | Start time since Unix epoch in seconds. |
63+
| `process_open_fds` | Number of open file descriptors. |
64+
| `process_max_fds` | Maximum number of open file descriptors. |
65+
66+
The module-level `PROCESS_COLLECTOR` is the default instance registered with `REGISTRY`.
67+
68+
### PlatformCollector
69+
70+
```python
71+
PlatformCollector(registry=REGISTRY, platform=None)
72+
```
73+
74+
Exports Python runtime metadata as a `python_info` gauge metric with labels.
75+
76+
| Parameter | Type | Default | Description |
77+
|-----------|------|---------|-------------|
78+
| `registry` | `CollectorRegistry` | `REGISTRY` | Registry to register with. Pass `None` to skip registration. |
79+
| `platform` | module | `None` | Override the `platform` module. Intended for testing. |
80+
81+
Labels on `python_info`: `version`, `implementation`, `major`, `minor`, `patchlevel`.
82+
On Jython, additional labels are added: `jvm_version`, `jvm_release`, `jvm_vendor`, `jvm_name`.
83+
84+
The module-level `PLATFORM_COLLECTOR` is the default instance registered with `REGISTRY`.
85+
86+
### GCCollector
87+
88+
```python
89+
GCCollector(registry=REGISTRY)
90+
```
91+
92+
Exports Python garbage collector statistics. Only active on CPython (skipped silently on
93+
other implementations).
94+
95+
| Parameter | Type | Default | Description |
96+
|-----------|------|---------|-------------|
97+
| `registry` | `CollectorRegistry` | `REGISTRY` | Registry to register with. |
98+
99+
Metrics exported:
100+
101+
| Metric | Description |
102+
|--------|-------------|
103+
| `python_gc_objects_collected_total` | Objects collected during GC, by generation. |
104+
| `python_gc_objects_uncollectable_total` | Uncollectable objects found during GC, by generation. |
105+
| `python_gc_collections_total` | Number of times each generation was collected. |
106+
107+
The module-level `GC_COLLECTOR` is the default instance registered with `REGISTRY`.

docs/content/collector/custom.md

Lines changed: 249 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,252 @@ not implemented and the CollectorRegistry was created with `auto_describe=True`
3535
(which is the case for the default registry) then `collect` will be called at
3636
registration time instead of `describe`. If this could cause problems, either
3737
implement a proper `describe`, or if that's not practical have `describe`
38-
return an empty list.
38+
return an empty list.
39+
40+
## Collector protocol
41+
42+
A collector is any object that implements a `collect` method. Optionally it
43+
can also implement `describe`.
44+
45+
### `collect()`
46+
47+
Returns an iterable of metric family objects (`GaugeMetricFamily`,
48+
`CounterMetricFamily`, etc.). Called every time the registry is scraped.
49+
50+
### `describe()`
51+
52+
Returns an iterable of metric family objects used only to determine the metric
53+
names the collector produces. Samples on the returned objects are ignored. If
54+
not implemented and the registry has `auto_describe=True`, `collect` is called
55+
at registration time instead.
56+
57+
## value vs labels
58+
59+
Every metric family constructor accepts either inline data or `labels`, but not
60+
both. The inline data parameter name varies by type: `value` for Gauge, Counter,
61+
and Info; `count_value`/`sum_value` for Summary; `buckets` for Histogram.
62+
63+
- Pass inline data to emit a single unlabelled metric directly from the constructor.
64+
- Pass `labels` (a sequence of label names) and then call `add_metric` one or
65+
more times to emit labelled metrics.
66+
67+
```python
68+
# single unlabelled value
69+
GaugeMetricFamily('my_gauge', 'Help text', value=7)
70+
71+
# labelled metrics via add_metric
72+
g = GaugeMetricFamily('my_gauge', 'Help text', labels=['region'])
73+
g.add_metric(['us-east-1'], 3)
74+
g.add_metric(['eu-west-1'], 5)
75+
```
76+
77+
## API Reference
78+
79+
### GaugeMetricFamily
80+
81+
```python
82+
GaugeMetricFamily(name, documentation, value=None, labels=None, unit='')
83+
```
84+
85+
| Parameter | Type | Default | Description |
86+
|-----------|------|---------|-------------|
87+
| `name` | `str` | required | Metric name. |
88+
| `documentation` | `str` | required | Help text shown in the `/metrics` output. |
89+
| `value` | `float` | `None` | Emit a single unlabelled sample with this value. Mutually exclusive with `labels`. |
90+
| `labels` | `Sequence[str]` | `None` | Label names. Use with `add_metric`. Mutually exclusive with `value`. |
91+
| `unit` | `str` | `''` | Optional unit suffix appended to the metric name. |
92+
93+
#### `add_metric(labels, value, timestamp=None)`
94+
95+
Add a labelled sample to the metric family.
96+
97+
| Parameter | Type | Description |
98+
|-----------|------|-------------|
99+
| `labels` | `Sequence[str]` | Label values in the same order as the `labels` constructor argument. |
100+
| `value` | `float` | The gauge value. |
101+
| `timestamp` | `float` or `Timestamp` | Optional Unix timestamp for the sample. |
102+
103+
```python
104+
g = GaugeMetricFamily('temperature_celsius', 'Temperature by location', labels=['location'])
105+
g.add_metric(['living_room'], 21.5)
106+
g.add_metric(['basement'], 18.0)
107+
yield g
108+
```
109+
110+
### CounterMetricFamily
111+
112+
```python
113+
CounterMetricFamily(name, documentation, value=None, labels=None, created=None, unit='', exemplar=None)
114+
```
115+
116+
If `name` ends with `_total`, the suffix is stripped automatically so the
117+
metric is stored without it and the `_total` suffix is added on exposition.
118+
119+
| Parameter | Type | Default | Description |
120+
|-----------|------|---------|-------------|
121+
| `name` | `str` | required | Metric name. A trailing `_total` is stripped and re-added on exposition. |
122+
| `documentation` | `str` | required | Help text. |
123+
| `value` | `float` | `None` | Emit a single unlabelled sample. Mutually exclusive with `labels`. |
124+
| `labels` | `Sequence[str]` | `None` | Label names. Use with `add_metric`. Mutually exclusive with `value`. |
125+
| `created` | `float` | `None` | Unix timestamp the counter was created at. Only used when `value` is set. |
126+
| `unit` | `str` | `''` | Optional unit suffix. |
127+
| `exemplar` | `Exemplar` | `None` | Exemplar for the single-value form. Only used when `value` is set. |
128+
129+
#### `add_metric(labels, value, created=None, timestamp=None, exemplar=None)`
130+
131+
| Parameter | Type | Description |
132+
|-----------|------|-------------|
133+
| `labels` | `Sequence[str]` | Label values. |
134+
| `value` | `float` | The counter value. |
135+
| `created` | `float` | Optional Unix timestamp the counter was created at. |
136+
| `timestamp` | `float` or `Timestamp` | Optional Unix timestamp for the sample. |
137+
| `exemplar` | `Exemplar` | Optional exemplar. See [Exemplars](../../instrumenting/exemplars/). |
138+
139+
```python
140+
c = CounterMetricFamily('http_requests_total', 'HTTP requests by status', labels=['status'])
141+
c.add_metric(['200'], 1200)
142+
c.add_metric(['404'], 43)
143+
c.add_metric(['500'], 7)
144+
yield c
145+
```
146+
147+
### SummaryMetricFamily
148+
149+
```python
150+
SummaryMetricFamily(name, documentation, count_value=None, sum_value=None, labels=None, unit='')
151+
```
152+
153+
`count_value` and `sum_value` must always be provided together or not at all.
154+
155+
| Parameter | Type | Default | Description |
156+
|-----------|------|---------|-------------|
157+
| `name` | `str` | required | Metric name. |
158+
| `documentation` | `str` | required | Help text. |
159+
| `count_value` | `int` | `None` | Observation count for a single unlabelled metric. Must be paired with `sum_value`. |
160+
| `sum_value` | `float` | `None` | Observation sum for a single unlabelled metric. Must be paired with `count_value`. |
161+
| `labels` | `Sequence[str]` | `None` | Label names. Use with `add_metric`. Mutually exclusive with `count_value`/`sum_value`. |
162+
| `unit` | `str` | `''` | Optional unit suffix. |
163+
164+
#### `add_metric(labels, count_value, sum_value, timestamp=None)`
165+
166+
| Parameter | Type | Description |
167+
|-----------|------|-------------|
168+
| `labels` | `Sequence[str]` | Label values. |
169+
| `count_value` | `int` | The number of observations. |
170+
| `sum_value` | `float` | The sum of all observed values. |
171+
| `timestamp` | `float` or `Timestamp` | Optional Unix timestamp for the sample. |
172+
173+
```python
174+
s = SummaryMetricFamily('rpc_duration_seconds', 'RPC duration', labels=['method'])
175+
s.add_metric(['get'], count_value=1000, sum_value=53.2)
176+
s.add_metric(['put'], count_value=400, sum_value=28.7)
177+
yield s
178+
```
179+
180+
### HistogramMetricFamily
181+
182+
```python
183+
HistogramMetricFamily(name, documentation, buckets=None, sum_value=None, labels=None, unit='')
184+
```
185+
186+
| Parameter | Type | Default | Description |
187+
|-----------|------|---------|-------------|
188+
| `name` | `str` | required | Metric name. |
189+
| `documentation` | `str` | required | Help text. |
190+
| `buckets` | `Sequence` | `None` | Bucket data for a single unlabelled metric. Each entry is a `(le, value)` pair or `(le, value, exemplar)` triple. Must include a `+Inf` bucket. Mutually exclusive with `labels`. |
191+
| `sum_value` | `float` | `None` | Observation sum. Cannot be set without `buckets`. Omitted for histograms with negative buckets. |
192+
| `labels` | `Sequence[str]` | `None` | Label names. Use with `add_metric`. Mutually exclusive with `buckets`. |
193+
| `unit` | `str` | `''` | Optional unit suffix. |
194+
195+
#### `add_metric(labels, buckets, sum_value, timestamp=None)`
196+
197+
| Parameter | Type | Description |
198+
|-----------|------|-------------|
199+
| `labels` | `Sequence[str]` | Label values. |
200+
| `buckets` | `Sequence` | Bucket data. Each entry is a `(le, value)` pair or `(le, value, exemplar)` triple. Must be sorted and include `+Inf`. |
201+
| `sum_value` | `float` or `None` | The sum of all observed values. Pass `None` for histograms with negative buckets. |
202+
| `timestamp` | `float` or `Timestamp` | Optional Unix timestamp. |
203+
204+
```python
205+
h = HistogramMetricFamily('request_size_bytes', 'Request sizes', labels=['handler'])
206+
h.add_metric(
207+
['api'],
208+
buckets=[('100', 5), ('1000', 42), ('+Inf', 50)],
209+
sum_value=18350.0,
210+
)
211+
yield h
212+
```
213+
214+
### InfoMetricFamily
215+
216+
```python
217+
InfoMetricFamily(name, documentation, value=None, labels=None)
218+
```
219+
220+
| Parameter | Type | Default | Description |
221+
|-----------|------|---------|-------------|
222+
| `name` | `str` | required | Metric name. The `_info` suffix is added automatically on exposition. |
223+
| `documentation` | `str` | required | Help text. |
224+
| `value` | `Dict[str, str]` | `None` | Key-value label pairs for a single unlabelled info metric. Mutually exclusive with `labels`. |
225+
| `labels` | `Sequence[str]` | `None` | Label names for the outer grouping. Use with `add_metric`. Mutually exclusive with `value`. |
226+
227+
#### `add_metric(labels, value, timestamp=None)`
228+
229+
| Parameter | Type | Description |
230+
|-----------|------|-------------|
231+
| `labels` | `Sequence[str]` | Outer label values (from the `labels` constructor argument). |
232+
| `value` | `Dict[str, str]` | Key-value label pairs that form the info payload. |
233+
| `timestamp` | `float` or `Timestamp` | Optional Unix timestamp. |
234+
235+
```python
236+
# single unlabelled info metric
237+
yield InfoMetricFamily('build', 'Build metadata', value={'version': '1.2.3', 'commit': 'abc123'})
238+
239+
# labelled: one info metric per service
240+
i = InfoMetricFamily('service_build', 'Per-service build info', labels=['service'])
241+
i.add_metric(['auth'], {'version': '2.0.1', 'commit': 'def456'})
242+
i.add_metric(['api'], {'version': '1.9.0', 'commit': 'ghi789'})
243+
yield i
244+
```
245+
246+
## Real-world example
247+
248+
Proxying metrics from an external source:
249+
250+
```python
251+
from prometheus_client.core import CounterMetricFamily, GaugeMetricFamily, REGISTRY
252+
from prometheus_client.registry import Collector
253+
from prometheus_client import start_http_server
254+
255+
# Simulated external data source
256+
_QUEUE_STATS = {
257+
'orders': {'depth': 14, 'processed': 9821},
258+
'notifications': {'depth': 3, 'processed': 45210},
259+
}
260+
261+
class QueueCollector(Collector):
262+
def collect(self):
263+
depth = GaugeMetricFamily(
264+
'queue_depth',
265+
'Current number of messages waiting in the queue',
266+
labels=['queue'],
267+
)
268+
processed = CounterMetricFamily(
269+
'queue_messages_processed_total',
270+
'Total messages processed from the queue',
271+
labels=['queue'],
272+
)
273+
for name, stats in _QUEUE_STATS.items():
274+
depth.add_metric([name], stats['depth'])
275+
processed.add_metric([name], stats['processed'])
276+
yield depth
277+
yield processed
278+
279+
REGISTRY.register(QueueCollector())
280+
281+
if __name__ == '__main__':
282+
start_http_server(8000)
283+
import time
284+
while True:
285+
time.sleep(1)
286+
```

0 commit comments

Comments
 (0)