Skip to content

Commit dd0531a

Browse files
authored
Merge pull request #18 from statful/validate-values
fix(TEL-NA): validate metric values, usage of ES6 methods to simplify…
2 parents 9f31845 + bcb3042 commit dd0531a

File tree

9 files changed

+307
-525
lines changed

9 files changed

+307
-525
lines changed

dist/statful.js

Lines changed: 88 additions & 144 deletions
Large diffs are not rendered by default.

dist/statful.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/statful.umd.js

Lines changed: 88 additions & 144 deletions
Large diffs are not rendered by default.

dist/statful.umd.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/metric.model.js

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,22 @@ export default class Metric {
1717
typeAggregationFrequency = config[type].aggregationFrequency;
1818
}
1919

20-
this.tags = this.setTags(options.tags, config.tags, typeTags, config.app);
21-
this.aggregations = this.setAggregations(options.aggregations, config.aggregations, typeAggregations);
22-
this.aggregationFrequency = this.setAggregationFrequency(options.aggregationFrequency, config.aggregationFrequency, typeAggregationFrequency);
20+
this.tags = this.buildTags(options.tags, config.tags, typeTags, config.app);
21+
this.aggregations = this.buildAggregations(options.aggregations, config.aggregations, typeAggregations);
22+
this.aggregationFrequency = this.buildAggregationFrequency(options.aggregationFrequency, config.aggregationFrequency, typeAggregationFrequency);
2323
this.namespace = options.namespace || config.namespace;
2424
this.sampleRate = options.sampleRate || config.sampleRate;
2525
}
2626

