From cb6596b8be1df79642867b040cef8862d8bd0328 Mon Sep 17 00:00:00 2001 From: Nilanshu Date: Mon, 5 Apr 2021 09:53:57 +0530 Subject: [PATCH] [WIP] node js performance monitor --- dashboard/public/assets/css/newdashboard.css | 13 +- .../src/actions/performanceMonitoring.js | 17 + .../components/basic/DateTimeRangePicker.js | 12 +- .../src/components/basic/performanceChart.js | 162 + .../src/components/modals/CreateIncident.js | 4 +- dashboard/src/components/nav/SideNav.js | 5 +- .../performanceMonitor/ChartComponent.js | 213 + .../performanceMonitor/PerformanceView.js | 262 + .../WebTransactionsChart.js | 49 + dashboard/src/pages/PerformanceMonitoring.js | 173 + dashboard/src/pages/index.js | 2 + dashboard/src/reducers/index.js | 2 + .../src/reducers/performanceMonitoring.js | 31 + dashboard/src/routes.js | 17 +- js-sdk/package-lock.json | 31171 ++++++++-------- js-sdk/src/index.js | 3 +- js-sdk/src/performanceMonitor.js | 89 + js-sdk/src/utils/incomingListener.js | 56 + js-sdk/src/utils/mongoose.js | 59 + js-sdk/webpack.config.js | 1 + probe/package-lock.json | 14792 ++++---- 21 files changed, 24538 insertions(+), 22595 deletions(-) create mode 100644 dashboard/src/actions/performanceMonitoring.js create mode 100644 dashboard/src/components/basic/performanceChart.js create mode 100644 dashboard/src/components/performanceMonitor/ChartComponent.js create mode 100644 dashboard/src/components/performanceMonitor/PerformanceView.js create mode 100644 dashboard/src/components/performanceMonitor/WebTransactionsChart.js create mode 100644 dashboard/src/pages/PerformanceMonitoring.js create mode 100644 dashboard/src/reducers/performanceMonitoring.js create mode 100644 js-sdk/src/performanceMonitor.js create mode 100644 js-sdk/src/utils/incomingListener.js create mode 100644 js-sdk/src/utils/mongoose.js diff --git a/dashboard/public/assets/css/newdashboard.css b/dashboard/public/assets/css/newdashboard.css index f1513362ee..3dd03fb7aa 100755 --- a/dashboard/public/assets/css/newdashboard.css +++ b/dashboard/public/assets/css/newdashboard.css @@ -16,7 +16,14 @@ min-width: 250px; font-size: 14px; } - +.db-select-in { + width: 150px; + font-size: 14px; +} +.db-select-in-flexible { + min-width: 150px; + font-size: 14px; +} .db-select-ne { width: 120px; font-size: 14px; @@ -42,6 +49,7 @@ .db-select-nw > div, .db-select-ne > div, .db-select-pr > div, +.db-select-in > div, .db-select-nw-300 > div { -webkit-flex-flow: unset; -ms-flex-flow: unset; @@ -50,7 +58,8 @@ } .db-select-nw > span + div, -.db-select-pr > span + div { +.db-select-pr > span + div, +.db-select-in > span + div { border: none; box-shadow: 0 0 0 1px rgba(50, 50, 93, 0), 0 0 0 1px rgba(50, 151, 211, 0.2), 0 0 0 2px rgba(50, 151, 211, 0.25), 0 1px 1px rgba(0, 0, 0, 0.08); diff --git a/dashboard/src/actions/performanceMonitoring.js b/dashboard/src/actions/performanceMonitoring.js new file mode 100644 index 0000000000..e7f3431529 --- /dev/null +++ b/dashboard/src/actions/performanceMonitoring.js @@ -0,0 +1,17 @@ +export function setStartDate(date) { + return function(dispatch) { + dispatch({ + type: 'SET_START_DATE', + payload: date, + }); + }; +} + +export function setEndDate(date) { + return function(dispatch) { + dispatch({ + type: 'SET_END_DATE', + payload: date, + }); + }; +} diff --git a/dashboard/src/components/basic/DateTimeRangePicker.js b/dashboard/src/components/basic/DateTimeRangePicker.js index 3ef92afb76..c7add4aa2d 100644 --- a/dashboard/src/components/basic/DateTimeRangePicker.js +++ b/dashboard/src/components/basic/DateTimeRangePicker.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useEffect, useState } from 'react'; import { connect } from 'react-redux'; import PropTypes from 'prop-types'; import originalMoment from 'moment'; @@ -16,9 +16,13 @@ function DateTimeRangePicker({ style, }) { const currentDate = moment(); + const [key, setkey] = useState(0); + useEffect(() => { + setkey(key + 1); + }, [currentDateRange.startDate, currentDateRange.endDate]); return (
-
+
{ + if (active) { + return ( +
+ {payload[0].payload.name ? ( + <> +

{payload[0].payload.name}

+

{`${payload[0].name} : ${payload[0].payload.display}`}

+ + ) : ( +

No data available

+ )} +
+ ); + } + + return null; +}; + +CustomTooltip.displayName = 'CustomTooltip'; + +CustomTooltip.propTypes = { + active: PropTypes.bool, + payload: PropTypes.array, +}; + +class PerformanceChart extends Component { + calcPercent = (val, total) => { + val = parseFloat(val); + total = parseFloat(total); + + if (isNaN(val) || isNaN(total)) { + return 0; + } + if (!total || total === 0) { + return 0; + } + if (!val || val === 0) { + return 0; + } + + return (val / total) * 100; + }; + + parseDate(a) { + return new Date(a).toLocaleString(); + } + getTime(a) { + return moment(a).format('LT'); + } + render() { + const { type, data, name, symbol, requesting } = this.props; + let processedData = [{ display: '', name: '', v: '' }]; + if (requesting) { + return ( +
+
+ {' '} + + We're currently in the process of collecting data + for this monitor.
+ More info will be available in few minutes +
+
+ ); + } + if (data && data.length > 0) { + processedData = data.map(a => { + return { + name: a.intervalDate || this.parseDate(a.createdAt), + v: a.value, + display: `${Math.round(a.value || 0)} ${symbol || 'ms'}`, + xData: a.createdAt, + }; + }); + } + return ( + + + } /> + + + + + + + ); + } +} + +PerformanceChart.displayName = 'PerformanceChart'; + +PerformanceChart.propTypes = { + data: PropTypes.array, + type: PropTypes.string.isRequired, + name: PropTypes.string, + symbol: PropTypes.string, + requesting: PropTypes.bool, +}; + +function mapStateToProps(state) { + return { + requesting: state.monitor.fetchMonitorLogsRequest, + }; +} + +export default connect(mapStateToProps)(PerformanceChart); diff --git a/dashboard/src/components/modals/CreateIncident.js b/dashboard/src/components/modals/CreateIncident.js index a98a74c4f1..e6ac21977b 100755 --- a/dashboard/src/components/modals/CreateIncident.js +++ b/dashboard/src/components/modals/CreateIncident.js @@ -363,9 +363,7 @@ class CreateIncident extends Component { ]} onChange={( event, - newValue, - previousValue, - name + newValue ) => { this.substituteVariables( newValue, diff --git a/dashboard/src/components/nav/SideNav.js b/dashboard/src/components/nav/SideNav.js index abe0c23587..90b44fcda1 100755 --- a/dashboard/src/components/nav/SideNav.js +++ b/dashboard/src/components/nav/SideNav.js @@ -186,7 +186,10 @@ class SideNav extends Component { /project\/([A-Za-z0-9-]+)\/([A-Za-z0-9-]+)\/error-tracker/ ) || location.pathname.match( - /project\/([A-Za-z0-9-]+)\/([A-Za-z0-9-]+)\/settings\/basic/ + /project\/([A-Za-z0-9-]+)\/([0-9]|[a-z])*\/performance-monitor/ + ) || + location.pathname.match( + /project\/([A-Za-z0-9-]+)\/([0-9]|[a-z])*\/settings\/basic/ ) || location.pathname.match( /project\/([A-Za-z0-9-]+)\/([A-Za-z0-9-]+)\/settings\/advanced/ diff --git a/dashboard/src/components/performanceMonitor/ChartComponent.js b/dashboard/src/components/performanceMonitor/ChartComponent.js new file mode 100644 index 0000000000..313dde3f0d --- /dev/null +++ b/dashboard/src/components/performanceMonitor/ChartComponent.js @@ -0,0 +1,213 @@ +import PropTypes from 'prop-types'; +import React, { Component, Fragment } from 'react'; +import { bindActionCreators } from 'redux'; +import { connect } from 'react-redux'; +import { setStartDate, setEndDate } from '../../actions/performanceMonitoring'; +import PerformanceChart from '../basic/performanceChart'; +import DateTimeRangePicker from '../basic/DateTimeRangePicker'; +import moment from 'moment'; +//import ShouldRender from '../../components/basic/ShouldRender'; + +export class ChartComponent extends Component { + render() { + const { + heading, + title, + subHeading, + startDate, + endDate, + setStartDate, + setEndDate, + } = this.props; + const status = { + display: 'inline-block', + borderRadius: '2px', + height: '8px', + width: '8px', + margin: '0 8px 1px 0', + backgroundColor: 'rgb(117, 211, 128)', + }; + return ( +
+
+
+
+
+ + {heading} + +

+ {subHeading} +

+
+
+ + setStartDate(moment(val)) + } + handleEndDateTimeChange={val => + setEndDate(moment(val)) + } + formId={`performanceMonitoringDateTime-${heading}`} + /> +
+
+
+
+ +
+ + 1.5 ms + +
+
+
+
+
+
+ + App Server + +
+
+
+
+
+
+
+
+
+
+ +
+
+
+ {title.map((t, i) => ( + + + + {t} + + +       + + + ))} +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ); + } +} + +ChartComponent.displayName = 'ChartComponent'; + +ChartComponent.propTypes = { + endDate: PropTypes.any, + heading: PropTypes.any, + setEndDate: PropTypes.any, + setStartDate: PropTypes.any, + startDate: PropTypes.any, + subHeading: PropTypes.any, + title: PropTypes.shape({ + map: PropTypes.func, + }), +}; + +const mapDispatchToProps = dispatch => + bindActionCreators({ setStartDate, setEndDate }, dispatch); + +function mapStateToProps(state) { + return { + currentProject: state.project.currentProject, + startDate: state.performanceMonitoring.dates.startDate, + endDate: state.performanceMonitoring.dates.endDate, + }; +} + +export default connect(mapStateToProps, mapDispatchToProps)(ChartComponent); diff --git a/dashboard/src/components/performanceMonitor/PerformanceView.js b/dashboard/src/components/performanceMonitor/PerformanceView.js new file mode 100644 index 0000000000..bb0913d337 --- /dev/null +++ b/dashboard/src/components/performanceMonitor/PerformanceView.js @@ -0,0 +1,262 @@ +import React, { Component } from 'react'; +import { bindActionCreators } from 'redux'; +import { connect } from 'react-redux'; +import PropTypes from 'prop-types'; +import { getMonitorLogs } from '../../actions/monitor'; +//import MonitorLogsList from '../monitor/MonitorLogsList'; +import Select from '../../components/basic/react-select-fyipe'; +//import ShouldRender from '../../components/basic/ShouldRender'; +//import DateTimeRangePicker from '../basic/DateTimeRangePicker'; +//import moment from 'moment'; + +//const endDate = moment(); +//const startDate = moment().subtract(30, 'd'); +export class PerformanceView extends Component { + /* constructor(props) { + super(props); + this.props = props; + this.state = { + probeValue: { value: '', label: 'All Probes' }, + startDate: startDate, + endDate: endDate, + page: 1, + }; + } + + prevClicked = (monitorId, skip, limit) => { + const { currentProject, getMonitorLogs } = this.props; + const incidentId = this.props.incidentId ? this.props.incidentId : null; + const start = incidentId ? '' : this.state.startDate.clone().utc(); + const end = incidentId ? '' : this.state.endDate.clone().utc(); + getMonitorLogs( + currentProject._id, + monitorId, + skip ? parseInt(skip, 10) - 10 : 10, + limit, + start, + end, + this.state.probeValue.value, + incidentId, + this.props.monitorType + ); + this.setState({ page: this.state.page - 1 }); + if (window.location.href.indexOf('localhost') <= -1) { + this.context.mixpanel.track('Previous Incident Requested', { + projectId: currentProject._id, + }); + } + }; + + nextClicked = (monitorId, skip, limit) => { + const { currentProject, getMonitorLogs } = this.props; + const incidentId = this.props.incidentId ? this.props.incidentId : null; + const start = incidentId ? '' : this.state.startDate.clone().utc(); + const end = incidentId ? '' : this.state.endDate.clone().utc(); + getMonitorLogs( + currentProject._id, + monitorId, + skip ? parseInt(skip, 10) + 10 : 10, + limit, + start, + end, + this.state.probeValue.value, + incidentId, + this.props.monitorType + ); + this.setState({ page: this.state.page + 1 }); + if (window.location.href.indexOf('localhost') <= -1) { + this.context.mixpanel.track('Next Incident Requested', { + projectId: currentProject._id, + }); + } + }; + handleStartDateTimeChange = val => { + const startDate = moment(val); + this.handleDateChange(startDate, this.state.endDate); + }; + handleEndDateTimeChange = val => { + const endDate = moment(val); + this.handleDateChange(this.state.startDate, endDate); + }; + + handleDateChange = (startDate, endDate) => { + const { currentProject, getMonitorLogs, monitorId } = this.props; + this.setState({ + startDate, + endDate, + }); + getMonitorLogs( + currentProject._id, + monitorId, + 0, + 10, + startDate.clone().utc(), + endDate.clone().utc(), + this.state.probeValue.value, + null, + this.props.monitorType + ); + }; + + handleTimeChange = (startDate, endDate) => { + const { currentProject, getMonitorLogs, monitorId } = this.props; + getMonitorLogs( + currentProject._id, + monitorId, + 0, + 10, + startDate.clone().utc(), + endDate.clone().utc(), + this.state.probeValue.value, + null, + this.props.monitorType + ); + }; + + handleProbeChange = data => { + this.setState({ probeValue: data }); + const { currentProject, getMonitorLogs, monitorId } = this.props; + getMonitorLogs( + currentProject._id, + monitorId, + 0, + 10, + this.state.startDate.clone().utc(), + this.state.endDate.clone().utc(), + data.value, + null, + this.props.monitorType + ); + };*/ + + render() { + /* const probeOptions = + this.props.probes && this.props.probes.length > 0 + ? this.props.probes.map(p => { + return { value: p._id, label: p.probeName }; + }) + : []; + probeOptions.unshift({ value: '', label: 'All Probes' });*/ + return ( +
+
+
+
+ +
+ +
+
+
+ +
+