mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-16 15:45:56 +08:00
feat: show rate limit warning in services page when total RPS > 100 (#4266)
* feat: show rate limit warning in services page when total rps > 100 * feat: update message * feat: rate limit message should be shown only to cloud users on trail --------- Co-authored-by: Vishal Sharma <makeavish786@gmail.com>
This commit is contained in:
parent
585d6e2a21
commit
2e0fdbb498
3
frontend/public/locales/en-GB/services.json
Normal file
3
frontend/public/locales/en-GB/services.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"rps_over_100": "You are sending data at more than 100 RPS, your ingestion may be rate limited. Please reach out to us via Intercom support."
|
||||
}
|
3
frontend/public/locales/en/services.json
Normal file
3
frontend/public/locales/en/services.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"rps_over_100": "You are sending data at more than 100 RPS, your ingestion may be rate limited. Please reach out to us via Intercom support."
|
||||
}
|
2
frontend/src/constants/global.ts
Normal file
2
frontend/src/constants/global.ts
Normal file
@ -0,0 +1,2 @@
|
||||
const MAX_RPS_LIMIT = 100;
|
||||
export { MAX_RPS_LIMIT };
|
@ -1,12 +1,20 @@
|
||||
import { WarningFilled } from '@ant-design/icons';
|
||||
import { Flex, Typography } from 'antd';
|
||||
import { ResizeTable } from 'components/ResizeTable';
|
||||
import { MAX_RPS_LIMIT } from 'constants/global';
|
||||
import ResourceAttributesFilter from 'container/ResourceAttributesFilter';
|
||||
import { useGetQueriesRange } from 'hooks/queryBuilder/useGetQueriesRange';
|
||||
import useLicense from 'hooks/useLicense';
|
||||
import { useNotifications } from 'hooks/useNotifications';
|
||||
import { useMemo } from 'react';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { AppState } from 'store/reducers';
|
||||
import { ServicesList } from 'types/api/metrics/getService';
|
||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||
import { isCloudUser } from 'utils/app';
|
||||
import { getTotalRPS } from 'utils/services';
|
||||
|
||||
import { getColumns } from '../Columns/ServiceColumn';
|
||||
import { ServiceMetricsTableProps } from '../types';
|
||||
@ -22,6 +30,10 @@ function ServiceMetricTable({
|
||||
>((state) => state.globalTime);
|
||||
|
||||
const { notifications } = useNotifications();
|
||||
const { t: getText } = useTranslation(['services']);
|
||||
|
||||
const { data: licenseData, isFetching } = useLicense();
|
||||
const isCloudUserVal = isCloudUser();
|
||||
|
||||
const queries = useGetQueriesRange(queryRangeRequestData, {
|
||||
queryKey: [
|
||||
@ -53,14 +65,38 @@ function ServiceMetricTable({
|
||||
|
||||
const { search } = useLocation();
|
||||
const tableColumns = useMemo(() => getColumns(search, true), [search]);
|
||||
const [RPS, setRPS] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isFetching && licenseData?.payload?.onTrial && isCloudUserVal) {
|
||||
if (services.length > 0) {
|
||||
const rps = getTotalRPS(services);
|
||||
setRPS(rps);
|
||||
} else {
|
||||
setRPS(0);
|
||||
}
|
||||
}
|
||||
}, [services, licenseData, isFetching, isCloudUserVal]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{RPS > MAX_RPS_LIMIT && (
|
||||
<Flex justify="center">
|
||||
<Typography.Title level={5} type="warning" style={{ marginTop: 0 }}>
|
||||
<WarningFilled /> {getText('rps_over_100')}
|
||||
</Typography.Title>
|
||||
</Flex>
|
||||
)}
|
||||
|
||||
<ResourceAttributesFilter />
|
||||
|
||||
<ResizeTable
|
||||
columns={tableColumns}
|
||||
loading={isLoading}
|
||||
dataSource={services}
|
||||
rowKey="serviceName"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,14 @@
|
||||
import { WarningFilled } from '@ant-design/icons';
|
||||
import { Flex, Typography } from 'antd';
|
||||
import { ResizeTable } from 'components/ResizeTable';
|
||||
import { useMemo } from 'react';
|
||||
import { MAX_RPS_LIMIT } from 'constants/global';
|
||||
import ResourceAttributesFilter from 'container/ResourceAttributesFilter';
|
||||
import useLicense from 'hooks/useLicense';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { isCloudUser } from 'utils/app';
|
||||
import { getTotalRPS } from 'utils/services';
|
||||
|
||||
import { getColumns } from '../Columns/ServiceColumn';
|
||||
import ServiceTableProps from '../types';
|
||||
@ -10,16 +18,43 @@ function ServiceTraceTable({
|
||||
loading,
|
||||
}: ServiceTableProps): JSX.Element {
|
||||
const { search } = useLocation();
|
||||
const [RPS, setRPS] = useState(0);
|
||||
const { t: getText } = useTranslation(['services']);
|
||||
|
||||
const { data: licenseData, isFetching } = useLicense();
|
||||
const isCloudUserVal = isCloudUser();
|
||||
const tableColumns = useMemo(() => getColumns(search, false), [search]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isFetching && licenseData?.payload?.onTrial && isCloudUserVal) {
|
||||
if (services.length > 0) {
|
||||
const rps = getTotalRPS(services);
|
||||
setRPS(rps);
|
||||
} else {
|
||||
setRPS(0);
|
||||
}
|
||||
}
|
||||
}, [services, licenseData, isFetching, isCloudUserVal]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{RPS > MAX_RPS_LIMIT && (
|
||||
<Flex justify="flex-end">
|
||||
<Typography.Text type="warning" style={{ marginTop: 0 }}>
|
||||
<WarningFilled /> {getText('rps_over_100')}
|
||||
</Typography.Text>
|
||||
</Flex>
|
||||
)}
|
||||
|
||||
<ResourceAttributesFilter />
|
||||
|
||||
<ResizeTable
|
||||
columns={tableColumns}
|
||||
loading={loading}
|
||||
dataSource={services}
|
||||
rowKey="serviceName"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,7 @@ function Services(): JSX.Element {
|
||||
|
||||
return (
|
||||
<ErrorBoundary FallbackComponent={ErrorBoundaryFallback}>
|
||||
<Container>
|
||||
<Container style={{ marginTop: 0 }}>
|
||||
{isSpanMetricEnabled ? <ServiceMetrics /> : <ServiceTraces />}
|
||||
</Container>
|
||||
</ErrorBoundary>
|
||||
|
@ -6,9 +6,12 @@ import { extractDomain } from 'utils/app';
|
||||
const useAnalytics = (): any => {
|
||||
const { user } = useSelector<AppState, AppReducer>((state) => state.app);
|
||||
|
||||
// Segment Page View - analytics.page([category], [name], [properties], [options], [callback]);
|
||||
const trackPageView = (pageName: string): void => {
|
||||
if (user && user.email) {
|
||||
window.analytics.page(pageName);
|
||||
window.analytics.page(null, pageName, {
|
||||
userId: user.email,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@ -22,6 +25,9 @@ const useAnalytics = (): any => {
|
||||
groupId: extractDomain(user?.email),
|
||||
},
|
||||
};
|
||||
|
||||
const updatedPropertes = { ...properties };
|
||||
updatedPropertes.userId = user.email;
|
||||
window.analytics.track(eventName, properties, context);
|
||||
}
|
||||
};
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { Space } from 'antd';
|
||||
import ReleaseNote from 'components/ReleaseNote';
|
||||
import ResourceAttributesFilter from 'container/ResourceAttributesFilter';
|
||||
import ServicesApplication from 'container/ServiceApplication';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
|
||||
@ -11,7 +10,6 @@ function Metrics(): JSX.Element {
|
||||
<Space direction="vertical" style={{ width: '100%' }}>
|
||||
<ReleaseNote path={location.pathname} />
|
||||
|
||||
<ResourceAttributesFilter />
|
||||
<ServicesApplication />
|
||||
</Space>
|
||||
);
|
||||
|
4
frontend/src/utils/services.ts
Normal file
4
frontend/src/utils/services.ts
Normal file
@ -0,0 +1,4 @@
|
||||
import { ServicesList } from 'types/api/metrics/getService';
|
||||
|
||||
export const getTotalRPS = (services: ServicesList[]): number =>
|
||||
services.reduce((accumulator, service) => accumulator + service.callRate, 0);
|
Loading…
x
Reference in New Issue
Block a user