From e358dce5943ea3c03a65dd3e76c1ee0c8b32d74d Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Mon, 9 Apr 2018 13:59:23 -0600 Subject: [PATCH] improved support --- app.js | 5 +++ middleware/logging.js | 1 + middleware/trace.js | 7 +++++ services/mongoose.js | 71 ++++++++++++++++++++----------------------- services/redis.js | 25 +++++++-------- 5 files changed, 59 insertions(+), 50 deletions(-) create mode 100644 middleware/trace.js diff --git a/app.js b/app.js index 47555f728..c5507da2e 100644 --- a/app.js +++ b/app.js @@ -1,4 +1,5 @@ const express = require('express'); +const trace = require('./middleware/trace'); const logging = require('./middleware/logging'); const path = require('path'); const merge = require('lodash/merge'); @@ -12,6 +13,10 @@ const { ENABLE_TRACING, APOLLO_ENGINE_KEY, PORT } = require('./config'); const app = express(); +// Add the trace middleware first, it will create a request ID for each request +// downstream. +app.use(trace); + //============================================================================== // PLUGIN PRE APPLICATION MIDDLEWARE //============================================================================== diff --git a/middleware/logging.js b/middleware/logging.js index ec1ca6bb0..efabbe34f 100644 --- a/middleware/logging.js +++ b/middleware/logging.js @@ -18,6 +18,7 @@ const log = (req, res, next) => { // Log this out. logger.info( { + traceID: req.id, url: req.originalUrl || req.url, method: req.method, statusCode: res.statusCode, diff --git a/middleware/trace.js b/middleware/trace.js new file mode 100644 index 000000000..24cbf38f4 --- /dev/null +++ b/middleware/trace.js @@ -0,0 +1,7 @@ +const uuid = require('uuid/v1'); + +// Trace middleware attaches a request id to each incoming request. +module.exports = (req, res, next) => { + req.id = uuid(); + next(); +}; diff --git a/services/mongoose.js b/services/mongoose.js index 20765293a..5e498cee8 100644 --- a/services/mongoose.js +++ b/services/mongoose.js @@ -1,48 +1,40 @@ -const { MONGO_URL, WEBPACK, CREATE_MONGO_INDEXES } = require('../config'); - +const { + MONGO_URL, + WEBPACK, + CREATE_MONGO_INDEXES, + LOGGING_LEVEL, +} = require('../config'); +const { logger } = require('./logging'); const mongoose = require('mongoose'); -const debug = require('debug')('talk:db'); -const enabled = require('debug').enabled; -const queryDebugger = require('debug')('talk:db:query'); - -// Loading the formatter from Mongoose: -// -// https://github.com/Automattic/mongoose/blob/1a93d1f4d12e441e17ddf451e96fbc5f6e8f54b8/lib/drivers/node-mongodb-native/collection.js#L182 -// -// so we can wrap parameters. -const formatter = require('mongoose').Collection.prototype.$format; // Provide a newly wrapped debugQuery function which wraps the `debug` package. -function debugQuery(name, i, ...args) { - let functionCall = ['db', name, i].join('.'); - let _args = []; - for (let j = args.length - 1; j >= 0; --j) { - if (formatter(args[j]) || _args.length) { - _args.unshift(formatter(args[j])); - } - } - - let params = `(${_args.join(', ')})`; - - queryDebugger(functionCall + params); +function debugQuery(name, operation, ...args) { + logger.debug( + { + query: `db.${name}.${operation}(${args + .map(arg => JSON.stringify(arg)) + .join(', ')})`, + }, + 'mongodb query' + ); } // Use native promises mongoose.Promise = global.Promise; -// Check if debugging is enabled on the talk:db prefix. -if (enabled('talk:db:query')) { +// Check if verbose logging is enabled. +if (['debug', 'trace'].includes(LOGGING_LEVEL)) { // Enable the mongoose debugger, here we wrap the similar print function // provided by setting the debug parameter. mongoose.set('debug', debugQuery); } if (WEBPACK) { - debug('Not connecting to mongodb during webpack build'); + logger.debug('Not connecting to mongodb during webpack build'); - // @wyattjoh: We didn't call connect, but because we include mongoose, it will hold the socket ready, - // preventing node from exiting. Calling disconnect here just ensures that the application - // can quit correctly. + // @wyattjoh: We didn't call connect, but because we include mongoose, it will + // hold the socket ready, preventing node from exiting. Calling disconnect + // here just ensures that the application can quit correctly. mongoose.disconnect(); } else { // Connect to the Mongo instance. @@ -54,7 +46,7 @@ if (WEBPACK) { }, }) .then(() => { - debug('connection established'); + logger.debug('mongodb connection established'); }) .catch(err => { console.error(err); @@ -66,10 +58,13 @@ module.exports = mongoose; // Here we include all the models that mongoose is used for, this ensures that // when we import mongoose that we also start up all the indexing operations -// here. -require('../models/action'); -require('../models/asset'); -require('../models/comment'); -require('../models/setting'); -require('../models/user'); -require('./migration'); +// here. No point also in importing this if we're not actually doing any +// indexing now. +if (CREATE_MONGO_INDEXES) { + require('../models/action'); + require('../models/asset'); + require('../models/comment'); + require('../models/setting'); + require('../models/user'); + require('./migration'); +} diff --git a/services/redis.js b/services/redis.js index 2576d2c13..0a25b34d6 100644 --- a/services/redis.js +++ b/services/redis.js @@ -1,7 +1,5 @@ const Redis = require('ioredis'); const merge = require('lodash/merge'); -const debug = require('debug')('talk:services:redis'); -const enabled = require('debug').enabled('talk:services:redis'); const { REDIS_URL, REDIS_RECONNECTION_BACKOFF_FACTOR, @@ -9,29 +7,32 @@ const { REDIS_CLIENT_CONFIG, REDIS_CLUSTER_MODE, REDIS_CLUSTER_CONFIGURATION, + LOGGING_LEVEL, } = require('../config'); +const { createLogger } = require('./logging'); +const logger = createLogger('redis'); const attachMonitors = client => { - debug('client created'); + logger.debug('client created'); // Debug events. - if (enabled) { - client.on('connect', () => debug('client connected')); - client.on('ready', () => debug('client ready')); - client.on('close', () => debug('client closed the connection')); + if (['debug', 'trace'].includes(LOGGING_LEVEL)) { + client.on('connect', () => logger.info('client connected')); + client.on('ready', () => logger.debug('client ready')); + client.on('close', () => logger.debug('client closed the connection')); client.on('reconnecting', () => - debug('client connection lost, attempting to reconnect') + logger.debug('client connection lost, attempting to reconnect') ); - client.on('end', () => debug('client ended')); + client.on('end', () => logger.debug('client ended')); } // Error events. client.on('error', err => { if (err) { - console.error('Error connecting to redis:', err); + logger.error({ err }, 'cannot connect to redis'); } }); - client.on('node error', err => debug('node error', err)); + client.on('node error', err => logger.error({ err }, 'node error')); }; function retryStrategy(times) { @@ -40,7 +41,7 @@ function retryStrategy(times) { REDIS_RECONNECTION_BACKOFF_MINIMUM_TIME ); - debug(`retry strategy: try to reconnect ${delay} ms from now`); + logger.debug(`retry strategy: try to reconnect ${delay} ms from now`); return delay; }