Loki: Update labels in log browser when time range changes (#37520)

* Refresh label when time range changes

* Refactor solution

* Add tests

* Update tests comments

* Update test

* Update public/app/plugins/datasource/loki/components/LokiQueryField.tsx

* Update public/app/plugins/datasource/loki/components/LokiQueryField.tsx
This commit is contained in:
Ivana Huckova 2021-08-04 08:37:19 -04:00 committed by GitHub
parent 224b062cac
commit 7fd94e69c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 123 additions and 8 deletions

View File

@ -11,7 +11,7 @@ import { LokiOptionFields } from './LokiOptionFields';
type Props = ExploreQueryFieldProps<LokiDatasource, LokiQuery, LokiOptions>;
export function LokiExploreQueryEditor(props: Props) {
const { query, data, datasource, history, onChange, onRunQuery } = props;
const { query, data, datasource, history, onChange, onRunQuery, range } = props;
return (
<LokiQueryField
@ -22,6 +22,7 @@ export function LokiExploreQueryEditor(props: Props) {
onRunQuery={onRunQuery}
history={history}
data={data}
range={range}
ExtraFieldElement={
<LokiOptionFields
queryType={query.instant ? 'instant' : 'range'}

View File

@ -0,0 +1,79 @@
import React, { ComponentProps } from 'react';
import { render } from '@testing-library/react';
import { LokiQueryField } from './LokiQueryField';
import { dateTime } from '@grafana/data';
type Props = ComponentProps<typeof LokiQueryField>;
const defaultProps: Props = {
datasource: {
languageProvider: {
start: () => Promise.resolve(['label1']),
fetchLabels: Promise.resolve(['label1']),
getSyntax: () => {},
getLabelKeys: () => ['label1'],
getLabelValues: () => ['value1'],
} as any,
getInitHints: () => [],
} as any,
range: {
from: dateTime([2021, 1, 11, 12, 0, 0]),
to: dateTime([2021, 1, 11, 18, 0, 0]),
raw: {
from: 'now-1h',
to: 'now',
},
},
query: { expr: '', refId: '' },
onRunQuery: () => {},
onChange: () => {},
history: [],
};
describe('LokiQueryField', () => {
it('refreshes metrics when time range changes over 1 minute', async () => {
const fetchLabelsMock = jest.fn();
const props = defaultProps;
props.datasource.languageProvider.fetchLabels = fetchLabelsMock;
const { rerender } = render(<LokiQueryField {...props} />);
expect(fetchLabelsMock).not.toHaveBeenCalled();
// 2 minutes difference over the initial time
const newRange = {
from: dateTime([2021, 1, 11, 12, 2, 0]),
to: dateTime([2021, 1, 11, 18, 2, 0]),
raw: {
from: 'now-1h',
to: 'now',
},
};
rerender(<LokiQueryField {...props} range={newRange} />);
expect(fetchLabelsMock).toHaveBeenCalledTimes(1);
});
it('does not refreshes metrics when time range change by less than 1 minute', async () => {
const fetchLabelsMock = jest.fn();
const props = defaultProps;
props.datasource.languageProvider.fetchLabels = fetchLabelsMock;
const { rerender } = render(<LokiQueryField {...props} />);
expect(fetchLabelsMock).not.toHaveBeenCalled();
// 20 seconds difference over the initial time
const newRange = {
from: dateTime([2021, 1, 11, 12, 0, 20]),
to: dateTime([2021, 1, 11, 18, 0, 20]),
raw: {
from: 'now-1h',
to: 'now',
},
};
rerender(<LokiQueryField {...props} range={newRange} />);
expect(fetchLabelsMock).not.toHaveBeenCalled();
});
});

View File

@ -1,6 +1,4 @@
// Libraries
import React, { ReactNode } from 'react';
import {
SlatePrism,
TypeaheadOutput,
@ -11,17 +9,13 @@ import {
DOMUtil,
Icon,
} from '@grafana/ui';
// Utils & Services
// dom also includes Element polyfills
import { Plugin, Node } from 'slate';
import { LokiLabelBrowser } from './LokiLabelBrowser';
// Types
import { ExploreQueryFieldProps } from '@grafana/data';
import { LokiQuery, LokiOptions } from '../types';
import { LanguageMap, languages as prismLanguages } from 'prismjs';
import LokiLanguageProvider, { LokiHistoryItem } from '../language_provider';
import { shouldRefreshLabels } from '../language_utils';
import LokiDatasource from '../datasource';
function getChooserText(hasSyntax: boolean, hasLogLabels: boolean) {
@ -98,6 +92,18 @@ export class LokiQueryField extends React.PureComponent<LokiQueryFieldProps, Lok
this.setState({ labelsLoaded: true });
}
componentDidUpdate(prevProps: LokiQueryFieldProps) {
const {
range,
datasource: { languageProvider },
} = this.props;
const refreshLabels = shouldRefreshLabels(range, prevProps.range);
// We want to refresh labels when range changes (we round up intervals to a minute)
if (refreshLabels) {
languageProvider.fetchLabels();
}
}
onChangeLabelBrowser = (selector: string) => {
this.onChangeQuery(selector, true);
this.setState({ labelBrowserVisible: false });

View File

@ -115,5 +115,15 @@ exports[`LokiExploreQueryEditor should render component 1`] = `
"refId": "A",
}
}
range={
Object {
"from": "2020-01-01T00:00:00.000Z",
"raw": Object {
"from": "2020-01-01T00:00:00.000Z",
"to": "2020-01-02T00:00:00.000Z",
},
"to": "2020-01-02T00:00:00.000Z",
}
}
/>
`;

View File

@ -0,0 +1,19 @@
import { TimeRange } from '@grafana/data';
function roundMsToMin(milliseconds: number): number {
return roundSecToMin(milliseconds / 1000);
}
function roundSecToMin(seconds: number): number {
return Math.floor(seconds / 60);
}
export function shouldRefreshLabels(range?: TimeRange, prevRange?: TimeRange): boolean {
if (range && prevRange) {
const sameMinuteFrom = roundMsToMin(range.from.valueOf()) === roundMsToMin(prevRange.from.valueOf());
const sameMinuteTo = roundMsToMin(range.to.valueOf()) === roundMsToMin(prevRange.to.valueOf());
// If both are same, don't need to refresh
return !(sameMinuteFrom && sameMinuteTo);
}
return false;
}