lib/Logger.js

/** @module logger */
const raven = require('raven');
const winston = require('winston');

const Config = require('../config/Config.js');

const logger = new winston.Logger();

if (/dev\w*/i.test(Config.environment)) {
  logger.add(winston.transports.Console, {
    timestamp: true,
    stringify: true,
    colorize: true,
  });
}

// if not dev or test so e.g prod, staging, canary etc
if (!/dev\w*|test\w*/i.test(Config.environment)) {
  logger.add(winston.transports.Console, {
    timestamp: true,
    json: true,
  });
  logger.add(require('winston-graylog2'), {
    name: 'Graylog',
    prelog: JSON.stringify,
    staticMeta: {environment: Config.environment},
    graylog: {
      servers: [{host: Config.graylogHost, port: Config.graylogPort}],
      hostname: Config.hostname,
      facility: Config.facility,
    },
  });
}

/**
 * A wrapper around logger.log because we can't export log on it's own
 * meant to be used as borq.log
 * @param {string} logLevel - The logLevel like error, warn etc.
 * @param {string} message - message of log, this could also just be a JSON object holding the message & metadata
 * @param {object} metadata - metadata for the log if the previous argument (message) is an object there's no need for this argment.
 */
function log(logLevel, message, metadata) {
  const level = message ? logLevel : 'info';
  const msg = message.message || '';

  if (typeof message === 'object' && !metadata) {
    logger.log(level, msg, message);
  } else if (typeof message === 'object' && metadata) {
    logger.log(level, msg, metadata);
  } else if (typeof message === 'string' && !metadata) {
    logger.log(level, message);
  } else {
    logger.log(level, message, metadata);
  }
}

/**
 * Configure Sentry using the env vars pased if in production
 * @param {string} sentryDSN The url given by Sentry tied to your account
 * @param {string} environment dev, testing, peoduction etc.
 * @param {string} loggingLevel error, info, warn etc.
 * @return {object} return raven object if in production
 */
function setupSentry(sentryDSN, environment, loggingLevel) {
  raven
    .config(sentryDSN, {
      logger: loggingLevel,
      environment,
    })
    .install();

  if (Config.sentryDSN) {
    return raven;
  }
  return null;
}

const sentry = Config.sentryDSN
  ? setupSentry(Config.sentryDSN, Config.environment, 'error')
  : undefined;

/**
 * A function to send rejected promise errors to both winston and sentry
 * @param {string} text the promise rejection error text
 */
function logRejectedPromise(text) {
  log('error', {
    type: 'Promise rejected',
    text,
  });
  if (Config.environment === 'production') {
    sentry.captureMessage(text);
  }
}

module.exports = {
  log,
  sentry,
  logRejectedPromise,
};