Skip to content

Ousman/front end changes #12

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Dec 31, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .DS_Store
Binary file not shown.
105 changes: 70 additions & 35 deletions Main.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const { app, BrowserWindow, ipcMain } = require('electron');
//node requirements
const { dialog, app, BrowserWindow, ipcMain } = require('electron');
const fs = require('fs');
const path = require('path');
const connectSQL = require('./model/sql-connect');
Expand All @@ -8,132 +9,166 @@ const HealthInfoSchema = require('./model/mongoose-healthInfoSchema');

//declare a variable pool for SQL connection
let pool;

//declare win variable ---> Ousman
let win;

//declaring a createWindow function ---> Ousman
function createWindow() {
//assign win to an instance of a new browser window.
win = new BrowserWindow({
//giving our window its width
width: 900,
//giving our window its hieght
height: 800,
//specify the path of the icon -- Which icon is this?.. note too tsure --> Ousman
icon: path.join(__dirname, 'app/assets/icons/icon.png'),
//enable node inegreation --> node intgeration, default is usally false --> Ousman
webPreferences: {
nodeIntegration: true,
},
});

// Development
//loads our application window to localHost 8080, application will not render without this loadUrl --> Ousman
win.loadURL('http://localhost:8080/');

// Production
// win.loadURL(`file://${path.join(__dirname, './dist/index.html')}`);


//assign window to null on close
win.on('closed', () => {
win = null;
});
}

//invoke createWindow function on Electron application load --> Ousman
app.on('ready', createWindow);

// quits the application when all windows are closed --> Ousman
app.on('window-all-closed', () => {
//process platform is a property that return a string identifying the OS platform on which NodeJs process is running --> Ousman
if (process.platform !== 'darwin') {
//quits application
app.quit();
}
});

//event 'activate' emmitted upon application starting
app.on('activate', () => {
//if there is no window present invoke the create window function --> Ousman
if (win === null) {
createWindow();
}
});

// Load settings JSON and returns current setup status back to the render process.
//ipc 'setup' route --> Ousman
ipcMain.on('setup', (message) => {
//assigns state to the returned the object returned from settings.json --> Ousman
const state = JSON.parse(
//read json from settings.json
fs.readFileSync(path.resolve(__dirname, './user/settings.json'), {
encoding: 'UTF-8',
}),
);
const { setupRequired } = state;
//destructure setupRequired from state constant ---> Ousman
const { setupRequired } = state;
//assigning message object a property of return value and assigning it the setupRequired from state destructuring --> Ousman
message.returnValue = setupRequired;
});

// Loads existing settings JSON and update settings to include new services entered by the user.
//on ipc 'submit' request --> Ousman
ipcMain.on('submit', (message, newService) => {
// set the variable 'state' to the contents of /user/settings.json
// contents => "setupRequired" (boolean),"services" (Array)
// setupRequired- toggle the page for adding database
// services - name of DB stores dbType, and uri
//assigning state to the parsed return of setting
const state = JSON.parse(
fs.readFileSync(path.resolve(__dirname, './user/settings.json'), {
encoding: 'UTF-8',
}),
);
// if statement is used to replace hard coded data. Hard coded data is needed to avoid a load error caused by Electron querying the database before a user has added or selected a database.
// if statement is used to replace hard coded data. Hard coded data and the michelleWasHere key is needed to avoid a load error caused by Electron querying the database before a user has added or selected a database.

//*** What is happening here --> Ousman */
if (state.setupRequired) {
state.setupRequired = false;
state.services = [JSON.parse(newService)];
//is updating the /user/settings.json file with the first new service
fs.writeFileSync(path.resolve(__dirname, './user/settings.json'), JSON.stringify(state));
} else {
//what is the new service?
state.setupRequired = false;
state.services.push(JSON.parse(newService));
//is updating the /user/settings.json file with the new service
fs.writeFileSync(path.resolve(__dirname, './user/settings.json'), JSON.stringify(state));
}
});

