From 00393f0417580528c1af899f5e893ebdb95e326f Mon Sep 17 00:00:00 2001 From: Amar Zavery Date: Wed, 1 Feb 2017 20:46:56 -0800 Subject: [PATCH] improved support for logging, added support to add custom log file path, dependency on a forked version of sway, added support for running cli commands. --- cli.js | 23 ++++++- lib/util/logging.js | 143 +++++++++++++++++++++++++------------------- lib/util/utils.js | 1 - package.json | 12 ++-- 4 files changed, 111 insertions(+), 68 deletions(-) diff --git a/cli.js b/cli.js index b2d6ea69..1baca8a5 100644 --- a/cli.js +++ b/cli.js @@ -1,24 +1,43 @@ +#!/usr/bin/env node + // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. 'use strict'; var yargs = require('yargs'), + os = require('os'), log = require('./lib/util/logging'); +var defaultLogDir = log.directory; +var logFilepath = log.filepath; + yargs .version("0.1.0") .commandDir('lib/commands') .option('h', {alias: 'help'}) .option('j', {alias: 'json', describe: 'Show json output', boolean: true}) - .option('l', {alias: 'logLevel', describe: 'Set the logging level for console.', choices: ['error', 'warn', 'info' , 'verbose', 'debug', 'silly'], default: 'warn'}) - .global(['h', 'j', 'l']) + .option('l', { + alias: 'logLevel', + describe: 'Set the logging level for console.', + choices: ['error', 'warn', 'info' , 'verbose', 'debug', 'silly'], + default: 'error' + }) + .option('f', { + alias: 'logFilepath', + describe: `Set the log file path. It must be an absolute filepath. ` + + `By default the logs will stored in a timestamp based log file at "${defaultLogDir}".` + }) + .global(['h', 'j', 'l', 'f']) .help() .argv; //setting console logging level to the value provided by the user. log.consoleLogLevel = yargs.argv.l; +//setting the logFilePath if provided. +log.filepath = yargs.argv.f || logFilepath; + if (yargs.argv._.length === 0 && yargs.argv.h === false && yargs.argv.j === false) { yargs.coerce('help', function(arg) {return true;}).argv; } \ No newline at end of file diff --git a/lib/util/logging.js b/lib/util/logging.js index 1ea15f8f..d09f634e 100644 --- a/lib/util/logging.js +++ b/lib/util/logging.js @@ -6,10 +6,35 @@ var winston = require('winston'), path = require('path'), fs = require('fs'), - logDir = path.resolve(__dirname, '../..', 'output'); + os = require('os'), + logDir = path.resolve(os.homedir(), 'oav_output'); var currentLogFile; +/* + * Provides current time in custom format that will be used in naming log files. Example:'20140820_151113' + * @return {string} Current time in a custom string format + */ +function getTimeStamp() { + // We pad each value so that sorted directory listings show the files in chronological order + function pad(number) { + if (number < 10) { + return '0' + number; + } + + return number; + } + + var now = new Date(); + return pad(now.getFullYear()) + + pad(now.getMonth() + 1) + + pad(now.getDate()) + + "_" + + pad(now.getHours()) + + pad(now.getMinutes()) + + pad(now.getSeconds()); +} + var logger = new (winston.Logger)({ transports: [ new (winston.transports.Console)({ @@ -17,73 +42,71 @@ var logger = new (winston.Logger)({ colorize: true, prettyPrint: true, humanReadableUnhandledException: true - }), - new (winston.transports.File)({ - level: 'silly', - colorize: false, - silent: false, - prettyPrint: true, - json: false, - filename: getLogFilePath() }) ] }); -/* - * Provides current time in custom format that will be used in naming log files. Example:'20140820_151113' - * @return {string} Current time in a custom string format - */ -function getTimeStamp() { - // We pad each value so that sorted directory listings show the files in chronological order - function pad(number){ - if (number < 10) - { - return '0' + number; +Object.defineProperties(logger, { + 'consoleLogLevel': { + enumerable: true, + get: function () { return this.transports.console.level; }, + set: function (level) { + if (!level) { + level = 'warn'; + } + let validLevels = ['error', 'warn', 'info', 'verbose', 'debug', 'silly']; + if (!validLevels.some(function (item) { return item === level; })) { + throw new Error(`The logging level provided is "${level}". Valid values are: "${validLevels}".`); + } + this.transports.console.level = level; + return; } + }, + 'directory': { + enumerable: true, + get: function () { + return logDir; + }, + set: function (logDirectory) { + if (!logDirectory || logDirectory && typeof logDirectory.valueOf() !== 'string') { + throw new Error('logDirectory cannot be null or undefined and must be of type "string".'); + } - return number; - } - - var now = new Date(); - return pad(now.getFullYear()) - + pad(now.getMonth() + 1) - + pad(now.getDate()) - + "_" - + pad(now.getHours()) - + pad(now.getMinutes()) - + pad(now.getSeconds()); -} - -//provides the log directory where the logs would reside -function getLogDir() { - if(!fs.existsSync(logDir)) { - fs.mkdirSync(logDir); - } - return logDir; -}; - -//provides the log file path where logs would be stored -function getLogFilePath() { - if (!currentLogFile) { - let filename = `validate_log_${getTimeStamp()}.log`; - currentLogFile = path.join(getLogDir(), filename); - } - - return currentLogFile; -} - -Object.defineProperty(logger, 'consoleLogLevel', { - get: function() { return this.transports.console.level; }, - set: function(level) { - if (!level) { - level = 'warn'; + if (!fs.existsSync(logDirectory)) { + fs.mkdirSync(logDirectory); + } + logDir = logDirectory; + return; } - let validLevels = ['error', 'warn', 'info' , 'verbose', 'debug', 'silly']; - if (!validLevels.some(function(item) { return item === level; })) { - throw new Error(`The logging level provided is "${level}". Valid values are: "${validLevels}".`); + }, + 'filepath': { + enumerable: true, + get: function () { + if (!currentLogFile) { + let filename = `validate_log_${getTimeStamp()}.log`; + currentLogFile = path.join(this.directory, filename); + } + + return currentLogFile; + }, + set: function (logFilePath) { + if (!logFilePath || logFilePath && typeof logFilePath.valueOf() !== 'string') { + throw new Error('filepath cannot be null or undefined and must be of type string. It must be an absolute file path.') + } + currentLogFile = logFilePath; + this.directory = path.dirname(logFilePath); + if (!this.transports.file) { + this.add(winston.transports.File, { + level: 'silly', + colorize: false, + silent: false, + prettyPrint: true, + json: false, + filename: logFilePath + }); + } + return; } - this.transports.console.level = level; - return; } }); diff --git a/lib/util/utils.js b/lib/util/utils.js index 66deda37..ae8bd52d 100644 --- a/lib/util/utils.js +++ b/lib/util/utils.js @@ -242,7 +242,6 @@ exports.joinPath = function joinPath() { let finalPath = path.join.apply(path, arguments); finalPath = finalPath.replace(/\\/gi, '/'); finalPath = finalPath.replace(/^(http|https):\/(.*)/gi, '$1://$2'); - log.silly(`The final path is: ${finalPath}.`); return finalPath; }; diff --git a/package.json b/package.json index a6908aa6..607c63a9 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "openapi-validator-tools", + "name": "openapi-validaton-tools", "private": true, "version": "0.1.0", "author": { @@ -13,10 +13,10 @@ "azure-arm-resource": "^1.6.1-preview", "json-pointer": "^0.6.0", "moment": "^2.14.1", - "ms-rest": "^1.15.2", - "ms-rest-azure": "^1.15.2", + "ms-rest": "^1.15.3", + "ms-rest-azure": "^1.15.3", "request": "^2.79.0", - "sway": "^1.0.0", + "sway": "amarzavery/sway#validation", "winston": "^2.3.0", "yargs": "^6.6.0" }, @@ -31,5 +31,7 @@ "scripts": { "pretest": "npm install -g mocha && npm install", "test": "mocha" - } + }, + "main": "./cli.js", + "bin": { "swag": "./cli.js" } }