From af58d085a0914be1042b9378b2667f9c9874c5b8 Mon Sep 17 00:00:00 2001 From: Nidhi Tandon Date: Sun, 30 May 2021 19:07:37 +0530 Subject: [PATCH] feat(FE: Reducers): Combine Metrics reducers and refactor Metrics actions --- frontend/src/modules/BaseLayout.tsx | 3 +- .../src/modules/Metrics/ErrorRateChart.tsx | 4 +- .../Metrics/ExternalApi/ExternalApiGraph.tsx | 4 +- .../modules/Metrics/GenericVisualization.tsx | 2 +- .../src/modules/Metrics/LatencyLineChart.tsx | 26 +- .../src/modules/Metrics/RequestRateChart.tsx | 2 +- .../src/modules/Metrics/ServiceMetrics.tsx | 31 +- .../src/modules/Metrics/ServicesTable.tsx | 18 +- .../src/modules/Metrics/TopEndpointsTable.tsx | 2 +- frontend/src/modules/RouteProvider.tsx | 2 +- .../src/modules/Servicemap/ServiceMap.tsx | 2 +- .../Traces/TraceCustomVisualizations.tsx | 34 +-- frontend/src/modules/Usage/UsageExplorer.tsx | 8 +- .../src/store/actions/MetricsActions/index.ts | 3 + .../MetricsActions/metricsActionTypes.ts | 34 +++ .../actions/MetricsActions/metricsActions.ts | 190 ++++++++++++ .../MetricsActions/metricsInterfaces.ts | 98 +++++++ frontend/src/store/actions/index.ts | 2 +- frontend/src/store/actions/metrics.ts | 277 ------------------ frontend/src/store/actions/types.ts | 34 +-- frontend/src/store/actions/usage.ts | 1 - frontend/src/store/reducers/index.ts | 38 +-- frontend/src/store/reducers/metrics.ts | 177 ++++++----- 23 files changed, 466 insertions(+), 526 deletions(-) create mode 100644 frontend/src/store/actions/MetricsActions/index.ts create mode 100644 frontend/src/store/actions/MetricsActions/metricsActionTypes.ts create mode 100644 frontend/src/store/actions/MetricsActions/metricsActions.ts create mode 100644 frontend/src/store/actions/MetricsActions/metricsInterfaces.ts delete mode 100644 frontend/src/store/actions/metrics.ts diff --git a/frontend/src/modules/BaseLayout.tsx b/frontend/src/modules/BaseLayout.tsx index 6e3f52769e..2afa2fcac8 100644 --- a/frontend/src/modules/BaseLayout.tsx +++ b/frontend/src/modules/BaseLayout.tsx @@ -4,7 +4,6 @@ import { Layout } from "antd"; import SideNav from "./Nav/SideNav"; import TopNav from "./Nav/TopNav"; import { useLocation } from "react-router-dom"; -import ROUTES from "Src/constants/routes"; import { useRoute } from "./RouteProvider"; const { Content, Footer } = Layout; @@ -18,7 +17,7 @@ const BaseLayout: React.FC = ({ children }) => { const { dispatch } = useRoute(); useEffect(() => { - dispatch({ type: "UPDATE_IS_LOADED", payload: location.pathname }); + dispatch({ type: "ROUTE_IS_LOADED", payload: location.pathname }); }, [location]); return ( diff --git a/frontend/src/modules/Metrics/ErrorRateChart.tsx b/frontend/src/modules/Metrics/ErrorRateChart.tsx index 8740844128..fa119ea0d8 100644 --- a/frontend/src/modules/Metrics/ErrorRateChart.tsx +++ b/frontend/src/modules/Metrics/ErrorRateChart.tsx @@ -6,7 +6,7 @@ import { RouteComponentProps } from "react-router-dom"; import styled from "styled-components"; import ROUTES from "Src/constants/routes"; -import { metricItem } from "../../store/actions/metrics"; +import { metricItem } from "../../store/actions/MetricsActions"; const ChartPopUpUnique = styled.div<{ ycoordinate: number; @@ -55,7 +55,7 @@ class ErrorRateChart extends React.Component { xcoordinate: 0, ycoordinate: 0, showpopUp: false, - firstpoint_ts: 0 + firstpoint_ts: 0, // graphInfo:{} }; diff --git a/frontend/src/modules/Metrics/ExternalApi/ExternalApiGraph.tsx b/frontend/src/modules/Metrics/ExternalApi/ExternalApiGraph.tsx index 1459de5e91..b7cc2999ee 100644 --- a/frontend/src/modules/Metrics/ExternalApi/ExternalApiGraph.tsx +++ b/frontend/src/modules/Metrics/ExternalApi/ExternalApiGraph.tsx @@ -1,11 +1,9 @@ import React from "react"; import { Line as ChartJSLine } from "react-chartjs-2"; -import { ChartOptions } from "chart.js"; import { withRouter } from "react-router"; import { RouteComponentProps } from "react-router-dom"; -import styled from "styled-components"; import { getOptions, borderColors } from "./graphConfig"; -import { externalMetricsItem } from "../../store/actions/metrics"; +import { externalMetricsItem } from "../../../store/actions/MetricsActions"; import { uniqBy, filter } from "lodash"; const theme = "dark"; diff --git a/frontend/src/modules/Metrics/GenericVisualization.tsx b/frontend/src/modules/Metrics/GenericVisualization.tsx index a68d08bcf2..c35e63679e 100644 --- a/frontend/src/modules/Metrics/GenericVisualization.tsx +++ b/frontend/src/modules/Metrics/GenericVisualization.tsx @@ -2,7 +2,7 @@ import React from "react"; import { Bar, Line as ChartJSLine } from "react-chartjs-2"; import styled from "styled-components"; -import { customMetricsItem } from "../../store/actions/metrics"; +import { customMetricsItem } from "../../store/actions/MetricsActions"; const GenVisualizationWrapper = styled.div` height: 160px; diff --git a/frontend/src/modules/Metrics/LatencyLineChart.tsx b/frontend/src/modules/Metrics/LatencyLineChart.tsx index daf63b43ac..eb41a28056 100644 --- a/frontend/src/modules/Metrics/LatencyLineChart.tsx +++ b/frontend/src/modules/Metrics/LatencyLineChart.tsx @@ -4,9 +4,7 @@ import { ChartOptions } from "chart.js"; import { withRouter } from "react-router"; import { RouteComponentProps } from "react-router-dom"; import styled from "styled-components"; -import ROUTES from "Src/constants/routes"; - -import { metricItem } from "../../store/actions/metrics"; +import { metricItem } from "../../store/actions/MetricsActions"; const ChartPopUpUnique = styled.div<{ ycoordinate: number; @@ -39,11 +37,8 @@ interface LatencyLineChartProps extends RouteComponentProps { popupClickHandler: Function; } -interface LatencyLineChart { - chartRef: any; -} - class LatencyLineChart extends React.Component { + private chartRef: React.RefObject; constructor(props: LatencyLineChartProps) { super(props); this.chartRef = React.createRef(); @@ -54,7 +49,6 @@ class LatencyLineChart extends React.Component { ycoordinate: 0, showpopUp: false, firstpoint_ts: 0, - // graphInfo:{} }; onClickhandler = async (e: any, event: any) => { @@ -69,7 +63,6 @@ class LatencyLineChart extends React.Component { ycoordinate: e.offsetY, showpopUp: true, firstpoint_ts: this.props.data[firstPoint._index].timestamp, - // graphInfo:{...event} }); } else { // if clicked outside of the graph line, then firstpoint is undefined -> close popup. @@ -80,15 +73,6 @@ class LatencyLineChart extends React.Component { } }; - gotoTracesHandler = (xc: any) => { - this.props.history.push(ROUTES.TRACES); - }; - - gotoAlertsHandler = () => { - this.props.history.push(ROUTES.SERVICE_MAP); - // PNOTE - Keeping service map for now, will replace with alerts when alert page is made - }; - options_charts: ChartOptions = { onClick: this.onClickhandler, @@ -161,9 +145,6 @@ class LatencyLineChart extends React.Component { xAxes: [ { type: "time", - // time: { - // unit: 'second' - // }, distribution: "linear", //'linear': data are spread according to their time (distances can vary) // From https://www.chartjs.org/docs/latest/axes/cartesian/time.html @@ -193,7 +174,6 @@ class LatencyLineChart extends React.Component { > View Traces - {/* Set Alerts */} ); } else return null; @@ -239,7 +219,7 @@ class LatencyLineChart extends React.Component {
{this.GraphTracePopUp()}
-
Application latency in ms
+
Application latency in ms
{ return { - externalErrCodeMetrics: state.externalErrCodeMetrics, - serviceMetrics: state.serviceMetrics, - topEndpointsList: state.topEndpointsList, - externalMetrics: state.externalMetrics, + externalErrCodeMetrics: state.metricsData.externalErrCodeMetricsItem, + serviceMetrics: state.metricsData.metricItems, + topEndpointsList: state.metricsData.topEndpointListItem, + externalMetrics: state.metricsData.externalMetricsItem, globalTime: state.globalTime, - dbOverviewMetrics: state.dbOverviewMetrics, - externalAvgDurationMetrics: state.externalAvgDurationMetrics, + dbOverviewMetrics: state.metricsData.dbOverviewMetricsItem, + externalAvgDurationMetrics: state.metricsData.externalMetricsAvgDurationItem, }; }; diff --git a/frontend/src/modules/Metrics/ServicesTable.tsx b/frontend/src/modules/Metrics/ServicesTable.tsx index 5da9568f98..5e4561d6dd 100644 --- a/frontend/src/modules/Metrics/ServicesTable.tsx +++ b/frontend/src/modules/Metrics/ServicesTable.tsx @@ -1,17 +1,12 @@ import React, { useEffect, useState } from "react"; -import { useLocation } from "react-router-dom"; import { NavLink } from "react-router-dom"; import { Button, Space, Spin, Table } from "antd"; import styled from "styled-components"; import { connect } from "react-redux"; import { SKIP_ONBOARDING } from "Src/constants/onboarding"; import ROUTES from "Src/constants/routes"; - -import { - getServicesList, - GlobalTime, - servicesListItem, -} from "../../store/actions"; +import { getServicesList, GlobalTime } from "../../store/actions"; +import { servicesListItem } from "../../store/actions/MetricsActions"; import { StoreState } from "../../store/reducers"; import { CustomModal } from "../../components/Modal"; @@ -75,7 +70,7 @@ const columns = [ key: "errorRate", sorter: (a: any, b: any) => a.errorRate - b.errorRate, // sortDirections: ['descend', 'ascend'], - render: (value: number) => (value).toFixed(2), + render: (value: number) => value.toFixed(2), }, { title: "Requests Per Second", @@ -88,8 +83,6 @@ const columns = [ ]; const _ServicesTable = (props: ServicesTableProps) => { - const search = useLocation().search; - const time_interval = new URLSearchParams(search).get("time"); const [initialDataFetch, setDataFetched] = useState(false); const [errorObject, setErrorObject] = useState({ message: "", @@ -210,7 +203,10 @@ const _ServicesTable = (props: ServicesTableProps) => { const mapStateToProps = ( state: StoreState, ): { servicesList: servicesListItem[]; globalTime: GlobalTime } => { - return { servicesList: state.servicesList, globalTime: state.globalTime }; + return { + servicesList: state.metricsData.serviceList, + globalTime: state.globalTime, + }; }; export const ServicesTable = connect(mapStateToProps, { diff --git a/frontend/src/modules/Metrics/TopEndpointsTable.tsx b/frontend/src/modules/Metrics/TopEndpointsTable.tsx index 6ab2022574..d87b2df92b 100644 --- a/frontend/src/modules/Metrics/TopEndpointsTable.tsx +++ b/frontend/src/modules/Metrics/TopEndpointsTable.tsx @@ -3,7 +3,7 @@ import { Table, Button, Tooltip } from "antd"; import { connect } from "react-redux"; import styled from "styled-components"; import { useHistory, useParams } from "react-router-dom"; -import { topEndpointListItem } from "../../store/actions/metrics"; +import { topEndpointListItem } from "../../store/actions/MetricsActions"; import { METRICS_PAGE_QUERY_PARAM } from "Src/constants/query"; import { GlobalTime } from "Src/store/actions"; import { StoreState } from "Src/store/reducers"; diff --git a/frontend/src/modules/RouteProvider.tsx b/frontend/src/modules/RouteProvider.tsx index 0680e912c8..6b1ebbf786 100644 --- a/frontend/src/modules/RouteProvider.tsx +++ b/frontend/src/modules/RouteProvider.tsx @@ -9,7 +9,7 @@ type State = { }; enum ActionTypes { - UPDATE_IS_LOADED = "UPDATE_IS_LOADED", + UPDATE_IS_LOADED = "ROUTE_IS_LOADED", } type Action = { diff --git a/frontend/src/modules/Servicemap/ServiceMap.tsx b/frontend/src/modules/Servicemap/ServiceMap.tsx index fe31b8d8fb..27785f95c3 100644 --- a/frontend/src/modules/Servicemap/ServiceMap.tsx +++ b/frontend/src/modules/Servicemap/ServiceMap.tsx @@ -1,4 +1,4 @@ -import React, { useContext, useEffect, useRef } from "react"; +import React, { useEffect, useRef } from "react"; import { connect } from "react-redux"; import { RouteComponentProps } from "react-router-dom"; import { diff --git a/frontend/src/modules/Traces/TraceCustomVisualizations.tsx b/frontend/src/modules/Traces/TraceCustomVisualizations.tsx index baf3271c64..5d9c1de26c 100644 --- a/frontend/src/modules/Traces/TraceCustomVisualizations.tsx +++ b/frontend/src/modules/Traces/TraceCustomVisualizations.tsx @@ -2,16 +2,11 @@ import React, { useState, useEffect } from "react"; import GenericVisualizations from "../Metrics/GenericVisualization"; import { Select, Card, Space, Form } from "antd"; import { connect } from "react-redux"; - import { StoreState } from "../../store/reducers"; -import { - customMetricsItem, - getFilteredTraceMetrics, - GlobalTime, - TraceFilters, -} from "../../store/actions"; +import { GlobalTime, TraceFilters } from "../../store/actions"; import { useRoute } from "../RouteProvider"; - +import { getFilteredTraceMetrics } from "../../store/actions/MetricsActions"; +import { customMetricsItem } from "../../store/actions/MetricsActions"; const { Option } = Select; const entity = [ @@ -81,8 +76,9 @@ interface TraceCustomVisualizationsProps { const _TraceCustomVisualizations = (props: TraceCustomVisualizationsProps) => { const [selectedEntity, setSelectedEntity] = useState("calls"); const [selectedAggOption, setSelectedAggOption] = useState("count"); - const [selectedStep, setSelectedStep] = useState("60"); const { state } = useRoute(); + const [form] = Form.useForm(); + const selectedStep = "60"; // Step should be multiples of 60, 60 -> 1 min @@ -124,16 +120,6 @@ const _TraceCustomVisualizations = (props: TraceCustomVisualizationsProps) => { //Custom metrics API called if time, tracefilters, selected entity or agg option changes - const [form] = Form.useForm(); - - function handleChange(value: string) { - // console.log(value); - } - - function handleFinish(value: string) { - // console.log(value); - } - // PNOTE - Can also use 'coordinate' option in antd Select for implementing this - https://ant.design/components/select/ const handleFormValuesChange = (changedValues: any) => { const formFieldName = Object.keys(changedValues)[0]; @@ -162,11 +148,9 @@ const _TraceCustomVisualizations = (props: TraceCustomVisualizationsProps) => { return ( - {/* */}
Custom Visualizations
{ - @@ -207,7 +191,7 @@ const _TraceCustomVisualizations = (props: TraceCustomVisualizationsProps) => { - @@ -216,7 +200,7 @@ const _TraceCustomVisualizations = (props: TraceCustomVisualizationsProps) => { {/* Need heading for each option */} - @@ -239,7 +223,7 @@ const mapStateToProps = ( traceFilters: TraceFilters; } => { return { - filteredTraceMetrics: state.filteredTraceMetrics, + filteredTraceMetrics: state.metricsData.customMetricsItem, globalTime: state.globalTime, traceFilters: state.traceFilters, }; diff --git a/frontend/src/modules/Usage/UsageExplorer.tsx b/frontend/src/modules/Usage/UsageExplorer.tsx index d02cc8eebb..65234b9cf0 100644 --- a/frontend/src/modules/Usage/UsageExplorer.tsx +++ b/frontend/src/modules/Usage/UsageExplorer.tsx @@ -1,19 +1,19 @@ -import React, { useEffect, useMemo, useState } from "react"; +import React, { useEffect, useState } from "react"; import { Bar } from "react-chartjs-2"; -import { Card, Form, Select, Space } from "antd"; +import { Card, Select, Space } from "antd"; import { connect } from "react-redux"; import { getServicesList, getUsageData, GlobalTime, - servicesListItem, usageDataItem, } from "../../store/actions"; import { StoreState } from "../../store/reducers"; import moment from "moment"; import { isOnboardingSkipped } from "../../utils/app"; import { useRoute } from "../RouteProvider"; +import { servicesListItem } from "../../store/actions/MetricsActions"; const { Option } = Select; interface UsageExplorerProps { @@ -212,7 +212,7 @@ const mapStateToProps = ( totalCount: totalCount, usageData: state.usageDate, globalTime: state.globalTime, - servicesList: state.servicesList, + servicesList: state.metricsData.serviceList, }; }; diff --git a/frontend/src/store/actions/MetricsActions/index.ts b/frontend/src/store/actions/MetricsActions/index.ts new file mode 100644 index 0000000000..24b7e2a725 --- /dev/null +++ b/frontend/src/store/actions/MetricsActions/index.ts @@ -0,0 +1,3 @@ +export * from "./metricsInterfaces"; +export * from "./metricsActionTypes"; +export * from "./metricsActions"; diff --git a/frontend/src/store/actions/MetricsActions/metricsActionTypes.ts b/frontend/src/store/actions/MetricsActions/metricsActionTypes.ts new file mode 100644 index 0000000000..13df5bdee7 --- /dev/null +++ b/frontend/src/store/actions/MetricsActions/metricsActionTypes.ts @@ -0,0 +1,34 @@ +import { + externalErrCodeMetricsActions, + externalMetricsAvgDurationAction, + getDbOverViewMetricsAction, + getExternalMetricsAction, + getFilteredTraceMetricsAction, + getServiceMetricsAction, + getServicesListAction, + getTopEndpointsAction, +} from "./metricsInterfaces"; + +export enum MetricsActionTypes { + updateInput = "UPDATE_INPUT", + fetchTraces = "FETCH_TRACES", + fetchTraceItem = "FETCH_TRACE_ITEM", + getServicesList = "GET_SERVICE_LIST", + getServiceMetrics = "GET_SERVICE_METRICS", + getAvgDurationMetrics = "GET_AVG_DURATION_METRICS", + getErrCodeMetrics = "GET_ERR_CODE_METRICS", + getDbOverviewMetrics = "GET_DB_OVERVIEW_METRICS", + getExternalMetrics = "GET_EXTERNAL_METRICS", + getTopEndpoints = "GET_TOP_ENDPOINTS", + getFilteredTraceMetrics = "GET_FILTERED_TRACE_METRICS", +} + +export type MetricsActions = + | getServicesListAction + | getServiceMetricsAction + | getTopEndpointsAction + | getFilteredTraceMetricsAction + | getExternalMetricsAction + | externalErrCodeMetricsActions + | getDbOverViewMetricsAction + | externalMetricsAvgDurationAction; diff --git a/frontend/src/store/actions/MetricsActions/metricsActions.ts b/frontend/src/store/actions/MetricsActions/metricsActions.ts new file mode 100644 index 0000000000..e0889df5e9 --- /dev/null +++ b/frontend/src/store/actions/MetricsActions/metricsActions.ts @@ -0,0 +1,190 @@ +import { Dispatch } from "redux"; +import api, { apiV1 } from "../../../api"; + +import { GlobalTime } from "../global"; +import { toUTCEpoch } from "../../../utils/timeUtils"; +import { MetricsActionTypes } from "./metricsActionTypes"; +import * as MetricsInterfaces from "./metricsInterfaces"; + +export const getServicesList = (globalTime: GlobalTime) => { + return async (dispatch: Dispatch) => { + let request_string = + "/services?start=" + globalTime.minTime + "&end=" + globalTime.maxTime; + + const response = await api.get( + apiV1 + request_string, + ); + + dispatch({ + type: MetricsActionTypes.getServicesList, + payload: response.data, + //PNOTE - response.data in the axios response has the actual API response + }); + }; +}; + +export const getDbOverViewMetrics = ( + serviceName: string, + globalTime: GlobalTime, +) => { + return async (dispatch: Dispatch) => { + let request_string = + "/service/dbOverview?service=" + + serviceName + + "&start=" + + globalTime.minTime + + "&end=" + + globalTime.maxTime + + "&step=60"; + const response = await api.get( + apiV1 + request_string, + ); + dispatch({ + type: MetricsActionTypes.getDbOverviewMetrics, + payload: response.data, + }); + }; +}; + +export const getExternalMetrics = ( + serviceName: string, + globalTime: GlobalTime, +) => { + return async (dispatch: Dispatch) => { + let request_string = + "/service/external?service=" + + serviceName + + "&start=" + + globalTime.minTime + + "&end=" + + globalTime.maxTime + + "&step=60"; + const response = await api.get( + apiV1 + request_string, + ); + dispatch({ + type: MetricsActionTypes.getExternalMetrics, + payload: response.data, + }); + }; +}; + +export const getExternalAvgDurationMetrics = ( + serviceName: string, + globalTime: GlobalTime, +) => { + return async (dispatch: Dispatch) => { + let request_string = + "/service/externalAvgDuration?service=" + + serviceName + + "&start=" + + globalTime.minTime + + "&end=" + + globalTime.maxTime + + "&step=60"; + + const response = await api.get< + MetricsInterfaces.externalMetricsAvgDurationItem[] + >(apiV1 + request_string); + dispatch({ + type: MetricsActionTypes.getAvgDurationMetrics, + payload: response.data, + }); + }; +}; +export const getExternalErrCodeMetrics = ( + serviceName: string, + globalTime: GlobalTime, +) => { + return async (dispatch: Dispatch) => { + let request_string = + "/service/externalErrors?service=" + + serviceName + + "&start=" + + globalTime.minTime + + "&end=" + + globalTime.maxTime + + "&step=60"; + const response = await api.get< + MetricsInterfaces.externalErrCodeMetricsItem[] + >(apiV1 + request_string); + + dispatch({ + type: MetricsActionTypes.getErrCodeMetrics, + payload: response.data, + }); + }; +}; + +export const getServicesMetrics = ( + serviceName: string, + globalTime: GlobalTime, +) => { + return async (dispatch: Dispatch) => { + let request_string = + "/service/overview?service=" + + serviceName + + "&start=" + + globalTime.minTime + + "&end=" + + globalTime.maxTime + + "&step=60"; + const response = await api.get( + apiV1 + request_string, + ); + + dispatch({ + type: MetricsActionTypes.getServiceMetrics, + payload: response.data, + //PNOTE - response.data in the axios response has the actual API response + }); + }; +}; + +export const getTopEndpoints = ( + serviceName: string, + globalTime: GlobalTime, +) => { + return async (dispatch: Dispatch) => { + let request_string = + "/service/top_endpoints?service=" + + serviceName + + "&start=" + + globalTime.minTime + + "&end=" + + globalTime.maxTime; + const response = await api.get( + apiV1 + request_string, + ); + + dispatch({ + type: MetricsActionTypes.getTopEndpoints, + payload: response.data, + //PNOTE - response.data in the axios response has the actual API response + }); + }; +}; + +export const getFilteredTraceMetrics = ( + filter_params: string, + globalTime: GlobalTime, +) => { + return async (dispatch: Dispatch) => { + let request_string = + "/spans/aggregates?start=" + + toUTCEpoch(globalTime.minTime) + + "&end=" + + toUTCEpoch(globalTime.maxTime) + + "&" + + filter_params; + const response = await api.get( + apiV1 + request_string, + ); + + dispatch({ + type: MetricsActionTypes.getFilteredTraceMetrics, + payload: response.data, + //PNOTE - response.data in the axios response has the actual API response + }); + }; +}; diff --git a/frontend/src/store/actions/MetricsActions/metricsInterfaces.ts b/frontend/src/store/actions/MetricsActions/metricsInterfaces.ts new file mode 100644 index 0000000000..c63967e64b --- /dev/null +++ b/frontend/src/store/actions/MetricsActions/metricsInterfaces.ts @@ -0,0 +1,98 @@ +import { MetricsActionTypes } from "./metricsActionTypes"; + +export interface servicesListItem { + serviceName: string; + p99: number; + avgDuration: number; + numCalls: number; + callRate: number; + numErrors: number; + errorRate: number; +} + +export interface metricItem { + timestamp: number; + p50: number; + p95: number; + p99: number; + numCalls: number; + callRate: number; + numErrors: number; + errorRate: number; +} + +export interface externalMetricsAvgDurationItem { + avgDuration: number; + timestamp: number; +} + +export interface externalErrCodeMetricsItem { + externalHttpUrl: string; + numCalls: number; + timestamp: number; + callRate: number; +} +export interface topEndpointListItem { + p50: number; + p90: number; + p99: number; + numCalls: number; + name: string; +} + +export interface externalMetricsItem { + avgDuration: number; + callRate: number; + externalHttpUrl: string; + numCalls: number; + timestamp: number; +} + +export interface dbOverviewMetricsItem { + avgDuration: number; + callRate: number; + dbSystem: string; + numCalls: number; + timestamp: number; +} + +export interface customMetricsItem { + timestamp: number; + value: number; +} + +export interface getServicesListAction { + type: MetricsActionTypes.getServicesList; + payload: servicesListItem[]; +} + +export interface externalErrCodeMetricsActions { + type: MetricsActionTypes.getErrCodeMetrics; + payload: externalErrCodeMetricsItem[]; +} +export interface externalMetricsAvgDurationAction { + type: MetricsActionTypes.getAvgDurationMetrics; + payload: externalMetricsAvgDurationItem[]; +} +export interface getServiceMetricsAction { + type: MetricsActionTypes.getServiceMetrics; + payload: metricItem[]; +} +export interface getExternalMetricsAction { + type: MetricsActionTypes.getExternalMetrics; + payload: externalMetricsItem[]; +} + +export interface getDbOverViewMetricsAction { + type: MetricsActionTypes.getDbOverviewMetrics; + payload: dbOverviewMetricsItem[]; +} +export interface getTopEndpointsAction { + type: MetricsActionTypes.getTopEndpoints; + payload: topEndpointListItem[]; +} + +export interface getFilteredTraceMetricsAction { + type: MetricsActionTypes.getFilteredTraceMetrics; + payload: customMetricsItem[]; +} diff --git a/frontend/src/store/actions/index.ts b/frontend/src/store/actions/index.ts index 28fb2a715f..37c75e41d7 100644 --- a/frontend/src/store/actions/index.ts +++ b/frontend/src/store/actions/index.ts @@ -2,6 +2,6 @@ export * from "./types"; export * from "./traceFilters"; export * from "./serviceMap"; export * from "./traces"; -export * from "./metrics"; +export * from "./MetricsActions"; export * from "./usage"; export * from "./global"; diff --git a/frontend/src/store/actions/metrics.ts b/frontend/src/store/actions/metrics.ts deleted file mode 100644 index 2643f9028f..0000000000 --- a/frontend/src/store/actions/metrics.ts +++ /dev/null @@ -1,277 +0,0 @@ -import { Dispatch } from "redux"; -import api, { apiV1 } from "../../api"; - -import { GlobalTime } from "./global"; -import { ActionTypes } from "./types"; -import { Token } from "../../utils/token"; -import { toUTCEpoch } from "../../utils/timeUtils"; - -export interface servicesListItem { - serviceName: string; - p99: number; - avgDuration: number; - numCalls: number; - callRate: number; - numErrors: number; - errorRate: number; -} - -export interface metricItem { - timestamp: number; - p50: number; - p95: number; - p99: number; - numCalls: number; - callRate: number; - numErrors: number; - errorRate: number; -} - -export interface externalMetricsAvgDurationItem { - avgDuration: number; - timestamp: number; -} - -export interface externalErrCodeMetricsItem { - errorRate: number; - externalHttpUrl: string; - numErrors: number; - timestamp: number; -} -export interface topEndpointListItem { - p50: number; - p90: number; - p99: number; - numCalls: number; - name: string; -} - -export interface externalMetricsItem { - avgDuration: number; - callRate: number; - externalHttpUrl: string; - numCalls: number; - timestamp: number; -} - -export interface dbOverviewMetricsItem { - avgDuration: number; - callRate: number; - dbSystem: string; - numCalls: number; - timestamp: number; -} - -export interface customMetricsItem { - timestamp: number; - value: number; -} - -export interface getServicesListAction { - type: ActionTypes.getServicesList; - payload: servicesListItem[]; -} - -export interface externalErrCodeMetricsActions { - type: ActionTypes.getErrCodeMetrics; - payload: externalErrCodeMetricsItem[]; -} -export interface externalMetricsAvgDurationAction { - type: ActionTypes.getAvgDurationMetrics; - payload: externalMetricsAvgDurationItem[]; -} -export interface getServiceMetricsAction { - type: ActionTypes.getServiceMetrics; - payload: metricItem[]; -} -export interface getExternalMetricsAction { - type: ActionTypes.getExternalMetrics; - payload: externalMetricsItem[]; -} - -export interface getDbOverViewMetricsAction { - type: ActionTypes.getDbOverviewMetrics; - payload: dbOverviewMetricsItem[]; -} -export interface getTopEndpointsAction { - type: ActionTypes.getTopEndpoints; - payload: topEndpointListItem[]; -} - -export interface getFilteredTraceMetricsAction { - type: ActionTypes.getFilteredTraceMetrics; - payload: customMetricsItem[]; -} - -export const getServicesList = (globalTime: GlobalTime) => { - return async (dispatch: Dispatch) => { - let request_string = - "/services?start=" + globalTime.minTime + "&end=" + globalTime.maxTime; - - const response = await api.get(apiV1 + request_string); - - dispatch({ - type: ActionTypes.getServicesList, - payload: response.data, - //PNOTE - response.data in the axios response has the actual API response - }); - }; -}; - -export const getDbOverViewMetrics = ( - serviceName: string, - globalTime: GlobalTime, -) => { - return async (dispatch: Dispatch) => { - let request_string = - "/service/dbOverview?service=" + - serviceName + - "&start=" + - globalTime.minTime + - "&end=" + - globalTime.maxTime + - "&step=60"; - const response = await api.get( - apiV1 + request_string, - ); - dispatch({ - type: ActionTypes.getDbOverviewMetrics, - payload: response.data, - }); - }; -}; - -export const getExternalMetrics = ( - serviceName: string, - globalTime: GlobalTime, -) => { - return async (dispatch: Dispatch) => { - let request_string = - "/service/external?service=" + - serviceName + - "&start=" + - globalTime.minTime + - "&end=" + - globalTime.maxTime + - "&step=60"; - const response = await api.get(apiV1 + request_string); - dispatch({ - type: ActionTypes.getExternalMetrics, - payload: response.data, - }); - }; -}; - -export const getExternalAvgDurationMetrics = ( - serviceName: string, - globalTime: GlobalTime, -) => { - return async (dispatch: Dispatch) => { - let request_string = - "/service/externalAvgDuration?service=" + - serviceName + - "&start=" + - globalTime.minTime + - "&end=" + - globalTime.maxTime + - "&step=60"; - - const response = await api.get( - apiV1 + request_string, - ); - dispatch({ - type: ActionTypes.getAvgDurationMetrics, - payload: response.data, - }); - }; -}; -export const getExternalErrCodeMetrics = ( - serviceName: string, - globalTime: GlobalTime, -) => { - return async (dispatch: Dispatch) => { - let request_string = - "/service/externalErrors?service=" + - serviceName + - "&start=" + - globalTime.minTime + - "&end=" + - globalTime.maxTime + - "&step=60"; - const response = await api.get( - apiV1 + request_string, - ); - - dispatch({ - type: ActionTypes.getErrCodeMetrics, - payload: response.data, - }); - }; -}; - -export const getServicesMetrics = ( - serviceName: string, - globalTime: GlobalTime, -) => { - return async (dispatch: Dispatch) => { - let request_string = - "/service/overview?service=" + - serviceName + - "&start=" + - globalTime.minTime + - "&end=" + - globalTime.maxTime + - "&step=60"; - const response = await api.get(apiV1 + request_string); - - dispatch({ - type: ActionTypes.getServiceMetrics, - payload: response.data, - //PNOTE - response.data in the axios response has the actual API response - }); - }; -}; - -export const getTopEndpoints = ( - serviceName: string, - globalTime: GlobalTime, -) => { - return async (dispatch: Dispatch) => { - let request_string = - "/service/top_endpoints?service=" + - serviceName + - "&start=" + - globalTime.minTime + - "&end=" + - globalTime.maxTime; - const response = await api.get(apiV1 + request_string); - - dispatch({ - type: ActionTypes.getTopEndpoints, - payload: response.data, - //PNOTE - response.data in the axios response has the actual API response - }); - }; -}; - -export const getFilteredTraceMetrics = ( - filter_params: string, - globalTime: GlobalTime, -) => { - return async (dispatch: Dispatch) => { - let request_string = - "/spans/aggregates?start=" + - toUTCEpoch(globalTime.minTime) + - "&end=" + - toUTCEpoch(globalTime.maxTime) + - "&" + - filter_params; - const response = await api.get(apiV1 + request_string); - - dispatch({ - type: ActionTypes.getFilteredTraceMetrics, - payload: response.data, - //PNOTE - response.data in the axios response has the actual API response - }); - }; -}; diff --git a/frontend/src/store/actions/types.ts b/frontend/src/store/actions/types.ts index bf05b41d70..e40c8c6707 100644 --- a/frontend/src/store/actions/types.ts +++ b/frontend/src/store/actions/types.ts @@ -1,36 +1,16 @@ import { FetchTracesAction, FetchTraceItemAction } from "./traces"; import { updateTraceFiltersAction, updateInputTagAction } from "./traceFilters"; -import { - getServicesListAction, - getServiceMetricsAction, - externalErrCodeMetricsActions, - externalMetricsAvgDurationAction, - getExternalMetricsAction, - getTopEndpointsAction, - getFilteredTraceMetricsAction, - getDbOverViewMetricsAction, -} from "./metrics"; + import { serviceMapItemAction, servicesAction } from "./serviceMap"; import { getUsageDataAction } from "./usage"; import { updateTimeIntervalAction } from "./global"; export enum ActionTypes { updateTraceFilters = "UPDATE_TRACES_FILTER", - updateInput = "UPDATE_INPUT", - fetchTraces = "FETCH_TRACES", - fetchTraceItem = "FETCH_TRACE_ITEM", - getServicesList = "GET_SERVICE_LIST", - getServiceMetrics = "GET_SERVICE_METRICS", - getAvgDurationMetrics = "GET_AVG_DURATION_METRICS", - getErrCodeMetrics = "GET_ERR_CODE_METRICS", - getDbOverviewMetrics = "GET_DB_OVERVIEW_METRICS", - getExternalMetrics = "GET_EXTERNAL_METRICS", - getTopEndpoints = "GET_TOP_ENDPOINTS", - getUsageData = "GET_USAGE_DATE", updateTimeInterval = "UPDATE_TIME_INTERVAL", - getFilteredTraceMetrics = "GET_FILTERED_TRACE_METRICS", getServiceMapItems = "GET_SERVICE_MAP_ITEMS", getServices = "GET_SERVICES", + getUsageData = "GET_USAGE_DATE", } export type Action = @@ -38,15 +18,7 @@ export type Action = | FetchTracesAction | updateTraceFiltersAction | updateInputTagAction - | getServicesListAction - | getServiceMetricsAction - | getTopEndpointsAction | getUsageDataAction | updateTimeIntervalAction - | getFilteredTraceMetricsAction - | getExternalMetricsAction - | externalErrCodeMetricsActions - | getDbOverViewMetricsAction | servicesAction - | serviceMapItemAction - | externalMetricsAvgDurationAction; + | serviceMapItemAction; diff --git a/frontend/src/store/actions/usage.ts b/frontend/src/store/actions/usage.ts index a46b684f4d..fb29114b3b 100644 --- a/frontend/src/store/actions/usage.ts +++ b/frontend/src/store/actions/usage.ts @@ -2,7 +2,6 @@ import { Dispatch } from "redux"; import api, { apiV1 } from "../../api"; import { ActionTypes } from "./types"; -import { GlobalTime } from "./global"; import { toUTCEpoch } from "../../utils/timeUtils"; export interface usageDataItem { diff --git a/frontend/src/store/reducers/index.ts b/frontend/src/store/reducers/index.ts index 8c33fde3d5..696a7f1750 100644 --- a/frontend/src/store/reducers/index.ts +++ b/frontend/src/store/reducers/index.ts @@ -2,48 +2,25 @@ import { combineReducers } from "redux"; import { traceResponseNew, spansWSameTraceIDResponse, - servicesListItem, - metricItem, - topEndpointListItem, - externalMetricsItem, - externalMetricsAvgDurationItem, usageDataItem, GlobalTime, - externalErrCodeMetricsItem, serviceMapStore, - customMetricsItem, TraceFilters, } from "../actions"; import { updateGlobalTimeReducer } from "./global"; -import { - filteredTraceMetricsReducer, - serviceMetricsReducer, - externalErrCodeMetricsReducer, - serviceTableReducer, - topEndpointsReducer, - dbOverviewMetricsReducer, - externalMetricsReducer, - externalAvgDurationMetricsReducer, -} from "./metrics"; +import { MetricsInitialState, metricsReducer } from "./metrics"; import { traceFiltersReducer, inputsReducer } from "./traceFilters"; import { traceItemReducer, tracesReducer } from "./traces"; import { usageDataReducer } from "./usage"; import { ServiceMapReducer } from "./serviceMap"; + export interface StoreState { + metricsData: MetricsInitialState; traceFilters: TraceFilters; - inputTag: string; traces: traceResponseNew; traceItem: spansWSameTraceIDResponse; - servicesList: servicesListItem[]; - serviceMetrics: metricItem[]; - topEndpointsList: topEndpointListItem[]; - externalMetrics: externalMetricsItem[]; - dbOverviewMetrics: externalMetricsItem[]; - externalAvgDurationMetrics: externalMetricsAvgDurationItem[]; - externalErrCodeMetrics: externalErrCodeMetricsItem[]; usageDate: usageDataItem[]; globalTime: GlobalTime; - filteredTraceMetrics: customMetricsItem[]; serviceMap: serviceMapStore; } @@ -52,16 +29,9 @@ const reducers = combineReducers({ inputTag: inputsReducer, traces: tracesReducer, traceItem: traceItemReducer, - servicesList: serviceTableReducer, - serviceMetrics: serviceMetricsReducer, - dbOverviewMetrics: dbOverviewMetricsReducer, - topEndpointsList: topEndpointsReducer, - externalAvgDurationMetrics: externalAvgDurationMetricsReducer, - externalMetrics: externalMetricsReducer, - externalErrCodeMetrics: externalErrCodeMetricsReducer, usageDate: usageDataReducer, globalTime: updateGlobalTimeReducer, - filteredTraceMetrics: filteredTraceMetricsReducer, + metricsData: metricsReducer, serviceMap: ServiceMapReducer, }); diff --git a/frontend/src/store/reducers/metrics.ts b/frontend/src/store/reducers/metrics.ts index f1afd73738..f469186525 100644 --- a/frontend/src/store/reducers/metrics.ts +++ b/frontend/src/store/reducers/metrics.ts @@ -1,6 +1,4 @@ import { - ActionTypes, - Action, servicesListItem, metricItem, topEndpointListItem, @@ -9,10 +7,21 @@ import { externalMetricsItem, dbOverviewMetricsItem, externalMetricsAvgDurationItem, -} from "../actions"; +} from "../actions/MetricsActions"; +import { MetricsActionTypes as ActionTypes } from "../actions/MetricsActions/metricsActionTypes"; -export const serviceTableReducer = ( - state: servicesListItem[] = [ +export type MetricsInitialState = { + serviceList?: servicesListItem[]; + metricItems?: metricItem[]; + topEndpointListItem?: topEndpointListItem[]; + externalMetricsAvgDurationItem?: externalMetricsAvgDurationItem[]; + externalErrCodeMetricsItem?: externalErrCodeMetricsItem[]; + externalMetricsItem?: externalMetricsItem[]; + dbOverviewMetricsItem?: dbOverviewMetricsItem[]; + customMetricsItem?: customMetricsItem[]; +}; +export const metricsInitialState: MetricsInitialState = { + serviceList: [ { serviceName: "", p99: 0, @@ -23,22 +32,11 @@ export const serviceTableReducer = ( errorRate: 0, }, ], - action: Action, -) => { - switch (action.type) { - case ActionTypes.getServicesList: - return action.payload; - default: - return state; - } -}; - -export const serviceMetricsReducer = ( - state: metricItem[] = [ + metricItems: [ { timestamp: 0, p50: 0, - p90: 0, + p95: 0, p99: 0, numCalls: 0, callRate: 0.0, @@ -46,49 +44,22 @@ export const serviceMetricsReducer = ( errorRate: 0, }, ], - action: Action, -) => { - switch (action.type) { - case ActionTypes.getServiceMetrics: - return action.payload; - default: - return state; - } -}; - -export const topEndpointsReducer = ( - state: topEndpointListItem[] = [ - { p50: 0, p90: 0, p99: 0, numCalls: 0, name: "" }, + topEndpointListItem: [ + { + p50: 0, + p90: 0, + p99: 0, + numCalls: 0, + name: "", + }, ], - action: Action, -) => { - switch (action.type) { - case ActionTypes.getTopEndpoints: - return action.payload; - default: - return state; - } -}; - -export const externalAvgDurationMetricsReducer = ( - state: externalMetricsAvgDurationItem[] = [ + externalMetricsAvgDurationItem: [ { avgDuration: 0, timestamp: 0, }, ], - action: Action, -) => { - switch (action.type) { - case ActionTypes.getAvgDurationMetrics: - return action.payload; - default: - return state; - } -}; - -export const externalErrCodeMetricsReducer = ( - state: externalErrCodeMetricsItem[] = [ + externalErrCodeMetricsItem: [ { callRate: 0, externalHttpUrl: "", @@ -96,18 +67,7 @@ export const externalErrCodeMetricsReducer = ( timestamp: 0, }, ], - action: Action, -) => { - switch (action.type) { - case ActionTypes.getErrCodeMetrics: - return action.payload; - default: - return state; - } -}; - -export const externalMetricsReducer = ( - state: externalMetricsItem[] = [ + externalMetricsItem: [ { avgDuration: 0, callRate: 0, @@ -116,18 +76,7 @@ export const externalMetricsReducer = ( timestamp: 0, }, ], - action: Action, -) => { - switch (action.type) { - case ActionTypes.getExternalMetrics: - return action.payload; - default: - return state; - } -}; - -export const dbOverviewMetricsReducer = ( - state: dbOverviewMetricsItem[] = [ + dbOverviewMetricsItem: [ { avgDuration: 0, callRate: 0, @@ -136,24 +85,68 @@ export const dbOverviewMetricsReducer = ( timestamp: 0, }, ], - action: Action, -) => { - switch (action.type) { - case ActionTypes.getDbOverviewMetrics: - return action.payload; - default: - return state; - } + customMetricsItem: [ + { + timestamp: 0, + value: 0, + }, + ], }; -export const filteredTraceMetricsReducer = ( - state: customMetricsItem[] = [{ timestamp: 0, value: 0 }], - action: Action, +type ActionType = { + type: string; + payload: any; +}; + +export const metricsReducer = ( + state: MetricsInitialState = metricsInitialState, + action: ActionType, ) => { switch (action.type) { case ActionTypes.getFilteredTraceMetrics: - return action.payload; + return { + ...state, + customMetricsItem: action.payload, + }; + case ActionTypes.getServiceMetrics: + return { + ...state, + metricItems: action.payload, + }; + case ActionTypes.getDbOverviewMetrics: + return { + ...state, + dbOverviewMetricsItem: action.payload, + }; + case ActionTypes.getExternalMetrics: + return { + ...state, + externalMetricsItem: action.payload, + }; + case ActionTypes.getTopEndpoints: + return { + ...state, + topEndpointListItem: action.payload, + }; + case ActionTypes.getErrCodeMetrics: + return { + ...state, + externalErrCodeMetricsItem: action.payload, + }; + case ActionTypes.getAvgDurationMetrics: + return { + ...state, + externalMetricsAvgDurationItem: action.payload, + }; + + case ActionTypes.getServicesList: + return { + ...state, + serviceList: action.payload, + }; default: - return state; + return { + ...state, + }; } };