ResultProcessor.ts 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. import { DataQueryResponse, DataQueryResponseData } from '@grafana/ui';
  2. import {
  3. TableData,
  4. isTableData,
  5. LogsModel,
  6. toDataFrame,
  7. guessFieldTypes,
  8. TimeSeries,
  9. GraphSeriesXY,
  10. LoadingState,
  11. } from '@grafana/data';
  12. import { ExploreItemState, ExploreMode } from 'app/types/explore';
  13. import { getProcessedDataFrames } from 'app/features/dashboard/state/PanelQueryState';
  14. import TableModel, { mergeTablesIntoModel } from 'app/core/table_model';
  15. import { sortLogsResult } from 'app/core/utils/explore';
  16. import { dataFrameToLogsModel } from 'app/core/logs_model';
  17. import { getGraphSeriesModel } from 'app/plugins/panel/graph2/getGraphSeriesModel';
  18. export class ResultProcessor {
  19. private rawData: DataQueryResponseData[] = [];
  20. private metrics: TimeSeries[] = [];
  21. private tables: TableData[] = [];
  22. constructor(
  23. private state: ExploreItemState,
  24. private replacePreviousResults: boolean,
  25. result?: DataQueryResponse | DataQueryResponseData[]
  26. ) {
  27. if (result && result.hasOwnProperty('data')) {
  28. this.rawData = (result as DataQueryResponse).data;
  29. } else {
  30. this.rawData = (result as DataQueryResponseData[]) || [];
  31. }
  32. if (this.state.mode !== ExploreMode.Metrics) {
  33. return;
  34. }
  35. for (let index = 0; index < this.rawData.length; index++) {
  36. const res: any = this.rawData[index];
  37. const isTable = isTableData(res);
  38. if (isTable) {
  39. this.tables.push(res);
  40. } else {
  41. this.metrics.push(res);
  42. }
  43. }
  44. }
  45. getRawData = (): any[] => {
  46. return this.rawData;
  47. };
  48. getGraphResult = (): GraphSeriesXY[] => {
  49. if (this.state.mode !== ExploreMode.Metrics) {
  50. return [];
  51. }
  52. const newResults = this.createGraphSeries(this.metrics);
  53. return this.mergeGraphResults(newResults, this.state.graphResult);
  54. };
  55. getTableResult = (): TableModel => {
  56. if (this.state.mode !== ExploreMode.Metrics) {
  57. return new TableModel();
  58. }
  59. const prevTableResults: any[] | TableModel = this.state.tableResult || [];
  60. const tablesToMerge = this.replacePreviousResults ? this.tables : [].concat(prevTableResults, this.tables);
  61. return mergeTablesIntoModel(new TableModel(), ...tablesToMerge);
  62. };
  63. getLogsResult = (): LogsModel => {
  64. if (this.state.mode !== ExploreMode.Logs) {
  65. return null;
  66. }
  67. const graphInterval = this.state.queryIntervals.intervalMs;
  68. const dataFrame = this.rawData.map(result => guessFieldTypes(toDataFrame(result)));
  69. const newResults = this.rawData ? dataFrameToLogsModel(dataFrame, graphInterval) : null;
  70. const sortedNewResults = sortLogsResult(newResults, this.state.refreshInterval);
  71. if (this.replacePreviousResults) {
  72. return sortedNewResults;
  73. }
  74. const prevLogsResult: LogsModel = this.state.logsResult || { hasUniqueLabels: false, rows: [] };
  75. const sortedLogResult = sortLogsResult(prevLogsResult, this.state.refreshInterval);
  76. const rowsInState = sortedLogResult.rows;
  77. const seriesInState = sortedLogResult.series || [];
  78. const processedRows = [];
  79. for (const row of rowsInState) {
  80. processedRows.push({ ...row, fresh: false });
  81. }
  82. for (const row of sortedNewResults.rows) {
  83. processedRows.push({ ...row, fresh: true });
  84. }
  85. const processedSeries = this.mergeGraphResults(sortedNewResults.series, seriesInState);
  86. const slice = -1000;
  87. const rows = processedRows.slice(slice);
  88. const series = processedSeries.slice(slice);
  89. return { ...sortedNewResults, rows, series };
  90. };
  91. private createGraphSeries = (rawData: any[]) => {
  92. const dataFrames = getProcessedDataFrames(rawData);
  93. const graphSeries = getGraphSeriesModel(
  94. { series: dataFrames, state: LoadingState.Done },
  95. {},
  96. { showBars: false, showLines: true, showPoints: false },
  97. {
  98. asTable: false,
  99. isVisible: true,
  100. placement: 'under',
  101. }
  102. );
  103. return graphSeries;
  104. };
  105. private isSameGraphSeries = (a: GraphSeriesXY, b: GraphSeriesXY) => {
  106. if (a.hasOwnProperty('label') && b.hasOwnProperty('label')) {
  107. const aValue = a.label;
  108. const bValue = b.label;
  109. if (aValue !== undefined && bValue !== undefined && aValue === bValue) {
  110. return true;
  111. }
  112. }
  113. return false;
  114. };
  115. private mergeGraphResults = (newResults: GraphSeriesXY[], prevResults: GraphSeriesXY[]): GraphSeriesXY[] => {
  116. if (!prevResults || prevResults.length === 0 || this.replacePreviousResults) {
  117. return newResults; // Hack before we use GraphSeriesXY instead
  118. }
  119. const results: GraphSeriesXY[] = prevResults.slice() as GraphSeriesXY[];
  120. // update existing results
  121. for (let index = 0; index < results.length; index++) {
  122. const prevResult = results[index];
  123. for (const newResult of newResults) {
  124. const isSame = this.isSameGraphSeries(prevResult, newResult);
  125. if (isSame) {
  126. prevResult.data = prevResult.data.concat(newResult.data);
  127. break;
  128. }
  129. }
  130. }
  131. // add new results
  132. for (const newResult of newResults) {
  133. let isNew = true;
  134. for (const prevResult of results) {
  135. const isSame = this.isSameGraphSeries(prevResult, newResult);
  136. if (isSame) {
  137. isNew = false;
  138. break;
  139. }
  140. }
  141. if (isNew) {
  142. results.push(newResult);
  143. }
  144. }
  145. return results;
  146. };
  147. }