From 2915e2904b4c784467f6cf5019bbdc5527d893aa Mon Sep 17 00:00:00 2001 From: Leela Prasad <47483946+leelaprasadv@users.noreply.github.com> Date: Mon, 6 May 2024 10:47:05 +0530 Subject: [PATCH] Add logger setup (#177) --- src/beats/index.js | 10 ++- src/cli.js | 8 +- src/commands/publish.js | 14 +++- src/extensions/index.js | 7 +- src/extensions/report-portal-history.js | 5 +- src/helpers/colors.js | 46 +++++++++++ src/utils/logger.js | 104 ++++++++++++++++++++++++ 7 files changed, 181 insertions(+), 13 deletions(-) create mode 100644 src/helpers/colors.js create mode 100644 src/utils/logger.js diff --git a/src/beats/index.js b/src/beats/index.js index 1c900a7..34510e4 100644 --- a/src/beats/index.js +++ b/src/beats/index.js @@ -1,6 +1,7 @@ const request = require('phin-retry'); const TestResult = require('test-results-parser/src/models/TestResult'); const { getCIInformation } = require('../helpers/ci'); +const logger = require('../utils/logger'); const { HOOK } = require('../helpers/constants'); function get_base_url() { @@ -20,7 +21,7 @@ async function run(config, result) { await attachTestBeatsFailureSummary(config, result, run_id); } } else { - console.warn('Missing testbeats config parameters'); + logger.warn('Missing testbeats config parameters'); } } @@ -47,7 +48,7 @@ function isValid(config) { * @param {TestResult} result */ async function publishTestResults(config, result) { - console.log("Publishing results to TestBeats"); + logger.info("Publishing results to TestBeats Cloud..."); try { const payload = { project: config.project, @@ -66,10 +67,11 @@ async function publishTestResults(config, result) { }, body: payload }); + logger.info("Result published to TestBeats Cloud successfully!"); return response.id; } catch (error) { - console.log("Unable to publish results to TestBeats"); - console.log(error); + logger.error(`Unable to publish results to TestBeats Cloud: ${error.message}`); + logger.debug(error); } } diff --git a/src/cli.js b/src/cli.js index 815383a..52c212e 100755 --- a/src/cli.js +++ b/src/cli.js @@ -5,17 +5,21 @@ const sade = require('sade'); const prog = sade('testbeats'); const publish = require('./commands/publish'); +const logger = require('./utils/logger'); prog .version('2.0.1') - .option('-c, --config', 'Provide path to custom config', 'config.json'); + .option('-c, --config', 'Provide path to custom config', 'config.json') + .option('-l, --logLevel', 'Log Level', "INFO"); prog.command('publish') .action(async (opts) => { try { + logger.setLevel(opts.logLevel); + logger.info(`Initiating...`); await publish.run(opts); } catch (error) { - console.error(error); + logger.error(`Report publish failed: ${error.message}`); process.exit(1); } }); diff --git a/src/commands/publish.js b/src/commands/publish.js index 6ea8a4e..f67c997 100644 --- a/src/commands/publish.js +++ b/src/commands/publish.js @@ -5,6 +5,7 @@ const prp = require('performance-results-parser'); const { processData } = require('../helpers/helper'); const beats = require('../beats'); const target_manager = require('../targets'); +const logger = require('../utils/logger'); /** * @param {import('../index').PublishOptions} opts @@ -35,6 +36,7 @@ async function run(opts) { validateConfig(config); await processReport(config); } + logger.info("Report successfully processed!") } /** @@ -42,6 +44,7 @@ async function run(opts) { * @param {import('../index').PublishReport} report */ async function processReport(report) { + logger.debug("processReport: Started") const parsed_results = []; for (const result_options of report.results) { if (result_options.type === 'custom') { @@ -61,9 +64,10 @@ async function processReport(report) { await target_manager.run(target, result); } } else { - console.log('No targets defined, skipping sending results to targets'); + logger.warn('No targets defined, skipping sending results to targets'); } } + logger.debug("processReport: Ended") } /** @@ -71,11 +75,13 @@ async function processReport(report) { * @param {import('../index').PublishReport} config */ function validateConfig(config) { + logger.info("Validating publish configuration...") if (!config) { throw new Error('Missing publish config'); } validateResults(config); validateTargets(config); + logger.info("Validating publish configuration sucessful") } /** @@ -83,6 +89,7 @@ function validateConfig(config) { * @param {import('../index').PublishReport} config */ function validateResults(config) { + logger.debug("Validating results...") if (!config.results) { throw new Error('Missing results properties in config'); } @@ -112,6 +119,7 @@ function validateResults(config) { } } } + logger.debug("Validating results - Successful!") } /** @@ -119,8 +127,9 @@ function validateResults(config) { * @param {import('../index').PublishReport} config */ function validateTargets(config) { + logger.debug("Validating targets...") if (!config.targets) { - console.warn('targets are not defined in config'); + logger.warn('Targets are not defined in config'); return; } if (!Array.isArray(config.targets)) { @@ -150,6 +159,7 @@ function validateTargets(config) { } } } + logger.debug("Validating targets - Successful!") } module.exports = { diff --git a/src/extensions/index.js b/src/extensions/index.js index ea4b485..a4e2aea 100644 --- a/src/extensions/index.js +++ b/src/extensions/index.js @@ -10,6 +10,7 @@ const ci_info = require('./ci-info'); const ai_failure_summary = require('./ai-failure-summary'); const { EXTENSION } = require('../helpers/constants'); const { checkCondition } = require('../helpers/helper'); +const logger = require('../utils/logger'); async function run(options) { const { target, result, hook } = options; @@ -25,9 +26,9 @@ async function run(options) { try { await extension_runner.run(options); } catch (error) { - console.log('Failed to run extension'); - console.log(extension); - console.log(error); + logger.error(`Failed to run extension: ${error.message}`); + logger.debug(`Extension details`, extension); + logger.debug(`Error: `, error); } } } diff --git a/src/extensions/report-portal-history.js b/src/extensions/report-portal-history.js index 9592d15..37cc5dc 100644 --- a/src/extensions/report-portal-history.js +++ b/src/extensions/report-portal-history.js @@ -1,6 +1,7 @@ const { getSuiteHistory, getLastLaunchByName, getLaunchDetails } = require('../helpers/report-portal'); const { addChatExtension, addSlackExtension, addTeamsExtension } = require('../helpers/extension.helper'); const { HOOK, STATUS } = require('../helpers/constants'); +const logger = require('../utils/logger'); async function getLaunchHistory(extension) { const { inputs, outputs } = extension; @@ -71,8 +72,8 @@ async function run({ extension, target, payload }) { } } } catch (error) { - console.log('Failed to get report portal history'); - console.log(error); + logger.error(`Failed to get report portal history: ${error.message}`); + logger.debug(`Error: ${error}`); } } diff --git a/src/helpers/colors.js b/src/helpers/colors.js new file mode 100644 index 0000000..192e78f --- /dev/null +++ b/src/helpers/colors.js @@ -0,0 +1,46 @@ +const options = { + disableColors: false + }; + + const textToFormat = (open, close, searchRegex, replaceValue) => (txt) => + !options.disableColors + ? open + + (~(txt += "").indexOf(close, 4) // skip opening \x1b[ + ? txt.replace(searchRegex, replaceValue) + : txt) + + close + : txt + + const init = (open, close) => { + return textToFormat( + `\x1b[${open}m`, + `\x1b[${close}m`, + new RegExp(`\\x1b\\[${close}m`, "g"), + `\x1b[${open}m` + ) + } + const colors = { + // modifiers + reset: init(0, 0), + bold: init(1, 22), + dim: init(2, 22), + italic: init(3, 23), + underline: init(4, 24), + + // colors + black: init(30, 39), + red: init(31, 39), + green: init(32, 39), + yellow: init(33, 39), + blue: init(34, 39), + magenta: init(35, 39), + cyan: init(36, 39), + white: init(37, 39), + gray: init(90, 39), + grey: init(90, 39), + + // setting options + options: options + } + + module.exports=colors \ No newline at end of file diff --git a/src/utils/logger.js b/src/utils/logger.js new file mode 100644 index 0000000..6a5dc49 --- /dev/null +++ b/src/utils/logger.js @@ -0,0 +1,104 @@ +const { magenta, blue, green, yellow, red, options } = require('../helpers/colors'); +const trm = console; + +const LEVEL_VERBOSE = 2; +const LEVEL_TRACE = 3; +const LEVEL_DEBUG = 4; +const LEVEL_INFO = 5; +const LEVEL_WARN = 6; +const LEVEL_ERROR = 7; +const LEVEL_SILENT = 8; + +/** + * returns log level value + * @param {string} level - log level + */ +function getLevelValue(level) { + const logLevel = level.toUpperCase(); + switch (logLevel) { + case 'TRACE': + return LEVEL_TRACE; + case 'DEBUG': + return LEVEL_DEBUG; + case 'INFO': + return LEVEL_INFO; + case 'WARN': + return LEVEL_WARN; + case 'ERROR': + return LEVEL_ERROR; + case 'SILENT': + return LEVEL_SILENT; + case 'VERBOSE': + return LEVEL_VERBOSE; + default: + return LEVEL_INFO; + } +} + +class Logger { + + constructor() { + this.level = process.env.TESTBEATS_LOG_LEVEL || 'INFO'; + this.levelValue = getLevelValue(this.level); + if (process.env.TESTBEATS_DISABLE_LOG_COLORS === 'true') { + options.disableColors = true; + } + } + + /** + * sets log level + * @param {('TRACE'|'DEBUG'|'INFO'|'WARN'|'ERROR')} level - log level + */ + setLevel(level) { + this.level = level; + this.levelValue = getLevelValue(this.level); + } + + trace(...msg) { + if (this.levelValue <= LEVEL_TRACE) { + process.stdout.write(`[${magenta('T')}] `); + msg.forEach(m => trm.debug(m)); + } + } + + debug(...msg) { + if (this.levelValue <= LEVEL_DEBUG) { + process.stdout.write(`[${blue('D')}] `); + msg.forEach(m => trm.debug(m)); + } + } + + info(...msg) { + if (this.levelValue <= LEVEL_INFO) { + process.stdout.write(`[${green('I')}] `); + msg.forEach(m => trm.info(m)); + } + } + + warn(...msg) { + if (this.levelValue <= LEVEL_WARN) { + process.stdout.write(`[${yellow('W')}] `); + msg.forEach(m => trm.warn(getMessage(m))); + } + } + + error(...msg) { + if (this.levelValue <= LEVEL_ERROR) { + process.stdout.write(`[${red('E')}] `); + msg.forEach(m => trm.error(getMessage(m))); + } + } + +} + + +function getMessage(msg) { + try { + return typeof msg === 'object' ? JSON.stringify(msg, null, 2) : msg; + } catch (_) { + return msg; + } +} + + +module.exports = new Logger(); \ No newline at end of file