2727
/**
28-
* Define tags for a metric type
28+
* Build tags for a metric type
2929
* @param {object} methodTags - list of method tags
3030
* @param {object} globalTags - list of global tags
3131
* @param {object} typeTags - list of type tags
3232
* @param {string} app - app tag value
3333
* @returns {*}
3434
*/
35-
setTags(methodTags = {}, globalTags = {}, typeTags = {}, app) {
35+
buildTags(methodTags = {}, globalTags = {}, typeTags = {}, app) {
3636
let tags = {};
3737

3838
Object.assign(tags, globalTags);
@@ -47,15 +47,16 @@ export default class Metric {
4747
}
4848

4949
/**
50-
* Define aggregations for a metric type
50+
* Build aggregations for a metric type
5151
* @param {Array} methodAggregations - list of method aggregations
5252
* @param {Array} globalAggregations - list of global aggregations
5353
* @param {Array} typeAggregations - list of type aggregations
5454
* @returns {*|Array}
5555
*/
56-
setAggregations(methodAggregations = [], globalAggregations = [], typeAggregations = []) {
57-
let aggregations = globalAggregations;
56+
buildAggregations(methodAggregations = [], globalAggregations = [], typeAggregations = []) {
57+
let aggregations = [];
5858

59+
aggregations = aggregations.concat(globalAggregations);
5960
aggregations = aggregations.concat(typeAggregations).filter(this.uniq);
6061
aggregations = aggregations.concat(methodAggregations).filter(this.uniq);
6162

@@ -74,12 +75,12 @@ export default class Metric {
7475
}
7576

7677
/**
77-
* Define aggregation frequency
78+
* Build aggregation frequency
7879
* @param {number} methodFrequency - method aggregation frequency
7980
* @param {number} globalFrequency - global aggregation frequency
8081
* @param {number} typeFrequency - type aggregation frequency
8182
*/
82-
setAggregationFrequency(methodFrequency, globalFrequency, typeFrequency) {
83+
buildAggregationFrequency(methodFrequency, globalFrequency, typeFrequency) {
8384
let frequency = methodFrequency || typeFrequency || globalFrequency;
8485

8586
return this.filterAggregationFrequency(frequency);
@@ -91,9 +92,7 @@ export default class Metric {
9192
* @returns {Array}
9293
*/
9394
filterAggregations(aggregations = []) {
94-
return aggregations.filter((item) => {
95-
return aggregationList.includes(item);
96-
});
95+
return aggregations.filter((item) => aggregationList.includes(item));
9796
}
9897

9998
/**
@@ -102,12 +101,6 @@ export default class Metric {
102101
* @returns {*}
103102
*/
104103
filterAggregationFrequency(frequency) {
105-
let freq = 10;
106-
107-
if (aggregationFrequencyList.includes(frequency)) {
108-
freq = frequency;
109-
}
110-
111-
return freq;
104+
return (aggregationFrequencyList.includes(frequency)) ? frequency : 10;
112105
}
113106
}

src/statful-util.js

Lines changed: 30 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,23 @@ import StatfulLogger from './logger';
33
export default class StatfulUtil {
44
constructor(config) {
55
this.config = {};
6-
this.listQueues = [];
7-
8-
Object.keys(config).forEach((key) => {
9-
this.config[key] = config[key];
10-
});
6+
Object.assign(this.config, config);
117

128
this.logger = new StatfulLogger(this.config.debug);
9+
if (this.config && this.config.flushInterval) {
10+
this.registerQueue(this.config.flushInterval);
11+
}
1312
}
1413

1514
/**
1615
* Sends HTTP request to the api
17-
* @param {string} endpoint - action
18-
* @param {string} requestData - request data
16+
* @param {object} requestData - request data
1917
*/
20-
sendRequest(endpoint, requestData) {
21-
let requestArr = [this.config.apiAddress, endpoint];
22-
const requestUrl = requestArr.join('/');
18+
sendRequest(requestData) {
19+
const requestUrl = `${this.config.apiAddress}/beacon/metrics`;
20+
requestData = JSON.stringify(requestData);
2321

24-
this.logger.debug('Request: ' + requestUrl, requestData);
22+
this.logger.debug('Request: ${requestUrl}', requestData);
2523

2624
let xmlHttp = new XMLHttpRequest();
2725
xmlHttp.open('POST', requestUrl, true);
@@ -42,32 +40,29 @@ export default class StatfulUtil {
4240

4341
/**
4442
* Register a new queue
45-
* @param {string} queueName - queue name
46-
* @param {string} endpoint - endpoint to send requests
47-
* @param {int} timeInterval - interval in milliseconds, default 30000 ms
43+
* @param {number} flushInterval
4844
*/
49-
registerQueue(queueName, endpoint, timeInterval) {
50-
timeInterval = timeInterval || this.config.flushInterval;
51-
52-
if (typeof queueName === 'string' && typeof timeInterval === 'number') {
53-
this.listQueues[queueName] = {
54-
data: [],
55-
endpoint: endpoint
56-
};
45+
registerQueue(flushInterval) {
46+
let metricsTimer;
5747

58-
this.listQueues[queueName].timer = setInterval(() => {
59-
let queue = this.listQueues[queueName];
48+
this.metricsQueue = [];
6049

61-
if (queue.data.length > 0) {
50+
if (typeof this.config.flushInterval === 'number' && flushInterval > 0) {
51+
metricsTimer = setInterval(() => {
52+
if (this.metricsQueue.length > 0) {
6253
if (!this.config.dryrun) {
63-
this.sendRequest(queue.endpoint, JSON.stringify(queue.data));
54+
this.sendRequest(this.metricsQueue);
6455
} else {
65-
this.logger.debug('Dryrun data', queue.endpoint, queue.data);
56+
this.logger.debug('Dryrun data', this.metricsQueue);
6657
}
67-
queue.data = [];
58+
this.metricsQueue = [];
6859
}
6960

70-
}, timeInterval);
61+
}, flushInterval);
62+
63+
window.addEventListener('beforeunload', () => {
64+
clearInterval(metricsTimer);
65+
});
7166

7267
return true;
7368
} else {
@@ -76,26 +71,14 @@ export default class StatfulUtil {
7671
}
7772

7873
/**
79-
* Unregister queue
80-
* @param {string} queueName - queue name
81-
*/
82-
unregisterQueue(queueName) {
83-
if (this.listQueues[queueName]) {
84-
clearInterval(this.listQueues[queueName].timer);
85-
this.listQueues[queueName] = undefined;
86-
}
87-
}
88-
89-
/**
90-
* Sends an Item to a specific queue
91-
* @param {string} queueName - queue name
92-
* @param {object} item - object to be sent
74+
* Sends a metric to the queue
75+
* @param {object} metric - object to be sent
9376
*/
94-
addItemToQueue(queueName, item = {}) {
95-
let sampleRateNormalized = (item.sampleRate || this.config.sampleRate || 100) / 100;
77+
addMetricToQueue(metric = {}) {
78+
const sampleRateNormalized = (metric.sampleRate || this.config.sampleRate || 100) / 100;
9679

97-
if (this.listQueues[queueName] && Math.random() <= sampleRateNormalized) {
98-
this.listQueues[queueName].data.push(item);
80+
if (Math.random() <= sampleRateNormalized) {
81+
this.metricsQueue.push(metric);
9982
return true;
10083
} else {
10184
this.logger.debug('Metric was discarded due to sample rate.');

src/statful.js

Lines changed: 36 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,6 @@ export default class Statful {
5757
apiAddress: 'https://beacon.statful.com'
5858
};
5959

60-
this.endpoints = {
61-
metrics: 'beacon/metrics'
62-
};
63-
6460
// Set default properties
6561
if (typeof clientConfig !== 'object' || clientConfig === null) {
6662
clientConfig = {};
@@ -73,16 +69,7 @@ export default class Statful {
7369
this.logger = new StatfulLogger(this.config.debug);
7470

7571
// Create Util
76-
this.util = new StatfulUtil({
77-
apiAddress: this.config.apiAddress,
78-
debug: this.config.debug,
79-
dryrun: this.config.dryrun,
80-
flushInterval: this.config.flushInterval,
81-
timeout: this.config.timeout
82-
});
83-
84-
//Register queue to send metrics
85-
this.util.registerQueue('metrics', this.endpoints.metrics, this.config.flushInterval);
72+
this.util = new StatfulUtil(this.config);
8673
}
8774

8875
/**
@@ -91,16 +78,14 @@ export default class Statful {
9178
* @returns {number}
9279
*/
9380
static measureTimeUserTiming(measureName = '') {
81+
const measure = window.performance.getEntriesByName(measureName).filter((entry) => entry.entryType === 'measure');
9482
let time;
95-
let measure = window.performance.getEntriesByName(measureName).filter((entry) => {
96-
return entry.entryType === 'measure';
97-
});
9883

9984
if (measure.length > 0) {
10085
// Always use the most recent measure if more exist
10186
time = measure[measure.length - 1].duration;
10287
} else {
103-
this.logger.debug('Measure ' + measureName + ' not found');
88+
this.logger.debug(`Measure ${measureName} not found`);
10489
}
10590

10691
return time;
@@ -112,7 +97,7 @@ export default class Statful {
11297
*/
11398
static clearMarks(marks) {
11499
try {
115-
if (marks) {
100+
if (Array.isArray(marks)) {
116101
marks.forEach((mark) => {
117102
if (mark) {
118103
window.performance.clearMarks(mark);
@@ -143,9 +128,11 @@ export default class Statful {
143128
*/
144129
static clearMeasures(measures) {
145130
try {
146-
if (measures) {
131+
if (Array.isArray(measures)) {
147132
measures.forEach((measure) => {
148-
window.performance.clearMeasures(measure);
133+
if (measure) {
134+
window.performance.clearMeasures(measure);
135+
}
149136
});
150137
} else {
151138
window.performance.clearMeasures();
@@ -187,11 +174,7 @@ export default class Statful {
187174
clearMeasures: false
188175
};
189176

190-
options = options || {};
191-
192-
Object.keys(options).forEach((key) => {
193-
defaults[key] = options[key];
194-
});
177+
Object.assign(defaults, options);
195178

196179
// Create endMark if none is set
197180
if (!defaults.endMark) {
@@ -207,7 +190,7 @@ export default class Statful {
207190
if (time) {
208191
// Push metrics to queue
209192
let metricItem = new Metric(metricName, 'timer', time, defaults, this.config);
210-
this.util.addItemToQueue('metrics', metricItem);
193+
this.util.addMetricToQueue(metricItem);
211194
} else {
212195
this.logger.error('Failed to get measure time to register as timer value');
213196
}
@@ -234,19 +217,14 @@ export default class Statful {
234217
* @param {object} options - set of option (tags, agg, aggFreq, namespace)
235218
*/
236219
static timer(metricName, metricValue, options = {}) {
237-
try {
238-
this.logger.debug('Register Timer', metricName, metricValue, options);
239-
if (metricName && metricValue >= 0) {
240-
options = options || {};
241-
242-
// Push metrics to queue
243-
let item = new Metric(metricName, 'timer', metricValue, options, this.config);
244-
this.util.addItemToQueue('metrics', item);
245-
} else {
246-
this.logger.error('Undefined metric name or invalid value to register as a timer');
247-
}
248-
} catch (ex) {
249-
this.logger.error(ex);
220+
this.logger.debug('Register Timer', metricName, metricValue, options);
221+
if (!isNaN(metricValue) && metricName) {
222+
metricValue = Math.abs(metricValue);
223+
// Push metrics to queue
224+
let item = new Metric(metricName, 'timer', metricValue, options, this.config);
225+
this.util.addMetricToQueue(item);
226+
} else {
227+
this.logger.error('Undefined metric name or invalid value to register as a timer');
250228
}
251229
}
252230

@@ -256,43 +234,33 @@ export default class Statful {
256234
* @param {number} metricValue - count value to be sent
257235
* @param {object} options - set of option (tags, agg, aggFreq, namespace)
258236
*/
259-
static counter(metricName, metricValue, options = {}) {
260-
try {
261-
this.logger.debug('Register Counter', metricName, options);
262-
metricValue = metricValue || 1;
263-
264-
if (metricName) {
265-
options = options || {};
237+
static counter(metricName, metricValue = 1, options = {}) {
238+
this.logger.debug('Register Counter', metricName, options);
239+
if (!isNaN(metricValue) && metricName) {
240+
metricValue = Math.abs(parseInt(metricValue, 10));
266241

267-
// Push metrics to queue
268-
let item = new Metric(metricName, 'counter', metricValue, options, this.config);
269-
this.util.addItemToQueue('metrics', item);
270-
} else {
271-
this.logger.error('Undefined metric name to register as a counter');
272-
}
273-
} catch (ex) {
274-
this.logger.error(ex);
242+
// Push metrics to queue
243+
let item = new Metric(metricName, 'counter', metricValue, options, this.config);
244+
this.util.addMetricToQueue(item);
245+
} else {
246+
this.logger.error('Undefined metric name or invalid value to register as a counter');
275247
}
276248
}
277249

278250
/**
279251
* Register gauge
280-
* @param {string} metricName metric name to be sent
281-
* @param {number} metricValue gauge value to be sent
252+
* @param {string} metricName - metric name to be sent
253+
* @param {number} metricValue - gauge value to be sent
282254
* @param {object} options - set of option (tags, agg, aggFreq, namespace)
283255
*/
284256
static gauge(metricName, metricValue, options = {}) {
285-
try {
286-
this.logger.debug('Register Gauge', metricName, metricValue, options);
287-
if (metricName && metricValue) {
288-
// Push metrics to queue
289-
let item = new Metric(metricName, 'gauge', metricValue, options, this.config);
290-
this.util.addItemToQueue('metrics', item);
291-
} else {
292-
this.logger.error('Undefined metric name/value to register as a gauge');
293-
}
294-
} catch (ex) {
295-
this.logger.error(ex);
257+
this.logger.debug('Register Gauge', metricName, metricValue, options);
258+
if (!isNaN(metricValue) && metricName) {
259+
// Push metrics to queue
260+
let item = new Metric(metricName, 'gauge', metricValue, options, this.config);
261+
this.util.addMetricToQueue(item);
262+
} else {
263+
this.logger.error('Undefined metric name or invalid value to register as a gauge');
296264
}
297265
}
298266
}

0 commit comments

Comments
 (0)