Skip to content

Commit f9f720b

Browse files
authored
Merge pull request #31 from NodeRedis/fix-errors
Fix stack traces
2 parents cd8566a + 67b02ed commit f9f720b

File tree

13 files changed

+103
-21
lines changed

13 files changed

+103
-21
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ logs
33
coverage
44
node_modules
55
.idea
6+
.vscode

.npmignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,5 @@ test
1111
.travis.yml
1212
.gitignore
1313
*.log
14+
.vscode
15+
.codeclimate.yml

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,12 @@ var myParser = new Parser(options);
3636

3737
### Error classes
3838

39-
All errors returned by the parser are of the class `ReplyError` that is a sub class of `RedisError`.
40-
Both types are exported by the parser.
39+
* `RedisError` sub class of Error
40+
* `ReplyError` sub class of RedisError
41+
* `ParserError` sub class of RedisError
42+
43+
All Redis errors will be returned as `ReplyErrors` while a parser error is returned as `ParserError`.
44+
All error classes are exported by the parser.
4145

4246
### Example
4347

changelog.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
## v.2.5.0 - 11 Mar, 2017
2+
3+
Features
4+
5+
- Added a `ParserError` class to differentiate them to ReplyErrors. The class is also exported
6+
7+
Bugfixes
8+
9+
- All errors now show their error message again next to the error name in the stack trace
10+
- ParserErrors now show the offset and buffer attributes while being logged
11+
112
## v.2.4.1 - 05 Feb, 2017
213

314
Bugfixes

index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
module.exports = require('./lib/parser')
44
module.exports.ReplyError = require('./lib/replyError')
55
module.exports.RedisError = require('./lib/redisError')
6+
module.exports.ParserError = require('./lib/redisError')

lib/hiredis.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,21 @@
22

33
var hiredis = require('hiredis')
44
var ReplyError = require('../lib/replyError')
5+
var ParserError = require('../lib/parserError')
56

