"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = exports.printWarning = exports.createExtensionLogger = exports.baseFileTransportOpts = void 0;

function _bluebird() {
  const data = require("bluebird");

  _bluebird = function () {
    return data;
  };

  return data;
}

function _yn() {
  const data = _interopRequireDefault(require("yn"));

  _yn = function () {
    return data;
  };

  return data;
}

function _serializeError() {
  const data = _interopRequireDefault(require("serialize-error"));

  _serializeError = function () {
    return data;
  };

  return data;
}

function _stringFormat() {
  const data = _interopRequireDefault(require("string-format"));

  _stringFormat = function () {
    return data;
  };

  return data;
}

function _winston() {
  const data = _interopRequireDefault(require("winston"));

  _winston = function () {
    return data;
  };

  return data;
}

function _path() {
  const data = _interopRequireDefault(require("path"));

  _path = function () {
    return data;
  };

  return data;
}

function _constants() {
  const data = require("../constants");

  _constants = function () {
    return data;
  };

  return data;
}

function _analytics() {
  const data = require("../analytics/analytics");

  _analytics = function () {
    return data;
  };

  return data;
}

function _globalConfig() {
  const data = require("../api/consumer/lib/global-config");

  _globalConfig = function () {
    return data;
  };

  return data;
}

function _chalk() {
  const data = _interopRequireDefault(require("chalk"));

  _chalk = function () {
    return data;
  };

  return data;
}

// Store the extensionsLoggers to prevent create more than one logger for the same extension
// in case the extension developer use api.logger more than once
const extensionsLoggers = new Map();
const baseFileTransportOpts = {
  filename: _constants().DEBUG_LOG,
  json: (0, _yn().default)((0, _globalConfig().getSync)(_constants().CFG_LOG_JSON_FORMAT), {
    default: false
  }),
  // Make it debug level also in production until the product will be more stable. in the future this should be changed to error
  level: process.env.NODE_ENV === 'production' ? 'debug' : 'debug',
  maxsize: 10 * 1024 * 1024,
  // 10MB
  maxFiles: 10,
  colorize: true,
  prettyPrint: true,
  // If true, log files will be rolled based on maxsize and maxfiles, but in ascending order.
  // The filename will always have the most recent log lines. The larger the appended number, the older the log file
  tailable: true
};
exports.baseFileTransportOpts = baseFileTransportOpts;
const exceptionsFileTransportOpts = Object.assign({}, baseFileTransportOpts, {
  filename: _path().default.join(_constants().GLOBAL_LOGS, 'exceptions.log')
});
const logger = new (_winston().default.Logger)({
  transports: [new (_winston().default.transports.File)(baseFileTransportOpts)],
  exceptionHandlers: [new (_winston().default.transports.File)(exceptionsFileTransportOpts)],
  exitOnError: false
});
/**
 * Create a logger instance for extension
 * The extension name will be added as label so it will appear in the begining of each log line
 * The logger is cached for each extension so there is no problem to use getLogger few times for the same extension
 * @param {string} extensionName
 */

const createExtensionLogger = extensionName => {
  // Getting logger from cache
  const existingLogger = extensionsLoggers.get(extensionName);

  if (existingLogger) {
    return existingLogger;
  }

  const extensionFileTransportOpts = Object.assign({}, baseFileTransportOpts, {
    filename: _path().default.join(_constants().GLOBAL_LOGS, 'extensions.log'),
    label: extensionName
  });
  const extLogger = new (_winston().default.Logger)({
    transports: [new (_winston().default.transports.File)(extensionFileTransportOpts)],
    exceptionHandlers: [new (_winston().default.transports.File)(extensionFileTransportOpts)],
    exitOnError: false
  });
  extensionsLoggers.set(extensionName, extLogger);
  return extLogger;
};

exports.createExtensionLogger = createExtensionLogger;

