mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
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:
@@ -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}`;
|
||||
}
|
||||
|
||||
@@ -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`
|
||||
|
||||
Reference in New Issue
Block a user