@adobe/helix-cli
Version:
Project Helix CLI
133 lines (119 loc) • 4.26 kB
JavaScript
/*
* Copyright 2018 Adobe. All rights reserved.
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
import path from 'path';
import fs from 'fs-extra';
import chalk from 'chalk-template';
import {
ConsoleLogger,
FileLogger,
messageFormatJsonString,
messageFormatTechnical, MultiLogger,
serializeMessage,
SimpleInterface,
} from '@adobe/helix-log';
const LEVEL_NAMES = {
info: chalk`{green info}`,
warn: chalk`{yellow warn}`,
error: chalk`{red error}`,
};
/**
* Log message filter that removes log entries produced during a progress bar
* (fields.progress === true), but only on a tty.
*/
const suppressProgress = (fields) => {
// eslint-disable-next-line no-underscore-dangle,no-console
if (fields.progress && console._stderr.isTTY) {
return undefined;
}
// eslint-disable-next-line no-param-reassign
delete fields.progress;
return fields;
};
/**
* Log message filter that removes the `progress` field so that it doesn't get logged.
*/
const filterProgress = (fields) => {
// eslint-disable-next-line no-param-reassign
delete fields.progress;
return fields;
};
/**
* Message format for the console that doesn't show the `info` level keyword for the `cli`
* category. prefixes the log entries with the category otherwise.
*/
const categoryAwareMessageFormatConsole = (fields) => {
// eslint-disable-next-line
const {level, timestamp, message, category = 'cli', ...rest} = fields;
const fullMsg = Object.keys(rest).length === 0 ? message : [...message, ' ', rest];
const ser = serializeMessage(fullMsg, { colors: false });
const lvl = LEVEL_NAMES[level] ?? level.toLowerCase();
if (category === 'cli' && level === 'info') {
return `${ser}`;
}
return `${lvl}: ${ser}`;
};
// module global loggers by category
const loggersByCategory = new Map();
/**
* Gets the logger for the respective category or creates a new one if it does not exist yet.
* @param {object|string} [config='cli'] The log config or the category name.
* @param {string} [config.category='cli'] The log category
* @param {string} [config.level='cli'] The log level
* @param {string} [config.logsDir='logs'] The log directory.
* @param {Array|string} [config.logFle=['-', '${category}-server.log']] The log files(s).
*
* @returns {SimpleInterface} a helix-log simple interface.
*/
export function getOrCreateLogger(config = 'cli') {
let categ;
if (typeof config === 'string') {
categ = config;
} else {
categ = (config && config.category) || 'cli';
}
if (loggersByCategory.has(categ)) {
return loggersByCategory.get(categ);
}
// setup helix logger
const level = (config && config.logLevel) || 'info';
const logsDir = path.normalize((config && config.logsDir) || 'logs');
const logFiles = config && Array.isArray(config.logFile)
? config.logFile
: ['-', (config && config.logFile) || path.join(logsDir, `${categ}-server.log`)];
const loggers = new Map();
logFiles.forEach((logFile) => {
const name = loggers.has('default') ? logFile : 'default';
if (logFile === '-') {
loggers.set(name, new ConsoleLogger({
filter: categ === 'cli' ? suppressProgress : filterProgress,
level,
formatter: categoryAwareMessageFormatConsole,
}));
} else {
fs.ensureDirSync(path.dirname(logFile));
loggers.set(name, new FileLogger(logFile, {
level: 'debug',
formatter: /\.json/.test(logFile) ? messageFormatJsonString : messageFormatTechnical,
}));
}
});
// create simple interface
const log = new SimpleInterface({
level,
defaultFields: {
category: categ,
},
logger: new MultiLogger(loggers),
});
loggersByCategory.set(categ, log);
return log;
}