// Load settings JSON and returns updated state back to the render process.
//on ipc 'dashboard' request --> Ousman
ipcMain.on('dashboard', (message) => {
//assign state to the parsed return of setting --> Ousman
const state = JSON.parse(
fs.readFileSync(path.resolve(__dirname, './user/settings.json'), {
encoding: 'UTF-8',
}),
);
//getting the array of databases [name, dbType, uri]
//destructure services from state... what is services? --> Ousman
const { services } = state;
//creates an array of the database names
const dashboardList = services.reduce((acc, curVal) => {
acc.push(curVal[0]);
return acc;
}, []);
//returns the array of the database names
message.returnValue = dashboardList;
});

// Queries the database for communications information and returns it back to the render process.
ipcMain.on('overviewRequest', (message, index) => {
//acquires the services from user settings.json file
const services = JSON.parse(
fs.readFileSync(path.resolve(__dirname, './user/settings.json'), { encoding: 'UTF-8' }),
).services
).services;

const databaseType = services[index][1];
const URI = services[index][2];

if (databaseType === 'MongoDB') {
connectMongoose(index,URI);
connectMongoose(index, URI);
CommunicationSchema.find({}, (err, data) => {
if (err) {
console.log(`An error occured while querying the database: ${err}`);
return message.sender.send('overviewResponse', JSON.stringify(err));
}
//queryResults is an array of objects with the following keys {"_id","currentMicroservice","targetedEndpoint","reqType","timeSent","resStatus","resMessage","__v"}
const queryResults = JSON.stringify(data);
message.sender.send('overviewResponse', JSON.stringify(err));
}

const queryResults = JSON.stringify(data);
// Asynchronous event emitter used to transmit query results back to the render process.
message.sender.send('overviewResponse', queryResults);


// Asynchronous event emitter used to transmit query results back to the render process.
return message.sender.send('overviewResponse', queryResults);
});
}

if (databaseType === 'SQL') {
pool = connectSQL(index,URI);
pool = connectSQL(index, URI);
const getCommunications = 'SELECT * FROM communications';
pool.query(getCommunications, (err, result) => {
if (err) {
return message.sender.send(JSON.stringify('Database info could not be retrieved.'));

//error object to log to Electron GUI ---> Ousman
const errorAlert = {
type: "error",
title: "Error in Main process",
message: "Database information could not be retreived. Check that table exists."
};

//after requiring dialog in the topmost section of main. We invoke the method showMessagebox passing the error object we created --> Ousman
dialog.showMessageBox(errorAlert);


message.sender.send(JSON.stringify('Database info could not be retreived.'));

} else {
console.log('Connected to SQL Database')
const queryResults = JSON.stringify(result.rows);
// Asynchronous event emitter used to transmit query results back to the render process.
message.sender.send('overviewResponse', queryResults);
}
console.log('Connected to SQL Database')
//queryResults is an array of objects with the following keys {"id","currentmicroservice","targetedendpoint","reqtype","resstatus","resmessage","timesent"}
const queryResults = JSON.stringify(result.rows);
// Asynchronous event emitter used to transmit query results back to the render process.
return message.sender.send('overviewResponse', queryResults);
});
}
});
Expand All @@ -145,27 +180,27 @@ ipcMain.on('detailsRequest', (message, index) => {
).services[index][1];

if (databaseType === 'MongoDB') {
connectMongoose(index);
HealthInfoSchema.find({}, (err, data) => {
if (err) {
message.sender.send('detailsResponse', JSON.stringify(err));
}
const queryResults = JSON.stringify(data);
// Asynchronous event emitter used to transmit query results back to the render process.
return message.sender.send('detailsResponse', queryResults);
message.sender.send('detailsResponse', queryResults);
});
}

if (databaseType === 'SQL') {

// const pool = connectSQL(index);
const pool = connectSQL(index);
const getHealth = 'SELECT * FROM healthInfo';
pool.query(getHealth, (err, result) => {
if (err) {
message.sender.send('detailsResponse', JSON.stringify('Database info could not be retreived.'));
}
const queryResults = JSON.stringify(result.rows);
// Asynchronous event emitter used to transmit query results back to the render process.
return message.sender.send('detailsResponse', queryResults);
message.sender.send('detailsResponse', queryResults);
});
}
});
114 changes: 51 additions & 63 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,88 +1,76 @@
# Chronos
Chronos consists of an NPM package to be required into a user’s microservices that intercepts all http and gRPC microservice communications, as well as monitors the health of each microservice over time. This information is written to a user-owned database (PostgreSQL or NoSQL) where it is queried and rendered by the frontend utilizing Node in conjunction with a native, cross-platform Electron desktop application with React components to ensure agreement between the frontend and database.
## Chronos Microservice Debugger
Chronos Microservice Debugger consists of an npm package with an optional Electron front end to visualize information collected through use of npm package.

