2017-02-07 16 views
9

Я возвращаю здесь ошибку из обещания Sequelize (Bluebird). Во-первых, это было сделано для изменения сообщения об ошибке, но, как оказалось, это также создает более информативную трассировку стека.Слияние следов стека в восстановленных ошибках

Это что-то вроде

sequelize.sync().catch(originalError => { 
    const rethrownError = new Error(originalError.msg + ': ' + originalError.sql); 
    throw rethrownError; 
}); 

Где originalError.stack не содержит строку, вызвавшую ошибку, но она имеет важную информацию, которая берет свое начало в Sequelize и MySQL драйвера:

SequelizeDatabaseError: ER_KEY_COLUMN_DOES_NOT_EXITS: Key column 'NonExisting' doesn't exist in table 
    at Query.formatError (...\node_modules\sequelize\lib\dialects\mysql\query.js:175:14) 
    at Query._callback (...\node_modules\sequelize\lib\dialects\mysql\query.js:49:21) 
    at Query.Sequence.end (...\node_modules\mysql\lib\protocol\sequences\Sequence.js:85:24) 
    at Query.ErrorPacket (...\node_modules\mysql\lib\protocol\sequences\Query.js:94:8) 
    at Protocol._parsePacket (...\node_modules\mysql\lib\protocol\Protocol.js:280:23) 
    at Parser.write (...\node_modules\mysql\lib\protocol\Parser.js:74:12) 
    at Protocol.write (...\node_modules\mysql\lib\protocol\Protocol.js:39:16) 
    at Socket.<anonymous> (...\node_modules\mysql\lib\Connection.js:109:28) 
    at emitOne (events.js:96:13) 
    at Socket.emit (events.js:188:7) 
    at readableAddChunk (_stream_readable.js:176:18) 
    at Socket.Readable.push (_stream_readable.js:134:10) 
    at TCP.onread (net.js:548:20) 

rethrownError.stack содержит представляющая интерес (первая строка в штабеле), но все остальное - мусор:

Error: ER_KEY_COLUMN_DOES_NOT_EXITS: Key column 'NonExisting' doesn't exist in table 
    at sequelize.sync.catch (...\app.js:59:17) 
    at tryCatcher (...\node_modules\bluebird\js\release\util.js:16:23) 
    at Promise._settlePromiseFromHandler (...\node_modules\bluebird\js\release\promise.js:504:31) 
    at Promise._settlePromise (...\node_modules\bluebird\js\release\promise.js:561:18) 
    at Promise._settlePromise0 (...\node_modules\bluebird\js\release\promise.js:606:10) 
    at Promise._settlePromises (...\node_modules\bluebird\js\release\promise.js:681:18) 
    at Async._drainQueue (...\node_modules\bluebird\js\release\async.js:138:16) 
    at Async._drainQueues (...\node_modules\bluebird\js\release\async.js:148:10) 
    at Immediate.Async.drainQueues (...\node_modules\bluebird\js\release\async.js:17:14) 
    at runCallback (timers.js:637:20) 
    at tryOnImmediate (timers.js:610:5) 
    at processImmediate [as _immediateCallback] (timers.js:582:5) 

Я хотел бы сохранить информацию об их обоих - и обозначить связь между ними, а не просто добавить как две несвязанные записи журнала.

Я думал о регистрации их как одной ошибки с конкатенированным стеком, rethrownError.stack += '\n' + originalError.stack.

Как следует обрабатывать эти две ошибки? Должны ли быть соединены следы стека? Существует ли соглашение о слиянии стеков ошибок в JavaScript (в частности, Node.js)?

Цель состоит в том, чтобы сохранить полученную ошибку значимой и не нарушать существующие инструменты, которые анализируют трассировки стека ошибок (а именно Stacktrace.js).

В рассматриваемых проектах используется логгер Winston или обычный console.error, поэтому в какой-то момент ошибка стробируется (в приведенном выше примере он был зарегистрирован с помощью обработчика необработанного отклонения).

+0

Как кто-то, кто использовал sequelize справедливый бит: почему вы вообще Повторное выбрасывание?Когда вы нажмете 'catch()', вы должны обрабатывать ошибку таким образом, чтобы не приводить к дальнейшим броскам. –

