2017-02-07 53 views
9

Powtarzam tutaj błąd związany z obietnicą Sequelize (Bluebird). Po pierwsze, zrobiono to, aby zmienić komunikat o błędzie, ale jak się okazało, to również daje bardziej przejrzysty ślad stosu.Scalanie śladów stosu w ponownym zgłoszeniu błędów

Jest coś

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

Gdzie originalError.stack nie zawiera wiersz, który spowodował błąd, ale posiada ważną informację, że pochodzi Sequelize i MySQL kierowcy:

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 zawiera punkt zainteresowania (pierwsza linia na stosie), ale wszystko inne to śmieć:

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) 

Chciałbym zachować informacje o nich obu - i wskazać połączenie między nimi, a nie tylko dodać jako dwa niepowiązane wpisy w dzienniku.

Zastanawiam się nad zarejestrowaniem ich jako pojedynczego błędu z połączonym stosem, rethrownError.stack += '\n' + originalError.stack.

Jak należy traktować te dwa błędy? Czy należy połączyć ślady ich stosów? Czy istnieje konwencja na łączenie stosów błędów w JavaScript (w szczególności Node.js)?

Zamiarem jest utrzymanie wynikowego błędu w sensie znaczącym i niezłomienie istniejących narzędzi, które analizują ślady stosu błędów (a mianowicie Stacktrace.js).

Dane projekty wykorzystują rejestrator Winston lub zwykły console.error, więc błąd jest w pewnym momencie usztywniany (w powyższym przykładzie został zarejestrowany za pomocą nieobsługiwanej procedury obsługi odrzucania).

+0

Jako ktoś, kto używane sequelize uzasadniona bit: dlaczego Ponowne generowanie w ogóle?W momencie, w którym trafisz 'catch()', powinieneś obsługiwać błąd w sposób, który nie prowadzi do kolejnych rzutów. –

+0

@ Mike'Pomax'Kamermans Jest to poza zakresem pytania, ale początkowo zrobiłem to, aby zgłosić błąd 'sql' prop do' msg', nie bardzo miło było zobaczyć w dziennikach ER_KEY_COLUMN_DOES_NOT_EXITS, które nie wyjaśniają byle co. Ale tutaj interesuje mnie stos odradzonego błędu, 'at sequelize.sync.catch ...'. Od oryginalnego błędu nie jest wcale oczywisty, gdzie się pojawił. – estus

+0

Zapobieganie zstępowaniu [XY Problem] (http://meta.stackexchange.com/a/66378) dziura od królika nigdy nie jest poza zakresem. Jeśli chodzi o błąd z twojego komentarza: to jest niesamowicie jasny błąd MySQL, który mówi ci, że używasz nazwy kolumny dla tabeli, która nie * ma * tej nazwy kolumny. Nic wartego ponownego wyrzucenia błędów tam, powinieneś po prostu zalogować nazwę tabeli, której próbujesz użyć, i zestaw kolumn, których używasz, abyś mógł zweryfikować przy pomocy MySQL 'show create table {tablename}' –

Odpowiedz

5

Oto lekka alternatywa dla VError: rerror (jestem autorem)

Pomysł jest taki sam: Zawijanie błędów w błędach. Jednak jest o wiele prostsze. Ma mniej funkcji, ale działa również w przeglądarce. Bierze również pod uwagę to, że tworzenie śladów stosu jest drogie. Zamiast tworzenia śladów stosu i dołączania ich do łańcucha tworzy on wewnętrznie stos błędów i tworzy tylko duży ślad stosu, jeśli jest to potrzebne (użyj gettera).

Przykład

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) 
} 

Wyjście

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) 

zalecanej przeczytać: https://www.joyent.com/node-js/production/design/errors

+0

Ocenię to. Rzeczywiście dobre czytanie, dzięki. – estus

3

O ile mi wiadomo, nie ma wbudowanego sposobu obsługi błędów zagnieżdżonych w pliku Node.js. Jedyne, co mogę ci polecić, to użyć VError library. Jest to bardzo przydatne w przypadku zaawansowanej obsługi błędów.

Można użyć fullStack połączyć ślady stosu z wieloma błędami:

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

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

Dzięki. Nie wiedziałem o tym pakiecie i oczywiście wygląda interesująco w tym kontekście. Nadal nie wiem, jak byłoby lepiej zastosować to w tej sytuacji. Próbowałem użyć 'MultiError', wypisuje' pierwszego z 2 błędów ... ', co jest miłe, ale ślady stosu są nadal utracone, gdy błąd jest zalogowany. – estus

+0

Poprawiłem moją odpowiedź, podając więcej szczegółów na temat metody 'fullStack'. –

+0

Dzięki, pomogło. – estus