mirror of
https://github.com/prometheus/prometheus.git
synced 2025-03-05 20:59:13 -08:00
React ui add query stats (#6190)
* Adds the query stats to UI Adds the query load time, resolution and total number of time series, as the current UI has Signed-off-by: cstdev <pietomb00@hotmail.com> * Implement unit test for QueryStats Signed-off-by: cstdev <pietomb00@hotmail.com> * Tidy Query Stats component Rename it and expose a interface for the values it displays Make it a functional component as it has no state or lifecycle Better null/undefined checks Only render if needed, decided by the panel Remove old stats if the next errors Signed-off-by: cstdev <pietomb00@hotmail.com>
This commit is contained in:
parent
5f1be2cf45
commit
4262ad92ce
|
@ -19,6 +19,7 @@ import GraphControls from './GraphControls';
|
||||||
import Graph from './Graph';
|
import Graph from './Graph';
|
||||||
import DataTable from './DataTable';
|
import DataTable from './DataTable';
|
||||||
import TimeInput from './TimeInput';
|
import TimeInput from './TimeInput';
|
||||||
|
import QueryStatsView, { QueryStats } from './QueryStatsView';
|
||||||
|
|
||||||
interface PanelProps {
|
interface PanelProps {
|
||||||
options: PanelOptions;
|
options: PanelOptions;
|
||||||
|
@ -36,7 +37,7 @@ interface PanelState {
|
||||||
} | null;
|
} | null;
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
error: string | null;
|
error: string | null;
|
||||||
stats: null; // TODO: Stats.
|
stats: QueryStats | null,
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PanelOptions {
|
export interface PanelOptions {
|
||||||
|
@ -100,6 +101,7 @@ class Panel extends Component<PanelProps, PanelState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
executeQuery = (expr: string): void => {
|
executeQuery = (expr: string): void => {
|
||||||
|
const queryStart = Date.now();
|
||||||
if (this.props.options.expr !== expr) {
|
if (this.props.options.expr !== expr) {
|
||||||
this.setOptions({expr: expr});
|
this.setOptions({expr: expr});
|
||||||
}
|
}
|
||||||
|
@ -119,7 +121,6 @@ class Panel extends Component<PanelProps, PanelState> {
|
||||||
const endTime = this.getEndTime().valueOf() / 1000; // TODO: shouldn't valueof only work when it's a moment?
|
const endTime = this.getEndTime().valueOf() / 1000; // TODO: shouldn't valueof only work when it's a moment?
|
||||||
const startTime = endTime - this.props.options.range;
|
const startTime = endTime - this.props.options.range;
|
||||||
const resolution = this.props.options.resolution || Math.max(Math.floor(this.props.options.range / 250), 1);
|
const resolution = this.props.options.resolution || Math.max(Math.floor(this.props.options.range / 250), 1);
|
||||||
|
|
||||||
const url = new URL(window.location.href);
|
const url = new URL(window.location.href);
|
||||||
const params: {[key: string]: string} = {
|
const params: {[key: string]: string} = {
|
||||||
'query': expr,
|
'query': expr,
|
||||||
|
@ -153,14 +154,29 @@ class Panel extends Component<PanelProps, PanelState> {
|
||||||
throw new Error(json.error || 'invalid response JSON');
|
throw new Error(json.error || 'invalid response JSON');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let resultSeries = 0;
|
||||||
|
if (json.data) {
|
||||||
|
const { resultType, result } = json.data;
|
||||||
|
if (resultType === "scalar") {
|
||||||
|
resultSeries = 1;
|
||||||
|
} else if (result && result.length > 0) {
|
||||||
|
resultSeries = result.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
error: null,
|
error: null,
|
||||||
data: json.data,
|
data: json.data,
|
||||||
lastQueryParams: {
|
lastQueryParams: {
|
||||||
startTime: startTime,
|
startTime,
|
||||||
endTime: endTime,
|
endTime,
|
||||||
resolution: resolution,
|
resolution,
|
||||||
},
|
},
|
||||||
|
stats: {
|
||||||
|
loadTime: Date.now() - queryStart,
|
||||||
|
resolution,
|
||||||
|
resultSeries
|
||||||
|
},
|
||||||
loading: false,
|
loading: false,
|
||||||
});
|
});
|
||||||
this.abortInFlightFetch = null;
|
this.abortInFlightFetch = null;
|
||||||
|
@ -246,6 +262,10 @@ class Panel extends Component<PanelProps, PanelState> {
|
||||||
Graph
|
Graph
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</NavItem>
|
</NavItem>
|
||||||
|
{
|
||||||
|
(!this.state.loading && !this.state.error && this.state.stats) &&
|
||||||
|
<QueryStatsView {...this.state.stats} />
|
||||||
|
}
|
||||||
</Nav>
|
</Nav>
|
||||||
<TabContent activeTab={this.props.options.type}>
|
<TabContent activeTab={this.props.options.type}>
|
||||||
<TabPane tabId="table">
|
<TabPane tabId="table">
|
||||||
|
|
5
web/ui/react-app/src/QueryStatsView.css
Normal file
5
web/ui/react-app/src/QueryStatsView.css
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
.query-stats{
|
||||||
|
flex-grow: 1;
|
||||||
|
font-size: 9px;
|
||||||
|
color: #999;
|
||||||
|
}
|
20
web/ui/react-app/src/QueryStatsView.tsx
Normal file
20
web/ui/react-app/src/QueryStatsView.tsx
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
import React, { FC } from 'react';
|
||||||
|
import './QueryStatsView.css';
|
||||||
|
|
||||||
|
export interface QueryStats {
|
||||||
|
loadTime: number;
|
||||||
|
resolution: number;
|
||||||
|
resultSeries: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QueryStatsView: FC<QueryStats> = props => {
|
||||||
|
const {loadTime, resolution, resultSeries} = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="query-stats">
|
||||||
|
<span className="float-right">Load time: {loadTime}ms   Resolution: {resolution}s   Result series: {resultSeries}</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default QueryStatsView;
|
Loading…
Reference in a new issue