diff --git a/lib/admin/admin-server.js b/lib/admin/admin-server.js index 15a4195d..f62ba24e 100644 --- a/lib/admin/admin-server.js +++ b/lib/admin/admin-server.js @@ -47,7 +47,7 @@ logger.info('Version: %s', version) const hostname = options.hostname if (!hostname) { - console.error('Error: no hostname specified.') + logger.error('no hostname specified.') process.exit(1) } @@ -55,7 +55,7 @@ module.exports = {run} function dbNotify () { return got.post('http://localhost:3030/dbChange') - .catch(e => console.error('Error: lamassu-server not responding')) + .catch(e => logger.error('lamassu-server not responding')) } const skip = (req, res) => req.path === '/api/status/' && res.statusCode === 200 @@ -216,7 +216,7 @@ app.patch('/api/customer/:id', (req, res, next) => { }) app.use((err, req, res, next) => { - console.error(err) + logger.error(err) return res.status(500).send(err.message) }) @@ -282,7 +282,7 @@ function authenticate (req, res, next) { } process.on('unhandledRejection', err => { - console.error(err.stack) + logger.error(err.stack) process.exit(1) }) @@ -336,6 +336,6 @@ function run () { const serverLog = `lamassu-admin-server listening on port ${serverPort}` const supportLog = `lamassu-support-server listening on port ${supportPort}` - webServer.listen(serverPort, () => console.log(serverLog)) - supportServer.run(supportPort).then(console.log(supportLog)) + webServer.listen(serverPort, () => logger.info(serverLog)) + supportServer.run(supportPort).then(logger.info(supportLog)) } diff --git a/lib/coinatmradar/coinatmradar.js b/lib/coinatmradar/coinatmradar.js index f90e03e7..be4eec28 100644 --- a/lib/coinatmradar/coinatmradar.js +++ b/lib/coinatmradar/coinatmradar.js @@ -128,7 +128,7 @@ function sendRadar (data) { } return axios.default(config) - .then(r => console.log(r.status)) + .then(r => logger.info(r.status)) } function mapRecord (rates, settings) { diff --git a/lib/customers.js b/lib/customers.js index 07c98019..3e2ba76c 100644 --- a/lib/customers.js +++ b/lib/customers.js @@ -23,6 +23,7 @@ const frontCameraBaseDir = _.get('frontCameraDir', options) const operatorDataDir = _.get('operatorDataDir', options) const sms = require('./sms') const settingsLoader = require('./new-settings-loader') +const logger = require('./logger') const TX_PASSTHROUGH_ERROR_CODES = ['operatorCancel'] @@ -131,7 +132,7 @@ async function updateCustomer (id, data, userToken) { Promise.all([getCustomerById(id), settingsLoader.loadLatest()]) .then(([customer, config]) => sms.getLookup(config, customer.phone)) .then(res => updateSubscriberData(id, res, userToken)) - .catch(console.error) + .catch(logger.error) } invalidateCustomerNotifications(id, formattedData) return getCustomerById(id) @@ -649,7 +650,7 @@ function updateIdCardData (patch, id) { const imagesData = _.get('photos', patch) return updatePhotos(imagesData, id, directory) .then(newPatch => newPatch) - .catch(err => console.log('An error ocurred while saving the image ', err)) + .catch(err => logger.error('while saving the image: ', err)) }) } diff --git a/lib/db-migrate-store.js b/lib/db-migrate-store.js index 3c28afab..93c59a24 100644 --- a/lib/db-migrate-store.js +++ b/lib/db-migrate-store.js @@ -1,4 +1,5 @@ const db = require('../lib/db') +const logger = require('./logger') const upsert = 'insert into migrations (id, data) values (1, $1) on conflict (id) do update set data = $1' @@ -10,7 +11,7 @@ DbMigrateStore.prototype.save = function (set, fn) { lastRun: set.lastRun, migrations: set.migrations }) - db.none(upsert, [insertData]).then(fn).catch(err => console.log(err)) + db.none(upsert, [insertData]).then(fn).catch(logger.error) } DbMigrateStore.prototype.load = function (fn) { diff --git a/lib/logger.js b/lib/logger.js index d8c1a56e..5b21e3c1 100644 --- a/lib/logger.js +++ b/lib/logger.js @@ -5,15 +5,23 @@ const options = require('./options') const logger = new winston.Logger({ level: options.logLevel, transports: [ - new (winston.transports.Console)({ timestamp: true, colorize: true }), + new (winston.transports.Console)({ + timestamp: true, + colorize: true, + handleExceptions: true, + humanReadableUnhandledException: true + }), new Postgres({ connectionString: options.postgresql, - tableName: 'server_logs' + tableName: 'server_logs', + handleExceptions: true, + humanReadableUnhandledException: true }) ], rewriters: [ (...[,, meta]) => meta instanceof Error ? { message: meta.message, stack: meta.stack } : meta - ] + ], + exitOnError: false }) logger.stream = { diff --git a/lib/middlewares/operatorId.js b/lib/middlewares/operatorId.js index baeffc22..0dceb527 100644 --- a/lib/middlewares/operatorId.js +++ b/lib/middlewares/operatorId.js @@ -5,6 +5,7 @@ const hkdf = require('futoin-hkdf') const state = require('./state') const mnemonicHelpers = require('../mnemonic-helpers') const options = require('../options') +const logger = require('../logger') function computeOperatorId (masterSeed) { return hkdf(masterSeed, 16, { salt: 'lamassu-server-salt', info: 'operator-id' }).toString('hex') @@ -25,7 +26,7 @@ function findOperatorId (req, res, next) { res.locals.operatorId = id return next() }).catch(e => { - console.error('Error while computing operator id\n' + e) + logger.error('Error while computing operator id\n' + e) next(e) }) } diff --git a/lib/middlewares/populateSettings.js b/lib/middlewares/populateSettings.js index 041a4f3a..146aafeb 100644 --- a/lib/middlewares/populateSettings.js +++ b/lib/middlewares/populateSettings.js @@ -1,6 +1,7 @@ const state = require('./state') const newSettingsLoader = require('../new-settings-loader') const helpers = require('../route-helpers') +const logger = require('../logger') const { settingsCache } = state @@ -28,7 +29,7 @@ const populateSettings = function (req, res, next) { .catch(next) } } catch (e) { - console.error(e) + logger.error(e) } newSettingsLoader.load(versionId) diff --git a/lib/migrate-options.js b/lib/migrate-options.js index 994be05b..921b8b1b 100644 --- a/lib/migrate-options.js +++ b/lib/migrate-options.js @@ -4,6 +4,7 @@ const makeDir = require('make-dir') const path = require('path') const load = require('./options-loader') +const logger = require('./logger') // current path of lamassu-server project const currentBasePath = path.dirname(__dirname) @@ -46,7 +47,7 @@ function updateOptionBasepath (result, optionName) { // update this option // if the value has changed if (!_.isEqual(currentPath, newPath)) { - console.log(`Migrating option ${optionName} to new path ${newPath}`) + logger.info(`Migrating option ${optionName} to new path ${newPath}`) result[optionName] = newPath } } @@ -64,7 +65,7 @@ async function run () { // get all the options // that ends with "Path" suffix - console.log(`Detected lamassu-server basepath: ${currentBasePath}`) + logger.info(`Detected lamassu-server basepath: ${currentBasePath}`) _.each(_.wrap(updateOptionBasepath, result), [ 'seedPath', @@ -92,7 +93,7 @@ async function run () { // find new opts _.difference(_.keys(result), _.keys(currentOpts)) ), result) - console.log('Updating options', newOpts) + logger.info('Updating options', newOpts) // store new lamassu.json file fs.writeFileSync(options.path, JSON.stringify(result, null, ' ')) @@ -105,7 +106,7 @@ async function run () { const path = _.attempt(() => makeDir.sync(v)) if (_.isError(path)) { - console.error(`Error while creating folder ${v}`, path) + logger.error(`while creating folder ${v}`, path) } } }, result) diff --git a/lib/new-admin/admin-server.js b/lib/new-admin/admin-server.js index 8ebb8faa..b666333f 100644 --- a/lib/new-admin/admin-server.js +++ b/lib/new-admin/admin-server.js @@ -14,6 +14,7 @@ const _ = require('lodash/fp') const { asyncLocalStorage, defaultStore } = require('../async-storage') const options = require('../options') const users = require('../users') +const logger = require('../logger') const session = require('./middlewares/session') const { AuthDirective } = require('./graphql/directives') @@ -26,7 +27,7 @@ const operatorDataBasedir = _.get('operatorDataDir', options) const hostname = options.hostname if (!hostname) { - console.error('Error: no hostname specified.') + logger.error('no hostname specified.') process.exit(1) } @@ -49,7 +50,7 @@ const apolloServer = new ApolloServer({ playground: false, introspection: false, formatError: error => { - console.log(error) + logger.error(error) return error }, context: async ({ req, res }) => { @@ -106,7 +107,7 @@ function run () { const serverLog = `lamassu-admin-server listening on port ${serverPort}` const webServer = https.createServer(certOptions, app) - webServer.listen(serverPort, () => console.log(serverLog)) + webServer.listen(serverPort, () => logger.info(serverLog)) }) } diff --git a/lib/new-admin/graphql-dev-insecure.js b/lib/new-admin/graphql-dev-insecure.js index 3ca8c5fe..8ec2b586 100644 --- a/lib/new-admin/graphql-dev-insecure.js +++ b/lib/new-admin/graphql-dev-insecure.js @@ -2,6 +2,7 @@ const express = require('express') const { ApolloServer } = require('apollo-server-express') const { typeDefs, resolvers } = require('./graphql/schema') +const logger = require('../logger') const app = express() const server = new ApolloServer({ @@ -16,7 +17,7 @@ app.use(express.json()) function run () { const serverLog = `lamassu-admin-server listening on port ${9010}${server.graphqlPath}` - app.listen(9010, () => console.log(serverLog)) + app.listen(9010, () => logger.info(serverLog)) } module.exports = { run } diff --git a/lib/new-admin/graphql/resolvers/settings.resolver.js b/lib/new-admin/graphql/resolvers/settings.resolver.js index 5f2f36b0..329be89e 100644 --- a/lib/new-admin/graphql/resolvers/settings.resolver.js +++ b/lib/new-admin/graphql/resolvers/settings.resolver.js @@ -1,9 +1,10 @@ const got = require('got') +const logger = require('../../../logger') const settingsLoader = require('../../../new-settings-loader') const notify = () => got.post('http://localhost:3030/dbChange') - .catch(e => console.error('Error: lamassu-server not responding')) + .catch(e => logger.error('lamassu-server not responding')) const resolvers = { Query: { diff --git a/lib/notifier/index.js b/lib/notifier/index.js index 0529ecbd..a4a4b39b 100644 --- a/lib/notifier/index.js +++ b/lib/notifier/index.js @@ -289,7 +289,7 @@ const notifyIfActive = (type, fnName, ...args) => { if (!notificationCenter[fnName]) return Promise.reject(new Error(`Notification function ${fnName} for type ${type} does not exist`)) if (!(notificationSettings.active && notificationSettings[type])) return Promise.resolve() return notificationCenter[fnName](...args) - }).catch(console.error) + }).catch(logger.error) } module.exports = { diff --git a/lib/notifier/queries.js b/lib/notifier/queries.js index bfa71742..d89e74fb 100644 --- a/lib/notifier/queries.js +++ b/lib/notifier/queries.js @@ -4,6 +4,7 @@ const _ = require('lodash/fp') const dbm = require('../postgresql_interface') const db = require('../db') +const logger = require('../logger') // types of notifications able to be inserted into db: /* @@ -17,64 +18,64 @@ error - notifications related to errors function getMachineName (machineId) { const sql = 'SELECT * FROM devices WHERE device_id=$1' return db.oneOrNone(sql, [machineId]) - .then(it => it.name).catch(console.error) + .then(it => it.name).catch(logger.error) } const addNotification = (type, message, detail) => { const sql = `INSERT INTO notifications (id, type, message, detail) VALUES ($1, $2, $3, $4)` - return db.oneOrNone(sql, [uuidv4(), type, message, detail]).catch(console.error) + return db.oneOrNone(sql, [uuidv4(), type, message, detail]).catch(logger.error) } const getAllValidNotifications = (type) => { const sql = `SELECT * FROM notifications WHERE type = $1 AND valid = 't'` - return db.any(sql, [type]).catch(console.error) + return db.any(sql, [type]).catch(logger.error) } const invalidateNotification = (detail, type) => { detail = _.omitBy(_.isEmpty, detail) const sql = `UPDATE notifications SET valid = 'f', read = 't' WHERE valid = 't' AND type = $1 AND detail::jsonb @> $2::jsonb` - return db.none(sql, [type, detail]).catch(console.error).catch(console.error) + return db.none(sql, [type, detail]).catch(logger.error) } const batchInvalidate = (ids) => { const formattedIds = _.map(pgp.as.text, ids).join(',') const sql = `UPDATE notifications SET valid = 'f', read = 't' WHERE id IN ($1^)` - return db.none(sql, [formattedIds]).catch(console.error) + return db.none(sql, [formattedIds]).catch(logger.error) } const clearBlacklistNotification = (cryptoCode, cryptoAddress) => { const sql = `UPDATE notifications SET valid = 'f', read = 't' WHERE type = 'compliance' AND detail->>'cryptoCode' = $1 AND detail->>'cryptoAddress' = $2 AND (detail->>'code' = 'BLOCKED' OR detail->>'code' = 'REUSED')` - return db.none(sql, [cryptoCode, cryptoAddress]).catch(console.error) + return db.none(sql, [cryptoCode, cryptoAddress]).catch(logger.error) } const getValidNotifications = (type, detail) => { const sql = `SELECT * FROM notifications WHERE type = $1 AND valid = 't' AND detail @> $2` - return db.any(sql, [type, detail]).catch(console.error) + return db.any(sql, [type, detail]).catch(logger.error) } const getNotifications = () => { const sql = `SELECT * FROM notifications ORDER BY created DESC` - return db.any(sql).catch(console.error) + return db.any(sql).catch(logger.error) } const setRead = (id, read) => { const sql = `UPDATE notifications SET read = $1 WHERE id = $2` - return db.none(sql, [read, id]).catch(console.error) + return db.none(sql, [read, id]).catch(logger.error) } const markAllAsRead = () => { const sql = `UPDATE notifications SET read = 't'` - return db.none(sql).catch(console.error) + return db.none(sql).catch(logger.error) } const hasUnreadNotifications = () => { const sql = `SELECT EXISTS (SELECT 1 FROM notifications WHERE read = 'f' LIMIT 1)` - return db.oneOrNone(sql).then(res => res.exists).catch(console.error) + return db.oneOrNone(sql).then(res => res.exists).catch(logger.error) } const getAlerts = () => { const types = ['fiatBalance', 'cryptoBalance', 'error'] const sql = `SELECT * FROM notifications WHERE valid = 't' AND type IN ($1:list) ORDER BY created DESC` - return db.any(sql, [types]).catch(console.error) + return db.any(sql, [types]).catch(logger.error) } module.exports = { diff --git a/lib/ofac/matching.js b/lib/ofac/matching.js index c1178177..3ddb883e 100644 --- a/lib/ofac/matching.js +++ b/lib/ofac/matching.js @@ -2,6 +2,7 @@ const jaro = require('talisman/metrics/distance/jaro') const _ = require('lodash/fp') const debugLog = require('../pp')(__filename) // KOSTIS TODO: remove +const logger = require('../logger') const stringSimilarity = _.curry(jaro) @@ -62,7 +63,7 @@ function match (structs, candidate, options) { const phoneticScore = phoneticMatches.has(aliasId) ? 1 : -1 const finalScore = stringWeight * stringScore + phoneticWeight * phoneticScore - verbose && console.log(finalScore.toFixed(2), stringScore.toFixed(2), phoneticScore.toFixed(2), word.value, wordEntry.value) + verbose && logger.debug(finalScore.toFixed(2), stringScore.toFixed(2), phoneticScore.toFixed(2), word.value, wordEntry.value) if (finalScore >= threshold) { const entry = {aliasId, score: finalScore, word: word.value, value: wordEntry.value} diff --git a/lib/pg-transport.js b/lib/pg-transport.js index 65f39494..3d757a46 100644 --- a/lib/pg-transport.js +++ b/lib/pg-transport.js @@ -36,4 +36,8 @@ module.exports = class CustomTransport extends Transport { callback() } + + logException (msg, meta, callback) { + this.log('error', msg, meta, callback) + } } diff --git a/lib/plugins.js b/lib/plugins.js index 89ad79c9..8ef30170 100644 --- a/lib/plugins.js +++ b/lib/plugins.js @@ -531,7 +531,7 @@ function plugins (settings, deviceId) { .catch(err => { updateTradeEntry(tradeEntry, newEntry, err) .then(() => { - console.log(err) + logger.error(err) throw err }) }) @@ -756,7 +756,7 @@ function plugins (settings, deviceId) { return db.any(sql) .then(rows => Promise.all(rows.map(sweepHdRow))) - .catch(err => logger.error(err)) + .catch(logger.error) } function getMachineNames () { diff --git a/lib/plugins/wallet/bitcoind/bitcoind.js b/lib/plugins/wallet/bitcoind/bitcoind.js index 508ebf45..a64e99c3 100644 --- a/lib/plugins/wallet/bitcoind/bitcoind.js +++ b/lib/plugins/wallet/bitcoind/bitcoind.js @@ -4,6 +4,7 @@ const jsonRpc = require('../../common/json-rpc') const options = require('../../../options') const BN = require('../../../bn') const E = require('../../../error') +const logger = require('../../../logger') const { utils: coinUtils } = require('lamassu-coins') const cryptoRec = coinUtils.getCryptoCurrency('BTC') @@ -135,7 +136,7 @@ function fetchRBF (txId) { return [txId, res['bip125-replaceable']] }) .catch(err => { - if (err.code === -5) console.log(`${err.message}`) + if (err.code === -5) logger.error(`${err.message}`) return [txId, true] }) } diff --git a/lib/wallet.js b/lib/wallet.js index de2ec3b8..f5078e12 100644 --- a/lib/wallet.js +++ b/lib/wallet.js @@ -11,6 +11,7 @@ const options = require('./options') const ph = require('./plugin-helper') const layer2 = require('./layer2') const httpError = require('./route-helpers').httpError +const logger = require('./logger') const FETCH_INTERVAL = 5000 const INSUFFICIENT_FUNDS_CODE = 570 @@ -50,7 +51,7 @@ function _balance (settings, cryptoCode) { return r }) .catch(err => { - console.error(err) + logger.error(err) return lastBalance[cryptoCode] }) }