UNPKG

7.64 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.MetricsGatherer = exports.MetricsGathererError = void 0;
4const express = require("express");
5const prometheus = require("prom-client");
6const typed_error_1 = require("typed-error");
7const Debug = require("debug");
8const debug = Debug('node-metrics-gatherer');
9const collect_1 = require("./collectors/api/collect");
10const types_1 = require("./types");
11class MetricsGathererError extends typed_error_1.TypedError {
12}
13exports.MetricsGathererError = MetricsGathererError;
14const constructors = {
15 gauge: new types_1.MetricConstructor(prometheus.Gauge),
16 counter: new types_1.MetricConstructor(prometheus.Counter),
17 summary: new types_1.MetricConstructor(prometheus.Summary),
18 histogram: new types_1.MetricConstructor(prometheus.Histogram),
19};
20class MetricsGatherer {
21 constructor() {
22 this.initState();
23 this.setupDescribe();
24 this.client = prometheus;
25 }
26 initState() {
27 try {
28 this.metrics = {
29 gauge: {},
30 counter: {},
31 histogram: {},
32 summary: {},
33 };
34 this.meta = {};
35 this.internalErrorCount = 0;
36 }
37 catch (e) {
38 this.err(e);
39 }
40 }
41 setupDescribe() {
42 this.describe = {};
43 for (const kind of ['gauge', 'counter', 'histogram', 'summary']) {
44 this.describe[kind] = (name, help, customParams = {}) => {
45 if (this.meta[name]) {
46 throw new MetricsGathererError(`tried to describe metric "${name}" twice`);
47 }
48 else {
49 this.meta[name] = {
50 kind,
51 help,
52 customParams,
53 };
54 }
55 };
56 }
57 }
58 gauge(name, val, labels = {}) {
59 try {
60 this.ensureExists('gauge', name, labels);
61 this.metrics.gauge[name].set(labels, val);
62 }
63 catch (e) {
64 this.err(e);
65 }
66 }
67 inc(name, val = 1, labels = {}) {
68 try {
69 const kind = /.+_total$/.test(name) ? 'counter' : 'gauge';
70 this.ensureExists(kind, name, labels);
71 if (!this.checkMetricType(name, ['gauge', 'counter'])) {
72 throw new MetricsGathererError(`Tried to increment non-gauge, non-counter metric ${name}`);
73 }
74 if (this.meta[name].kind === 'gauge') {
75 this.metrics.gauge[name].inc(labels, val);
76 }
77 else {
78 this.metrics.counter[name].inc(labels, val);
79 }
80 }
81 catch (e) {
82 this.err(e);
83 }
84 }
85 dec(name, val = 1, labels = {}) {
86 try {
87 this.ensureExists('gauge', name, labels);
88 if (!this.checkMetricType(name, ['gauge'])) {
89 throw new MetricsGathererError(`Tried to decrement non-gauge metric ${name}`);
90 }
91 this.metrics.gauge[name].dec(labels, val);
92 }
93 catch (e) {
94 this.err(e);
95 }
96 }
97 counter(name, val = 1, labels = {}) {
98 try {
99 this.ensureExists('counter', name, labels);
100 this.metrics.counter[name].inc(labels, val);
101 }
102 catch (e) {
103 this.err(e);
104 }
105 }
106 summary(name, val, labels = {}, customParams = {}) {
107 try {
108 this.ensureExists('summary', name, labels, customParams);
109 this.metrics.summary[name].observe(labels, val);
110 }
111 catch (e) {
112 this.err(e);
113 }
114 }
115 histogram(name, val, labels = {}, customParams = {}) {
116 try {
117 this.ensureExists('histogram', name, labels, customParams);
118 this.metrics.histogram[name].observe(labels, val);
119 }
120 catch (e) {
121 this.err(e);
122 }
123 }
124 histogramSummary(name, val, labels = {}) {
125 try {
126 this.histogram(`${name}_hist`, val, labels);
127 this.summary(`${name}_summary`, val, labels);
128 }
129 catch (e) {
130 this.err(e);
131 }
132 }
133 checkMetricType(name, kinds) {
134 try {
135 return kinds.includes(this.meta[name].kind);
136 }
137 catch (e) {
138 this.err(e);
139 }
140 }
141 getMetric(name) {
142 if (this.meta[name]) {
143 return this.metrics[this.meta[name].kind][name];
144 }
145 }
146 exists(name) {
147 return this.getMetric(name) != null;
148 }
149 ensureExists(kind, name, labels = {}, customParams = {}) {
150 try {
151 if (this.exists(name)) {
152 return;
153 }
154 if (!this.meta[name]) {
155 this.describe[kind](name, `undescribed ${kind} metric`, Object.assign({ labelNames: Object.keys(labels) }, customParams));
156 }
157 else if (this.meta[name].kind !== kind) {
158 throw new MetricsGathererError(`tried to use ${name} twice - first as ` +
159 `${this.meta[name].kind}, then as ${kind}`);
160 }
161 this.metrics[kind][name] = constructors[kind].create(Object.assign(Object.assign({ name, help: this.meta[name].help, labelNames: Object.keys(labels) }, customParams), this.meta[name].customParams));
162 }
163 catch (e) {
164 this.err(e);
165 }
166 }
167 reset(name) {
168 try {
169 if (!name) {
170 prometheus.register.resetMetrics();
171 }
172 else {
173 const metric = this.getMetric(name);
174 if (metric) {
175 metric.reset();
176 }
177 }
178 }
179 catch (e) {
180 this.err(e);
181 }
182 }
183 exportOn(port, path = '/metrics', requestHandler) {
184 const app = express();
185 app.use(path, requestHandler !== null && requestHandler !== void 0 ? requestHandler : this.requestHandler());
186 app.listen(port);
187 }
188 requestHandler(authTest) {
189 return (req, res) => {
190 if (authTest && !authTest(req)) {
191 return res.status(403).send();
192 }
193 res.writeHead(200, { 'Content-Type': 'text/plain' });
194 res.end(prometheus.register.metrics());
195 };
196 }
197 aggregateRequestHandler(authTest) {
198 const aggregatorRegistry = new prometheus.AggregatorRegistry();
199 return (req, res) => {
200 if (authTest && !authTest(req)) {
201 return res.status(403).send();
202 }
203 aggregatorRegistry
204 .clusterMetrics()
205 .then((metrics) => {
206 res.set('Content-Type', aggregatorRegistry.contentType);
207 res.send(metrics);
208 })
209 .catch((err) => {
210 this.err(err);
211 res.status(500).send();
212 });
213 };
214 }
215 collectDefaultMetrics() {
216 prometheus.collectDefaultMetrics();
217 }
218 collectAPIMetrics(app) {
219 app.use(collect_1.collectAPIMetrics(this));
220 return app;
221 }
222 output() {
223 try {
224 return prometheus.register.metrics();
225 }
226 catch (e) {
227 this.err(e);
228 return '';
229 }
230 }
231 clear() {
232 try {
233 prometheus.register.clear();
234 this.initState();
235 }
236 catch (e) {
237 this.err(e);
238 }
239 }
240 err(e) {
241 debug(e);
242 this.internalErrorCount++;
243 }
244}
245exports.MetricsGatherer = MetricsGatherer;
246//# sourceMappingURL=metrics-gatherer.js.map
\No newline at end of file