Skip to content

Commit 3654928

Browse files
authored
Merge pull request #1 from metrics-js/remove_global_registry
Remove global registry
2 parents 8d8bf9b + bc90699 commit 3654928

File tree

9 files changed

+341
-155
lines changed

9 files changed

+341
-155
lines changed

.eslintrc

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,12 @@
33
"parserOptions": {
44
"ecmaVersion": 2018
55
},
6+
"env": {
7+
"node": true,
8+
"jest": true
9+
},
610
"rules": {
711
"strict": [0, "global"],
812
"class-methods-use-this": [0]
9-
},
10-
"overrides": [
11-
{
12-
"files": "src/layouts/frontpage/assets/**/*",
13-
"env": {
14-
"browser": true
15-
}
16-
}
17-
]
13+
}
1814
}

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ cache:
55
notifications:
66
email: false
77
node_js:
8+
- '11'
89
- '10'
9-
- '9'
1010
- '8'
1111
dist: trusty

CHANGELOG.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Changelog
2+
3+
Notable changes to this project will be documented in this file.
4+
5+
The latest version of this document is always available in [releases][releases-url].
6+
7+
## [Unreleased]
8+
9+
## [2.0.0] - 2018-11-22
10+
11+
- prom-client global state removed
12+
- .metrics() method added
13+
- .contentType() method added
14+
- lint fixing
15+
16+
[unreleased]: https://github.com/metrics-js/prometheus-consumer/compare/v2.0.0...HEAD
17+
[2.0.0]: https://github.com/metrics-js/prometheus-consumer/compare/v1.0.0...v2.0.0
18+
[releases-url]: https://github.com/metrics-js/prometheus-consumer/blob/master/CHANGELOG.md

README.md

Lines changed: 97 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -52,64 +52,123 @@ const metricsConsumer = new PrometheusConsumer({ client: promClient });
5252

5353
### Step 2.
5454

55-
Pipe the metrics output stream directly into our consumer
55+
Pipe the metrics output stream directly into our consumer making sure to add an error handler to avoid uncaught exceptions.
5656

5757
```js
5858
const client = new MetricsClient();
5959

60+
metricsConsumer.on('error', err => console.error(err));
61+
6062
client.pipe(metricsConsumer);
6163
```
6264

65+
### Step 3.
66+
67+
Render a metrics page for prometheus to scrape.
68+
In this example we use express (though any framework will work) to render out metrics on the route `/metrics`.
69+
70+
```js
71+
app.get('/metrics', (req, res) => {
72+
res.set('Content-Type', metricsConsumer.contentType()).send(
73+
metricsConsumer.metrics(),
74+
);
75+
});
76+
```
77+
6378
## API
6479