67
/**
78
* Parse data
89
* @param parser
910
* @returns {*}
1011
*/
11-
function parseData (parser) {
12+
function parseData (parser, data) {
1213
try {
1314
return parser.reader.get()
1415
} catch (err) {
1516
// Protocol errors land here
1617
// Reset the parser. Otherwise new commands can't be processed properly
1718
parser.reader = new hiredis.Reader(parser.options)
18-
parser.returnFatalError(new ReplyError(err.message))
19+
parser.returnFatalError(new ParserError(err.message, JSON.stringify(data), -1))
1920
}
2021
}
2122

@@ -37,15 +38,15 @@ function HiredisReplyParser (options) {
3738

3839
HiredisReplyParser.prototype.execute = function (data) {
3940
this.reader.feed(data)
40-
var reply = parseData(this)
41+
var reply = parseData(this, data)
4142

4243
while (reply !== undefined) {
4344
if (reply && reply.name === 'Error') {
4445
this.returnError(new ReplyError(reply.message))
4546
} else {
4647
this.returnReply(reply)
4748
}
48-
reply = parseData(this)
49+
reply = parseData(this, data)
4950
}
5051
}
5152

lib/parser.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
var StringDecoder = require('string_decoder').StringDecoder
44
var decoder = new StringDecoder()
55
var ReplyError = require('./replyError')
6+
var ParserError = require('./parserError')
67
var bufferPool = new Buffer(32 * 1024)
78
var bufferOffset = 0
89
var interval = null
@@ -290,10 +291,11 @@ function parseType (parser, type) {
290291
case 45: // -
291292
return parseError(parser)
292293
default:
293-
var err = new ReplyError('Protocol error, got ' + JSON.stringify(String.fromCharCode(type)) + ' as reply type byte', 20)
294-
err.offset = parser.offset
295-
err.buffer = JSON.stringify(parser.buffer)
296-
return handleError(parser, err)
294+
return handleError(parser, new ParserError(
295+
'Protocol error, got ' + JSON.stringify(String.fromCharCode(type)) + ' as reply type byte',
296+
JSON.stringify(parser.buffer),
297+
parser.offset
298+
))
297299
}
298300
}
299301

lib/parserError.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
'use strict'
2+
3+
var util = require('util')
4+
var assert = require('assert')
5+
var RedisError = require('./redisError')
6+
var ADD_STACKTRACE = false
7+
8+
function ParserError (message, buffer, offset) {
9+
assert(buffer)
10+
assert.strictEqual(typeof offset, 'number')
11+
RedisError.call(this, message, ADD_STACKTRACE)
12+
this.offset = offset
13+
this.buffer = buffer
14+
Error.captureStackTrace(this, ParserError)
15+
}
16+
17+
util.inherits(ParserError, RedisError)
18+
19+
Object.defineProperty(ParserError.prototype, 'name', {
20+
value: 'ParserError',
21+
configurable: true,
22+
writable: true
23+
})
24+
25+
module.exports = ParserError

lib/redisError.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,22 @@
22

33
var util = require('util')
44

5-
function RedisError (message) {
6-
Error.call(this, message)
7-
Error.captureStackTrace(this, this.constructor)
5+
function RedisError (message, stack) {
86
Object.defineProperty(this, 'message', {
97
value: message || '',
8+
configurable: true,
109
writable: true
1110
})
11+
if (stack || stack === undefined) {
12+
Error.captureStackTrace(this, RedisError)
13+
}
1214
}
1315

1416
util.inherits(RedisError, Error)
1517

1618
Object.defineProperty(RedisError.prototype, 'name', {
1719
value: 'RedisError',
20+
configurable: true,
1821
writable: true
1922
})
2023

lib/replyError.js

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,21 @@
22

33
var util = require('util')
44
var RedisError = require('./redisError')
5+
var ADD_STACKTRACE = false
56

6-
function ReplyError (message, newLimit) {
7-
var limit = Error.stackTraceLimit
8-
Error.stackTraceLimit = newLimit || 2
9-
RedisError.call(this, message)
10-
Error.stackTraceLimit = limit
7+
function ReplyError (message) {
8+
var tmp = Error.stackTraceLimit
9+
Error.stackTraceLimit = 2
10+
RedisError.call(this, message, ADD_STACKTRACE)
11+
Error.captureStackTrace(this, ReplyError)
12+
Error.stackTraceLimit = tmp
1113
}
1214

1315
util.inherits(ReplyError, RedisError)
1416

1517
Object.defineProperty(ReplyError.prototype, 'name', {
1618
value: 'ReplyError',
19+
configurable: true,
1720
writable: true
1821
})
1922

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
"scripts": {
77
"test": "npm run coverage",
88
"benchmark": "node ./benchmark",
9-
"posttest": "standard && npm run coverage:check",
9+
"lint": "standard --fix",
10+
"posttest": "npm run lint && npm run coverage:check",
1011
"coverage": "node ./node_modules/istanbul/lib/cli.js cover --preserve-comments ./node_modules/mocha/bin/_mocha -- -R spec",
1112
"coverage:check": "node ./node_modules/istanbul/lib/cli.js check-coverage --branch 100 --statement 100"
1213
},

test/errors.spec.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
'use strict'
2+
3+
/* eslint-env mocha */
4+
5+
var assert = require('assert')
6+
var ReplyError = require('../lib/replyError')
7+
var ParserError = require('../lib/parserError')
8+
var RedisError = require('../lib/redisError')
9+
10+
describe('errors', function () {
11+
it('errors should have a stack trace with error message', function () {
12+
var err1 = new RedisError('test')
13+
var err2 = new ReplyError('test')
14+
var err3 = new ParserError('test', new Buffer(''), 0)
15+
assert(err1.stack)
16+
assert(err2.stack)
17+
assert(err3.stack)
18+
assert(/RedisError: test/.test(err1.stack))
19+
assert(/ReplyError: test/.test(err2.stack))
20+
assert(/ParserError: test/.test(err3.stack))
21+
})
22+
})

test/parsers.spec.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
/* eslint-env mocha */
44

55
var assert = require('assert')
6+
var util = require('util')
67
var JavascriptParser = require('../')
78
var HiredisParser = require('../lib/hiredis')
89
var ReplyError = JavascriptParser.ReplyError
10+
var ParserError = JavascriptParser.ParserError
911
var RedisError = JavascriptParser.RedisError
1012
var parsers = [HiredisParser, JavascriptParser]
1113

@@ -318,10 +320,14 @@ describe('parsers', function () {
318320
Abc.prototype.checkReply = function (err) {
319321
assert.strictEqual(typeof this.log, 'function')
320322
assert.strictEqual(err.message, 'Protocol error, got "a" as reply type byte')
321-
assert.strictEqual(err.name, 'ReplyError')
323+
assert.strictEqual(err.name, 'ParserError')
322324
assert(err instanceof RedisError)
323-
assert(err instanceof ReplyError)
325+
assert(err instanceof ParserError)
324326
assert(err instanceof Error)
327+
assert(err.offset)
328+
assert(err.buffer)
329+
assert(/\[97,42,49,13,42,49,13,36,49,96,122,97,115,100,13,10,97]/.test(err.buffer))
330+
assert(/ParserError: Protocol error, got "a" as reply type byte/.test(util.inspect(err)))
325331
replyCount++
326332
}
327333
Abc.prototype.log = console.log

0 commit comments

Comments
 (0)