doublemarked / loopback-console

A command-line tool for Loopback app debugging and administration
MIT License
68 stars 6 forks source link

async/await promise exception output broken #14

Open kevzettler opened 6 years ago

kevzettler commented 6 years ago

my app uses es7 async await all over the place with try/catch exception handling in the async/await code. When an exception is thrown in the console the output is mangled. The exception message is output as an array instead of a string or something. example below.

2018-05-18T00:37:18.074Z [45470] ============================================
Loopback Console

Primary handles available:
 - app: The Loopback app handle
 - cb: A simplistic results callback that stores and prints
 - result: The handle on which cb() stores results

Other handles available:
  - Models: AccessToken, Affiliate, Announcement, APIKey, Application, Broker, Chat, ChatChannel, ConnectedUsers, Email, Error, Execution, Funding, IndexComposite, Instrument, InstrumentInterval, Insurance, Leaderboard, Liquidation, LiquidationOrder, LoginRecord, Margin, Notification, Order, OrderBook, OrderBookL2, Position, Quote, RoleMapping, Role, Scope, Schema, Secret, Settlement, Stats, StatsHistory, StatsUSD, Trade, TradeBin, Transaction, User, UserCommission, UserPreferences, Wallet, Webhook, accessToken, roleMapping, user
============================================

Loopback-console >User.new(
...         'user1@email.com',
...         'hadof78909ads8f',
...         'testuserfromconsole',
...         'user1',
...         'testuser',
...         true,
...         null,
...         'US'
...       );
2018-05-18T00:37:32.425Z [45470] Error during creation of user testuserfromconsole[user1@email.com](75633): undefined
2018-05-18T00:37:33.990Z [45470] [Promise Rejection]
OperationalError {
  '0': 'c',
  '1': 'o',
  '2': 'n',
  '3': 'n',
  '4': 'e',
  '5': 'c',
  '6': 't',
  '7': ' ',
  '8': 'E',
  '9': 'C',
  '10': 'O',
  '11': 'N',
  '12': 'N',
  '13': 'R',
  '14': 'E',
  '15': 'F',
  '16': 'U',
  '17': 'S',
  '18': 'E',
  '19': 'D',
  '20': ' ',
  '21': '1',
  '22': '2',
  '23': '7',
  '24': '.',
  '25': '0',
  '26': '.',
  '27': '0',
  '28': '.',
  '29': '1',
  '30': ':',
  '31': '4',
  '32': '6',
  '33': '5',
  cause: { '0': 'c',
     '1': 'o',
     '2': 'n',
     '3': 'n',
     '4': 'e',
     '5': 'c',
     '6': 't',
     '7': ' ',
     '8': 'E',
     '9': 'C',
     '10': 'O',
     '11': 'N',
     '12': 'N',
     '13': 'R',
     '14': 'E',
     '15': 'F',
     '16': 'U',
     '17': 'S',
     '18': 'E',
     '19': 'D',
     '20': ' ',
     '21': '1',
     '22': '2',
     '23': '7',
     '24': '.',
     '25': '0',
     '26': '.',
     '27': '0',
     '28': '.',
     '29': '1',
     '30': ':',
     '31': '4',
     '32': '6',
     '33': '5',
     error: undefined,
     errno: 'ECONNREFUSED',
     code: 'ECONNREFUSED',
     syscall: 'connect',
     address: '127.0.0.1',
     port: 465 },
  __cachedRelations: {},
  __data:
   { '0': 'c',
     '1': 'o',
     '2': 'n',
     '3': 'n',
     '4': 'e',
     '5': 'c',
     '6': 't',
     '7': ' ',
     '8': 'E',
     '9': 'C',
     '10': 'O',
     '11': 'N',
     '12': 'N',
     '13': 'R',
     '14': 'E',
     '15': 'F',
     '16': 'U',
     '17': 'S',
     '18': 'E',
     '19': 'D',
     '20': ' ',
     '21': '1',
     '22': '2',
     '23': '7',
     '24': '.',
     '25': '0',
     '26': '.',
     '27': '0',
     '28': '.',
     '29': '1',
     '30': ':',
     '31': '4',
     '32': '6',
     '33': '5',
     error: undefined,
     errno: 'ECONNREFUSED',
     code: 'ECONNREFUSED',
     syscall: 'connect',
     address: '127.0.0.1',
     port: 465 },
  __dataSource: undefined,
  __strict: false,
  __persisted: false,
  errno: 'ECONNREFUSED',
  code: 'ECONNECTION',
  syscall: 'connect',
  address: '127.0.0.1',
  port: 465,
  command: 'CONN' }
Loopback-console >2018-05-18T00:37:49.010Z [45470] 127.0.0.1 (Chrome 65.0.3325.181, Mac OS)  - "GET /api/v1/geo " 404 9b - 177.891 ms
doublemarked commented 6 years ago

Hey @kevzettler - sorry for the trouble. Hmm. Async/await should not complicate how errors are handled, because async methods are just returning promises and exceptions are transformed into promise rejections.

What I see from your output is that your code is throwing an error of type OperationalError. Is it possible that your OperationalError is not stringifying itself nicely? The loopback-console code for printing errors is very simple, using just console.log.

If you send me a small sample project reproducing the problem I'd be happy to dig in deeper!

kevzettler commented 6 years ago

@doublemarked the promises in use here are from the BlueBird promise library: https://github.com/petkaantonov/bluebird

OperationalError seems to stem from that. https://github.com/petkaantonov/bluebird/blob/master/docs/docs/api/operationalerror.md

looks like we are trying to use generic Errors for OperationalError:

declare class OperationalError extends Error {}

Any further thoughts?

doublemarked commented 6 years ago

Can you put together a small sample project demonstrating the problem? I'd be happy to then debug and fix it.