65-
### new PrometheusConsumer(options)
80+
- [constructor](#constructoroptions)
81+
- [override](#overridenameconfig)
82+
- [metrics](#metrics)
83+
- [contentType](#contenttype)
84+
85+
### constructor(options)
6686

6787
Create a new metrics consumer instance ready to have metrics piped into it.
6888

69-
**options**
89+
_Examples_
90+
91+
```js
92+
const consumer = new PrometheusConsumer({ client: promClient });
93+
```
7094

71-
| name | description | type | default |
72-
| ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------- |
73-
| client | Prom client dependency. Passed in this way in order to avoid having a hard dependency on a specific version of prom-client which polutes the global space |
74-
| bucketStepStart | Value to start bucket generation from. Each step increases from here by `bucketStepFactor` | `number` | 0.001 |
75-
| bucketStepFactor | Scaling factor for bucket creation. Must be > 1 | `number` | 1.15 |
76-
| bucketStepCount | Number of times `bucketStepFactor` should be applied to `bucketStepStart` | `number` | 45 |
95+
remember to add an error handler to the consumer to avoid uncaught exception errors.
96+
97+
```js
98+
consumer.on('error', err => console.error(err));
99+
```
100+
101+
#### options
102+
103+
| name | description | type | default |
104+
| ------------------------------------- | ------------------------------------------------------------------------------------------ | -------- | ------- |
105+
| [client](#client) | Prom client module dependency. |
106+
| [bucketStepStart](#bucketstepstart) | Value to start bucket generation from. Each step increases from here by `bucketStepFactor` | `number` | 0.001 |
107+
| [bucketStepFactor](#bucketstepfactor) | Scaling factor for bucket creation. Must be > 1 | `number` | 1.15 |
108+
| [bucketStepCount](#bucketstepcount) | Number of times `bucketStepFactor` should be applied to `bucketStepStart` | `number` | 45 |
109+
110+
##### client
111+
112+
Prom client module dependency. Passed in this way in order to avoid having a hard dependency on a specific version of prom-client.
77113

78114
_Example_
79115

80116
```js
81-
const consumer = new PrometheusConsumer({
82-
client: promClient,
83-
bucketStepStart: 1,
84-
bucketStepFactor: 2,
85-
bucketStepCount: 8,
86-
});
117+
const consumer = new PrometheusConsumer({ client: promClient });
87118
```
88119

89-
This example will use buckets: 1,2,4,8,16,32,64,128,256
120+
##### bucketStepStart
121+
122+
Value to start bucket generation from. Each step increases from here by `bucketStepFactor`
123+
124+
_Example_
125+
126+
```js
127+
const consumer = new PrometheusConsumer({ bucketStepStart: 1 });
128+
```
90129

91-
### instance.override(name, config)
130+
##### bucketStepFactor
131+
132+
Scaling factor for bucket creation. Must be > 1
133+
134+
_Example_
135+
136+
```js
137+
const consumer = new PrometheusConsumer({ bucketStepFactor: 2 });
138+
```
139+
140+
##### bucketStepCount
141+
142+
Number of times `bucketStepFactor` should be applied to `bucketStepStart`
143+
144+
_Example_
145+
146+
```js
147+
const consumer = new PrometheusConsumer({ bucketStepCount: 8 });
148+
```
149+
150+
### .override(name, config)
92151

93152
Override handling of a specific metric (by name). This is useful if the defaults
94153
do not produce the desired result for a given metric. You can change what type
95154
of prometheus metrics are generated by setting `type` and for histograms, you
96155
can override bucket handling.
97156

98-
**name**
157+
#### name
99158

100159
An alpha-numeric (plus the underscore character) string name of metric to be
101160
overriden. Any metrics that match this name will be processed using the override
102161
config (see below)
103162

104-
**config**
163+
#### config
105164

106165
| name | description | type | default |
107166
| ------- | --------------------------------------------------------------------------- | ---------- | --------- |
108167
| type | One of `histogram`, `counter`, `gauge` or `summary` | `string` | |
109168
| labels | Array with allowed values: `url`, `method`, `status`, `layout` and `podlet` | `string[]` | |
110169
| buckets | An object, see `config.buckets` below | `object` | see below |
111170

112-
**config.buckets**
171+
##### buckets
113172

114173
| name | description | type | default |
115174
| ---------------- | ------------------------------------------------------------------------------------------ | -------- | ------- |
@@ -148,3 +207,21 @@ consumer.override('my_time_based_metric', {
148207
},
149208
});
150209
```
210+
211+
### .metrics()
212+
213+
Returns the generated metrics text ready for scraping by prometheus. This should be used in conjunction with [.contentType()](#contenttype)
214+
215+
_Example_
216+
217+
```js
218+
app.get('/metrics', (req, res) => {
219+
res.set('Content-Type', metricsConsumer.contentType()).send(
220+
metricsConsumer.metrics(),
221+
);
222+
});
223+
```
224+
225+
### .contentType()
226+
227+
Returns the correct content type to use when rendering metrics text for scraping by prometheus. See [.metrics()](#metrics) for an express js usage example.

lib/index.js

Lines changed: 41 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
'use strict';
22

3+
const Joi = require('joi');
34
const { Writable } = require('readable-stream');
45
const {
56
createCounter,
@@ -14,7 +15,7 @@ const {
1415
overrideConfig,
1516
constructorOptions,
1617
} = require('../schemas');
17-
const Joi = require('joi');
18+
1819
const overrides = new Map();
1920
const metricTypes = {
2021
HISTOGRAM: 'histogram',
@@ -29,29 +30,26 @@ module.exports = class PrometheusMetricsConsumer extends Writable {
2930
this.options = Joi.attempt(
3031
options,
3132
constructorOptions,
32-
'Invalid `options` object given to new FinnPodiumMetrics.'
33+
'Invalid `options` object given to new PrometheusMetricsConsumer.',
3334
);
3435

35-
const client = this.options.client;
36+
const { client } = this.options;
3637
this.Counter = client.Counter;
3738
this.Gauge = client.Gauge;
3839
this.Histogram = client.Histogram;
3940
this.Summary = client.Summary;
4041
this.bucketFunction = client.exponentialBuckets;
41-
this.register = client.register;
42+
this.registry = new client.Registry();
4243
}
4344

4445
get [Symbol.toStringTag]() {
4546
return 'PrometheusMetricsConsumer';
4647
}
4748

4849
labels(metric) {
49-
const labelNames = [];
50-
const labelValues = [];
51-
for (const [key, val] of Object.entries(metric.meta || {})) {
52-
labelNames.push(key);
53-
labelValues.push(val);
54-
}
50+
const labelNames = Object.keys(metric.meta || {});
51+
const labelValues = Object.values(metric.meta || {});
52+
5553
return { labelNames, labelValues };
5654
}
5755

@@ -63,11 +61,14 @@ module.exports = class PrometheusMetricsConsumer extends Writable {
6361
const { name } = metric;
6462
const { labelNames, labelValues } = this.labels(metric);
6563

66-
if (!this.register.getSingleMetric(name)) {
67-
createCounter(this.Counter, metric, { labels: labelNames });
64+
if (!this.registry.getSingleMetric(name)) {
65+
createCounter(this.Counter, metric, {
66+
labels: labelNames,
67+
registry: this.registry,
68+
});
6869
}
6970

70-
this.register
71+
this.registry
7172
.getSingleMetric(name)
7273
.labels(...labelValues)
7374
.inc(1);
@@ -77,11 +78,14 @@ module.exports = class PrometheusMetricsConsumer extends Writable {
7778
const { name } = metric;
7879
const { labelNames, labelValues } = this.labels(metric);
7980

80-
if (!this.register.getSingleMetric(name)) {
81-
createGauge(this.Gauge, metric, { labels: labelNames });
81+
if (!this.registry.getSingleMetric(name)) {
82+
createGauge(this.Gauge, metric, {
83+
labels: labelNames,
84+
registry: this.registry,
85+
});
8286
}
8387

84-
this.register
88+
this.registry
8589
.getSingleMetric(name)
8690
.labels(...labelValues)
8791
.set(metric.value);
@@ -91,14 +95,15 @@ module.exports = class PrometheusMetricsConsumer extends Writable {
9195
const { name, time } = metric;
9296
const { labelNames, labelValues } = this.labels(metric);
9397

94-
if (!this.register.getSingleMetric(name)) {
98+
if (!this.registry.getSingleMetric(name)) {
9599
createHistogram(this.Histogram, this.bucketFunction, metric, {
96100
...this.options,
97101
...this.bucketsForHistogram(name),
98102
labels: labelNames,
103+
registry: this.registry,
99104
});
100105
}
101-
this.register
106+
this.registry
102107
.getSingleMetric(name)
103108
.labels(...labelValues)
104109
.observe(time);
@@ -108,12 +113,13 @@ module.exports = class PrometheusMetricsConsumer extends Writable {
108113
const { name, time } = metric;
109114
const { labelNames, labelValues } = this.labels(metric);
110115

111-
if (!this.register.getSingleMetric(name)) {
116+
if (!this.registry.getSingleMetric(name)) {
112117
createSummary(this.Summary, metric, {
113118
labels: labelNames,
119+
registry: this.registry,
114120
});
115121
}
116-
this.register
122+
this.registry
117123
.getSingleMetric(name)
118124
.labels(...labelValues)
119125
.observe(time);
@@ -124,13 +130,13 @@ module.exports = class PrometheusMetricsConsumer extends Writable {
124130
Joi.attempt(
125131
name,
126132
metricName,
127-
'Invalid `name` given to prometheusMetricsConsumer.override.'
133+
'Invalid `name` given to prometheusMetricsConsumer.override.',
128134
),
129135
Joi.attempt(
130136
config,
131137
overrideConfig,
132-
'Invalid `config` object given to prometheusMetricsConsumer.override.'
133-
)
138+
'Invalid `config` object given to prometheusMetricsConsumer.override.',
139+
),
134140
);
135141
}
136142

@@ -153,13 +159,14 @@ module.exports = class PrometheusMetricsConsumer extends Writable {
153159
_write(metric, enc, cb) {
154160
if (this.typeFor(metric) === metricTypes.HISTOGRAM) {
155161
if (!isHistogram(metric)) {
156-
return cb(
162+
cb(
157163
new Error(
158164
`Attempted to plot metric "${
159165
metric.name
160-
}" on a histogram, however metric was missing \`time\` value`
161-
)
166+
}" on a histogram, however metric was missing \`time\` value`,
167+
),
162168
);
169+
return;
163170
}
164171
this.histogram(metric);
165172
} else if (this.typeFor(metric) === metricTypes.GAUGE) {
@@ -171,4 +178,12 @@ module.exports = class PrometheusMetricsConsumer extends Writable {
171178
}
172179
cb();
173180
}
181+
182+
metrics() {
183+
return this.registry.metrics();
184+
}
185+
186+
contentType() {
187+
return this.registry.contentType;
188+
}
174189
};

0 commit comments

Comments
 (0)