mirror of
https://github.com/grafana/grafana.git
synced 2026-07-30 00:08:10 -05:00
Loki: RemoveTimeSrv dependency (#78642)
* Loki: Remove dependency * Update loadUnwrapOptions
This commit is contained in:
@@ -407,7 +407,11 @@ describe('Query imports', () => {
|
||||
maxLines: DEFAULT_MAX_LINES_SAMPLE,
|
||||
refId: 'data-samples',
|
||||
},
|
||||
undefined
|
||||
// mocked default time range
|
||||
expect.objectContaining({
|
||||
from: 0,
|
||||
to: 1,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
@@ -428,7 +432,11 @@ describe('Query imports', () => {
|
||||
maxLines: 5,
|
||||
refId: 'data-samples',
|
||||
},
|
||||
undefined
|
||||
// mocked default time range
|
||||
expect.objectContaining({
|
||||
from: 0,
|
||||
to: 1,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -267,7 +267,7 @@ export default class LokiLanguageProvider extends LanguageProvider {
|
||||
refId: 'data-samples',
|
||||
maxLines: options?.maxLines || DEFAULT_MAX_LINES_SAMPLE,
|
||||
},
|
||||
options?.timeRange
|
||||
options?.timeRange ?? this.getDefaultTimeRange()
|
||||
);
|
||||
|
||||
if (!series.length) {
|
||||
|
||||
@@ -1474,26 +1474,26 @@ describe('LokiDatasource', () => {
|
||||
});
|
||||
it('ignores invalid queries', () => {
|
||||
const spy = jest.spyOn(ds, 'query');
|
||||
ds.getDataSamples({ expr: 'not a query', refId: 'A' });
|
||||
ds.getDataSamples({ expr: 'not a query', refId: 'A' }, mockTimeRange);
|
||||
expect(spy).not.toHaveBeenCalled();
|
||||
});
|
||||
it('ignores metric queries', () => {
|
||||
const spy = jest.spyOn(ds, 'query');
|
||||
ds.getDataSamples({ expr: 'count_over_time({a="b"}[1m])', refId: 'A' });
|
||||
ds.getDataSamples({ expr: 'count_over_time({a="b"}[1m])', refId: 'A' }, mockTimeRange);
|
||||
expect(spy).not.toHaveBeenCalled();
|
||||
});
|
||||
it('uses the current interval in the request', () => {
|
||||
const spy = jest.spyOn(ds, 'query').mockImplementation(() => of({} as DataQueryResponse));
|
||||
ds.getDataSamples({ expr: '{job="bar"}', refId: 'A' });
|
||||
ds.getDataSamples({ expr: '{job="bar"}', refId: 'A' }, mockTimeRange);
|
||||
expect(spy).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
range: ds.getTimeRange(),
|
||||
range: mockTimeRange,
|
||||
})
|
||||
);
|
||||
});
|
||||
it('hides the request from the inspector', () => {
|
||||
const spy = jest.spyOn(ds, 'query').mockImplementation(() => of({} as DataQueryResponse));
|
||||
ds.getDataSamples({ expr: '{job="bar"}', refId: 'A' });
|
||||
ds.getDataSamples({ expr: '{job="bar"}', refId: 'A' }, mockTimeRange);
|
||||
expect(spy).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
hideFromInspector: true,
|
||||
@@ -1503,7 +1503,7 @@ describe('LokiDatasource', () => {
|
||||
});
|
||||
it('sets the supporting query type in the request', () => {
|
||||
const spy = jest.spyOn(ds, 'query').mockImplementation(() => of({} as DataQueryResponse));
|
||||
ds.getDataSamples({ expr: '{job="bar"}', refId: 'A' });
|
||||
ds.getDataSamples({ expr: '{job="bar"}', refId: 'A' }, mockTimeRange);
|
||||
expect(spy).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
targets: [expect.objectContaining({ supportingQueryType: SupportingQueryType.DataSample })],
|
||||
@@ -1828,18 +1828,18 @@ describe('makeStatsRequest', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('getTimeRange*()', () => {
|
||||
it('exposes the current time range', () => {
|
||||
describe('getTimeRangeParams()', () => {
|
||||
it('turns time range into a Loki range parameters', () => {
|
||||
const ds = createLokiDatasource();
|
||||
const timeRange = ds.getTimeRange();
|
||||
|
||||
expect(timeRange.from).toBeDefined();
|
||||
expect(timeRange.to).toBeDefined();
|
||||
});
|
||||
|
||||
it('exposes time range as params', () => {
|
||||
const ds = createLokiDatasource();
|
||||
const params = ds.getTimeRangeParams();
|
||||
const range = {
|
||||
from: dateTime(1524650400000),
|
||||
to: dateTime(1524654000000),
|
||||
raw: {
|
||||
from: 'now-1h',
|
||||
to: 'now',
|
||||
},
|
||||
};
|
||||
const params = ds.getTimeRangeParams(range);
|
||||
|
||||
// Returns a very big integer, so we stringify it for the assertion
|
||||
expect(JSON.stringify(params)).toEqual('{"start":1524650400000000000,"end":1524654000000000000}');
|
||||
|
||||
@@ -45,7 +45,6 @@ import {
|
||||
import { Duration } from '@grafana/lezer-logql';
|
||||
import { BackendSrvRequest, config, DataSourceWithBackend, getTemplateSrv, TemplateSrv } from '@grafana/runtime';
|
||||
import { DataQuery } from '@grafana/schema';
|
||||
import { getTimeSrv, TimeSrv } from 'app/features/dashboard/services/TimeSrv';
|
||||
|
||||
import { queryLogsSample, queryLogsVolume } from '../../../features/logs/logsModel';
|
||||
import { getLogLevelFromKey } from '../../../features/logs/utils';
|
||||
@@ -152,8 +151,7 @@ export class LokiDatasource
|
||||
|
||||
constructor(
|
||||
private instanceSettings: DataSourceInstanceSettings<LokiOptions>,
|
||||
private readonly templateSrv: TemplateSrv = getTemplateSrv(),
|
||||
private readonly timeSrv: TimeSrv = getTimeSrv()
|
||||
private readonly templateSrv: TemplateSrv = getTemplateSrv()
|
||||
) {
|
||||
super(instanceSettings);
|
||||
|
||||
@@ -455,21 +453,12 @@ export class LokiDatasource
|
||||
return query.expr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the current time range.
|
||||
* @returns The current time range as provided by the timeSrv.
|
||||
*/
|
||||
getTimeRange() {
|
||||
return this.timeSrv.timeRange();
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a time range, returns it as Loki parameters.
|
||||
* @returns An object containing the start and end times in nanoseconds since the Unix epoch.
|
||||
*/
|
||||
getTimeRangeParams(timeRange?: TimeRange) {
|
||||
const range = timeRange ?? this.getTimeRange();
|
||||
return { start: range.from.valueOf() * NS_IN_MS, end: range.to.valueOf() * NS_IN_MS };
|
||||
getTimeRangeParams(timeRange: TimeRange) {
|
||||
return { start: timeRange.from.valueOf() * NS_IN_MS, end: timeRange.to.valueOf() * NS_IN_MS };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -734,7 +723,7 @@ export class LokiDatasource
|
||||
* Currently, it works for logs data only.
|
||||
* @returns A Promise that resolves to an array of DataFrames containing data samples.
|
||||
*/
|
||||
async getDataSamples(query: LokiQuery, timeRange?: TimeRange): Promise<DataFrame[]> {
|
||||
async getDataSamples(query: LokiQuery, timeRange: TimeRange): Promise<DataFrame[]> {
|
||||
// Currently works only for logs sample
|
||||
if (!isLogsQuery(query.expr) || isQueryWithError(this.interpolateString(query.expr, placeHolderScopedVars))) {
|
||||
return [];
|
||||
@@ -748,8 +737,7 @@ export class LokiDatasource
|
||||
supportingQueryType: SupportingQueryType.DataSample,
|
||||
};
|
||||
|
||||
const range = timeRange ?? this.getTimeRange();
|
||||
const request = makeRequest(lokiLogsQuery, range, CoreApp.Unknown, REF_ID_DATA_SAMPLES, true);
|
||||
const request = makeRequest(lokiLogsQuery, timeRange, CoreApp.Unknown, REF_ID_DATA_SAMPLES, true);
|
||||
return await lastValueFrom(this.query(request).pipe(switchMap((res) => of(res.data))));
|
||||
}
|
||||
|
||||
|
||||
@@ -99,13 +99,14 @@ export const LokiQueryBuilder = React.memo<Props>(
|
||||
useEffect(() => {
|
||||
const onGetSampleData = async () => {
|
||||
const lokiQuery = { expr: lokiQueryModeller.renderQuery(query), refId: 'data-samples' };
|
||||
const series = await datasource.getDataSamples(lokiQuery);
|
||||
const sampleData = { series, state: LoadingState.Done, timeRange: getDefaultTimeRange() };
|
||||
const range = timeRange ?? getDefaultTimeRange();
|
||||
const series = await datasource.getDataSamples(lokiQuery, range);
|
||||
const sampleData = { series, state: LoadingState.Done, timeRange: range };
|
||||
setSampleData(sampleData);
|
||||
};
|
||||
|
||||
onGetSampleData().catch(console.error);
|
||||
}, [datasource, query]);
|
||||
}, [datasource, query, timeRange]);
|
||||
|
||||
const lang = { grammar: logqlGrammar, name: 'logql' };
|
||||
return (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import { SelectableValue, toOption } from '@grafana/data';
|
||||
import { SelectableValue, getDefaultTimeRange, toOption } from '@grafana/data';
|
||||
import { Select } from '@grafana/ui';
|
||||
|
||||
import { getOperationParamId } from '../../../prometheus/querybuilder/shared/operationUtils';
|
||||
@@ -19,6 +19,7 @@ export function UnwrapParamEditor({
|
||||
value,
|
||||
query,
|
||||
datasource,
|
||||
timeRange,
|
||||
}: QueryBuilderOperationParamEditorProps) {
|
||||
const [state, setState] = useState<{
|
||||
options?: Array<SelectableValue<string>>;
|
||||
@@ -32,7 +33,7 @@ export function UnwrapParamEditor({
|
||||
// This check is always true, we do it to make typescript happy
|
||||
if (datasource instanceof LokiDatasource) {
|
||||
setState({ isLoading: true });
|
||||
const options = await loadUnwrapOptions(query, datasource);
|
||||
const options = await loadUnwrapOptions(query, datasource, timeRange);
|
||||
setState({ options, isLoading: undefined });
|
||||
}
|
||||
}}
|
||||
@@ -53,7 +54,8 @@ export function UnwrapParamEditor({
|
||||
|
||||
async function loadUnwrapOptions(
|
||||
query: LokiVisualQuery,
|
||||
datasource: LokiDatasource
|
||||
datasource: LokiDatasource,
|
||||
timeRange = getDefaultTimeRange()
|
||||
): Promise<Array<SelectableValue<string>>> {
|
||||
const queryExpr = lokiQueryModeller.renderQuery(query);
|
||||
const logExpr = getLogQueryFromMetricsQuery(queryExpr);
|
||||
@@ -61,7 +63,7 @@ async function loadUnwrapOptions(
|
||||
return [];
|
||||
}
|
||||
|
||||
const samples = await datasource.getDataSamples({ expr: logExpr, refId: 'unwrap_samples' });
|
||||
const samples = await datasource.getDataSamples({ expr: logExpr, refId: 'unwrap_samples' }, timeRange);
|
||||
const unwrapLabels = extractUnwrapLabelKeysFromDataFrame(samples[0]);
|
||||
|
||||
const labelOptions = unwrapLabels.map((label) => ({
|
||||
|
||||
@@ -2,7 +2,7 @@ import { css, cx } from '@emotion/css';
|
||||
import React, { useEffect, useId, useState } from 'react';
|
||||
import { Draggable } from 'react-beautiful-dnd';
|
||||
|
||||
import { DataSourceApi, GrafanaTheme2 } from '@grafana/data';
|
||||
import { DataSourceApi, GrafanaTheme2, TimeRange } from '@grafana/data';
|
||||
import { Button, Icon, InlineField, Tooltip, useTheme2, Stack } from '@grafana/ui';
|
||||
import { isConflictingFilter } from 'app/plugins/datasource/loki/querybuilder/operationUtils';
|
||||
import { LokiOperationId } from 'app/plugins/datasource/loki/querybuilder/types';
|
||||
@@ -29,6 +29,7 @@ export interface Props {
|
||||
onRunQuery: () => void;
|
||||
flash?: boolean;
|
||||
highlight?: boolean;
|
||||
timeRange?: TimeRange;
|
||||
}
|
||||
|
||||
export function OperationEditor({
|
||||
@@ -42,6 +43,7 @@ export function OperationEditor({
|
||||
datasource,
|
||||
flash,
|
||||
highlight,
|
||||
timeRange,
|
||||
}: Props) {
|
||||
const def = queryModeller.getOperationDef(operation.id);
|
||||
const shouldFlash = useFlash(flash);
|
||||
@@ -106,6 +108,7 @@ export function OperationEditor({
|
||||
onRunQuery={onRunQuery}
|
||||
query={query}
|
||||
datasource={datasource}
|
||||
timeRange={timeRange}
|
||||
/>
|
||||
{paramDef.restParam && (operation.params.length > def.params.length || paramDef.optional) && (
|
||||
<Button
|
||||
|
||||
@@ -3,7 +3,7 @@ import React, { useState } from 'react';
|
||||
import { DragDropContext, Droppable, DropResult } from 'react-beautiful-dnd';
|
||||
import { useMountedState, usePrevious } from 'react-use';
|
||||
|
||||
import { DataSourceApi, GrafanaTheme2 } from '@grafana/data';
|
||||
import { DataSourceApi, GrafanaTheme2, TimeRange } from '@grafana/data';
|
||||
import { Button, Cascader, CascaderOption, useStyles2, Stack } from '@grafana/ui';
|
||||
|
||||
import { OperationEditor } from './OperationEditor';
|
||||
@@ -17,6 +17,7 @@ export interface Props<T extends QueryWithOperations> {
|
||||
queryModeller: VisualQueryModeller;
|
||||
explainMode?: boolean;
|
||||
highlightedOp?: QueryBuilderOperation;
|
||||
timeRange?: TimeRange;
|
||||
}
|
||||
|
||||
export function OperationList<T extends QueryWithOperations>({
|
||||
@@ -26,6 +27,7 @@ export function OperationList<T extends QueryWithOperations>({
|
||||
onChange,
|
||||
onRunQuery,
|
||||
highlightedOp,
|
||||
timeRange,
|
||||
}: Props<T>) {
|
||||
const styles = useStyles2(getStyles);
|
||||
const { operations } = query;
|
||||
@@ -104,6 +106,7 @@ export function OperationList<T extends QueryWithOperations>({
|
||||
onRunQuery={onRunQuery}
|
||||
flash={opsToHighlight[index]}
|
||||
highlight={highlightedOp === op}
|
||||
timeRange={timeRange}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
import { ComponentType } from 'react';
|
||||
|
||||
import { DataSourceApi, RegistryItem, SelectableValue } from '@grafana/data';
|
||||
import { DataSourceApi, RegistryItem, SelectableValue, TimeRange } from '@grafana/data';
|
||||
|
||||
export interface QueryBuilderLabelFilter {
|
||||
label: string;
|
||||
@@ -92,6 +92,7 @@ export interface QueryBuilderOperationParamEditorProps {
|
||||
operationId: string;
|
||||
query: any;
|
||||
datasource: DataSourceApi;
|
||||
timeRange?: TimeRange;
|
||||
onChange: (index: number, value: QueryBuilderOperationParamValue) => void;
|
||||
onRunQuery: () => void;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user