mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
logs: merge log-lines-based and full-range histogram (#50507)
* logs: merge old-histogram and new-histogram * better variable names * better names * refactor * refactor * refactor * logs: remove log-volume-loading indicator
This commit is contained in:
parent
033654f93f
commit
a22e9a0e0a
@ -24,7 +24,6 @@ import {
|
|||||||
DataQueryResponse,
|
DataQueryResponse,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { reportInteraction } from '@grafana/runtime';
|
import { reportInteraction } from '@grafana/runtime';
|
||||||
import { TooltipDisplayMode } from '@grafana/schema';
|
|
||||||
import {
|
import {
|
||||||
RadioButtonGroup,
|
RadioButtonGroup,
|
||||||
LogRows,
|
LogRows,
|
||||||
@ -40,7 +39,6 @@ import { dedupLogRows, filterLogLevels } from 'app/core/logs_model';
|
|||||||
import store from 'app/core/store';
|
import store from 'app/core/store';
|
||||||
import { ExploreId } from 'app/types/explore';
|
import { ExploreId } from 'app/types/explore';
|
||||||
|
|
||||||
import { ExploreGraph } from './ExploreGraph';
|
|
||||||
import { LogsMetaRow } from './LogsMetaRow';
|
import { LogsMetaRow } from './LogsMetaRow';
|
||||||
import LogsNavigation from './LogsNavigation';
|
import LogsNavigation from './LogsNavigation';
|
||||||
import { LogsVolumePanel } from './LogsVolumePanel';
|
import { LogsVolumePanel } from './LogsVolumePanel';
|
||||||
@ -330,30 +328,19 @@ class UnthemedLogs extends PureComponent<Props, State> {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{logsSeries && logsSeries.length ? (
|
|
||||||
<>
|
|
||||||
<div className={styles.infoText}>
|
|
||||||
This datasource does not support full-range histograms. The graph is based on the logs seen in the
|
|
||||||
response.
|
|
||||||
</div>
|
|
||||||
<ExploreGraph
|
|
||||||
graphStyle="lines"
|
|
||||||
data={logsSeries}
|
|
||||||
height={150}
|
|
||||||
width={width}
|
|
||||||
tooltipDisplayMode={TooltipDisplayMode.Multi}
|
|
||||||
absoluteRange={visibleRange || absoluteRange}
|
|
||||||
timeZone={timeZone}
|
|
||||||
loadingState={loadingState}
|
|
||||||
onChangeTime={onChangeTime}
|
|
||||||
onHiddenSeriesChanged={this.onToggleLogLevel}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
) : undefined}
|
|
||||||
<LogsVolumePanel
|
<LogsVolumePanel
|
||||||
absoluteRange={absoluteRange}
|
absoluteRange={absoluteRange}
|
||||||
width={width}
|
width={width}
|
||||||
logsVolumeData={logsVolumeData}
|
logsVolumeData={logsVolumeData}
|
||||||
|
logLinesBasedData={
|
||||||
|
logsSeries
|
||||||
|
? {
|
||||||
|
data: logsSeries,
|
||||||
|
state: loadingState,
|
||||||
|
}
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
logLinesBasedDataVisibleRange={visibleRange}
|
||||||
onUpdateTimeRange={onChangeTime}
|
onUpdateTimeRange={onChangeTime}
|
||||||
timeZone={timeZone}
|
timeZone={timeZone}
|
||||||
splitOpen={splitOpen}
|
splitOpen={splitOpen}
|
||||||
@ -547,9 +534,5 @@ const getStyles = (theme: GrafanaTheme2, wrapLogMessage: boolean) => {
|
|||||||
overflow-y: visible;
|
overflow-y: visible;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
`,
|
`,
|
||||||
infoText: css`
|
|
||||||
font-size: ${theme.typography.size.sm};
|
|
||||||
color: ${theme.colors.text.secondary};
|
|
||||||
`,
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -21,6 +21,8 @@ function renderPanel(logsVolumeData?: DataQueryResponse) {
|
|||||||
width={100}
|
width={100}
|
||||||
onUpdateTimeRange={() => {}}
|
onUpdateTimeRange={() => {}}
|
||||||
logsVolumeData={logsVolumeData}
|
logsVolumeData={logsVolumeData}
|
||||||
|
logLinesBasedData={undefined}
|
||||||
|
logLinesBasedDataVisibleRange={undefined}
|
||||||
onLoadLogsVolume={() => {}}
|
onLoadLogsVolume={() => {}}
|
||||||
onHiddenSeriesChanged={() => null}
|
onHiddenSeriesChanged={() => null}
|
||||||
/>
|
/>
|
||||||
|
@ -1,14 +1,24 @@
|
|||||||
import { css } from '@emotion/css';
|
import { css } from '@emotion/css';
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
import { AbsoluteTimeRange, DataQueryError, DataQueryResponse, LoadingState, SplitOpen, TimeZone } from '@grafana/data';
|
import {
|
||||||
|
AbsoluteTimeRange,
|
||||||
|
DataQueryError,
|
||||||
|
DataQueryResponse,
|
||||||
|
GrafanaTheme2,
|
||||||
|
LoadingState,
|
||||||
|
SplitOpen,
|
||||||
|
TimeZone,
|
||||||
|
} from '@grafana/data';
|
||||||
import { Alert, Button, Collapse, InlineField, TooltipDisplayMode, useStyles2, useTheme2 } from '@grafana/ui';
|
import { Alert, Button, Collapse, InlineField, TooltipDisplayMode, useStyles2, useTheme2 } from '@grafana/ui';
|
||||||
|
|
||||||
import { ExploreGraph } from './ExploreGraph';
|
import { ExploreGraph } from './ExploreGraph';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
logsVolumeData?: DataQueryResponse;
|
logsVolumeData: DataQueryResponse | undefined;
|
||||||
absoluteRange: AbsoluteTimeRange;
|
absoluteRange: AbsoluteTimeRange;
|
||||||
|
logLinesBasedData: DataQueryResponse | undefined;
|
||||||
|
logLinesBasedDataVisibleRange: AbsoluteTimeRange | undefined;
|
||||||
timeZone: TimeZone;
|
timeZone: TimeZone;
|
||||||
splitOpen: SplitOpen;
|
splitOpen: SplitOpen;
|
||||||
width: number;
|
width: number;
|
||||||
@ -46,29 +56,64 @@ function ErrorAlert(props: { error: DataQueryError }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createVisualisationData(
|
||||||
|
logLinesBased: DataQueryResponse | undefined,
|
||||||
|
logLinesBasedVisibleRange: AbsoluteTimeRange | undefined,
|
||||||
|
fullRangeData: DataQueryResponse | undefined,
|
||||||
|
absoluteRange: AbsoluteTimeRange
|
||||||
|
):
|
||||||
|
| {
|
||||||
|
logsVolumeData: DataQueryResponse;
|
||||||
|
fullRangeData: boolean;
|
||||||
|
range: AbsoluteTimeRange;
|
||||||
|
}
|
||||||
|
| undefined {
|
||||||
|
if (fullRangeData !== undefined) {
|
||||||
|
return {
|
||||||
|
logsVolumeData: fullRangeData,
|
||||||
|
fullRangeData: true,
|
||||||
|
range: absoluteRange,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (logLinesBased !== undefined) {
|
||||||
|
return {
|
||||||
|
logsVolumeData: logLinesBased,
|
||||||
|
fullRangeData: false,
|
||||||
|
range: logLinesBasedVisibleRange || absoluteRange,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
export function LogsVolumePanel(props: Props) {
|
export function LogsVolumePanel(props: Props) {
|
||||||
const {
|
const { width, timeZone, splitOpen, onUpdateTimeRange, onLoadLogsVolume, onHiddenSeriesChanged } = props;
|
||||||
width,
|
|
||||||
logsVolumeData,
|
|
||||||
absoluteRange,
|
|
||||||
timeZone,
|
|
||||||
splitOpen,
|
|
||||||
onUpdateTimeRange,
|
|
||||||
onLoadLogsVolume,
|
|
||||||
onHiddenSeriesChanged,
|
|
||||||
} = props;
|
|
||||||
const theme = useTheme2();
|
const theme = useTheme2();
|
||||||
const styles = useStyles2(getStyles);
|
const styles = useStyles2(getStyles);
|
||||||
const spacing = parseInt(theme.spacing(2).slice(0, -2), 10);
|
const spacing = parseInt(theme.spacing(2).slice(0, -2), 10);
|
||||||
const height = 150;
|
const height = 150;
|
||||||
|
|
||||||
|
const data = createVisualisationData(
|
||||||
|
props.logLinesBasedData,
|
||||||
|
props.logLinesBasedDataVisibleRange,
|
||||||
|
props.logsVolumeData,
|
||||||
|
props.absoluteRange
|
||||||
|
);
|
||||||
|
|
||||||
|
if (data === undefined) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { logsVolumeData, fullRangeData, range } = data;
|
||||||
|
|
||||||
|
if (logsVolumeData.error !== undefined) {
|
||||||
|
return <ErrorAlert error={logsVolumeData.error} />;
|
||||||
|
}
|
||||||
|
|
||||||
let LogsVolumePanelContent;
|
let LogsVolumePanelContent;
|
||||||
|
|
||||||
if (!logsVolumeData) {
|
if (logsVolumeData?.state === LoadingState.Loading) {
|
||||||
return null;
|
|
||||||
} else if (logsVolumeData?.error) {
|
|
||||||
return <ErrorAlert error={logsVolumeData?.error} />;
|
|
||||||
} else if (logsVolumeData?.state === LoadingState.Loading) {
|
|
||||||
LogsVolumePanelContent = <span>Log volume is loading...</span>;
|
LogsVolumePanelContent = <span>Log volume is loading...</span>;
|
||||||
} else if (logsVolumeData?.data) {
|
} else if (logsVolumeData?.data) {
|
||||||
if (logsVolumeData.data.length > 0) {
|
if (logsVolumeData.data.length > 0) {
|
||||||
@ -79,7 +124,7 @@ export function LogsVolumePanel(props: Props) {
|
|||||||
data={logsVolumeData.data}
|
data={logsVolumeData.data}
|
||||||
height={height}
|
height={height}
|
||||||
width={width - spacing}
|
width={width - spacing}
|
||||||
absoluteRange={absoluteRange}
|
absoluteRange={range}
|
||||||
onChangeTime={onUpdateTimeRange}
|
onChangeTime={onUpdateTimeRange}
|
||||||
timeZone={timeZone}
|
timeZone={timeZone}
|
||||||
splitOpenFn={splitOpen}
|
splitOpenFn={splitOpen}
|
||||||
@ -92,30 +137,37 @@ export function LogsVolumePanel(props: Props) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const zoomRatio = logsLevelZoomRatio(logsVolumeData, absoluteRange);
|
let extraInfo;
|
||||||
let zoomLevelInfo;
|
if (fullRangeData) {
|
||||||
|
const zoomRatio = logsLevelZoomRatio(logsVolumeData, range);
|
||||||
|
|
||||||
if (zoomRatio !== undefined && zoomRatio < 1) {
|
if (zoomRatio !== undefined && zoomRatio < 1) {
|
||||||
zoomLevelInfo = (
|
extraInfo = (
|
||||||
<InlineField label="Reload log volume" transparent>
|
<InlineField label="Reload log volume" transparent>
|
||||||
<Button size="xs" icon="sync" variant="secondary" onClick={onLoadLogsVolume} id="reload-volume" />
|
<Button size="xs" icon="sync" variant="secondary" onClick={onLoadLogsVolume} id="reload-volume" />
|
||||||
</InlineField>
|
</InlineField>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
extraInfo = (
|
||||||
|
<div className={styles.oldInfoText}>
|
||||||
|
This datasource does not support full-range histograms. The graph is based on the logs seen in the response.
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Collapse label="" isOpen={true} loading={logsVolumeData?.state === LoadingState.Loading}>
|
<Collapse label="" isOpen={true}>
|
||||||
<div style={{ height }} className={styles.contentContainer}>
|
<div style={{ height }} className={styles.contentContainer}>
|
||||||
{LogsVolumePanelContent}
|
{LogsVolumePanelContent}
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.zoomInfoContainer}>{zoomLevelInfo}</div>
|
<div className={styles.extraInfoContainer}>{extraInfo}</div>
|
||||||
</Collapse>
|
</Collapse>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const getStyles = () => {
|
const getStyles = (theme: GrafanaTheme2) => {
|
||||||
return {
|
return {
|
||||||
zoomInfoContainer: css`
|
extraInfoContainer: css`
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: end;
|
justify-content: end;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -127,6 +179,10 @@ const getStyles = () => {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
`,
|
`,
|
||||||
|
oldInfoText: css`
|
||||||
|
font-size: ${theme.typography.size.sm};
|
||||||
|
color: ${theme.colors.text.secondary};
|
||||||
|
`,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user