## Why was Chronos created?
As companies grow larger and begin to scale, they have a tendency to move from a monolithic code architecture and microservices and distributed systems architecture in order to build faster, more maintainable code.

The process of modularizing a code bases and breaking a monolith into individual services can be a daunting task. How do you break apart and re-connect these services? There is often a transitional period where valuable time is spent debugging these connections between services.

Chronos is deigned to meet the needs of companies and developers working to break down their monoliths into distributed systems by combining an NPM package together with an Electron application to monitor and assist in the debugging of their services.

## How to Install Chronos
The Chronos-Microservice-Debugger Express Middleware can be found on npm: https://www.npmjs.com/package/chronos-microservice-debugger

To install the NPM package:
## Install
```javascript
npm install chronos-microservice-debugger
npm install chronos-microservice-debugger3
```

The Chronos Electron application is in progress and will soon be availble for public download for all platforms. Please stay tuned.

## How to Use Chronos
## Usage
There are two main aspects to Chronos-Microservice-Debugger
1. Communication Monitor: Listens in on all microservice-microservice and microservice-client communication and monitors the response statuses and messages to ensure communications are making it to the correct destination successfully.
2. Health Monitor: The health monitor checks the status of your microservice every second and sends this health information to an optional electron frontend where it is visualized for easier use.

To use the npm package, there are three required parameters and an optional fourth parameter. You can enter the items as individual strings or as an array containing the three required parameters and one optional parameter.
2. Health Monitor: The health monitor checks the status of your microservice every second and sends this health information to an optional electron frontend where it is visualized for easier use.
To use the npm package, there are four required parameters and an optional fifth parameter. You can enter the items as individual strings or as an array containing the three required parameters and one optional parameter.

The parameters are:
1. microserviceName: What do you want to name the current microservice
2. databaseType: We currently support PostgreSQL and Mongo. Enter "mongo" or "sql"
2. databaseType: We currently support PostgreSQL and Mongo. Enter mongo or sql
3. databaseURL: Where would you like to store your information? Enter the URL to your database
4. queryFrequency: How often do you want microHealth to monitor the health of your database? It defaults to every second, but you can choose:
* "s" : The default, monitors every second
* "m" : Monitors every minute
* "h" : Monitors every hour
* "d" : Monitors once per day
* "w" : Monitors once per week

4. wantMicroHealth: Do you want the microHealth of your microservice to be monitor? Enter “yes” or “no”
5. queryFrequency: How often do you want microHealth to monitor the health of your database? It defaults to every minute, but you can choose:
* “s” : Monitors every second
* “m” : The default, monitors every minute
* “h” : Monitors every hour
* “d” : Monitors once per day
* “w” : Monitors once per week

