mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
CloudWatch Logs: Set default logs query and disable button when empty (#61956)
This commit is contained in:
parent
e46aa2e4e6
commit
7c85db5bfa
@ -6,6 +6,7 @@ import { config } from '@grafana/runtime';
|
|||||||
|
|
||||||
import { setupMockedDataSource } from '../__mocks__/CloudWatchDataSource';
|
import { setupMockedDataSource } from '../__mocks__/CloudWatchDataSource';
|
||||||
import { validLogsQuery, validMetricSearchBuilderQuery } from '../__mocks__/queries';
|
import { validLogsQuery, validMetricSearchBuilderQuery } from '../__mocks__/queries';
|
||||||
|
import { DEFAULT_LOGS_QUERY_STRING } from '../defaultQueries';
|
||||||
|
|
||||||
import QueryHeader from './QueryHeader';
|
import QueryHeader from './QueryHeader';
|
||||||
|
|
||||||
@ -16,11 +17,10 @@ const ds = setupMockedDataSource({
|
|||||||
ds.datasource.resources.getRegions = jest.fn().mockResolvedValue([]);
|
ds.datasource.resources.getRegions = jest.fn().mockResolvedValue([]);
|
||||||
|
|
||||||
describe('QueryHeader', () => {
|
describe('QueryHeader', () => {
|
||||||
afterEach(() => {
|
|
||||||
config.featureToggles.cloudWatchCrossAccountQuerying = originalFeatureToggleValue;
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('when changing region', () => {
|
describe('when changing region', () => {
|
||||||
|
afterEach(() => {
|
||||||
|
config.featureToggles.cloudWatchCrossAccountQuerying = originalFeatureToggleValue;
|
||||||
|
});
|
||||||
const { datasource } = setupMockedDataSource();
|
const { datasource } = setupMockedDataSource();
|
||||||
datasource.resources.getRegions = jest.fn().mockResolvedValue([
|
datasource.resources.getRegions = jest.fn().mockResolvedValue([
|
||||||
{ value: 'us-east-2', label: 'us-east-2' },
|
{ value: 'us-east-2', label: 'us-east-2' },
|
||||||
@ -117,4 +117,91 @@ describe('QueryHeader', () => {
|
|||||||
expect(datasource.resources.isMonitoringAccount).not.toHaveBeenCalledWith();
|
expect(datasource.resources.isMonitoringAccount).not.toHaveBeenCalledWith();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('when changing query mode', () => {
|
||||||
|
const { datasource } = setupMockedDataSource();
|
||||||
|
it('should set default log query when switching to log mode', async () => {
|
||||||
|
const onChange = jest.fn();
|
||||||
|
datasource.resources.isMonitoringAccount = jest.fn().mockResolvedValue(false);
|
||||||
|
render(
|
||||||
|
<QueryHeader
|
||||||
|
datasource={datasource}
|
||||||
|
query={{ ...validMetricSearchBuilderQuery, expression: 'foo' }}
|
||||||
|
onChange={onChange}
|
||||||
|
onRunQuery={jest.fn()}
|
||||||
|
dataIsStale={false}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
expect(await screen.findByText('CloudWatch Metrics')).toBeInTheDocument();
|
||||||
|
await selectEvent.select(await screen.findByLabelText('Query mode'), 'CloudWatch Logs', {
|
||||||
|
container: document.body,
|
||||||
|
});
|
||||||
|
expect(onChange).toHaveBeenCalledWith({
|
||||||
|
...validMetricSearchBuilderQuery,
|
||||||
|
logGroupNames: undefined,
|
||||||
|
logGroups: [],
|
||||||
|
queryMode: 'Logs',
|
||||||
|
sqlExpression: '',
|
||||||
|
expression: DEFAULT_LOGS_QUERY_STRING,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set expression to empty when switching to metrics mode', async () => {
|
||||||
|
const onChange = jest.fn();
|
||||||
|
datasource.resources.isMonitoringAccount = jest.fn().mockResolvedValue(false);
|
||||||
|
render(
|
||||||
|
<QueryHeader
|
||||||
|
datasource={datasource}
|
||||||
|
query={{ ...validMetricSearchBuilderQuery, queryMode: 'Logs', expression: 'foo' }}
|
||||||
|
onChange={onChange}
|
||||||
|
onRunQuery={jest.fn()}
|
||||||
|
dataIsStale={false}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
expect(await screen.findByText('CloudWatch Logs')).toBeInTheDocument();
|
||||||
|
await selectEvent.select(await screen.findByLabelText('Query mode'), 'CloudWatch Metrics', {
|
||||||
|
container: document.body,
|
||||||
|
});
|
||||||
|
expect(onChange).toHaveBeenCalledWith({
|
||||||
|
...validMetricSearchBuilderQuery,
|
||||||
|
logGroupNames: undefined,
|
||||||
|
logGroups: [],
|
||||||
|
sqlExpression: '',
|
||||||
|
expression: '',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('log expression', () => {
|
||||||
|
const { datasource } = setupMockedDataSource();
|
||||||
|
it('should disable run query button when empty', async () => {
|
||||||
|
const onChange = jest.fn();
|
||||||
|
datasource.resources.isMonitoringAccount = jest.fn().mockResolvedValue(false);
|
||||||
|
render(
|
||||||
|
<QueryHeader
|
||||||
|
datasource={datasource}
|
||||||
|
query={{ ...validMetricSearchBuilderQuery, queryMode: 'Logs', expression: '' }}
|
||||||
|
onChange={onChange}
|
||||||
|
onRunQuery={jest.fn()}
|
||||||
|
dataIsStale={false}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
expect(await screen.findByText('Run queries')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('Run queries').closest('button')).toBeDisabled();
|
||||||
|
});
|
||||||
|
it('should enable run query button when set', async () => {
|
||||||
|
const onChange = jest.fn();
|
||||||
|
datasource.resources.isMonitoringAccount = jest.fn().mockResolvedValue(false);
|
||||||
|
render(
|
||||||
|
<QueryHeader
|
||||||
|
datasource={datasource}
|
||||||
|
query={{ ...validMetricSearchBuilderQuery, queryMode: 'Logs', expression: DEFAULT_LOGS_QUERY_STRING }}
|
||||||
|
onChange={onChange}
|
||||||
|
onRunQuery={jest.fn()}
|
||||||
|
dataIsStale={false}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
expect(await screen.findByText('Run queries')).toBeInTheDocument();
|
||||||
|
expect(screen.getByText('Run queries').closest('button')).not.toBeDisabled();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -6,7 +6,8 @@ import { config } from '@grafana/runtime';
|
|||||||
import { Badge, Button } from '@grafana/ui';
|
import { Badge, Button } from '@grafana/ui';
|
||||||
|
|
||||||
import { CloudWatchDatasource } from '../datasource';
|
import { CloudWatchDatasource } from '../datasource';
|
||||||
import { isCloudWatchMetricsQuery } from '../guards';
|
import { DEFAULT_LOGS_QUERY_STRING } from '../defaultQueries';
|
||||||
|
import { isCloudWatchLogsQuery, isCloudWatchMetricsQuery } from '../guards';
|
||||||
import { useIsMonitoringAccount, useRegions } from '../hooks';
|
import { useIsMonitoringAccount, useRegions } from '../hooks';
|
||||||
import { CloudWatchJsonData, CloudWatchQuery, CloudWatchQueryMode, MetricQueryType } from '../types';
|
import { CloudWatchJsonData, CloudWatchQuery, CloudWatchQueryMode, MetricQueryType } from '../types';
|
||||||
|
|
||||||
@ -34,12 +35,19 @@ const QueryHeader: React.FC<Props> = ({
|
|||||||
const { queryMode, region } = query;
|
const { queryMode, region } = query;
|
||||||
const isMonitoringAccount = useIsMonitoringAccount(datasource.resources, query.region);
|
const isMonitoringAccount = useIsMonitoringAccount(datasource.resources, query.region);
|
||||||
const [regions, regionIsLoading] = useRegions(datasource);
|
const [regions, regionIsLoading] = useRegions(datasource);
|
||||||
|
const emptyLogsExpression = isCloudWatchLogsQuery(query) ? !query.expression : false;
|
||||||
|
|
||||||
const onQueryModeChange = ({ value }: SelectableValue<CloudWatchQueryMode>) => {
|
const onQueryModeChange = ({ value }: SelectableValue<CloudWatchQueryMode>) => {
|
||||||
if (value && value !== queryMode) {
|
if (value && value !== queryMode) {
|
||||||
|
// reset expression to a default string when the query mode changes
|
||||||
|
let expression = '';
|
||||||
|
if (value === 'Logs') {
|
||||||
|
expression = DEFAULT_LOGS_QUERY_STRING;
|
||||||
|
}
|
||||||
onChange({
|
onChange({
|
||||||
...datasource.getDefaultQuery(CoreApp.Unknown),
|
...datasource.getDefaultQuery(CoreApp.Unknown),
|
||||||
...query,
|
...query,
|
||||||
|
expression,
|
||||||
queryMode: value,
|
queryMode: value,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -100,7 +108,7 @@ const QueryHeader: React.FC<Props> = ({
|
|||||||
size="sm"
|
size="sm"
|
||||||
onClick={onRunQuery}
|
onClick={onRunQuery}
|
||||||
icon={data?.state === LoadingState.Loading ? 'fa fa-spinner' : undefined}
|
icon={data?.state === LoadingState.Loading ? 'fa fa-spinner' : undefined}
|
||||||
disabled={data?.state === LoadingState.Loading}
|
disabled={data?.state === LoadingState.Loading || emptyLogsExpression}
|
||||||
>
|
>
|
||||||
Run queries
|
Run queries
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -16,13 +16,14 @@ export const DEFAULT_METRICS_QUERY: Omit<CloudWatchMetricsQuery, 'refId'> = {
|
|||||||
matchExact: true,
|
matchExact: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const DEFAULT_LOGS_QUERY_STRING = 'fields @timestamp, @message |\n sort @timestamp desc |\n limit 20';
|
||||||
|
|
||||||
export const getDefaultLogsQuery = (
|
export const getDefaultLogsQuery = (
|
||||||
defaultLogGroups?: LogGroup[],
|
defaultLogGroups?: LogGroup[],
|
||||||
legacyDefaultLogGroups?: string[]
|
legacyDefaultLogGroups?: string[]
|
||||||
): Omit<CloudWatchLogsQuery, 'refId' | 'queryMode'> => ({
|
): Omit<CloudWatchLogsQuery, 'refId' | 'queryMode'> => ({
|
||||||
id: '',
|
id: '',
|
||||||
region: 'default',
|
region: 'default',
|
||||||
expression: '',
|
|
||||||
// in case legacy default log groups have been defined in the ConfigEditor, they will be migrated in the LogGroupsField component or the next time the ConfigEditor is opened.
|
// in case legacy default log groups have been defined in the ConfigEditor, they will be migrated in the LogGroupsField component or the next time the ConfigEditor is opened.
|
||||||
// the migration requires async backend calls, so we don't want to do it here as it would block the UI.
|
// the migration requires async backend calls, so we don't want to do it here as it would block the UI.
|
||||||
logGroupNames: legacyDefaultLogGroups,
|
logGroupNames: legacyDefaultLogGroups,
|
||||||
|
Loading…
Reference in New Issue
Block a user