Graphite: Rollup Indicator (#22738)

* WIP: Rollup indiator progress

* Progress

* Progress, can now open inspector with right tab

* changed type and made inspect

* Showing stats

* Progress

* Progress

* Getting ready for v1

* Added option and fixed some strict nulls

* Updated

* Fixed test
This commit is contained in:
Torkel Ödegaard
2020-03-18 13:00:14 +01:00
committed by GitHub
parent 579abad9cc
commit 044ec40112
21 changed files with 631 additions and 226 deletions

View File

@@ -1,17 +1,16 @@
import React, { FC } from 'react';
import { css } from 'emotion';
import { Icon, selectThemeVariant, stylesFactory, Tab, TabsBar, useTheme } from '@grafana/ui';
import { GrafanaTheme, SelectableValue } from '@grafana/data';
import { GrafanaTheme, SelectableValue, PanelData, getValueFormat, formattedValueToString } from '@grafana/data';
import { InspectTab } from './PanelInspector';
import { PanelModel } from '../../state';
interface Props {
tab: InspectTab;
tabs: Array<{ label: string; value: InspectTab }>;
stats: { requestTime: number; queries: number; dataSources: number };
panelData: PanelData;
panel: PanelModel;
isExpanded: boolean;
onSelectTab: (tab: SelectableValue<InspectTab>) => void;
onClose: () => void;
onToggleExpand: () => void;
@@ -24,7 +23,7 @@ export const InspectHeader: FC<Props> = ({
onClose,
onToggleExpand,
panel,
stats,
panelData,
isExpanded,
}) => {
const theme = useTheme();
@@ -42,7 +41,7 @@ export const InspectHeader: FC<Props> = ({
</div>
<div className={styles.titleWrapper}>
<h3>{panel.title}</h3>
<div>{formatStats(stats)}</div>
<div className="muted">{formatStats(panelData)}</div>
</div>
<TabsBar className={styles.tabsBar}>
{tabs.map((t, index) => {
@@ -95,10 +94,15 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => {
};
});
function formatStats(stats: { requestTime: number; queries: number; dataSources: number }) {
const queries = `${stats.queries} ${stats.queries === 1 ? 'query' : 'queries'}`;
const dataSources = `${stats.dataSources} ${stats.dataSources === 1 ? 'data source' : 'data sources'}`;
const requestTime = `${stats.requestTime === -1 ? 'N/A' : stats.requestTime}ms`;
function formatStats(panelData: PanelData) {
const { request } = panelData;
if (!request) {
return '';
}
return `${queries} - ${dataSources} - ${requestTime}`;
const queryCount = request.targets.length;
const requestTime = request.endTime ? request.endTime - request.startTime : 0;
const formatted = formattedValueToString(getValueFormat('ms')(requestTime));
return `${queryCount} queries with total query time of ${formatted}`;
}

View File

@@ -16,7 +16,9 @@ import {
toCSV,
DataQueryError,
PanelData,
DataQuery,
getValueFormat,
formattedValueToString,
QueryResultMetaStat,
} from '@grafana/data';
import { config } from 'app/core/config';
@@ -51,8 +53,6 @@ interface State {
// If the datasource supports custom metadata
metaDS?: DataSourceApi;
stats: { requestTime: number; queries: number; dataSources: number; processingTime: number };
drawerWidth: string;
}
@@ -65,7 +65,6 @@ export class PanelInspector extends PureComponent<Props, State> {
selected: 0,
tab: props.selectedTab || InspectTab.Data,
drawerWidth: '50%',
stats: { requestTime: 0, queries: 0, dataSources: 0, processingTime: 0 },
};
}
@@ -89,23 +88,13 @@ export class PanelInspector extends PureComponent<Props, State> {
const error = lastResult.error;
const targets = lastResult.request?.targets || [];
const requestTime = lastResult.request?.endTime ? lastResult.request?.endTime - lastResult.request.startTime : -1;
const dataSources = new Set(targets.map(t => t.datasource)).size;
const processingTime = lastResult.timings?.dataProcessingTime || -1;
// Find the first DataSource wanting to show custom metadata
if (data && targets.length) {
const queries: Record<string, DataQuery> = {};
for (const target of targets) {
queries[target.refId] = target;
}
for (const frame of data) {
const q = queries[frame.refId];
if (q && frame.meta && frame.meta.custom) {
const dataSource = await getDataSourceSrv().get(q.datasource);
if (frame.meta && frame.meta.custom) {
// get data source from first query
const dataSource = await getDataSourceSrv().get(targets[0].datasource);
if (dataSource && dataSource.components?.MetadataInspector) {
metaDS = dataSource;
@@ -121,12 +110,6 @@ export class PanelInspector extends PureComponent<Props, State> {
data,
metaDS,
tab: error ? InspectTab.Error : prevState.tab,
stats: {
requestTime,
queries: targets.length,
dataSources,
processingTime,
},
}));
}
@@ -184,7 +167,6 @@ export class PanelInspector extends PureComponent<Props, State> {
};
});
// Apply dummy styles
const processed = applyFieldOverrides({
data,
theme: config.theme,
@@ -251,29 +233,66 @@ export class PanelInspector extends PureComponent<Props, State> {
}
renderStatsTab() {
const { stats } = this.state;
const { last } = this.state;
const { request } = last;
if (!request) {
return null;
}
let stats: QueryResultMetaStat[] = [];
const requestTime = request.endTime ? request.endTime - request.startTime : -1;
const processingTime = last.timings?.dataProcessingTime || -1;
let dataRows = 0;
for (const frame of last.series) {
dataRows += frame.length;
}
stats.push({ title: 'Total request time', value: requestTime, unit: 'ms' });
stats.push({ title: 'Data processing time', value: processingTime, unit: 'ms' });
stats.push({ title: 'Number of queries', value: request.targets.length });
stats.push({ title: 'Total number rows', value: dataRows });
let dataStats: QueryResultMetaStat[] = [];
for (const series of last.series) {
if (series.meta && series.meta.stats) {
dataStats = dataStats.concat(series.meta.stats);
}
}
return (
<table className="filter-table width-30">
<tbody>
<tr>
<td>Query time</td>
<td>{`${stats.requestTime === -1 ? 'N/A' : stats.requestTime + 'ms'}`}</td>
</tr>
<tr>
<td>Data processing time</td>
<td>{`${
stats.processingTime === -1
? 'N/A'
: Math.round((stats.processingTime + Number.EPSILON) * 100) / 100 + 'ms'
}`}</td>
</tr>
</tbody>
</table>
<>
{this.renderStatsTable('Stats', stats)}
{dataStats.length && this.renderStatsTable('Data source stats', dataStats)}
</>
);
}
renderStatsTable(name: string, stats: QueryResultMetaStat[]) {
return (
<div style={{ paddingBottom: '16px' }}>
<div className="section-heading">{name}</div>
<table className="filter-table width-30">
<tbody>
{stats.map(stat => {
return (
<tr>
<td>{stat.title}</td>
<td style={{ textAlign: 'right' }}>{formatStat(stat.value, stat.unit)}</td>
</tr>
);
})}
</tbody>
</table>
</div>
);
}
drawerHeader = () => {
const { tab, last, stats } = this.state;
const { tab, last } = this.state;
const error = last?.error;
const tabs = [];
@@ -296,7 +315,7 @@ export class PanelInspector extends PureComponent<Props, State> {
<InspectHeader
tabs={tabs}
tab={tab}
stats={stats}
panelData={last}
onSelectTab={this.onSelectTab}
onClose={this.onDismiss}
panel={this.props.panel}
@@ -327,6 +346,14 @@ export class PanelInspector extends PureComponent<Props, State> {
}
}
function formatStat(value: any, unit?: string): string {
if (unit) {
return formattedValueToString(getValueFormat(unit)(value));
} else {
return value;
}
}
const getStyles = stylesFactory(() => {
return {
toolbar: css`