+0

@ Mike'Pomax'Kamermans Это выходит за рамки вопроса, но я изначально сделал это, чтобы выполнить ошибку 'sql' prop' 'msg', я был не очень рад видеть в журналах ER_KEY_COLUMN_DOES_NOT_EXITS, что не объясняет что-нибудь. Но здесь меня интересует стек из перезапущенной ошибки, 'at sequelize.sync.catch ...'. Исходная ошибка не очевидна вообще там, где она произошла. – estus

+0

Предотвращение спуска [XY Problem] (http://meta.stackexchange.com/a/66378) кроличьей дыры никогда не выходит за рамки. Что касается ошибки из вашего комментария: это невероятно ясная ошибка MySQL, которая говорит вам, что вы используете имя столбца для таблицы, которая не имеет * имя * этого столбца. Ничего не стоит реконструировать ошибки там, вы должны просто зарегистрировать имя таблицы, которую вы пытались использовать, и набор столбцов, которые вы используете, чтобы вы могли проверить против MySQL 'show create table {tablename}' –

ответ

5

Вот легкий альтернатива VError: rerror (я автор)

Идея та же: Обертывание ошибок в ошибках. Однако это намного проще. Он имеет меньше возможностей, но также работает в браузере. Он также учитывает, что создание трассировки стека является дорогостоящим. Вместо того, чтобы создавать трассировки стека и добавлять их в строку, он создает стек ошибок внутри и создает большую трассировку стека, если вам это нужно (используйте getter).

Пример

function fail() { 
    throw new RError({ 
    name: 'BAR', 
    message: 'I messed up.' 
    }) 
} 

function failFurther() { 
    try { 
    fail() 
    } catch (err) { 
    throw new RError({ 
     name: 'FOO', 
     message: 'Something went wrong.', 
     cause: err 
    }) 
    } 
} 

try { 
    failFurther() 
} catch (err) { 
    console.error(err.why) 
    console.error(err.stacks) 
} 

Выход

FOO: Something went wrong. <- BAR: I messed up. 
Error 
    at failFurther (/Users/boris/Workspace/playground/es5/index.js:98:11) 
    at Object.<anonymous> (/Users/boris/Workspace/playground/es5/index.js:107:3) 
    at Module._compile (module.js:556:32) 
    at Object.Module._extensions..js (module.js:565:10) 
    at Module.load (module.js:473:32) 
    at tryModuleLoad (module.js:432:12) 
    at Function.Module._load (module.js:424:3) 
    at Module.runMain (module.js:590:10) 
    at run (bootstrap_node.js:394:7) 
<- Error 
    at fail (/Users/boris/Workspace/playground/es5/index.js:88:9) 
    at failFurther (/Users/boris/Workspace/playground/es5/index.js:96:5) 
    at Object.<anonymous> (/Users/boris/Workspace/playground/es5/index.js:107:3) 
    at Module._compile (module.js:556:32) 
    at Object.Module._extensions..js (module.js:565:10) 
    at Module.load (module.js:473:32) 
    at tryModuleLoad (module.js:432:12) 
    at Function.Module._load (module.js:424:3) 
    at Module.runMain (module.js:590:10) 

рекомендуемого чтения: https://www.joyent.com/node-js/production/design/errors

+0

Я буду его оценивать. Хорошее чтение действительно, спасибо. – estus

3

Насколько я знаю, нет встроенного способа обработки вложенных ошибок в Node.js. Единственное, что я могу вам посоветовать, это использовать VError library. Это действительно полезно при работе с расширенной обработкой ошибок.

Вы можете использовать fullStack объединить стек следы многих ошибок:

var err1 = new VError('something bad happened'); 
var err2 = new VError(err1, 'something really bad happened here'); 

console.log(VError.fullStack(err2)); 
+0

Спасибо. Не знал об этом пакете, и он явно выглядит интересным в этом контексте. Все еще не уверен, как было бы лучше применить его к этой ситуации. Я пытался использовать «MultiError», он выводит «первую из двух ошибок ...», что хорошо, но трассировки стека все равно теряются при регистрации ошибки. – estus

+0

Я отредактировал свой ответ с более подробной информацией о методе 'fullStack'. –

+0

Спасибо, это помогло. – estus