datalinks.ts 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. import { DataFrame, DataLink, DataQueryRequest, DataQueryResponse, ScopedVars, TimeRange } from '@grafana/data';
  2. import { getDataSourceSrv } from '@grafana/runtime';
  3. import { AwsUrl, encodeUrl } from '../aws_url';
  4. import { CloudWatchLogsQuery, CloudWatchQuery } from '../types';
  5. type ReplaceFn = (
  6. target?: string,
  7. scopedVars?: ScopedVars,
  8. displayErrorIfIsMultiTemplateVariable?: boolean,
  9. fieldName?: string
  10. ) => string;
  11. export async function addDataLinksToLogsResponse(
  12. response: DataQueryResponse,
  13. request: DataQueryRequest<CloudWatchQuery>,
  14. range: TimeRange,
  15. replaceFn: ReplaceFn,
  16. getVariableValueFn: (value: string, scopedVars: ScopedVars) => string[],
  17. getRegion: (region: string) => string,
  18. tracingDatasourceUid?: string
  19. ): Promise<void> {
  20. const replace = (target: string, fieldName?: string) => replaceFn(target, request.scopedVars, true, fieldName);
  21. const getVariableValue = (target: string) => getVariableValueFn(target, request.scopedVars);
  22. for (const dataFrame of response.data as DataFrame[]) {
  23. const curTarget = request.targets.find((target) => target.refId === dataFrame.refId) as CloudWatchLogsQuery;
  24. const interpolatedRegion = getRegion(replace(curTarget.region ?? '', 'region'));
  25. for (const field of dataFrame.fields) {
  26. if (field.name === '@xrayTraceId' && tracingDatasourceUid) {
  27. getRegion(replace(curTarget.region ?? '', 'region'));
  28. const xrayLink = await createInternalXrayLink(tracingDatasourceUid, interpolatedRegion);
  29. if (xrayLink) {
  30. field.config.links = [xrayLink];
  31. }
  32. } else {
  33. // Right now we add generic link to open the query in xray console to every field so it shows in the logs row
  34. // details. Unfortunately this also creates link for all values inside table which look weird.
  35. field.config.links = [createAwsConsoleLink(curTarget, range, interpolatedRegion, replace, getVariableValue)];
  36. }
  37. }
  38. }
  39. }
  40. async function createInternalXrayLink(datasourceUid: string, region: string) {
  41. let ds;
  42. try {
  43. ds = await getDataSourceSrv().get(datasourceUid);
  44. } catch (e) {
  45. console.error('Could not load linked xray data source, it was probably deleted after it was linked', e);
  46. return undefined;
  47. }
  48. return {
  49. title: ds.name,
  50. url: '',
  51. internal: {
  52. query: { query: '${__value.raw}', queryType: 'getTrace', region: region },
  53. datasourceUid: datasourceUid,
  54. datasourceName: ds.name,
  55. },
  56. } as DataLink;
  57. }
  58. function createAwsConsoleLink(
  59. target: CloudWatchLogsQuery,
  60. range: TimeRange,
  61. region: string,
  62. replace: (target: string, fieldName?: string) => string,
  63. getVariableValue: (value: string) => string[]
  64. ) {
  65. const interpolatedExpression = target.expression ? replace(target.expression) : '';
  66. const interpolatedGroups = target.logGroupNames?.flatMap(getVariableValue) ?? [];
  67. const urlProps: AwsUrl = {
  68. end: range.to.toISOString(),
  69. start: range.from.toISOString(),
  70. timeType: 'ABSOLUTE',
  71. tz: 'UTC',
  72. editorString: interpolatedExpression,
  73. isLiveTail: false,
  74. source: interpolatedGroups,
  75. };
  76. const encodedUrl = encodeUrl(urlProps, region);
  77. return {
  78. url: encodedUrl,
  79. title: 'View in CloudWatch console',
  80. targetBlank: true,
  81. };
  82. }