mirror of
https://github.com/grafana/grafana.git
synced 2025-02-15 01:53:33 -06:00
PanelInspector: Add Stats Tab (#22683)
* add tab * add process measurement * Fixed some design issues * Align tabs margin Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
This commit is contained in:
parent
c75574298c
commit
08d8190c02
@ -434,6 +434,10 @@ export interface DataQueryRequest<TQuery extends DataQuery = DataQuery> {
|
||||
endTime?: number;
|
||||
}
|
||||
|
||||
export interface DataQueryTimings {
|
||||
dataProcessingTime: number;
|
||||
}
|
||||
|
||||
export interface QueryFix {
|
||||
type: string;
|
||||
label: string;
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { ComponentClass, ComponentType } from 'react';
|
||||
import { DataQueryError, DataQueryRequest } from './datasource';
|
||||
import { DataQueryError, DataQueryRequest, DataQueryTimings } from './datasource';
|
||||
import { GrafanaPlugin, PluginMeta } from './plugin';
|
||||
import { ScopedVars } from './ScopedVars';
|
||||
import { LoadingState } from './data';
|
||||
@ -19,6 +19,7 @@ export interface PanelData {
|
||||
state: LoadingState;
|
||||
series: DataFrame[];
|
||||
request?: DataQueryRequest;
|
||||
timings?: DataQueryTimings;
|
||||
error?: DataQueryError;
|
||||
// Contains the range from the request or a shifted time range if a request uses relative time
|
||||
timeRange: TimeRange;
|
||||
|
@ -44,7 +44,7 @@ export const InspectHeader: FC<Props> = ({
|
||||
<h3>{panel.title}</h3>
|
||||
<div>{formatStats(stats)}</div>
|
||||
</div>
|
||||
<TabsBar>
|
||||
<TabsBar className={styles.tabsBar}>
|
||||
{tabs.map((t, index) => {
|
||||
return (
|
||||
<Tab
|
||||
@ -67,13 +67,15 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => {
|
||||
background-color: ${headerBackground};
|
||||
z-index: 1;
|
||||
flex-grow: 0;
|
||||
padding: ${theme.spacing.sm} ${theme.spacing.sm} 0 ${theme.spacing.lg};
|
||||
`,
|
||||
actions: css`
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
margin-bottom: ${theme.spacing.md};
|
||||
margin: ${theme.spacing.md};
|
||||
`,
|
||||
tabsBar: css`
|
||||
padding-left: ${theme.spacing.md};
|
||||
`,
|
||||
iconWrapper: css`
|
||||
cursor: pointer;
|
||||
@ -88,6 +90,7 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => {
|
||||
`,
|
||||
titleWrapper: css`
|
||||
margin-bottom: ${theme.spacing.lg};
|
||||
padding: ${theme.spacing.sm} ${theme.spacing.sm} 0 ${theme.spacing.lg};
|
||||
`,
|
||||
};
|
||||
});
|
||||
|
@ -28,17 +28,18 @@ interface Props {
|
||||
|
||||
export enum InspectTab {
|
||||
Data = 'data',
|
||||
Raw = 'raw',
|
||||
Request = 'request',
|
||||
Issue = 'issue',
|
||||
Meta = 'meta', // When result metadata exists
|
||||
Error = 'error',
|
||||
Stats = 'stats',
|
||||
}
|
||||
|
||||
interface State {
|
||||
// The last raw response
|
||||
last: PanelData;
|
||||
|
||||
// Data frem the last response
|
||||
// Data from the last response
|
||||
data: DataFrame[];
|
||||
|
||||
// The selected data frame
|
||||
@ -50,7 +51,7 @@ interface State {
|
||||
// If the datasource supports custom metadata
|
||||
metaDS?: DataSourceApi;
|
||||
|
||||
stats: { requestTime: number; queries: number; dataSources: number };
|
||||
stats: { requestTime: number; queries: number; dataSources: number; processingTime: number };
|
||||
|
||||
drawerWidth: string;
|
||||
}
|
||||
@ -63,8 +64,8 @@ export class PanelInspector extends PureComponent<Props, State> {
|
||||
data: [],
|
||||
selected: 0,
|
||||
tab: props.selectedTab || InspectTab.Data,
|
||||
drawerWidth: '40%',
|
||||
stats: { requestTime: 0, queries: 0, dataSources: 0 },
|
||||
drawerWidth: '50%',
|
||||
stats: { requestTime: 0, queries: 0, dataSources: 0, processingTime: 0 },
|
||||
};
|
||||
}
|
||||
|
||||
@ -90,6 +91,7 @@ export class PanelInspector extends PureComponent<Props, State> {
|
||||
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) {
|
||||
@ -123,6 +125,7 @@ export class PanelInspector extends PureComponent<Props, State> {
|
||||
requestTime,
|
||||
queries: targets.length,
|
||||
dataSources,
|
||||
processingTime,
|
||||
},
|
||||
}));
|
||||
}
|
||||
@ -163,11 +166,7 @@ export class PanelInspector extends PureComponent<Props, State> {
|
||||
if (!metaDS || !metaDS.components?.MetadataInspector) {
|
||||
return <div>No Metadata Inspector</div>;
|
||||
}
|
||||
return (
|
||||
<CustomScrollbar>
|
||||
<metaDS.components.MetadataInspector datasource={metaDS} data={data} />
|
||||
</CustomScrollbar>
|
||||
);
|
||||
return <metaDS.components.MetadataInspector datasource={metaDS} data={data} />;
|
||||
}
|
||||
|
||||
renderDataTab() {
|
||||
@ -232,32 +231,44 @@ export class PanelInspector extends PureComponent<Props, State> {
|
||||
);
|
||||
}
|
||||
|
||||
renderIssueTab() {
|
||||
return <CustomScrollbar>TODO: show issue form</CustomScrollbar>;
|
||||
}
|
||||
|
||||
renderErrorTab(error?: DataQueryError) {
|
||||
if (!error) {
|
||||
return null;
|
||||
}
|
||||
if (error.data) {
|
||||
return (
|
||||
<CustomScrollbar>
|
||||
<>
|
||||
<h3>{error.data.message}</h3>
|
||||
<pre>
|
||||
<code>{error.data.error}</code>
|
||||
</pre>
|
||||
</CustomScrollbar>
|
||||
<JSONFormatter json={error} open={2} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
return <div>{error.message}</div>;
|
||||
}
|
||||
|
||||
renderRawJsonTab(last: PanelData) {
|
||||
renderRequestTab() {
|
||||
return <JSONFormatter json={this.state.last} open={3} />;
|
||||
}
|
||||
|
||||
renderStatsTab() {
|
||||
const { stats } = this.state;
|
||||
return (
|
||||
<CustomScrollbar>
|
||||
<JSONFormatter json={last} open={2} />
|
||||
</CustomScrollbar>
|
||||
<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>
|
||||
);
|
||||
}
|
||||
|
||||
@ -270,6 +281,9 @@ export class PanelInspector extends PureComponent<Props, State> {
|
||||
tabs.push({ label: 'Data', value: InspectTab.Data });
|
||||
}
|
||||
|
||||
tabs.push({ label: 'Stats', value: InspectTab.Stats });
|
||||
tabs.push({ label: 'Request', value: InspectTab.Request });
|
||||
|
||||
if (this.state.metaDS) {
|
||||
tabs.push({ label: 'Meta Data', value: InspectTab.Meta });
|
||||
}
|
||||
@ -278,8 +292,6 @@ export class PanelInspector extends PureComponent<Props, State> {
|
||||
tabs.push({ label: 'Error', value: InspectTab.Error });
|
||||
}
|
||||
|
||||
tabs.push({ label: 'Raw JSON', value: InspectTab.Raw });
|
||||
|
||||
return (
|
||||
<InspectHeader
|
||||
tabs={tabs}
|
||||
@ -302,25 +314,13 @@ export class PanelInspector extends PureComponent<Props, State> {
|
||||
return (
|
||||
<Drawer title={this.drawerHeader} width={drawerWidth} onClose={this.onDismiss}>
|
||||
<TabContent className={styles.tabContent}>
|
||||
{tab === InspectTab.Data ? (
|
||||
this.renderDataTab()
|
||||
) : (
|
||||
<AutoSizer>
|
||||
{({ width, height }) => {
|
||||
if (width === 0) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<div style={{ width, height }}>
|
||||
{tab === InspectTab.Meta && this.renderMetadataInspector()}
|
||||
{tab === InspectTab.Issue && this.renderIssueTab()}
|
||||
{tab === InspectTab.Raw && this.renderRawJsonTab(last)}
|
||||
{tab === InspectTab.Error && this.renderErrorTab(error)}
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
</AutoSizer>
|
||||
)}
|
||||
<CustomScrollbar autoHeightMin="100%">
|
||||
{tab === InspectTab.Data && this.renderDataTab()}
|
||||
{tab === InspectTab.Meta && this.renderMetadataInspector()}
|
||||
{tab === InspectTab.Request && this.renderRequestTab()}
|
||||
{tab === InspectTab.Error && this.renderErrorTab(error)}
|
||||
{tab === InspectTab.Stats && this.renderStatsTab()}
|
||||
</CustomScrollbar>
|
||||
</TabContent>
|
||||
</Drawer>
|
||||
);
|
||||
|
@ -216,8 +216,13 @@ export function preProcessPanelData(data: PanelData, lastResult: PanelData): Pan
|
||||
}
|
||||
|
||||
// Make sure the data frames are properly formatted
|
||||
const STARTTIME = performance.now();
|
||||
const processedDataFrames = getProcessedDataFrames(series);
|
||||
const STOPTIME = performance.now();
|
||||
|
||||
return {
|
||||
...data,
|
||||
series: getProcessedDataFrames(series),
|
||||
series: processedDataFrames,
|
||||
timings: { dataProcessingTime: STOPTIME - STARTTIME },
|
||||
};
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user