bit-bin
Version:
<a href="https://opensource.org/licenses/Apache-2.0"><img alt="apache" src="https://img.shields.io/badge/License-Apache%202.0-blue.svg"></a> <a href="https://github.com/teambit/bit/blob/master/CONTRIBUTING.md"><img alt="prs" src="https://img.shields.io/b
430 lines (341 loc) • 12.6 kB
JavaScript
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getFormat = getFormat;
exports.default = exports.printWarning = exports.createExtensionLogger = exports.baseFileTransportOpts = void 0;
function _bluebird() {
const data = require("bluebird");
_bluebird = function () {
return data;
};
return data;
}
function _defineProperty2() {
const data = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
_defineProperty2 = function () {
return data;
};
return data;
}
function _chalk() {
const data = _interopRequireDefault(require("chalk"));
_chalk = function () {
return data;
};
return data;
}
function _yn() {
const data = _interopRequireDefault(require("yn"));
_yn = function () {
return data;
};
return data;
}
function _serializeError() {
const data = 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 = _interopRequireWildcard(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 _defaultErrorHandler() {
const data = _interopRequireDefault(require("../cli/default-error-handler"));
_defaultErrorHandler = function () {
return data;
};
return data;
}
// @ts-ignore AUTO-ADDED-AFTER-MIGRATION-PLEASE-FIX!
// 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 jsonFormat = (0, _yn().default)((0, _globalConfig().getSync)(_constants().CFG_LOG_JSON_FORMAT), {
default: false
});
const logLevel = (0, _globalConfig().getSync)(_constants().CFG_LOG_LEVEL) || 'debug';
const baseFileTransportOpts = {
filename: _constants().DEBUG_LOG,
format: jsonFormat ? _winston().default.format.combine(_winston().default.format.timestamp(), _winston().default.format.json()) : getFormat(),
level: logLevel,
maxsize: 10 * 1024 * 1024,
// 10MB
maxFiles: 10,
// 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;
function getFormat() {
return _winston().default.format.combine(_winston().default.format.metadata(), _winston().default.format.colorize(), _winston().default.format.timestamp(), _winston().default.format.splat(), // does nothing?
_winston().default.format.errors({
stack: true
}), _winston().default.format.prettyPrint({
depth: 3,
colorize: true
}), // does nothing?
_winston().default.format.printf(info => customPrint(info)));
function customPrint(info) {
const getMetadata = () => {
if (!Object.keys(info.metadata).length) return '';
try {
return JSON.stringify(info.metadata, null, 2);
} catch (err) {
return `logger error: logging failed to stringify the metadata Json. (error: ${err.message})`;
}
};
return `${info.timestamp} ${info.level}: ${info.message} ${getMetadata()}`;
}
}
const exceptionsFileTransportOpts = Object.assign({}, baseFileTransportOpts, {
filename: path().join(_constants().GLOBAL_LOGS, 'exceptions.log')
});
class BitLogger {
/**
* being set on command-registrar, once the flags are parsed. here, it's a workaround to have
* it set before the command-registrar is loaded. at this stage we don't know for sure the "-j"
* is actually "json". that's why this variable is overridden once the command-registrar is up.
*/
constructor(logger) {
(0, _defineProperty2().default)(this, "logger", void 0);
(0, _defineProperty2().default)(this, "shouldWriteToConsole", !process.argv.includes('--json') && !process.argv.includes('-j'));
this.logger = logger;
logger.on('error', err => {
// eslint-disable-next-line no-console
console.log('got an error from the logger', err);
});
}
silly(...args) {
// @ts-ignore
this.logger.silly(...args);
}
debug(...args) {
// @ts-ignore
this.logger.debug(...args);
}
warn(...args) {
// @ts-ignore
this.logger.warn(...args);
}
info(...args) {
// @ts-ignore
this.logger.info(...args);
}
error(...args) {
// @ts-ignore
this.logger.error(...args);
}
console(msg, level = 'info', color) {
let actualMessage = msg;
if (msg instanceof Error) {
const {
message
} = (0, _defaultErrorHandler().default)(msg);
actualMessage = message;
}
if (!this.shouldWriteToConsole) {
this[level](actualMessage);
return;
}
if (color) {
try {
// @ts-ignore
actualMessage = _chalk().default.keyword(color)(actualMessage);
} catch (e) {
this.silly('a wrong color provided to logger.console method');
}
}
_winston().default.loggers.get('consoleOnly')[level](actualMessage);
}
exitAfterFlush(code = 0, commandName) {
var _this = this;
return (0, _bluebird().coroutine)(function* () {
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}`;
}
_this.logger[level](msg);
yield waitForLogger();
process.exit(code);
})();
}
debugAndAddBreadCrumb(category, message, data, extraData) {
this.addToLoggerAndToBreadCrumb('debug', category, message, data, extraData);
}
warnAndAddBreadCrumb(category, message, data, extraData) {
this.addToLoggerAndToBreadCrumb('warn', category, message, data, extraData);
}
errorAndAddBreadCrumb(category, message, data, extraData) {
this.addToLoggerAndToBreadCrumb('error', category, message, data, extraData);
}
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;
this.logger[level](`${category}, ${messageWithData}`, extraData);
addBreadCrumb(category, message, data, extraData);
}
}
const winstonLogger = _winston().default.createLogger({
transports: [new (_winston().default.transports.File)(baseFileTransportOpts)],
exceptionHandlers: [new (_winston().default.transports.File)(exceptionsFileTransportOpts)],
exitOnError: false
});
const logger = new BitLogger(winstonLogger);
/**
* 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().join(_constants().GLOBAL_LOGS, 'extensions.log'),
label: extensionName
});
const extLogger = _winston().default.createLogger({
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 dpraul from https://github.com/winstonjs/winston/issues/1250
* it solves an issue when exiting the code explicitly and the log file is not written
*
* there are still two issues though.
* 1. sometimes, an error is thrown "write after end". can be reproduced by running the
* performance e2e-test on 3,000 components, 100 dependencies, on export.
* 2. sometimes, it doesn't write all messages to the log. can be reproduced by the same method as
* above, but even with 300 components and 10 dependencies.
*
* if you try to fix these issues, please make sure that after your fix, the following are working:
* 1. the two cases should work.
* 2. when error is thrown, it exists successfully with the correct error-code. (the standard
* e2e-tests cover this multiple times).
* 3. the ssh is working. (not covered by the e2e-tests). run a simple export to an ssh and make
* sure it doesn't hang.
*
* for the record, the following was working for #1 and #2 but not for #3.
* ```
* const loggerDone = new Promise(resolve => logger.logger.on(code ? 'finish' : 'close', resolve));
* if (code) logger.logger.end();
* ```
*/
exports.printWarning = printWarning;
function waitForLogger() {
return _waitForLogger.apply(this, arguments);
}
function _waitForLogger() {
_waitForLogger = (0, _bluebird().coroutine)(function* () {
const loggerDone = new Promise(resolve => logger.logger.on('finish', resolve));
logger.logger.end();
return loggerDone;
});
return _waitForLogger.apply(this, arguments);
}
function addBreadCrumb(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().serializeError)(extraData) : extraData;
_analytics().Analytics.addBreadCrumb(category, messageWithHashedData, 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'];
const isLevel = levels.includes(process.env.BIT_LOG);
const prefixes = process.env.BIT_LOG.split(',');
const filterPrefix = _winston().default.format(info => {
if (isLevel) return info;
if (prefixes.some(prefix => info.message.startsWith(prefix))) return info;
return false;
});
logger.logger.add(new (_winston().default.transports.Console)({
level: isLevel ? process.env.BIT_LOG : 'silly',
format: _winston().default.format.combine(filterPrefix(), _winston().default.format.printf(info => info.message))
}));
}
/**
* useful when in the middle of the process, Bit needs to print to the console.
* it's better than using `console.log` because, this way, it's possible to turn it on/off
*/
_winston().default.loggers.add('consoleOnly', {
format: _winston().default.format.combine(_winston().default.format.printf(info => info.message)),
transports: [new (_winston().default.transports.Console)({
level: 'silly'
})]
});
var _default = logger;
exports.default = _default;
;