Addressed PR comments

*Console.js*
- Moved `DEFAULT_PROCESS` const to outside of the `Console` class (but inside the module).
- Removed `(` and `)` from `.filter` in `getProcessLogs()`.
- Updated comments

*logger.js*
- Moved `dateFormat` and `logRegex` to constants outside of `Logger` class
- Moved the `parseLogFile` method inside of the `Logger` class (ES6 style)
- Added a log limit to the `parseLogFile` method
- Added the log path to the constants file and used inside of `Logger`

*cmd_controller.js*
- Defaulted `this.context` to `[constants.context.any]` in the constructor.
- Changed `’embark’` to split modules`coreProcess` and `loggerApi`.

*engine.js*
- Changed `’embark’` to split modules`coreProcess` and `loggerApi`.
This commit is contained in:
emizzle 2018-10-10 10:15:39 +11:00 committed by Pascal Precht
parent 0760965bda
commit d4d7e3b8ac
No known key found for this signature in database
GPG Key ID: 0EE28D8D6FD85D7D
8 changed files with 113 additions and 80 deletions

View File

@ -11,6 +11,10 @@ class EmbarkController {
constructor(options) {
this.version = version;
this.options = options || {};
// set a default context. should be overwritten by an action
// method before being used
this.context = [constants.contexts.any];
}
initConfig(env, options) {
@ -126,7 +130,8 @@ class EmbarkController {
}
engine.startService("processManager");
engine.startService("embark");
engine.startService("coreProcess");
engine.startService("loggerApi");
engine.startService("serviceMonitor");
engine.startService("libraryManager");
engine.startService("codeRunner");

View File

@ -34,17 +34,19 @@ class Console extends Component {
getProcessLogs(processName){
const log = this.props.processLogs
.reverse()
.filter((item) => item.process === processName);
.filter(item => item.process === processName);
if(!log.length) return [];
//should be only one item in the array
// the selector should have reduced `processLogs` down to one
// record per process, and therefore after filtering, the array
// should have only one item
return log[0].logs;
}
renderCommandsResult(){
const {commands} = this.props;
return (
this.state.selectedProcess === this.DEFAULT_PROCESS &&
this.state.selectedProcess === DEFAULT_PROCESS &&
commands.map((command, index) => {
return <CommandResult key={index} result={command.result}/>;
})
@ -55,8 +57,8 @@ class Console extends Component {
const {processes} = this.props;
return processes
.sort((a, b) => { // ensure the "Embark" tab is displayed first
if (a.name === this.DEFAULT_PROCESS) return -1;
if (b.name === this.DEFAULT_PROCESS) return 1;
if (a.name === DEFAULT_PROCESS) return -1;
if (b.name === DEFAULT_PROCESS) return 1;
return 0;
})
.map(process => (

View File

@ -52,5 +52,8 @@
},
"codeGenerator": {
"gasLimit": 6000000
},
"logs": {
"logPath": ".embark/logs/"
}
}

View File

@ -79,7 +79,8 @@ class Engine {
"testRunner": this.testRunnerService,
"codeCoverage": this.codeCoverageService,
"scaffolding": this.scaffoldingService,
"embark": this.embarkService
"coreProcess": this.coreProcessService,
"loggerApi": this.loggerApiService
};
let service = services[serviceName];
@ -93,9 +94,14 @@ class Engine {
return service.apply(this, [options]);
}
embarkService(_options){
this.registerModule('embark', {
events: this.events,
coreProcessService(_options){
this.registerModule('core_process', {
events: this.events
});
}
loggerApiService(_options){
this.registerModule('logger_api', {
logger: this.logger
});
}

View File

@ -1,6 +1,10 @@
require('colors');
let fs = require('./fs.js');
const date = require('date-and-time');
const constants = require('../constants');
const DATE_FORMAT = 'YYYY-MM-DD HH:mm:ss:SSS';
const LOG_REGEX = /\[(?<date>\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d:\d\d\d)\] (?:\[(?<logLevel>\w*)\]:?)?\s?\s?(?<msg>.*)/gmi;
class Logger {
constructor(options) {
@ -10,17 +14,52 @@ class Logger {
this.logFunction = options.logFunction || console.log;
this.logFile = options.logFile;
this.context = options.context;
this.dateFormat = 'YYYY-MM-DD HH:mm:ss:SSS';
this.logRegex = /\[(?<date>\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d:\d\d\d)\] (?:\[(?<logLevel>\w*)\]:?)?\s?\s?(?<msg>.*)/gmi;
// Use a default logFile if none is specified in the cli,
// in the format .embark/logs/embark_<context>.log.
if (!this.logFile) {
this.logFile = fs.dappPath(`.embark/logs/embark_${this.context}.log`);
this.logFile = fs.dappPath(`${constants.logs.logPath}embark_${this.context}.log`);
// creates log dir if it doesn't exist, and overwrites existing log file if it exists
fs.outputFileSync(this.logFile, '');
}
}
/**
* Parses the logFile, returning an array of JSON objects containing the
* log messages.
* @param {Number} limit specifies how many log messages to return from the
* end of the log file
* @returns {Array} array containing
* - msg: the log message
* - logLevel: log level (ie 'info', 'debug')
* - name: process name (always "embark")
* - timestamp: timestamp of log message (milliseconds since 1/1/1970)
*/
parseLogFile(limit) {
let matches;
let logs = [];
const logFile = fs.readFileSync(this.logFile, 'utf8');
while ((matches = LOG_REGEX.exec(logFile)) !== null) {
// This is necessary to avoid infinite loops with zero-width matches
if (matches.index === LOG_REGEX.lastIndex) {
LOG_REGEX.lastIndex++;
}
if (matches && matches.groups) {
logs.push({
msg: [matches.groups.msg],
logLevel: matches.groups.logLevel,
name: 'embark',
timestamp: date.parse(matches.groups.date, DATE_FORMAT).getTime()
});
}
}
// if 'limit' is specified, get log lines from the end of the log file
if(limit && logs.length > limit){
logs.slice(limit * -1);
}
return logs;
};
}
Logger.logLevels = {
@ -46,41 +85,8 @@ Logger.prototype.registerAPICall = function (plugins) {
);
};
/**
* Parses the logFile, returning an array of JSON objects containing the
* log messages.
*
* @returns {Array} array containing
* - msg: the log message
* - logLevel: log level (ie 'info', 'debug')
* - name: process name (always "embark")
* - timestamp: timestamp of log message (milliseconds since 1/1/1970)
*/
Logger.prototype.parseLogFile = function () {
let matches;
let logs = [];
const logFile = fs.readFileSync(this.logFile, 'utf8');
while ((matches = this.logRegex.exec(logFile)) !== null) {
// This is necessary to avoid infinite loops with zero-width matches
if (matches.index === this.logRegex.lastIndex) {
this.logRegex.lastIndex++;
}
if(matches && matches.groups){
logs.push({
msg: [matches.groups.msg],
logLevel: matches.groups.logLevel,
name: 'embark',
timestamp: date.parse(matches.groups.date, this.dateFormat).getTime()
});
}
}
return logs;
};
Logger.prototype.writeToFile = function (_txt) {
const formattedDate = [`[${date.format(new Date(), this.dateFormat)}]`]; // adds a timestamp to the logs in the logFile
const formattedDate = [`[${date.format(new Date(), DATE_FORMAT)}]`]; // adds a timestamp to the logs in the logFile
fs.appendFileSync(this.logFile, "\n" + formattedDate.concat(Array.from(arguments)).join(' '));
};
@ -89,7 +95,7 @@ Logger.prototype.error = function () {
return;
}
this.events.emit("log", "error", ...arguments);
this.logFunction(...Array.from(arguments).map(t => { return t ? t.red : t; }));
this.logFunction(...Array.from(arguments).map(t => {return t ? t.red : t;}));
this.writeToFile("[error]: ", ...arguments);
};
@ -98,7 +104,7 @@ Logger.prototype.warn = function () {
return;
}
this.events.emit("log", "warn", ...arguments);
this.logFunction(...Array.from(arguments).map(t => { return t ? t.yellow : t; }));
this.logFunction(...Array.from(arguments).map(t => {return t ? t.yellow : t;}));
this.writeToFile("[warning]: ", ...arguments);
};
@ -107,7 +113,7 @@ Logger.prototype.info = function () {
return;
}
this.events.emit("log", "info", ...arguments);
this.logFunction(...Array.from(arguments).map(t => { return t ? t.green : t; }));
this.logFunction(...Array.from(arguments).map(t => {return t ? t.green : t;}));
this.writeToFile("[info]: ", ...arguments);
};

View File

@ -0,0 +1,20 @@
class CoreProcess {
constructor(embark) {
this.embark = embark;
this.events = embark.events;
this.registerProcess();
}
// Register 'embark' as a process
registerProcess() {
this.events.request('processes:register', 'embark', (setRunning) => {
// on 'outputDone', set 'embark' process to 'running'
this.events.on('outputDone', setRunning);
});
// set 'embark' process to 'starting'
this.events.request('processes:launch', 'embark', () => {});
}
}
module.exports = CoreProcess;

View File

@ -1,29 +0,0 @@
class Embark {
constructor(embark) {
this.embark = embark;
this.logger = embark.logger;
this.events = embark.events;
this.registerProcess();
this.registerAPICalls();
}
registerProcess() {
this.events.request('processes:register', 'embark', (setRunning) => {
this.events.on('outputDone', setRunning);
});
this.events.request('processes:launch', 'embark', () => {});
}
registerAPICalls(){
this.embark.registerAPICall(
'get',
'/embark-api/process-logs/embark',
(req, res) => {
res.send(this.logger.parseLogFile());
}
);
}
}
module.exports = Embark;

View File

@ -0,0 +1,20 @@
class LoggerApi {
constructor(embark) {
this.embark = embark;
this.logger = embark.logger;
this.registerAPICalls();
}
registerAPICalls(){
this.embark.registerAPICall(
'get',
'/embark-api/process-logs/embark',
(req, res) => {
res.send(this.logger.parseLogFile(req.query.limit));
}
);
}
}
module.exports = LoggerApi;