mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
CloudWatch Logs: Add selected region to autocomplete requests (#42194)
* Add region to get fields query * Fix and add tests
This commit is contained in:
parent
879cdcd0c7
commit
802ffa3f03
@ -263,7 +263,7 @@ export class CloudWatchLogsQueryField extends React.PureComponent<CloudWatchLogs
|
||||
};
|
||||
|
||||
onTypeahead = async (typeahead: TypeaheadInput): Promise<TypeaheadOutput> => {
|
||||
const { datasource } = this.props;
|
||||
const { datasource, query } = this.props;
|
||||
const { selectedLogGroups } = this.state;
|
||||
|
||||
if (!datasource.languageProvider) {
|
||||
@ -276,7 +276,12 @@ export class CloudWatchLogsQueryField extends React.PureComponent<CloudWatchLogs
|
||||
|
||||
return await cloudwatchLanguageProvider.provideCompletionItems(
|
||||
{ text, value, prefix, wrapperClasses, labelKey, editor },
|
||||
{ history, absoluteRange, logGroupNames: selectedLogGroups.map((logGroup) => logGroup.value!) }
|
||||
{
|
||||
history,
|
||||
absoluteRange,
|
||||
logGroupNames: selectedLogGroups.map((logGroup) => logGroup.value!),
|
||||
region: query.region,
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -125,6 +125,34 @@ describe('datasource', () => {
|
||||
expect(fetchMock.mock.calls[1][0].data.queries[0].region).toBe('eu-east');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getLogGroupFields', () => {
|
||||
it('passes region correctly', async () => {
|
||||
const { datasource, fetchMock } = setupMockedDataSource();
|
||||
fetchMock.mockReturnValueOnce(
|
||||
of({
|
||||
data: {
|
||||
results: {
|
||||
A: {
|
||||
frames: [
|
||||
dataFrameToJSON(
|
||||
new MutableDataFrame({
|
||||
fields: [
|
||||
{ name: 'key', values: [] },
|
||||
{ name: 'val', values: [] },
|
||||
],
|
||||
})
|
||||
),
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
await datasource.getLogGroupFields({ region: 'us-west-1', logGroupName: 'test' });
|
||||
expect(fetchMock.mock.calls[0][0].data.queries[0].region).toBe('us-west-1');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function setupForLogs() {
|
||||
|
@ -49,6 +49,7 @@ import {
|
||||
TSDBResponse,
|
||||
Dimensions,
|
||||
MetricFindSuggestData,
|
||||
CloudWatchLogsRequest,
|
||||
} from './types';
|
||||
import { CloudWatchLanguageProvider } from './language_provider';
|
||||
import { VariableWithMultiSupport } from 'app/features/variables/types';
|
||||
@ -547,7 +548,7 @@ export class CloudWatchDatasource
|
||||
|
||||
makeLogActionRequest(
|
||||
subtype: LogAction,
|
||||
queryParams: Array<GetLogEventsRequest | StartQueryRequest | DescribeLogGroupsRequest | GetLogGroupFieldsRequest>,
|
||||
queryParams: CloudWatchLogsRequest[],
|
||||
options: {
|
||||
scopedVars?: ScopedVars;
|
||||
makeReplacements?: boolean;
|
||||
@ -562,47 +563,43 @@ export class CloudWatchDatasource
|
||||
const requestParams = {
|
||||
from: range.from.valueOf().toString(),
|
||||
to: range.to.valueOf().toString(),
|
||||
queries: queryParams.map(
|
||||
(param: GetLogEventsRequest | StartQueryRequest | DescribeLogGroupsRequest | GetLogGroupFieldsRequest) => ({
|
||||
refId: (param as StartQueryRequest).refId || 'A',
|
||||
intervalMs: 1, // dummy
|
||||
maxDataPoints: 1, // dummy
|
||||
datasource: this.getRef(),
|
||||
type: 'logAction',
|
||||
subtype: subtype,
|
||||
...param,
|
||||
})
|
||||
),
|
||||
queries: queryParams.map((param: CloudWatchLogsRequest) => ({
|
||||
refId: (param as StartQueryRequest).refId || 'A',
|
||||
intervalMs: 1, // dummy
|
||||
maxDataPoints: 1, // dummy
|
||||
datasource: this.getRef(),
|
||||
type: 'logAction',
|
||||
subtype: subtype,
|
||||
...param,
|
||||
})),
|
||||
};
|
||||
|
||||
if (options.makeReplacements) {
|
||||
requestParams.queries.forEach(
|
||||
(query: GetLogEventsRequest | StartQueryRequest | DescribeLogGroupsRequest | GetLogGroupFieldsRequest) => {
|
||||
const fieldsToReplace: Array<
|
||||
keyof (GetLogEventsRequest & StartQueryRequest & DescribeLogGroupsRequest & GetLogGroupFieldsRequest)
|
||||
> = ['queryString', 'logGroupNames', 'logGroupName', 'logGroupNamePrefix'];
|
||||
requestParams.queries.forEach((query: CloudWatchLogsRequest) => {
|
||||
const fieldsToReplace: Array<
|
||||
keyof (GetLogEventsRequest & StartQueryRequest & DescribeLogGroupsRequest & GetLogGroupFieldsRequest)
|
||||
> = ['queryString', 'logGroupNames', 'logGroupName', 'logGroupNamePrefix'];
|
||||
|
||||
const anyQuery: any = query;
|
||||
for (const fieldName of fieldsToReplace) {
|
||||
if (query.hasOwnProperty(fieldName)) {
|
||||
if (Array.isArray(anyQuery[fieldName])) {
|
||||
anyQuery[fieldName] = anyQuery[fieldName].map((val: string) =>
|
||||
this.replace(val, options.scopedVars, true, fieldName)
|
||||
);
|
||||
} else {
|
||||
anyQuery[fieldName] = this.replace(anyQuery[fieldName], options.scopedVars, true, fieldName);
|
||||
}
|
||||
const anyQuery: any = query;
|
||||
for (const fieldName of fieldsToReplace) {
|
||||
if (query.hasOwnProperty(fieldName)) {
|
||||
if (Array.isArray(anyQuery[fieldName])) {
|
||||
anyQuery[fieldName] = anyQuery[fieldName].map((val: string) =>
|
||||
this.replace(val, options.scopedVars, true, fieldName)
|
||||
);
|
||||
} else {
|
||||
anyQuery[fieldName] = this.replace(anyQuery[fieldName], options.scopedVars, true, fieldName);
|
||||
}
|
||||
}
|
||||
// TODO: seems to be some sort of bug that we don't really send region with all queries. This means
|
||||
// if you select different than default region in editor you will get results for autocomplete from wrong
|
||||
// region.
|
||||
if (anyQuery.region) {
|
||||
anyQuery.region = this.replace(anyQuery.region, options.scopedVars, true, 'region');
|
||||
anyQuery.region = this.getActualRegion(anyQuery.region);
|
||||
}
|
||||
}
|
||||
);
|
||||
// TODO: seems to be some sort of bug that we don't really send region with all queries. This means
|
||||
// if you select different than default region in editor you will get results for autocomplete from wrong
|
||||
// region.
|
||||
if (anyQuery.region) {
|
||||
anyQuery.region = this.replace(anyQuery.region, options.scopedVars, true, 'region');
|
||||
anyQuery.region = this.getActualRegion(anyQuery.region);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const resultsToDataFrames = (val: any): DataFrame[] => toDataQueryResponse(val).data || [];
|
||||
|
@ -127,7 +127,7 @@ function getProvideCompletionItems(query: string): Promise<TypeaheadOutput> {
|
||||
{
|
||||
value,
|
||||
} as any,
|
||||
{ logGroupNames: ['logGroup1'] }
|
||||
{ logGroupNames: ['logGroup1'], region: 'custom' }
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@ type TypeaheadContext = {
|
||||
history?: CloudWatchHistoryItem[];
|
||||
absoluteRange?: AbsoluteTimeRange;
|
||||
logGroupNames?: string[];
|
||||
region: string;
|
||||
};
|
||||
|
||||
export class CloudWatchLanguageProvider extends LanguageProvider {
|
||||
@ -104,7 +105,7 @@ export class CloudWatchLanguageProvider extends LanguageProvider {
|
||||
}
|
||||
|
||||
if (isInsideFunctionParenthesis(curToken)) {
|
||||
return await this.getFieldCompletionItems(context?.logGroupNames ?? []);
|
||||
return await this.getFieldCompletionItems(context?.logGroupNames ?? [], context?.region || 'default');
|
||||
}
|
||||
|
||||
if (isAfterKeyword('by', curToken)) {
|
||||
@ -133,7 +134,7 @@ export class CloudWatchLanguageProvider extends LanguageProvider {
|
||||
}
|
||||
| undefined;
|
||||
|
||||
private fetchFields = async (logGroups: string[]): Promise<string[]> => {
|
||||
private fetchFields = async (logGroups: string[], region: string): Promise<string[]> => {
|
||||
if (
|
||||
this.fetchedFieldsCache &&
|
||||
Date.now() - this.fetchedFieldsCache.time < 30 * 1000 &&
|
||||
@ -143,7 +144,7 @@ export class CloudWatchLanguageProvider extends LanguageProvider {
|
||||
}
|
||||
|
||||
const results = await Promise.all(
|
||||
logGroups.map((logGroup) => this.datasource.getLogGroupFields({ logGroupName: logGroup }))
|
||||
logGroups.map((logGroup) => this.datasource.getLogGroupFields({ logGroupName: logGroup, region }))
|
||||
);
|
||||
|
||||
const fields = [
|
||||
@ -162,7 +163,7 @@ export class CloudWatchLanguageProvider extends LanguageProvider {
|
||||
};
|
||||
|
||||
private handleKeyword = async (context?: TypeaheadContext): Promise<TypeaheadOutput> => {
|
||||
const suggs = await this.getFieldCompletionItems(context?.logGroupNames ?? []);
|
||||
const suggs = await this.getFieldCompletionItems(context?.logGroupNames ?? [], context?.region || 'default');
|
||||
const functionSuggestions: CompletionItemGroup[] = [
|
||||
{
|
||||
searchFunctionType: SearchFunctionType.Prefix,
|
||||
@ -190,7 +191,7 @@ export class CloudWatchLanguageProvider extends LanguageProvider {
|
||||
|
||||
if (queryCommand === 'parse') {
|
||||
if (currentTokenIsFirstArg) {
|
||||
return await this.getFieldCompletionItems(context?.logGroupNames ?? []);
|
||||
return await this.getFieldCompletionItems(context?.logGroupNames ?? [], context?.region || 'default');
|
||||
}
|
||||
}
|
||||
|
||||
@ -207,7 +208,10 @@ export class CloudWatchLanguageProvider extends LanguageProvider {
|
||||
}
|
||||
|
||||
if (['display', 'fields'].includes(queryCommand)) {
|
||||
const typeaheadOutput = await this.getFieldCompletionItems(context?.logGroupNames ?? []);
|
||||
const typeaheadOutput = await this.getFieldCompletionItems(
|
||||
context?.logGroupNames ?? [],
|
||||
context?.region || 'default'
|
||||
);
|
||||
typeaheadOutput.suggestions.push(...this.getFieldAndFilterFunctionCompletionItems().suggestions);
|
||||
|
||||
return typeaheadOutput;
|
||||
@ -224,7 +228,7 @@ export class CloudWatchLanguageProvider extends LanguageProvider {
|
||||
}
|
||||
|
||||
if (queryCommand === 'filter' && currentTokenIsFirstArg) {
|
||||
const sugg = await this.getFieldCompletionItems(context?.logGroupNames ?? []);
|
||||
const sugg = await this.getFieldCompletionItems(context?.logGroupNames ?? [], context?.region || 'default');
|
||||
const boolFuncs = this.getBoolFuncCompletionItems();
|
||||
sugg.suggestions.push(...boolFuncs.suggestions);
|
||||
return sugg;
|
||||
@ -238,7 +242,7 @@ export class CloudWatchLanguageProvider extends LanguageProvider {
|
||||
context?: TypeaheadContext
|
||||
): Promise<TypeaheadOutput> {
|
||||
if (isFirstArgument) {
|
||||
return await this.getFieldCompletionItems(context?.logGroupNames ?? []);
|
||||
return await this.getFieldCompletionItems(context?.logGroupNames ?? [], context?.region || 'default');
|
||||
} else if (isTokenType(prevNonWhitespaceToken(curToken), 'field-name')) {
|
||||
// suggest sort options
|
||||
return {
|
||||
@ -261,7 +265,10 @@ export class CloudWatchLanguageProvider extends LanguageProvider {
|
||||
}
|
||||
|
||||
private handleComparison = async (context?: TypeaheadContext) => {
|
||||
const fieldsSuggestions = await this.getFieldCompletionItems(context?.logGroupNames ?? []);
|
||||
const fieldsSuggestions = await this.getFieldCompletionItems(
|
||||
context?.logGroupNames ?? [],
|
||||
context?.region || 'default'
|
||||
);
|
||||
const comparisonSuggestions = this.getComparisonCompletionItems();
|
||||
fieldsSuggestions.suggestions.push(...comparisonSuggestions.suggestions);
|
||||
return fieldsSuggestions;
|
||||
@ -313,8 +320,8 @@ export class CloudWatchLanguageProvider extends LanguageProvider {
|
||||
};
|
||||
};
|
||||
|
||||
private getFieldCompletionItems = async (logGroups: string[]): Promise<TypeaheadOutput> => {
|
||||
const fields = await this.fetchFields(logGroups);
|
||||
private getFieldCompletionItems = async (logGroups: string[], region: string): Promise<TypeaheadOutput> => {
|
||||
const fields = await this.fetchFields(logGroups, region);
|
||||
|
||||
return {
|
||||
suggestions: [
|
||||
|
@ -164,7 +164,7 @@ describe('CloudWatchDatasource', () => {
|
||||
'container-insights-prometheus-demo',
|
||||
];
|
||||
|
||||
const logGroups = await ds.describeLogGroups({});
|
||||
const logGroups = await ds.describeLogGroups({ region: 'default' });
|
||||
|
||||
expect(logGroups).toEqual(expectedLogGroups);
|
||||
});
|
||||
|
@ -122,6 +122,12 @@ export interface QueryStatistics {
|
||||
|
||||
export type QueryStatus = 'Scheduled' | 'Running' | 'Complete' | 'Failed' | 'Cancelled' | string;
|
||||
|
||||
export type CloudWatchLogsRequest =
|
||||
| GetLogEventsRequest
|
||||
| StartQueryRequest
|
||||
| DescribeLogGroupsRequest
|
||||
| GetLogGroupFieldsRequest;
|
||||
|
||||
export interface GetLogEventsRequest {
|
||||
/**
|
||||
* The name of the log group.
|
||||
@ -182,7 +188,7 @@ export interface DescribeLogGroupsRequest {
|
||||
*/
|
||||
limit?: number;
|
||||
refId?: string;
|
||||
region?: string;
|
||||
region: string;
|
||||
}
|
||||
|
||||
export interface TSDBResponse<T = any> {
|
||||
@ -256,6 +262,7 @@ export interface GetLogGroupFieldsRequest {
|
||||
* The time to set as the center of the query. If you specify time, the 8 minutes before and 8 minutes after this time are searched. If you omit time, the past 15 minutes are queried. The time value is specified as epoch time, the number of seconds since January 1, 1970, 00:00:00 UTC.
|
||||
*/
|
||||
time?: number;
|
||||
region: string;
|
||||
}
|
||||
|
||||
export interface LogGroupField {
|
||||
|
Loading…
Reference in New Issue
Block a user