Merge branch 'main' into query_refactor

This commit is contained in:
Ankit Anand 2021-05-28 11:43:38 +05:30
commit e524ce5743
13 changed files with 294 additions and 44 deletions

30
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -0,0 +1,30 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
## Bug description
*Please describe.*
*If this affects the front-end, screenshots would be of great help.*
## Expected behavior
## How to reproduce
1.
2.
3.
## Additional context
#### *Thank you* for your bug report we love squashing them!

View File

@ -0,0 +1,29 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
## Is your feature request related to a problem?
*Please describe.*
## Describe the solution you'd like
## Describe alternatives you've considered
## Additional context
#### *Thank you* for your feature request we love each and every one!
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@ -0,0 +1,33 @@
---
name: Performance issue report
about: Long response times, high resource usage? Ensuring that SigNoz is scalable
is our top priority
title: ''
labels: ''
assignees: ''
---
## In what situation are you experiencing subpar performance?
*Please describe.*
## How to reproduce
1.
2.
3.
## Your Environment
- [ ] Linux
- [ ] Mac
- [ ] Windows
Please provide details of OS version etc.
## Additional context
#### *Thank you* for your performance issue report we want SigNoz to be blazing fast!

View File

@ -8,7 +8,7 @@
<img alt="License" src="https://img.shields.io/badge/license-MIT-brightgreen"> </a> <img alt="License" src="https://img.shields.io/badge/license-MIT-brightgreen"> </a>
<img alt="Downloads" src="https://img.shields.io/docker/pulls/signoz/frontend?label=Downloads"> </a> <img alt="Downloads" src="https://img.shields.io/docker/pulls/signoz/frontend?label=Downloads"> </a>
<img alt="GitHub issues" src="https://img.shields.io/github/issues/signoz/signoz"> </a> <img alt="GitHub issues" src="https://img.shields.io/github/issues/signoz/signoz"> </a>
<a href="https://twitter.com/intent/tweet?text=Monitor%20your%20applications%20and%20troubleshoot%20problems%20with%20SigNoz,%20an%20open-source%20alternative%20to%20DataDog,%20NewRelic.&url=https://signoz.io/&via=SigNoz_io&hashtags=opensource,signoz,observability"> <a href="https://twitter.com/intent/tweet?text=Monitor%20your%20applications%20and%20troubleshoot%20problems%20with%20SigNoz,%20an%20open-source%20alternative%20to%20DataDog,%20NewRelic.&url=https://signoz.io/&via=SigNozHQ&hashtags=opensource,signoz,observability">
<img alt="tweet" src="https://img.shields.io/twitter/url/http/shields.io.svg?style=social"> </a> <img alt="tweet" src="https://img.shields.io/twitter/url/http/shields.io.svg?style=social"> </a>
</p> </p>

View File