String parameter example:
```javascript
// How to use chronos-microservice-debugger
app.use('/', chronos-microservice-debgugger.microCom('microserviceName', 'databaseType', 'databaseURL'))

chronos-microservice-debugger.microHealth('microserviceName', 'databaseType', 'databaseURL', 'queryFrequency'))

// How to use chronos-microservice-debugger3
// Place the following two lines before requiring express
const cmd = require(‘chronos-microservice-debugger3’);
cmd.propagate();
// Place the following line of code before the microservice re-routes the request (for string parameters)
app.use(‘/’, cmd.microCom(‘microserviceName’, ‘databaseType’, ‘databaseURL’,‘wantMicroHealth’,‘queryFrequency’))
// Or place the following line of code before the microservice re-routes the request (for array parameter)
app.use(‘/’, cmd.microCom([‘microserviceName’, ‘databaseType’, ‘databaseURL’,‘wantMicroHealth’,‘queryFrequency’]))
// Example using string parameters
app.use('/', chronos-microservice-debugger.microCom('books', 'sql', 'thisIsMyURL'))
// Note: microCom does not utilize queryFreq because it logs all communication when an endpoint is hit

chronos-microservice-debugger.microHealth('books', 'sql', 'thisIsMyURL', 'h')
app.use(‘/’, cmd.microCom(‘books’, ‘sql’, ‘thisIsMyURL’,‘yes’, ‘m’))
```

Array parameter example:
```javascript
let values = [
'microserviceName',
'databaseType',
'databaseURL',
'queryFrequency'
‘microserviceName’,
‘databaseType’,
‘databaseURL’,
‘wantMicroHealth’,
‘queryFrequency’
]
// How to use chronos-micrservice-debugger with an array parameter
app.use('/', chronos-microservice-debgugger.microCom(values)

chronos-microservice-debugger.microHealth(values)

// How to use chronos-micrservice-debugger2 with an array parameter
app.use(‘/’, cmd.microCom(values)
// Example using an array parameter
let values = [
'books',
'mongo',
'thisIsMyNewURL',
'w'
‘books’,
‘mongo’,
‘thisIsMyNewURL’,
‘yes’,
‘w’
]
app.use(‘/’, cmd.microCom(values)
```
Chronos uses a user-owned and provided database to ensure that your private data stays private. We currently support MongoDB and SQL/PostgreSQL databases.

app.use('/', chronos-microservice-debgugger.microCom(values)
// Note: microCom does not utilize queryFreq because it logs all communication when an endpoint is hit

chronos-microservice-debugger.microHealth(values)
## Things in the Works
1. gRPC support
3. ‘Time Travel’ to see how your microservices have changed over time
4. Docker health information for containerized microservices
5. Implement additional unit testing
6. Published Electron application with cross-browser compatibility
7. Microservice Architecture Visualizer

```
## Links
1. Gitub Page: https://github.com/Chronos2-0/Chronos

## How to Contribute to Chronos
Chronos hopes to inspire an active community of both users and developers. For questions, comments, suggestions, please contact us at teammicronos@gmail.com or submit a pull request.
## Contact Us
For questions, requests, or more information, please contact us at chronosjobtc@gmail.com

## Created By
* Duane McFarlane
* Michelle Herrera
* Mohtasim Chowdhury
* Natalie Umanzor
Binary file added app/.DS_Store
Binary file not shown.
Binary file removed app/assets/pieChart.png
Binary file not shown.
2 changes: 1 addition & 1 deletion app/charts/latency-chart.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { useContext } from 'react';
import { Line } from 'react-chartjs-2';
import HealthContext from '../context/DetailsContext';

const LatencyChart = (props) => {
const LatencyChart = (props) => {
const xAxis = [];
const yAxis = [];
const healthData = useContext(HealthContext).detailData;
Expand Down
2 changes: 2 additions & 0 deletions app/charts/response-code-chart.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import CommunicationsContext from '../context/OverviewContext';

const ResponseCodeChart = (props) => {
const communicationsData = useContext(CommunicationsContext).overviewData;



const createChart = () => {
const responseCodes = {
Expand Down
Loading