mirror of
https://github.com/grafana/grafana.git
synced 2025-07-25 16:33:51 +08:00
Loki: Remove lokiQueryHints
feature toggle (#106620)
* Loki: Remove lokiQueryHints feature toggle * Remove unused imports * Fix tests
This commit is contained in:
@ -53,7 +53,6 @@ Most [generally available](https://grafana.com/docs/release-life-cycle/#general-
|
||||
| `ssoSettingsApi` | Enables the SSO settings API and the OAuth configuration UIs in Grafana | Yes |
|
||||
| `logsInfiniteScrolling` | Enables infinite scrolling for the Logs panel in Explore and Dashboards | Yes |
|
||||
| `logRowsPopoverMenu` | Enable filtering menu displayed when text of a log line is selected | Yes |
|
||||
| `lokiQueryHints` | Enables query hints for Loki | Yes |
|
||||
| `alertingQueryOptimization` | Optimizes eligible queries in order to reduce load on datasources | |
|
||||
| `onPremToCloudMigrations` | Enable the Grafana Migration Assistant, which helps you easily migrate various on-prem resources to your Grafana Cloud stack. | Yes |
|
||||
| `groupToNestedTableTransformation` | Enables the group to nested table transformation | Yes |
|
||||
@ -103,6 +102,7 @@ Most [generally available](https://grafana.com/docs/release-life-cycle/#general-
|
||||
| `cloudWatchBatchQueries` | Runs CloudWatch metrics queries as separate batches |
|
||||
| `pdfTables` | Enables generating table data as PDF in reporting |
|
||||
| `canvasPanelPanZoom` | Allow pan and zoom in canvas panel |
|
||||
| `regressionTransformation` | Enables regression analysis transformation |
|
||||
| `alertingSaveStateCompressed` | Enables the compressed protobuf-based alert state storage |
|
||||
| `tableNextGen` | Allows access to the new react-data-grid based table component. |
|
||||
| `enableSCIM` | Enables SCIM support for user and group management |
|
||||
|
@ -420,10 +420,9 @@ export interface FeatureToggles {
|
||||
*/
|
||||
tableSharedCrosshair?: boolean;
|
||||
/**
|
||||
* Enables query hints for Loki
|
||||
* @default true
|
||||
* Enables regression analysis transformation
|
||||
*/
|
||||
lokiQueryHints?: boolean;
|
||||
regressionTransformation?: boolean;
|
||||
/**
|
||||
* Use the kubernetes API for feature toggle management in the frontend
|
||||
*/
|
||||
|
@ -698,14 +698,11 @@ var (
|
||||
Owner: grafanaDatavizSquad,
|
||||
},
|
||||
{
|
||||
// this is mainly used as a way to quickly disable query hints as a safeguard for our infrastructure
|
||||
Name: "lokiQueryHints",
|
||||
Description: "Enables query hints for Loki",
|
||||
Stage: FeatureStageGeneralAvailability,
|
||||
FrontendOnly: true,
|
||||
Expression: "true",
|
||||
Owner: grafanaObservabilityLogsSquad,
|
||||
AllowSelfServe: false,
|
||||
Name: "regressionTransformation",
|
||||
Description: "Enables regression analysis transformation",
|
||||
Stage: FeatureStagePublicPreview,
|
||||
FrontendOnly: true,
|
||||
Owner: grafanaDatavizSquad,
|
||||
},
|
||||
{
|
||||
Name: "kubernetesFeatureToggles",
|
||||
|
@ -92,7 +92,7 @@ logsInfiniteScrolling,GA,@grafana/observability-logs,false,false,true
|
||||
logRowsPopoverMenu,GA,@grafana/observability-logs,false,false,true
|
||||
pluginsSkipHostEnvVars,experimental,@grafana/plugins-platform-backend,false,false,false
|
||||
tableSharedCrosshair,experimental,@grafana/dataviz-squad,false,false,true
|
||||
lokiQueryHints,GA,@grafana/observability-logs,false,false,true
|
||||
regressionTransformation,preview,@grafana/dataviz-squad,false,false,true
|
||||
kubernetesFeatureToggles,experimental,@grafana/grafana-operator-experience-squad,false,false,true
|
||||
cloudRBACRoles,preview,@grafana/identity-access-team,false,true,false
|
||||
alertingQueryOptimization,GA,@grafana/alerting-squad,false,false,false
|
||||
|
|
@ -379,9 +379,9 @@ const (
|
||||
// Enables shared crosshair in table panel
|
||||
FlagTableSharedCrosshair = "tableSharedCrosshair"
|
||||
|
||||
// FlagLokiQueryHints
|
||||
// Enables query hints for Loki
|
||||
FlagLokiQueryHints = "lokiQueryHints"
|
||||
// FlagRegressionTransformation
|
||||
// Enables regression analysis transformation
|
||||
FlagRegressionTransformation = "regressionTransformation"
|
||||
|
||||
// FlagKubernetesFeatureToggles
|
||||
// Use the kubernetes API for feature toggle management in the frontend
|
||||
|
@ -1868,8 +1868,9 @@
|
||||
{
|
||||
"metadata": {
|
||||
"name": "lokiQueryHints",
|
||||
"resourceVersion": "1750434297879",
|
||||
"creationTimestamp": "2023-12-18T20:43:16Z"
|
||||
"resourceVersion": "1743693517832",
|
||||
"creationTimestamp": "2023-12-18T20:43:16Z",
|
||||
"deletionTimestamp": "2025-06-12T12:14:47Z"
|
||||
},
|
||||
"spec": {
|
||||
"description": "Enables query hints for Loki",
|
||||
|
@ -681,14 +681,6 @@ describe('Query imports', () => {
|
||||
});
|
||||
|
||||
describe('getParserAndLabelKeys()', () => {
|
||||
const queryHintsFeatureToggle = config.featureToggles.lokiQueryHints;
|
||||
beforeAll(() => {
|
||||
config.featureToggles.lokiQueryHints = true;
|
||||
});
|
||||
afterAll(() => {
|
||||
config.featureToggles.lokiQueryHints = queryHintsFeatureToggle;
|
||||
});
|
||||
|
||||
let datasource: LokiDatasource, languageProvider: LanguageProvider;
|
||||
const extractLogParserFromDataFrameMock = jest.mocked(extractLogParserFromDataFrame);
|
||||
const extractedLabelKeys = ['extracted', 'label'];
|
||||
@ -810,12 +802,6 @@ describe('Query imports', () => {
|
||||
mockTimeRange
|
||||
);
|
||||
});
|
||||
it('does not call dataSample with feature toggle disabled', async () => {
|
||||
config.featureToggles.lokiQueryHints = false;
|
||||
jest.spyOn(datasource, 'getDataSamples');
|
||||
languageProvider.getParserAndLabelKeys('{place="luna"}', { timeRange: mockTimeRange });
|
||||
expect(datasource.getDataSamples).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -477,9 +477,6 @@ export default class LokiLanguageProvider extends LanguageProvider {
|
||||
hasLogfmt: false,
|
||||
hasPack: false,
|
||||
};
|
||||
if (!config.featureToggles.lokiQueryHints) {
|
||||
return empty;
|
||||
}
|
||||
|
||||
const series = await this.datasource.getDataSamples(
|
||||
{
|
||||
|
@ -4,7 +4,6 @@ import { ComponentProps } from 'react';
|
||||
|
||||
import { DataSourceApi } from '@grafana/data';
|
||||
import { QueryBuilderOperation, QueryBuilderOperationParamDef } from '@grafana/plugin-ui';
|
||||
import { config } from '@grafana/runtime';
|
||||
|
||||
import { LokiDatasource } from '../../datasource';
|
||||
import { createLokiDatasource } from '../../mocks/datasource';
|
||||
@ -14,14 +13,6 @@ import { LokiOperationId } from '../types';
|
||||
import { LabelParamEditor } from './LabelParamEditor';
|
||||
|
||||
describe('LabelParamEditor', () => {
|
||||
const queryHintsFeatureToggle = config.featureToggles.lokiQueryHints;
|
||||
beforeAll(() => {
|
||||
config.featureToggles.lokiQueryHints = true;
|
||||
});
|
||||
afterAll(() => {
|
||||
config.featureToggles.lokiQueryHints = queryHintsFeatureToggle;
|
||||
});
|
||||
|
||||
it('shows label options', async () => {
|
||||
const props = createProps({}, ['label1', 'label2']);
|
||||
render(<LabelParamEditor {...props} />);
|
||||
|
@ -2,7 +2,6 @@ import { render, screen, getAllByRole, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
import { dateTime } from '@grafana/data';
|
||||
import { config } from '@grafana/runtime';
|
||||
|
||||
import { createLokiDatasource } from '../../mocks/datasource';
|
||||
import { LokiOperationId, LokiVisualQuery } from '../types';
|
||||
@ -40,14 +39,6 @@ const createDefaultProps = () => {
|
||||
};
|
||||
|
||||
describe('LokiQueryBuilder', () => {
|
||||
const originalLokiQueryHints = config.featureToggles.lokiQueryHints;
|
||||
beforeEach(() => {
|
||||
config.featureToggles.lokiQueryHints = true;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
config.featureToggles.lokiQueryHints = originalLokiQueryHints;
|
||||
});
|
||||
it('tries to load label names', async () => {
|
||||
const props = createDefaultProps();
|
||||
props.datasource.getDataSamples = jest.fn().mockResolvedValue([]);
|
||||
|
@ -15,7 +15,6 @@ import {
|
||||
QueryBuilderLabelFilter,
|
||||
QueryBuilderOperation,
|
||||
} from '@grafana/plugin-ui';
|
||||
import { config } from '@grafana/runtime';
|
||||
|
||||
import { testIds } from '../../components/LokiQueryEditor';
|
||||
import { LokiDatasource } from '../../datasource';
|
||||
@ -126,7 +125,7 @@ export const LokiQueryBuilder = memo<Props>(({ datasource, query, onChange, onRu
|
||||
(Math.abs(timeRange.to.valueOf() - prevTimeRange.to.valueOf()) > TIME_SPAN_TO_TRIGGER_SAMPLES ||
|
||||
Math.abs(timeRange.from.valueOf() - prevTimeRange.from.valueOf()) > TIME_SPAN_TO_TRIGGER_SAMPLES);
|
||||
const updateBasedOnChangedQuery = !isEqual(prevQuery, query);
|
||||
if (config.featureToggles.lokiQueryHints && (updateBasedOnChangedTimeRange || updateBasedOnChangedQuery)) {
|
||||
if (updateBasedOnChangedTimeRange || updateBasedOnChangedQuery) {
|
||||
onGetSampleData().catch(console.error);
|
||||
}
|
||||
}, [datasource, query, timeRange, prevQuery, prevTimeRange]);
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { render, screen, waitFor, findAllByRole } from '@testing-library/react';
|
||||
import { render, screen, waitFor, findAllByRole, act } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
import { createLokiDatasource } from '../../mocks/datasource';
|
||||
@ -19,7 +19,9 @@ describe('LokiQueryBuilderContainer', () => {
|
||||
};
|
||||
props.datasource.getDataSamples = jest.fn().mockResolvedValue([]);
|
||||
|
||||
render(<LokiQueryBuilderContainer {...props} />);
|
||||
await act(async () => {
|
||||
render(<LokiQueryBuilderContainer {...props} />);
|
||||
});
|
||||
const selector = await screen.findByLabelText('selector');
|
||||
expect(selector.textContent).toBe('{job="testjob"}');
|
||||
await addOperation('Range functions', 'Rate');
|
||||
@ -45,7 +47,9 @@ describe('LokiQueryBuilderContainer', () => {
|
||||
props.datasource.languageProvider.fetchLabelValues = jest.fn().mockReturnValue(['grafana', 'loki']);
|
||||
props.onChange = jest.fn();
|
||||
|
||||
render(<LokiQueryBuilderContainer {...props} />);
|
||||
await act(async () => {
|
||||
render(<LokiQueryBuilderContainer {...props} />);
|
||||
});
|
||||
await userEvent.click(screen.getByLabelText('Add'));
|
||||
const labels = screen.getByText(/Label filters/);
|
||||
const selects = await findAllByRole(getSelectParent(labels)!, 'combobox');
|
||||
@ -78,7 +82,9 @@ describe('LokiQueryBuilderContainer', () => {
|
||||
showExplain: false,
|
||||
};
|
||||
props.datasource.getDataSamples = jest.fn().mockResolvedValue([]);
|
||||
render(<LokiQueryBuilderContainer {...props} />);
|
||||
await act(async () => {
|
||||
render(<LokiQueryBuilderContainer {...props} />);
|
||||
});
|
||||
expect(screen.getByText('{')).toHaveClass('token punctuation');
|
||||
expect(screen.getByText('"baz"')).toHaveClass('token label-value attr-value');
|
||||
expect(screen.getByText('|')).toHaveClass('token pipe-operator operator');
|
||||
@ -98,7 +104,9 @@ describe('LokiQueryBuilderContainer', () => {
|
||||
};
|
||||
props.datasource.getDataSamples = jest.fn().mockResolvedValue([]);
|
||||
|
||||
render(<LokiQueryBuilderContainer {...props} />);
|
||||
await act(async () => {
|
||||
render(<LokiQueryBuilderContainer {...props} />);
|
||||
});
|
||||
expect(screen.getAllByText('You have conflicting label filters')).toHaveLength(2);
|
||||
});
|
||||
|
||||
@ -115,7 +123,9 @@ describe('LokiQueryBuilderContainer', () => {
|
||||
};
|
||||
props.datasource.getDataSamples = jest.fn().mockResolvedValue([]);
|
||||
|
||||
render(<LokiQueryBuilderContainer {...props} />);
|
||||
await act(async () => {
|
||||
render(<LokiQueryBuilderContainer {...props} />);
|
||||
});
|
||||
expect(screen.getByText('<')).toBeInTheDocument();
|
||||
expect(screen.getByText('expr')).toBeInTheDocument();
|
||||
expect(screen.getByText('>')).toBeInTheDocument();
|
||||
|
@ -4,7 +4,6 @@ import { ComponentProps } from 'react';
|
||||
|
||||
import { DataFrame, DataSourceApi, FieldType, toDataFrame } from '@grafana/data';
|
||||
import { QueryBuilderOperation, QueryBuilderOperationParamDef } from '@grafana/plugin-ui';
|
||||
import { config } from '@grafana/runtime';
|
||||
|
||||
import { LokiDatasource } from '../../datasource';
|
||||
import { createLokiDatasource } from '../../mocks/datasource';
|
||||
@ -14,14 +13,6 @@ import { LokiOperationId } from '../types';
|
||||
import { UnwrapParamEditor } from './UnwrapParamEditor';
|
||||
|
||||
describe('UnwrapParamEditor', () => {
|
||||
const queryHintsFeatureToggle = config.featureToggles.lokiQueryHints;
|
||||
beforeAll(() => {
|
||||
config.featureToggles.lokiQueryHints = true;
|
||||
});
|
||||
afterAll(() => {
|
||||
config.featureToggles.lokiQueryHints = queryHintsFeatureToggle;
|
||||
});
|
||||
|
||||
it('shows value if value present', () => {
|
||||
const props = createProps({ value: 'unique' });
|
||||
render(<UnwrapParamEditor {...props} />);
|
||||
@ -60,16 +51,6 @@ describe('UnwrapParamEditor', () => {
|
||||
expect(await screen.findByText('status')).toBeInTheDocument();
|
||||
expect(await screen.findByText('duration')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('does not show labels with unwrap-friendly values when feature is disabled', async () => {
|
||||
config.featureToggles.lokiQueryHints = false;
|
||||
const props = createProps({}, frames);
|
||||
render(<UnwrapParamEditor {...props} />);
|
||||
const input = screen.getByRole('combobox');
|
||||
await userEvent.click(input);
|
||||
expect(screen.queryByText('status')).not.toBeInTheDocument();
|
||||
expect(screen.queryByText('duration')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
const createProps = (
|
||||
|
@ -2,7 +2,6 @@ import { useState } from 'react';
|
||||
|
||||
import { SelectableValue, getDefaultTimeRange, toOption } from '@grafana/data';
|
||||
import { QueryBuilderOperationParamEditorProps, VisualQueryModeller } from '@grafana/plugin-ui';
|
||||
import { config } from '@grafana/runtime';
|
||||
import { Select } from '@grafana/ui';
|
||||
|
||||
import { placeHolderScopedVars } from '../../components/monaco-query-field/monaco-completion-provider/validation';
|
||||
@ -32,7 +31,7 @@ export function UnwrapParamEditor({
|
||||
inputId={getOperationParamId(operationId, index)}
|
||||
onOpenMenu={async () => {
|
||||
// This check is always true, we do it to make typescript happy
|
||||
if (datasource instanceof LokiDatasource && config.featureToggles.lokiQueryHints) {
|
||||
if (datasource instanceof LokiDatasource) {
|
||||
setState({ isLoading: true });
|
||||
const options = await loadUnwrapOptions(query, datasource, queryModeller, timeRange);
|
||||
setState({ options, isLoading: undefined });
|
||||
|
Reference in New Issue
Block a user