@hkube/metrics 1.0.41 → 1.0.43

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/counter.js CHANGED
@@ -24,6 +24,16 @@ class CounterMeasure {
24
24
  remove() {
25
25
  client.register.removeSingleMetric(this._name + COUNTER_POSTFIX);
26
26
  }
27
+ removeEntriesByLabel(labelName, labelValue) {
28
+ const keysToDelete = [];
29
+ const hashKeys = Object.keys(this._requestCounter.hashMap);
30
+ hashKeys.forEach((key) => {
31
+ if (this._requestCounter.hashMap[key].labels[labelName] === labelValue) {
32
+ keysToDelete.push(key);
33
+ }
34
+ });
35
+ keysToDelete.forEach(key => delete this._requestCounter.hashMap[key]);
36
+ }
27
37
  }
28
38
 
29
39
  module.exports = CounterMeasure;
package/lib/gauge.js CHANGED
@@ -36,6 +36,16 @@ class GaugeMeasure {
36
36
  remove() {
37
37
  client.register.removeSingleMetric(this._name + GAUGE_POSTFIX);
38
38
  }
39
+ removeEntriesByLabel(labelName, labelValue) {
40
+ const keysToDelete = [];
41
+ const hashKeys = Object.keys(this._requestGauge.hashMap);
42
+ hashKeys.forEach((key) => {
43
+ if (this._requestGauge.hashMap[key].labels[labelName] === labelValue) {
44
+ keysToDelete.push(key);
45
+ }
46
+ });
47
+ keysToDelete.forEach(key => delete this._requestGauge.hashMap[key]);
48
+ }
39
49
  }
40
50
 
41
51
  module.exports = GaugeMeasure;
package/lib/metrics.js CHANGED
@@ -1,14 +1,15 @@
1
- const optional = require('optional');
2
- const djsv = require('djsv');
3
1
  const { initSchema } = require('./schema');
4
2
  const client = require('prom-client');
3
+ const validator = require('./validator');
5
4
  const TimeMeasure = require('./timeMeasure');
6
5
  const Summary = require('./summary');
7
6
  const CounterMeasure = require('./counter');
8
7
  const GaugeMeasure = require('./gauge');
9
8
  const { addTimeMeasureSchema, addCounterMeasureSchema, addTimeMeasureSummarySchema } = require('./schema');
10
9
  const router = require('./router');
