mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Datasource/CloudWatch: Add data links to CloudWatch logs for deep linking to AWS (#24334)
* Datasource/CloudWatch: Fix encoding of CloudWatch Logs deep link URL * Adds data links to cloudwatch logs responses for deep linking to aws console * Implements PR feedback
This commit is contained in:
parent
35c097e475
commit
a655aa1ca8
@ -12,7 +12,7 @@ export interface AwsUrl {
|
||||
}
|
||||
|
||||
export function encodeUrl(obj: AwsUrl, region: string): string {
|
||||
return `https://${region}.console.aws.amazon.com/cloudwatch/home?region=${region}#logsV2:logs-insights$3FqueryDetail$3D${JSURL.stringify(
|
||||
return `https://${region}.console.aws.amazon.com/cloudwatch/home?region=${region}#logs-insights:queryDetail=${JSURL.stringify(
|
||||
obj
|
||||
)}`;
|
||||
}
|
||||
|
@ -47,6 +47,7 @@ import { CloudWatchLanguageProvider } from './language_provider';
|
||||
const TSDB_QUERY_ENDPOINT = '/api/tsdb/query';
|
||||
import { VariableWithMultiSupport } from 'app/features/templating/types';
|
||||
import { RowContextOptions } from '@grafana/ui/src/components/Logs/LogRowContextProvider';
|
||||
import { AwsUrl, encodeUrl } from './aws_url';
|
||||
|
||||
const displayAlert = (datasourceName: string, region: string) =>
|
||||
store.dispatch(
|
||||
@ -118,7 +119,8 @@ export class CloudWatchDatasource extends DataSourceApi<CloudWatchQuery, CloudWa
|
||||
refId: dataFrame.refId,
|
||||
}))
|
||||
)
|
||||
)
|
||||
),
|
||||
map(response => this.addDataLinksToLogsResponse(response, options))
|
||||
);
|
||||
}
|
||||
|
||||
@ -224,12 +226,48 @@ export class CloudWatchDatasource extends DataSourceApi<CloudWatchQuery, CloudWa
|
||||
);
|
||||
}
|
||||
|
||||
private addDataLinksToLogsResponse(response: DataQueryResponse, options: DataQueryRequest<CloudWatchQuery>) {
|
||||
for (const dataFrame of response.data as DataFrame[]) {
|
||||
const range = this.timeSrv.timeRange();
|
||||
const start = range.from.toISOString();
|
||||
const end = range.to.toISOString();
|
||||
|
||||
const curTarget = options.targets.find(target => target.refId === dataFrame.refId) as CloudWatchLogsQuery;
|
||||
const urlProps: AwsUrl = {
|
||||
end,
|
||||
start,
|
||||
timeType: 'ABSOLUTE',
|
||||
tz: 'UTC',
|
||||
editorString: curTarget.expression,
|
||||
isLiveTail: false,
|
||||
source: curTarget.logGroupNames,
|
||||
};
|
||||
|
||||
const encodedUrl = encodeUrl(
|
||||
urlProps,
|
||||
this.getActualRegion(this.replace(curTarget.region, options.scopedVars, true, 'region'))
|
||||
);
|
||||
|
||||
for (const field of dataFrame.fields) {
|
||||
field.config.links = [
|
||||
{
|
||||
url: encodedUrl,
|
||||
title: 'View in CloudWatch console',
|
||||
targetBlank: true,
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
stopQueries() {
|
||||
if (this.logQueries.size > 0) {
|
||||
this.makeLogActionRequest(
|
||||
'StopQuery',
|
||||
[...this.logQueries.values()].map(logQuery => ({ queryId: logQuery.id, region: logQuery.region })),
|
||||
null,
|
||||
undefined,
|
||||
false
|
||||
).pipe(finalize(() => this.logQueries.clear()));
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import '../datasource';
|
||||
import { CloudWatchDatasource } from '../datasource';
|
||||
import * as redux from 'app/store/store';
|
||||
import { DataSourceInstanceSettings, dateMath, getFrameDisplayTitle } from '@grafana/data';
|
||||
import { DataSourceInstanceSettings, dateMath, getFrameDisplayTitle, DataQueryResponse } from '@grafana/data';
|
||||
import { TemplateSrv } from 'app/features/templating/template_srv';
|
||||
import { CustomVariable } from 'app/features/templating/all';
|
||||
import { CloudWatchQuery, CloudWatchMetricsQuery } from '../types';
|
||||
@ -28,7 +28,7 @@ describe('CloudWatchDatasource', () => {
|
||||
const defaultTimeRange = { from: new Date(start), to: new Date(start + 3600 * 1000) };
|
||||
|
||||
const timeSrv = {
|
||||
time: { from: 'now-1h', to: 'now' },
|
||||
time: { from: '2016-12-31 15:00:00', to: '2016-12-31 16:00:00' },
|
||||
timeRange: () => {
|
||||
return {
|
||||
from: dateMath.parse(timeSrv.time.from, false),
|
||||
@ -105,6 +105,59 @@ describe('CloudWatchDatasource', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('When performing CloudWatch logs query', () => {
|
||||
it('should add data links to response', () => {
|
||||
const mockResponse: DataQueryResponse = {
|
||||
data: [
|
||||
{
|
||||
fields: [
|
||||
{
|
||||
config: {
|
||||
links: [],
|
||||
},
|
||||
},
|
||||
],
|
||||
refId: 'A',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const mockOptions = {
|
||||
targets: [
|
||||
{
|
||||
refId: 'A',
|
||||
expression: 'stats count(@message) by bin(1h)',
|
||||
logGroupNames: ['fake-log-group-one', 'fake-log-group-two'],
|
||||
region: 'default',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const saturatedResponse = ctx.ds.addDataLinksToLogsResponse(mockResponse, mockOptions);
|
||||
expect(saturatedResponse).toMatchObject({
|
||||
data: [
|
||||
{
|
||||
fields: [
|
||||
{
|
||||
config: {
|
||||
links: [
|
||||
{
|
||||
url:
|
||||
"https://us-east-1.console.aws.amazon.com/cloudwatch/home?region=us-east-1#logs-insights:queryDetail=~(end~'2016-12-31T16*3a00*3a00.000Z~start~'2016-12-31T15*3a00*3a00.000Z~timeType~'ABSOLUTE~tz~'UTC~editorString~'stats*20count*28*40message*29*20by*20bin*281h*29~isLiveTail~false~source~(~'fake-log-group-one~'fake-log-group-two))",
|
||||
title: 'View in CloudWatch console',
|
||||
targetBlank: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
refId: 'A',
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('When performing CloudWatch metrics query', () => {
|
||||
const query = {
|
||||
range: defaultTimeRange,
|
||||
|
Loading…
Reference in New Issue
Block a user