const printWarning = msg => {
  const cfgNoWarnings = (0, _globalConfig().getSync)(_constants().CFG_NO_WARNINGS);

  if (cfgNoWarnings !== 'true') {
    // eslint-disable-next-line no-console
    console.log(_chalk().default.yellow(`Warning: ${msg}`));
  }
}; // @credit Kegsay from https://github.com/winstonjs/winston/issues/228
// it solves an issue when exiting the code explicitly and the log file is not written


exports.printWarning = printWarning;

logger.exitAfterFlush =
/*#__PURE__*/
function () {
  var _ref = (0, _bluebird().coroutine)(function* (code = 0, commandName) {
    yield _analytics().Analytics.sendData();
    let level;
    let msg;

    if (code === 0) {
      level = 'info';
      msg = `[*] the command ${commandName} has been completed successfully`;
    } else {
      level = 'error';
      msg = `[*] the command ${commandName} has been terminated with an error code ${code}`;
    }

    logger.log(level, msg, () => {
      let numFlushes = 0;
      let numFlushed = 0;
      Object.keys(logger.transports).forEach(k => {
        if (logger.transports[k]._stream) {
          numFlushes += 1;

          logger.transports[k]._stream.once('finish', () => {
            numFlushed += 1;

            if (numFlushes === numFlushed) {
              process.exit(code);
            }
          });

          logger.transports[k]._stream.end();
        }
      });

      if (numFlushes === 0) {
        process.exit(code);
      }
    });
  });

  return function () {
    return _ref.apply(this, arguments);
  };
}();

function addBreakCrumb(category, message, data = {}, extraData) {
  const hashedData = {};
  Object.keys(data).forEach(key => hashedData[key] = _analytics().Analytics.hashData(data[key]));
  const messageWithHashedData = (0, _stringFormat().default)(message, hashedData);
  extraData = extraData instanceof Error ? (0, _serializeError().default)(extraData) : extraData;

  _analytics().Analytics.addBreadCrumb(category, messageWithHashedData, extraData);
}

logger.debugAndAddBreadCrumb = (category, message, data, extraData) => {
  addToLoggerAndToBreadCrumb('debug', category, message, data);
};

logger.warnAndAddBreadCrumb = (category, message, data, extraData) => {
  addToLoggerAndToBreadCrumb('warn', category, message, data, extraData);
};

logger.errorAndAddBreadCrumb = (category, message, data, extraData) => {
  addToLoggerAndToBreadCrumb('error', category, message, data, extraData);
};

function addToLoggerAndToBreadCrumb(level, category, message, data, extraData) {
  if (!category) throw new TypeError('addToLoggerAndToBreadCrumb, category is missing');
  if (!message) throw new TypeError('addToLoggerAndToBreadCrumb, message is missing');
  const messageWithData = data ? (0, _stringFormat().default)(message, data) : message;
  logger[level](category, messageWithData, extraData);
  addBreakCrumb(category, message, data, extraData);
}
/**
 * prefix BIT_LOG to the command, provides the ability to log into the console.
 * two options are available here:
 * 1) use the level. e.g. `BIT_LOG=error bit import`.
 * 2) use the message prefix, e.g. `BIT_LOG=ssh bit import`.
 * 3) use multiple message prefixes, e.g. `BIT_LOG=ssh,env bit import`.
 */


if (process.env.BIT_LOG) {
  const levels = ['error', 'warn', 'info', 'verbose', 'debug', 'silly'];

  if (levels.includes(process.env.BIT_LOG)) {
    const level = process.env.BIT_LOG;
    logger.add(_winston().default.transports.Console, {
      level
    });
    logger.cli();
  } else {
    const prefixes = process.env.BIT_LOG.split(',');
    logger.on('logging', (transport, level, msg) => {
      if (prefixes.some(prefix => msg.startsWith(prefix))) {
        console.log(`\n${msg}`);
      }
    });
  }
}

var _default = logger;
exports.default = _default;