11
- const RestServer = optional('@hkube/rest-server');
10
+ const RestServer = require('@hkube/rest-server');
11
+ const promUtils = require('prom-client/lib/util.js');
12
+
12
13
  const {
13
14
  beforeRoutesMiddlewares,
14
15
  afterRoutesMiddlewares,
@@ -16,6 +17,7 @@ const {
16
17
  resetMeasureForMiddleware
17
18
  } = require('./middleware');
18
19
 
20
+
19
21
  class Metrics {
20
22
  constructor() {
21
23
  this._metrics = new Map();
@@ -23,19 +25,12 @@ class Metrics {
23
25
  }
24
26
 
25
27
  async init(options) {
26
- this._prefix = (options && options.prefix) || ''
28
+ this._prefix = (options && options.prefix) || '';
27
29
  client.register.clear();
28
30
  this._metrics.clear();
29
31
  resetMeasureForMiddleware(this);
30
- options = options || {};
31
- const validator = djsv(initSchema);
32
- const validatadOptions = validator(options);
33
- if (validatadOptions.valid) {
34
- this._options = validatadOptions.instance;
35
- }
36
- else {
37
- throw new Error(validatadOptions.error);
38
- }
32
+ this._options = options || {};
33
+ validator.validate(initSchema, this._options);
39
34
 
40
35
  if (this._options.collectDefault) {
41
36
  const { collectDefaultMetrics } = client;
@@ -49,9 +44,11 @@ class Metrics {
49
44
  });
50
45
  }
51
46
  }
47
+
52
48
  getRouter() {
53
49
  return { route: this._options.server.path, router: router(this) };
54
50
  }
51
+
55
52
  getMiddleware() {
56
53
  createMeasureForMiddleware(this);
57
54
  return {
@@ -59,6 +56,7 @@ class Metrics {
59
56
  afterRoutesMiddlewares: [afterRoutesMiddlewares([this._options.server.path])]
60
57
  };
61
58
  }
59
+
62
60
  metrics() {
63
61
  return client.register.metrics();
64
62
  }
@@ -77,15 +75,8 @@ class Metrics {
77
75
  */
78
76
  addTimeMeasure(options) {
79
77
  options = options || {};
80
- const validator = djsv(addTimeMeasureSchema);
81
- const validatadOptions = validator(options);
82
- if (validatadOptions.valid) {
83
- options = validatadOptions.instance;
84
- }
85
- else {
86
- throw new Error(validatadOptions.error);
87
- }
88
- options.name = this.prefix + (options.name || '');
78
+ validator.validate(addTimeMeasureSchema, options);
79
+ options.name = this.prefix + options.name;
89
80
  if (this._metrics.has(options.name)) {
90
81
  throw new Error(`the measure ${options.name} is already registered`);
91
82
  }
@@ -93,6 +84,7 @@ class Metrics {
93
84
  this._metrics.set(options.name, measure);
94
85
  return measure;
95
86
  }
87
+
96
88
  /**
97
89
  *
98
90
  * @param {Object} options
@@ -104,15 +96,8 @@ class Metrics {
104
96
  */
105
97
  addSummary(options) {
106
98
  options = options || {};
107
- const validator = djsv(addTimeMeasureSummarySchema);
108
- const validatadOptions = validator(options);
109
- if (validatadOptions.valid) {
110
- options = validatadOptions.instance;
111
- }
112
- else {
113
- throw new Error(validatadOptions.error);
114
- }
115
- options.name = this.prefix + (options.name || '');
99
+ validator.validate(addTimeMeasureSummarySchema, options);
100
+ options.name = this.prefix + options.name;
116
101
  if (this._metrics.has(options.name)) {
117
102
  throw new Error(`the summary ${options.name} is already registered`);
118
103
  }
@@ -130,15 +115,8 @@ class Metrics {
130
115
  */
131
116
  addCounterMeasure(options) {
132
117
  options = options || {};
133
- const validator = djsv(addCounterMeasureSchema);
134
- const validatadOptions = validator(options);
135
- if (validatadOptions.valid) {
136
- options = validatadOptions.instance;
137
- }
138
- else {
139
- throw new Error(validatadOptions.error);
140
- }
141
- options.name = this.prefix + (options.name || '');
118
+ validator.validate(addCounterMeasureSchema, options);
119
+ options.name = this.prefix + options.name;
142
120
  if (this._metrics.has(options.name)) {
143
121
  throw new Error(`the measure ${options.name} is already registered`);
144
122
  }
@@ -146,6 +124,7 @@ class Metrics {
146
124
  this._metrics.set(options.name, measure);
147
125
  return measure;
148
126
  }
127
+
149
128
  /**
150
129
  *
151
130
  * @param {Object} options
@@ -156,15 +135,8 @@ class Metrics {
156
135
  */
157
136
  addGaugeMeasure(options) {
158
137
  options = options || {};
159
- const validator = djsv(addCounterMeasureSchema);
160
- const validatadOptions = validator(options);
161
- if (validatadOptions.valid) {
162
- options = validatadOptions.instance;
163
- }
164
- else {
165
- throw new Error(validatadOptions.error);
166
- }
167
- options.name = this.prefix + (options.name || '');
138
+ validator.validate(addCounterMeasureSchema, options);
139
+ options.name = this.prefix + options.name;
168
140
  if (this._metrics.has(options.name)) {
169
141
  throw new Error(`the measure ${options.name} is already registered`);
170
142
  }
@@ -172,7 +144,7 @@ class Metrics {
172
144
  this._metrics.set(options.name, measure);
173
145
  return measure;
174
146
  }
175
-
147
+
176
148
  /**
177
149
  * get metric by name
178
150
  * @param name metric name, without prefix
@@ -196,6 +168,23 @@ class Metrics {
196
168
  this._metrics.delete(this.prefix + name);
197
169
  }
198
170
  }
171
+
172
+ /**
173
+ * remove all entries in the specified metrics, that are assosiated with the specified jobId
174
+ * @param {*} options
175
+ * @param {string} options.labelName
176
+ * @param {string} options.labelValue
177
+ * @param {string[]} options.metricsToRemove array of metric names to remove
178
+ */
179
+ removeMeasureEntries(options) {
180
+ const { labelName, labelValue, metricsToRemove } = options;
181
+ metricsToRemove.forEach((metricName) => {
182
+ const measureInstance = this.get(metricName);
183
+ if (measureInstance) {
184
+ measureInstance.removeEntriesByLabel(labelName, labelValue);
185
+ }
186
+ });
187
+ }
199
188
  }
200
189
 
201
190
  module.exports = new Metrics();
package/lib/router.js CHANGED
@@ -1,5 +1,5 @@
1
- const optional = require('optional');
2
- const express = optional('express');
1
+ const express = require('express');
2
+
3
3
  const metricsRoute = (metrics) => {
4
4
  const router = express.Router();
5
5
  router.get('/', (req, res, next) => {
package/lib/schema.js CHANGED
@@ -26,7 +26,8 @@ const addCounterMeasureSchema = {
26
26
  type: 'object',
27
27
  properties: {
28
28
  name: {
29
- type: 'string'
29
+ type: 'string',
30
+ minLength: 1
30
31
  },
31
32
  description: {
32
33
  type: 'string'
@@ -46,7 +47,8 @@ const addTimeMeasureSchema = {
46
47
  type: 'object',
47
48
  properties: {
48
49
  name: {
49
- type: 'string'
50
+ type: 'string',
51
+ minLength: 1
50
52
  },
51
53
  description: {
52
54
  type: 'string'
@@ -74,7 +76,8 @@ const addTimeMeasureSummarySchema = {
74
76
  type: 'object',
75
77
  properties: {
76
78
  name: {
77
- type: 'string'
79
+ type: 'string',
80
+ minLength: 1
78
81
  },
79
82
  description: {
80
83
  type: 'string'
@@ -1,6 +1,6 @@
1
1
  const client = require('prom-client');
2
2
  const uuid = require('uuid/v4');
3
- const HISTORGRAM_POSTFIX = '_histogram';
3
+ const HISTOGRAM_POSTFIX = '_histogram';
4
4
  const COUNTER_POSTFIX = '_counter';
5
5
  class TimeMeasure {
6
6
  /**
@@ -9,13 +9,13 @@ class TimeMeasure {
9
9
  * @param {string} options.name The name of the measure. Must be unique
10
10
  * @param {string} options.description The description of the measure. If not specified, the name is used
11
11
  * @param {string[]} [options.labels] array of label names
12
- * @param {number[]} [options.buckets] array of historgram buckets. in not defined, the defualt is used
12
+ * @param {number[]} [options.buckets] array of histogram buckets. in not defined, the default is used
13
13
  */
14
14
  constructor(options) {
15
15
  this._name = options.name;
16
16
  this._startedMeasures = new Map();
17
17
  this._histogram = new client.Histogram({
18
- name: options.name + HISTORGRAM_POSTFIX,
18
+ name: options.name + HISTOGRAM_POSTFIX,
19
19
  help: options.description || options.name,
20
20
  labelNames: options.labels,
21
21
  buckets: options.buckets
@@ -72,7 +72,7 @@ class TimeMeasure {
72
72
  }
73
73
 
74
74
  remove() {
75
- client.register.removeSingleMetric(this._name + HISTORGRAM_POSTFIX);
75
+ client.register.removeSingleMetric(this._name + HISTOGRAM_POSTFIX);
76
76
  client.register.removeSingleMetric(this._name + COUNTER_POSTFIX);
77
77
  }
78
78
  }
package/lib/tracer.js CHANGED
@@ -1,6 +1,6 @@
1
1
  const { initTracer } = require('jaeger-client');
2
2
  const opentracing = require('opentracing');
3
- const djsv = require('djsv');
3
+ const validator = require('./validator');
4
4
  const uuid = require('uuid/v4');
5
5
  const { tracerSchema, startSpanSchema, parentRelationships } = require('./schema');
6
6
 
@@ -12,27 +12,13 @@ class Tracer {
12
12
  options = options || {};
13
13
  const tracerConfig = options.tracerConfig || {};
14
14
  const tracerOptions = options.tracerOptions || {};
15
- const validator = djsv(tracerSchema);
16
- const validatadOptions = validator(tracerConfig);
17
- if (validatadOptions.valid) {
18
- this._options = validatadOptions.instance;
19
- }
20
- else {
21
- throw new Error(validatadOptions.error);
22
- }
15
+ validator.validate(tracerSchema, tracerConfig);
23
16
  this._tracer = initTracer(tracerConfig, tracerOptions);
24
17
  }
25
18
 
26
19
  startSpan(options) {
27
20
  options = options || {};
28
- const validator = djsv(startSpanSchema);
29
- const validatadOptions = validator(options);
30
- if (validatadOptions.valid) {
31
- options = validatadOptions.instance;
32
- }
33
- else {
34
- throw new Error(validatadOptions.error);
35
- }
21
+ validator.validate(startSpanSchema, options);
36
22
  const id = options.id || uuid();
37
23
  const spanOptions = {};
38
24
  let parentContext;
@@ -0,0 +1,16 @@
1
+ const Ajv = require('ajv');
2
+ const validator = new Ajv({ useDefaults: true });
3
+
4
+ class Validator {
5
+ validate(schema, options) {
6
+ const valid = validator.validate(schema, options);
7
+
8
+ if (!valid) {
9
+ const { errors } = validator;
10
+ const error = validator.errorsText(errors);
11
+ throw new Error(error);
12
+ }
13
+ }
14
+ }
15
+
16
+ module.exports = new Validator();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hkube/metrics",
3
- "version": "1.0.41",
3
+ "version": "1.0.43",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -9,18 +9,18 @@
9
9
  "build": "npm publish"
10
10
  },
11
11
  "keywords": [],
12
- "author": "",
12
+ "author": "Hkube",
13
13
  "license": "ISC",
14
14
  "dependencies": {
15
- "djsv": "^3.0.3",
15
+ "@hkube/rest-server": "^1.0.16",
16
+ "ajv": "^6.12.0",
17
+ "express": "^4.16.0",
16
18
  "jaeger-client": "^3.7.0",
17
19
  "opentracing": "^0.14.1",
18
- "optional": "^0.1.4",
19
20
  "prom-client": "^10.2.2",
20
21
  "uuid": "^3.1.0"
21
22
  },
22
23
  "devDependencies": {
23
- "@hkube/rest-server": "^1.0.4",
24
24
  "chai": "^4.1.2",
25
25
  "chai-as-promised": "^7.1.1",
26
26
  "coveralls": "^3.0.0",
@@ -32,9 +32,5 @@
32
32
  "istanbul": "^1.1.0-alpha.1",
33
33
  "mocha": "^4.0.1",
34
34
  "node-mocks-http": "^1.6.6"
35
- },
36
- "peerDependencies": {
37
- "@hkube/rest-server": "^1.0.3",
38
- "express": "^4.16.0"
39
35
  }
40
36
  }
@@ -1,4 +1,4 @@
1
- const {metrics} = require('../index');
1
+ const { metrics } = require('../index');
2
2
  const chai = require('chai');
3
3
  const { expect } = chai;
4
4
  const chaiAsPromised = require('chai-as-promised');
@@ -111,10 +111,10 @@ describe('Counter Measure', () => {
111
111
  name: 'm1',
112
112
  labels: ['l1', 'l2']
113
113
  });
114
- measure.inc({labelValues: { l1: 'l1Val' }});
115
- measure.inc({labelValues: { l1: 'l1Val' }});
114
+ measure.inc({ labelValues: { l1: 'l1Val' } });
115
+ measure.inc({ labelValues: { l1: 'l1Val' } });
116
116
  expect(client.register.metrics()).to.include('m1_counter{l1="l1Val"} 2');
117
- measure.inc({labelValues: { l1: 'l1Val2' }});
117
+ measure.inc({ labelValues: { l1: 'l1Val2' } });
118
118
  expect(client.register.metrics()).to.include('m1_counter{l1="l1Val2"} 1');
119
119
  });
120
120
  });
package/test/test.js CHANGED
@@ -31,6 +31,10 @@ describe('Init metrics', () => {
31
31
  await metrics.init();
32
32
  expect(() => metrics.addTimeMeasure({})).to.throw("data should have required property 'name'");
33
33
  });
34
+ it('Should throw with empty name', async () => {
35
+ await metrics.init();
36
+ expect(() => metrics.addTimeMeasure({name: ''})).to.throw('data.name should NOT be shorter than 1 characters');
37
+ });
34
38
  it('Should throw if no options', async () => {
35
39
  await metrics.init();
36
40
  expect(() => metrics.addTimeMeasure()).to.throw("data should have required property 'name'");