@ -17,6 +17,7 @@ import {
SettingsPage, SettingsPage,
IntstrumentationPage, IntstrumentationPage,
} from "Src/pages"; } from "Src/pages";
import { RouteProvider } from "./RouteProvider";
const App = () => { const App = () => {
const { status } = useThemeSwitcher(); const { status } = useThemeSwitcher();
@ -30,36 +31,38 @@ const App = () => {
<Suspense fallback={<Spin size="large" />}> <Suspense fallback={<Spin size="large" />}>
<Route path={"/"}> <Route path={"/"}>
<Switch> <Switch>
<BaseLayout> <RouteProvider>
<Route path={ROUTES.SIGN_UP} exact component={Signup} /> <BaseLayout>
<Route path={ROUTES.APPLICATION} exact component={ServicesTable} /> <Route path={ROUTES.SIGN_UP} exact component={Signup} />
<Route path={ROUTES.SERVICE_METRICS} exact component={ServiceMetrics} /> <Route path={ROUTES.APPLICATION} exact component={ServicesTable} />
<Route path={ROUTES.SERVICE_MAP} exact component={ServiceMap} /> <Route path={ROUTES.SERVICE_METRICS} exact component={ServiceMetrics} />
<Route path={ROUTES.TRACES} exact component={TraceDetail} /> <Route path={ROUTES.SERVICE_MAP} exact component={ServiceMap} />
<Route path={ROUTES.TRACE_GRAPH} exact component={TraceGraph} /> <Route path={ROUTES.TRACES} exact component={TraceDetail} />
<Route path={ROUTES.SETTINGS} exact component={SettingsPage} /> <Route path={ROUTES.TRACE_GRAPH} exact component={TraceGraph} />
<Route <Route path={ROUTES.SETTINGS} exact component={SettingsPage} />
path={ROUTES.INSTRUMENTATION} <Route
exact path={ROUTES.INSTRUMENTATION}
component={IntstrumentationPage} exact
/> component={IntstrumentationPage}
<Route />
path={ROUTES.USAGE_EXPLORER} <Route
exactexact path={ROUTES.USAGE_EXPLORER}
component={UsageExplorer} exactexact
/> component={UsageExplorer}
<Route />
path="/" <Route
exact path="/"
render={() => { exact
return localStorage.getItem(IS_LOGGED_IN) === "yes" ? ( render={() => {
<Redirect to={ROUTES.APPLICATION} /> return localStorage.getItem(IS_LOGGED_IN) === "yes" ? (
) : ( <Redirect to={ROUTES.APPLICATION} />
<Redirect to={ROUTES.SIGN_UP} /> ) : (
); <Redirect to={ROUTES.SIGN_UP} />
}} );
/> }}
</BaseLayout> />
</BaseLayout>
</RouteProvider>
</Switch> </Switch>
</Route> </Route>
</Suspense> </Suspense>

View File

@ -1,8 +1,12 @@
import React, { ReactNode } from "react"; import React, { ReactNode, useEffect } from "react";
import { Layout } from "antd"; import { Layout } from "antd";
import SideNav from "./Nav/SideNav"; import SideNav from "./Nav/SideNav";
import TopNav from "./Nav/TopNav"; 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; const { Content, Footer } = Layout;
interface BaseLayoutProps { interface BaseLayoutProps {
@ -10,6 +14,13 @@ interface BaseLayoutProps {
} }
const BaseLayout: React.FC<BaseLayoutProps> = ({ children }) => { const BaseLayout: React.FC<BaseLayoutProps> = ({ children }) => {
const location = useLocation();
const { dispatch } = useRoute();
useEffect(() => {
dispatch({ type: "UPDATE_IS_LOADED", payload: location.pathname });
}, [location]);
return ( return (
<Layout style={{ minHeight: "100vh" }}> <Layout style={{ minHeight: "100vh" }}>
<SideNav /> <SideNav />

View File

@ -0,0 +1,12 @@
@media only screen and (min-width: 768px) {
.topEndpointsButton {
white-space: nowrap;
padding: 0;
}
.topEndpointsButton span {
text-overflow: ellipsis;
overflow: hidden;
max-width: 120px;
}
}

View File

@ -1,5 +1,5 @@
import React from "react"; import React from "react";
import { Table, Button } from "antd"; import { Table, Button, Tooltip } from "antd";
import { connect } from "react-redux"; import { connect } from "react-redux";
import styled from "styled-components"; import styled from "styled-components";
import { useHistory, useParams } from "react-router-dom"; import { useHistory, useParams } from "react-router-dom";
@ -7,12 +7,16 @@ import { topEndpointListItem } from "../../store/actions/metrics";
import { METRICS_PAGE_QUERY_PARAM } from "Src/constants/query"; import { METRICS_PAGE_QUERY_PARAM } from "Src/constants/query";
import { GlobalTime } from "Src/store/actions"; import { GlobalTime } from "Src/store/actions";
import { StoreState } from "Src/store/reducers"; import { StoreState } from "Src/store/reducers";
import "./TopEndpointsTable.css";
const Wrapper = styled.div` const Wrapper = styled.div`
padding-top: 10px; padding-top: 10px;
padding-bottom: 10px; padding-bottom: 10px;
padding-left: 20px; padding-left: 8px;
padding-right: 20px; padding-right: 8px;
@media only screen and (max-width: 767px) {
padding: 0;
}
.ant-table table { .ant-table table {
font-size: 12px; font-size: 12px;
} }
@ -22,6 +26,9 @@ const Wrapper = styled.div`
.ant-table-thead > tr > th { .ant-table-thead > tr > th {
padding: 10px; padding: 10px;
} }
.ant-table-column-sorters {
padding: 6px;
}
`; `;
interface TopEndpointsTableProps { interface TopEndpointsTableProps {
@ -58,9 +65,15 @@ const _TopEndpointsTable = (props: TopEndpointsTableProps) => {
key: "name", key: "name",
render: (text: string) => ( render: (text: string) => (
<Button type="link" onClick={() => handleOnClick(text)}> <Tooltip placement="topLeft" title={text}>
{text} <Button
</Button> className="topEndpointsButton"
type="link"
onClick={() => handleOnClick(text)}
>
{text}
</Button>
</Tooltip>
), ),
}, },
{ {

View File

@ -0,0 +1,83 @@
import React, { useContext, createContext, ReactNode, Dispatch } from "react";
import ROUTES from "Src/constants/routes";
type State = {
[key: string]: {
route: string;
isLoaded: boolean;
};
};
enum ActionTypes {
UPDATE_IS_LOADED = "UPDATE_IS_LOADED",
}
type Action = {
type: ActionTypes;
payload: string;
};
interface ContextType {
state: State;
dispatch: Dispatch<Action>;
}
const RouteContext = createContext<ContextType | null>(null);
interface RouteProviderProps {
children: ReactNode;
}
interface RouteObj {
[key: string]: {
route: string;
isLoaded: boolean;
};
}
const updateLocation = (state: State, action: Action): State => {
if (action.type === ActionTypes.UPDATE_IS_LOADED) {
/*
Update the isLoaded property in routes obj
if the route matches the current pathname
Why: Checkout this issue https://github.com/SigNoz/signoz/issues/110
To avoid calling the api's twice for Date picker,
We will only call once the route is changed
*/
Object.keys(ROUTES).map((items) => {
state[items].isLoaded = state[items].route === action.payload;
});
return {
...state,
};
}
return {
...state,
};
};
const getInitialState = () => {
const routes: RouteObj = {};
Object.keys(ROUTES).map((items) => {
routes[items] = {
route: `${ROUTES[items]}`,
isLoaded: false,
};
});
return routes;
};
const RouteProvider: React.FC<RouteProviderProps> = ({ children }) => {
const [state, dispatch] = React.useReducer(updateLocation, getInitialState());
const value = { state, dispatch };
return <RouteContext.Provider value={value}>{children}</RouteContext.Provider>;
};
const useRoute = (): ContextType => {
const context = useContext(RouteContext);
if (context === undefined) {
throw new Error("useRoute must be used within a RouteProvider");
}
return context as ContextType;
};
export { RouteProvider, useRoute };

View File

@ -1,4 +1,4 @@
import React, { useEffect, useRef, useState } from "react"; import React, { useContext, useEffect, useRef } from "react";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { RouteComponentProps } from "react-router-dom"; import { RouteComponentProps } from "react-router-dom";
import { import {
@ -14,6 +14,7 @@ import { StoreState } from "../../store/reducers";
import { getZoomPx, getGraphData, getTooltip, transformLabel } from "./utils"; import { getZoomPx, getGraphData, getTooltip, transformLabel } from "./utils";
import SelectService from "./SelectService"; import SelectService from "./SelectService";
import { ForceGraph2D } from "react-force-graph"; import { ForceGraph2D } from "react-force-graph";
import { useRoute } from "../RouteProvider";
const Container = styled.div` const Container = styled.div`
.force-graph-container .graph-tooltip { .force-graph-container .graph-tooltip {
@ -53,6 +54,8 @@ export interface graphDataType {
const ServiceMap = (props: ServiceMapProps) => { const ServiceMap = (props: ServiceMapProps) => {
const fgRef = useRef(); const fgRef = useRef();
const { state } = useRoute();
const { const {
getDetailedServiceMapItems, getDetailedServiceMapItems,
getServiceMapItems, getServiceMapItems,
@ -61,8 +64,14 @@ const ServiceMap = (props: ServiceMapProps) => {
} = props; } = props;
useEffect(() => { useEffect(() => {
getServiceMapItems(globalTime); /*
getDetailedServiceMapItems(globalTime); Call the apis only when the route is loaded.
Check this issue: https://github.com/SigNoz/signoz/issues/110
*/
if (state.SERVICE_MAP.isLoaded) {
getServiceMapItems(globalTime);
getDetailedServiceMapItems(globalTime);
}
}, [globalTime]); }, [globalTime]);
useEffect(() => { useEffect(() => {

View File

@ -10,6 +10,7 @@ import {
GlobalTime, GlobalTime,
TraceFilters, TraceFilters,
} from "../../store/actions"; } from "../../store/actions";
import { useRoute } from "../RouteProvider";
const { Option } = Select; const { Option } = Select;
@ -81,6 +82,8 @@ const _TraceCustomVisualizations = (props: TraceCustomVisualizationsProps) => {
const [selectedEntity, setSelectedEntity] = useState("calls"); const [selectedEntity, setSelectedEntity] = useState("calls");
const [selectedAggOption, setSelectedAggOption] = useState("count"); const [selectedAggOption, setSelectedAggOption] = useState("count");
const [selectedStep, setSelectedStep] = useState("60"); const [selectedStep, setSelectedStep] = useState("60");
const { state } = useRoute();
// Step should be multiples of 60, 60 -> 1 min // Step should be multiples of 60, 60 -> 1 min
useEffect(() => { useEffect(() => {
@ -109,7 +112,14 @@ const _TraceCustomVisualizations = (props: TraceCustomVisualizationsProps) => {
minTime: props.globalTime.minTime - 15 * 60 * 1000000000, minTime: props.globalTime.minTime - 15 * 60 * 1000000000,
maxTime: props.globalTime.maxTime + 15 * 60 * 1000000000, maxTime: props.globalTime.maxTime + 15 * 60 * 1000000000,
}; };
props.getFilteredTraceMetrics(request_string, plusMinus15);
/*
Call the apis only when the route is loaded.
Check this issue: https://github.com/SigNoz/signoz/issues/110
*/
if (state.TRACES.isLoaded) {
props.getFilteredTraceMetrics(request_string, plusMinus15);
}
}, [selectedEntity, selectedAggOption, props.traceFilters, props.globalTime]); }, [selectedEntity, selectedAggOption, props.traceFilters, props.globalTime]);
//Custom metrics API called if time, tracefilters, selected entity or agg option changes //Custom metrics API called if time, tracefilters, selected entity or agg option changes

View File

@ -18,6 +18,7 @@ import FormItem from "antd/lib/form/FormItem";
import api, { apiV1 } from "../../api"; import api, { apiV1 } from "../../api";
import { useLocation } from "react-router-dom"; import { useLocation } from "react-router-dom";
import { METRICS_PAGE_QUERY_PARAM } from "Src/constants/query"; import { METRICS_PAGE_QUERY_PARAM } from "Src/constants/query";
import { useRoute } from "../RouteProvider";
const { Option } = Select; const { Option } = Select;
@ -45,6 +46,7 @@ const _TraceFilter = (props: TraceFilterProps) => {
const [tagKeyOptions, setTagKeyOptions] = useState<TagKeyOptionItem[]>([]); const [tagKeyOptions, setTagKeyOptions] = useState<TagKeyOptionItem[]>([]);
const location = useLocation(); const location = useLocation();
const urlParams = new URLSearchParams(location.search.split("?")[1]); const urlParams = new URLSearchParams(location.search.split("?")[1]);
const { state } = useRoute();
useEffect(() => { useEffect(() => {
handleApplyFilterForm({ handleApplyFilterForm({
@ -122,7 +124,13 @@ const _TraceFilter = (props: TraceFilterProps) => {
"&tags=" + "&tags=" +
encodeURIComponent(JSON.stringify(props.traceFilters.tags)); encodeURIComponent(JSON.stringify(props.traceFilters.tags));
props.fetchTraces(props.globalTime, request_string); /*
Call the apis only when the route is loaded.
Check this issue: https://github.com/SigNoz/signoz/issues/110
*/
if (state.TRACES.isLoaded) {
props.fetchTraces(props.globalTime, request_string);
}
}, [props.traceFilters, props.globalTime]); }, [props.traceFilters, props.globalTime]);
useEffect(() => { useEffect(() => {

View File

@ -13,6 +13,7 @@ import {
import { StoreState } from "../../store/reducers"; import { StoreState } from "../../store/reducers";
import moment from "moment"; import moment from "moment";
import { isOnboardingSkipped } from "../../utils/app"; import { isOnboardingSkipped } from "../../utils/app";
import { useRoute } from "../RouteProvider";
const { Option } = Select; const { Option } = Select;
interface UsageExplorerProps { interface UsageExplorerProps {
@ -56,6 +57,8 @@ const _UsageExplorer = (props: UsageExplorerProps) => {
const [selectedInterval, setSelectedInterval] = useState(interval[2]); const [selectedInterval, setSelectedInterval] = useState(interval[2]);
const [selectedService, setSelectedService] = useState<string>(""); const [selectedService, setSelectedService] = useState<string>("");
const { state } = useRoute();
useEffect(() => { useEffect(() => {
if (selectedTime && selectedInterval) { if (selectedTime && selectedInterval) {
const maxTime = new Date().getTime() * 1000000; const maxTime = new Date().getTime() * 1000000;
@ -71,7 +74,13 @@ const _UsageExplorer = (props: UsageExplorerProps) => {
}, [selectedTime, selectedInterval, selectedService]); }, [selectedTime, selectedInterval, selectedService]);
useEffect(() => { useEffect(() => {
props.getServicesList(props.globalTime); /*
Call the apis only when the route is loaded.
Check this issue: https://github.com/SigNoz/signoz/issues/110
*/
if (state.USAGE_EXPLORER.isLoaded) {
props.getServicesList(props.globalTime);
}
}, []); }, []);
const data = { const data = {