feat: add monitor data metrics in monitor info

This commit is contained in:
moonrailgun 2023-10-13 00:55:41 +08:00
parent b4f2170e51
commit 7bc245eb45
4 changed files with 201 additions and 19 deletions

View File

@ -5,12 +5,14 @@ import { HealthBar, HealthBarBeat, HealthBarProps } from '../HealthBar';
import dayjs from 'dayjs';
import { trpc } from '../../api/trpc';
import { useCurrentWorkspaceId } from '../../store/user';
import { useWatch } from '../../hooks/useWatch';
interface MonitorHealthBarProps {
monitorId: string;
count?: number;
size?: HealthBarProps['size'];
showCurrentStatus?: boolean;
onBeatsItemUpdate?: (items: { value: number; createdAt: string }[]) => void;
}
export const MonitorHealthBar: React.FC<MonitorHealthBarProps> = React.memo(
(props) => {
@ -38,28 +40,34 @@ export const MonitorHealthBar: React.FC<MonitorHealthBarProps> = React.memo(
);
}, [newDataList, recent, count]);
const beats = items.map((item): HealthBarBeat => {
if (!item) {
return {
status: 'none',
};
}
const beats = useMemo(() => {
return items.map((item): HealthBarBeat => {
if (!item) {
return {
status: 'none',
};
}
const title = `${dayjs(item.createdAt).format('YYYY-MM-DD HH:mm')} | ${
item.value
}ms`;
const title = `${dayjs(item.createdAt).format('YYYY-MM-DD HH:mm')} | ${
item.value
}ms`;
if (item.value < 0) {
return {
title,
status: 'error',
};
}
if (item.value < 0) {
return {
title,
status: 'error',
status: 'health',
};
}
});
}, [items]);
return {
title,
status: 'health',
};
useWatch([items], () => {
props.onBeatsItemUpdate?.(items);
});
return (

View File

@ -10,7 +10,8 @@ import { MonitorInfo as MonitorInfoType } from '../../../types';
import { Area, AreaConfig } from '@ant-design/charts';
import { MonitorHealthBar } from './MonitorHealthBar';
import { useSocketSubscribeList } from '../../api/socketio';
import { uniqBy } from 'lodash';
import { last, uniqBy } from 'lodash-es';
import { ErrorTip } from '../ErrorTip';
interface MonitorInfoProps {
monitorId: string;
@ -18,6 +19,7 @@ interface MonitorInfoProps {
export const MonitorInfo: React.FC<MonitorInfoProps> = React.memo((props) => {
const workspaceId = useCurrentWorkspaceId();
const { monitorId } = props;
const [currectResponse, setCurrentResponse] = useState(0);
const { data: monitorInfo, isLoading } = trpc.monitor.get.useQuery({
workspaceId,
@ -59,6 +61,16 @@ export const MonitorInfo: React.FC<MonitorInfoProps> = React.memo((props) => {
count={40}
size="large"
showCurrentStatus={true}
onBeatsItemUpdate={(items) => {
setCurrentResponse(last(items)?.value ?? 0);
}}
/>
</Card>
<Card>
<MonitorDataMetrics
monitorId={monitorId}
currectResponse={currectResponse}
/>
</Card>
@ -71,6 +83,70 @@ export const MonitorInfo: React.FC<MonitorInfoProps> = React.memo((props) => {
});
MonitorInfo.displayName = 'MonitorInfo';
export const MonitorDataMetrics: React.FC<{
monitorId: string;
currectResponse: number;
}> = React.memo((props) => {
const workspaceId = useCurrentWorkspaceId();
const { monitorId, currectResponse } = props;
const { data, isLoading } = trpc.monitor.dataMetrics.useQuery({
workspaceId,
monitorId,
});
if (isLoading) {
return <Loading />;
}
if (!data) {
return <ErrorTip />;
}
return (
<div className="flex justify-between text-center">
<div>
<div className="font-bold mb-0.5">Response</div>
<div className="text-gray-500">(Current)</div>
<div>{currectResponse} ms</div>
</div>
<div>
<div className="font-bold mb-0.5">Avg. Response</div>
<div className="text-gray-500">(24 hour)</div>
<div>{parseFloat(data.recent1DayAvg.toFixed(0))} ms</div>
</div>
<div>
<div className="font-bold mb-0.5">Uptime</div>
<div className="text-gray-500 mb-2 text-xs">(24 hour)</div>
<div>
{parseFloat(
(
(data.recent1DayOnlineCount /
(data.recent1DayOnlineCount + data.recent1DayOfflineCount)) *
100
).toFixed(2)
)}
%
</div>
</div>
<div>
<div className="font-bold mb-0.5">Uptime</div>
<div className="text-gray-500">(30 days)</div>
<div>
{parseFloat(
(
(data.recent30DayOnlineCount /
(data.recent30DayOnlineCount + data.recent30DayOfflineCount)) *
100
).toFixed(2)
)}
%
</div>
</div>
</div>
);
});
MonitorDataMetrics.displayName = 'MonitorDataMetrics';
const MonitorDataChart: React.FC<{ monitorId: string }> = React.memo(
(props) => {
const workspaceId = useCurrentWorkspaceId();

View File

@ -0,0 +1,12 @@
import { DependencyList, useLayoutEffect } from 'react';
import { useEvent } from './useEvent';
/**
*
*/
export function useWatch(deps: DependencyList, cb: () => void) {
const memoizedFn = useEvent(cb);
useLayoutEffect(() => {
memoizedFn();
}, deps);
}

View File

@ -3,6 +3,7 @@ import { prisma } from '../../model/_client';
import { z } from 'zod';
import { monitorManager } from '../../model/monitor';
import { MonitorInfo } from '../../../types';
import dayjs from 'dayjs';
export const monitorRouter = router({
all: workspaceProcedure.query(async ({ input }) => {
@ -58,7 +59,7 @@ export const monitorRouter = router({
return monitor;
}),
data: workspaceOwnerProcedure
data: workspaceProcedure
.input(
z.object({
monitorId: z.string().cuid2(),
@ -86,7 +87,7 @@ export const monitorRouter = router({
},
});
}),
recentData: workspaceOwnerProcedure
recentData: workspaceProcedure
.input(
z.object({
monitorId: z.string().cuid2(),
@ -107,4 +108,89 @@ export const monitorRouter = router({
},
});
}),
dataMetrics: workspaceProcedure
.input(
z.object({
monitorId: z.string().cuid2(),
})
)
.query(async ({ input }) => {
const { monitorId } = input;
const now = dayjs();
const [
recent1DayAvg,
recent1DayOnlineCount,
recent1DayOfflineCount,
recent30DayOnlineCount,
recent30DayOfflineCount,
] = await Promise.all([
prisma.monitorData
.aggregate({
_avg: {
value: true,
},
where: {
monitorId,
createdAt: {
lte: now.toDate(),
gte: now.subtract(1, 'day').toDate(),
},
},
})
.then((res) => res._avg.value ?? -1),
prisma.monitorData.count({
where: {
monitorId,
createdAt: {
lte: now.toDate(),
gte: now.subtract(1, 'day').toDate(),
},
value: {
gte: 0,
},
},
}),
prisma.monitorData.count({
where: {
monitorId,
createdAt: {
lte: now.toDate(),
gte: now.subtract(1, 'day').toDate(),
},
value: -1,
},
}),
prisma.monitorData.count({
where: {
monitorId,
createdAt: {
lte: now.toDate(),
gte: now.subtract(30, 'day').toDate(),
},
value: {
gte: 0,
},
},
}),
prisma.monitorData.count({
where: {
monitorId,
createdAt: {
lte: now.toDate(),
gte: now.subtract(30, 'day').toDate(),
},
value: -1,
},
}),
]);
return {
recent1DayAvg,
recent1DayOnlineCount,
recent1DayOfflineCount,
recent30DayOnlineCount,
recent30DayOfflineCount,
};
}),
});