prometheus
129 строк · 3.8 Кб
1import React, { FC } from 'react';
2import { Table } from 'reactstrap';
3
4import { useFetch } from '../../hooks/useFetch';
5import { withStatusIndicator } from '../../components/withStatusIndicator';
6import { usePathPrefix } from '../../contexts/PathPrefixContext';
7import { API_PATH } from '../../constants/constants';
8
9interface Stats {
10name: string;
11value: number;
12}
13
14interface HeadStats {
15numSeries: number;
16numLabelPairs: number;
17chunkCount: number;
18minTime: number;
19maxTime: number;
20}
21
22export interface TSDBMap {
23headStats: HeadStats;
24seriesCountByMetricName: Stats[];
25labelValueCountByLabelName: Stats[];
26memoryInBytesByLabelName: Stats[];
27seriesCountByLabelValuePair: Stats[];
28}
29
30export const TSDBStatusContent: FC<TSDBMap> = ({
31headStats,
32labelValueCountByLabelName,
33seriesCountByMetricName,
34memoryInBytesByLabelName,
35seriesCountByLabelValuePair,
36}) => {
37const unixToTime = (unix: number): string => {
38try {
39return `${new Date(unix).toISOString()} (${unix})`;
40} catch {
41if (numSeries === 0) {
42return 'No datapoints yet';
43}
44return `Error parsing time (${unix})`;
45}
46};
47const { chunkCount, numSeries, numLabelPairs, minTime, maxTime } = headStats;
48const stats = [
49{ header: 'Number of Series', value: numSeries },
50{ header: 'Number of Chunks', value: chunkCount },
51{ header: 'Number of Label Pairs', value: numLabelPairs },
52{ header: 'Current Min Time', value: `${unixToTime(minTime)}` },
53{ header: 'Current Max Time', value: `${unixToTime(maxTime)}` },
54];
55return (
56<div>
57<h2>TSDB Status</h2>
58<h3 className="p-2">Head Stats</h3>
59<div className="p-2">
60<Table bordered size="sm" striped>
61<thead>
62<tr>
63{stats.map(({ header }) => {
64return <th key={header}>{header}</th>;
65})}
66</tr>
67</thead>
68<tbody>
69<tr>
70{stats.map(({ header, value }) => {
71return <td key={header}>{value}</td>;
72})}
73</tr>
74</tbody>
75</Table>
76</div>
77<h3 className="p-2">Head Cardinality Stats</h3>
78{[
79{ title: 'Top 10 label names with value count', stats: labelValueCountByLabelName },
80{ title: 'Top 10 series count by metric names', stats: seriesCountByMetricName },
81{ title: 'Top 10 label names with high memory usage', unit: 'Bytes', stats: memoryInBytesByLabelName },
82{ title: 'Top 10 series count by label value pairs', stats: seriesCountByLabelValuePair },
83].map(({ title, unit = 'Count', stats }) => {
84return (
85<div className="p-2" key={title}>
86<h3>{title}</h3>
87<Table bordered size="sm" striped>
88<thead>
89<tr>
90<th>Name</th>
91<th>{unit}</th>
92</tr>
93</thead>
94<tbody>
95{stats.map(({ name, value }) => {
96return (
97<tr key={name}>
98<td>{name}</td>
99<td>{value}</td>
100</tr>
101);
102})}
103</tbody>
104</Table>
105</div>
106);
107})}
108</div>
109);
110};
111TSDBStatusContent.displayName = 'TSDBStatusContent';
112
113const TSDBStatusContentWithStatusIndicator = withStatusIndicator(TSDBStatusContent);
114
115const TSDBStatus: FC = () => {
116const pathPrefix = usePathPrefix();
117const { response, error, isLoading } = useFetch<TSDBMap>(`${pathPrefix}/${API_PATH}/status/tsdb`);
118
119return (
120<TSDBStatusContentWithStatusIndicator
121error={error}
122isLoading={isLoading}
123{...response.data}
124componentTitle="TSDB Status information"
125/>
126);
127};
128
129export default TSDBStatus;
130