@contentstack/cli-utilities
Version:
Utilities for contentstack projects
190 lines (189 loc) • 7.5 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const traverse_1 = tslib_1.__importDefault(require("traverse"));
const full_1 = require("klona/full");
const path_1 = require("path");
const winston = tslib_1.__importStar(require("winston"));
const logging_1 = require("../constants/logging");
class Logger {
constructor(config) {
this.sensitiveKeys = [
/authtoken/i,
/^email$/i,
/^password$/i,
/secret/i,
/token/i,
/api[-._]?key/i,
/management[-._]?token/i,
/sessionid/i,
/orgid/i,
];
this.config = config;
this.loggers = {
error: this.getLoggerInstance('error'),
warn: this.getLoggerInstance('warn'),
info: this.getLoggerInstance('info'),
debug: this.getLoggerInstance('debug'),
success: this.getLoggerInstance('info'), // Map success to info
};
}
getLoggerInstance(level = 'info') {
const filePath = (0, path_1.normalize)(process.env.CS_CLI_LOG_PATH || this.config.basePath).replace(/^(\.\.(\/|\\|$))+/, '');
if (level === 'hidden') {
return this.createLogger('error', filePath);
}
return this.createLogger(level, filePath);
}
get loggerOptions() {
return {
filename: '',
maxFiles: 20,
tailable: true,
maxsize: 1000000,
};
}
createLogger(level, filePath) {
return winston.createLogger({
levels: logging_1.logLevels,
level: level,
transports: [
new winston.transports.File(Object.assign(Object.assign({}, this.loggerOptions), { filename: `${filePath}/${level}.log`, format: winston.format.combine(winston.format.timestamp(), winston.format.json()) })),
new winston.transports.Console({
format: winston.format.combine(winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), winston.format.printf((info) => {
const colorizer = winston.format.colorize();
const levelText = info.level.toUpperCase();
const timestamp = info.timestamp;
const message = info.message;
const meta = info.meta;
let fullLine = `[${timestamp}] ${levelText}: ${message}`;
if (meta && (info.level !== 'info' && info.level !== 'success')) {
const redactedMeta = this.isLogEntry(meta) ? JSON.stringify(this.redact(meta)) : JSON.stringify(this.redact(meta));
fullLine += ` - ${redactedMeta}`;
}
return colorizer.colorize(info.level, fullLine);
})),
}),
],
});
}
isSensitiveKey(keyStr) {
return keyStr && typeof keyStr === 'string'
? this.sensitiveKeys.some((regex) => regex.test(keyStr))
: false;
}
redactObject(obj) {
const self = this;
(0, traverse_1.default)(obj).forEach(function redactor() {
if (this.key && self.isSensitiveKey(this.key)) {
this.update('[REDACTED]');
}
});
}
redact(info) {
try {
const copy = (0, full_1.klona)(info);
this.redactObject(copy);
const splat = copy[Symbol.for('splat')];
if (splat)
this.redactObject(splat);
return copy;
}
catch (error) {
return info;
}
}
isLogEntry(obj) {
return typeof obj === 'object' && 'level' in obj && 'message' in obj;
}
shouldLog(level, target) {
const configLevel = target === 'console' ? this.config.consoleLogLevel : this.config.logLevel;
const minLevel = configLevel ? logging_1.logLevels[configLevel] : 2; // default: info
const entryLevel = logging_1.logLevels[level];
return entryLevel <= minLevel;
}
/* === Public Log Methods === */
error(message, meta) {
if (this.shouldLog('error', 'console') || this.shouldLog('error', 'file')) {
this.loggers.error.error(message, meta);
}
}
warn(message, meta) {
if (this.shouldLog('warn', 'console') || this.shouldLog('warn', 'file')) {
this.loggers.warn.warn(message, meta);
}
}
info(message, meta) {
if (this.shouldLog('info', 'console') || this.shouldLog('info', 'file')) {
this.loggers.info.info(message, meta);
}
}
success(message, meta) {
if (this.shouldLog('info', 'console') || this.shouldLog('info', 'file')) {
this.loggers.success.info(message, Object.assign(Object.assign({}, meta), { type: 'success' }));
}
}
debug(message, meta) {
if (this.shouldLog('debug', 'console') || this.shouldLog('debug', 'file')) {
this.loggers.debug.debug(message, meta);
}
}
/* === Structured Logging === */
logError(params) {
const logPayload = {
level: logging_1.logLevels.error,
message: params.message,
timestamp: new Date(),
meta: Object.assign({ type: params.type, error: params.error, context: params.context }, params.meta),
};
const targetLevel = params.hidden ? 'debug' : 'error';
if (this.shouldLog(targetLevel, 'console') || this.shouldLog(targetLevel, 'file')) {
this.loggers[targetLevel].error(logPayload);
}
}
logWarn(params) {
const logPayload = {
level: logging_1.logLevels.warn,
message: params.message,
timestamp: new Date(),
meta: Object.assign({ type: params.type, context: params.context }, params.meta),
};
if (this.shouldLog('warn', 'console') || this.shouldLog('warn', 'file')) {
this.loggers.warn.warn(logPayload);
}
}
logInfo(params) {
const logPayload = {
level: logging_1.logLevels.info,
message: params.message,
timestamp: new Date(),
meta: Object.assign({ type: params.type, info: params.info, context: params.context }, params.meta),
};
if (this.shouldLog('info', 'console') || this.shouldLog('info', 'file')) {
this.loggers.info.info(logPayload);
}
}
logSuccess(params) {
const logPayload = {
level: logging_1.logLevels.success,
message: params.message,
timestamp: new Date(),
meta: Object.assign({ type: params.type, data: params.data, context: params.context }, params.meta),
};
if (this.shouldLog('info', 'console') || this.shouldLog('info', 'file')) {
this.loggers.success.info(logPayload);
}
}
logDebug(params) {
const logPayload = {
level: logging_1.logLevels.debug,
message: params.message,
timestamp: new Date(),
meta: Object.assign({ type: params.type, debug: params.debug, context: params.context }, params.meta),
};
if (this.shouldLog('debug', 'console') || this.shouldLog('debug', 'file')) {
this.loggers.debug.debug(logPayload);
}
}
}
exports.default = Logger;