Skip to content

Commit aeeb279

Browse files
authored
Add details to errors (#9)
1 parent 7bdfbdb commit aeeb279

File tree

7 files changed

+66
-8
lines changed

7 files changed

+66
-8
lines changed

index.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
const sample = require('sample-size');
2+
const betterror = require('./lib/betterror');
23
const flush = require('./lib/flush');
34
const formatter = require('./lib/formatter');
45
const push = require('./lib/push');
@@ -131,10 +132,10 @@ class SDC {
131132

132133
if (rate) {
133134
if (typeof rate !== 'number') {
134-
throw new TypeError(`Expected 'rate' to be a number, instead got ${rate} (${typeof rate})`);
135+
throw betterror(new TypeError(`Expected 'rate' to be a number, instead got ${rate} (${typeof rate})`), { type, key, value, rate, tags });
135136
}
136137
if (rate > 1) {
137-
throw new TypeError(`Expected 'rate' to be a number between 0 and 1, instead got ${rate}`);
138+
throw betterror(new TypeError(`Expected 'rate' to be a number between 0 and 1, instead got ${rate}`), { type, key, value, rate, tags });
138139
}
139140

140141
if (this.enforceRate && !sample(rate)) {

lib/betterror/index.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/**
2+
* Mutate: enrich error with details
3+
* @param {Error} error
4+
* @param {...any} arguments
5+
* @return {void}
6+
*/
7+
module.exports = function betterror(error, details) {
8+
if (details && typeof details === 'object') {
9+
error.details = Object.assign(
10+
error.details || {},
11+
details
12+
);
13+
}
14+
return error;
15+
};

lib/betterror/spec.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
const betterror = require('.');
2+
3+
describe('betterror', () => {
4+
it('Should return the original error', () => {
5+
const error = new Error('Something must have gone terribly wrong');
6+
expect(betterror(error)).to.equal(error);
7+
});
8+
it('Should not a "details" field when not applicable', () => {
9+
const error = betterror(new Error('Something must have gone terribly wrong'));
10+
expect(error).to.not.have.keys(['details']);
11+
});
12+
it('Should add a "details" field when applicable', () => {
13+
const error = betterror(new Error('Something must have gone terribly wrong'), { a: 1 });
14+
expect(error).to.have.keys(['details']);
15+
});
16+
it('Should add "details" to error', () => {
17+
const error = betterror(new Error('Something must have gone terribly wrong'), { a: 1 });
18+
expect(error.details).to.deep.equal({ a: 1 });
19+
});
20+
it('Should assign details if there is are some already', () => {
21+
const err = new Error('Something must have gone terribly wrong');
22+
err.details = { a: 1 };
23+
const error = betterror(err, { b: 2 });
24+
expect(error.details).to.deep.equal({ a: 1, b: 2 });
25+
});
26+
});

lib/formatter/index.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
const isNumber = require('is-number');
2+
const betterror = require('../betterror');
23
const sanitiser = require('../sanitiser');
34
const types = require('../types');
45

@@ -62,13 +63,13 @@ module.exports = function formatter({prefix, sanitise = sanitiser, scheme = 'dat
6263
if (type in types) {
6364
type = types[type];
6465
} else {
65-
throw new RangeError(`Expected 'type' to be one of ${Object.keys(types).join(', ')}, instead got ${type}`);
66+
throw betterror(new RangeError(`Expected 'type' to be one of ${Object.keys(types).join(', ')}, instead got ${type}`), { type, key, value, rate, tags });
6667
}
6768
if (typeof key !== 'string') {
68-
throw new TypeError(`Expected 'key' to be a string, instead got ${key} (${typeof key})`);
69+
throw betterror(new TypeError(`Expected 'key' to be a string, instead got ${key} (${typeof key})`), { type, key, value, rate, tags });
6970
}
7071
if (!prefix && !letterLeading(key)) {
71-
throw new Error(`Expected 'key' to start with an alphabetical character (${key}).`);
72+
throw betterror(new Error(`Expected 'key' to start with an alphabetical character (${key}).`), { type, key, value, rate, tags });
7273
}
7374
if (value instanceof Date) {
7475
value = new Date() - value;
@@ -77,7 +78,7 @@ module.exports = function formatter({prefix, sanitise = sanitiser, scheme = 'dat
7778
value = Number(process.hrtime.bigint() - value) / 1e6;
7879
}
7980
if (typeof value !== 'number' || !isNumber(value)) {
80-
throw new TypeError(`Expected 'value' to be a number, instead got ${value} (${typeof value})`);
81+
throw betterror(new TypeError(`Expected 'value' to be a number, instead got ${value} (${typeof value})`), { type, key, value, rate, tags });
8182
}
8283

8384
if (prefix) {

lib/formatter/spec.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,19 @@ describe('formatter', () => {
6565
(type) => expect(() => format(type, 'Hello', undefined)).to.throw()
6666
)
6767
);
68+
it(
69+
'Should add details to errors',
70+
() => {
71+
let error;
72+
try {
73+
format('time', 'Hello', NaN);
74+
} catch (e) {
75+
error = e;
76+
}
77+
console.log(error);
78+
expect(error.details).to.deep.equal({ type: 'ms', key: 'Hello', value: NaN, rate: undefined, tags: undefined });
79+
}
80+
);
6881
it(
6982
'Should default type to counter',
7083
() => {
@@ -135,7 +148,8 @@ describe('formatter', () => {
135148
expect(time).to.be.a('number');
136149
expect(time).to.be.at.least(9);
137150
});
138-
it('Should use a BigInt in order to get the time diff', async() => {
151+
it('Should use a BigInt in order to get the time diff', async function() {
152+
this.retries(3);
139153
let time;
140154
const format = formatter({scheme: ({value}) => {
141155
time = value;

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@fiverr/statsd-client",
3-
"version": "1.0.0",
3+
"version": "1.0.1",
44
"description": "📈 A feature packed, highly customisable StatsD client",
55
"keywords": [
66
"StatsD",

test/spec.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ describe('Integration: bulk sending', () => {
109109

110110
new Array(4).fill('a').forEach(client.count);
111111
expect(metrics).to.be.undefined;
112+
await wait(5);
112113

113114
client.flush();
114115
expect(metrics).to.be.instanceof(Buffer);

0 commit comments

Comments
 (0)