ResultProcessor.ts 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. import {
  2. DataQueryResponse,
  3. TableData,
  4. isTableData,
  5. LogsModel,
  6. toDataFrame,
  7. guessFieldTypes,
  8. DataQueryResponseData,
  9. TimeSeries,
  10. } from '@grafana/ui';
  11. import { ExploreItemState, ExploreMode } from 'app/types/explore';
  12. import { getProcessedDataFrame } from 'app/features/dashboard/state/PanelQueryState';
  13. import TableModel, { mergeTablesIntoModel } from 'app/core/table_model';
  14. import { sortLogsResult } from 'app/core/utils/explore';
  15. import { dataFrameToLogsModel } from 'app/core/logs_model';
  16. import { default as TimeSeries2 } from 'app/core/time_series2';
  17. import { DataProcessor } from 'app/plugins/panel/graph/data_processor';
  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 = (): TimeSeries[] => {
  49. if (this.state.mode !== ExploreMode.Metrics) {
  50. return [];
  51. }
  52. const newResults = this.makeTimeSeriesList(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. if (this.replacePreviousResults) {
  71. return newResults;
  72. }
  73. const prevLogsResult: LogsModel = this.state.logsResult || { hasUniqueLabels: false, rows: [] };
  74. const sortedLogResult = sortLogsResult(prevLogsResult, this.state.refreshInterval);
  75. const rowsInState = sortedLogResult.rows;
  76. const seriesInState = sortedLogResult.series || [];
  77. const processedRows = [];
  78. for (const row of rowsInState) {
  79. processedRows.push({ ...row, fresh: false });
  80. }
  81. for (const row of newResults.rows) {
  82. processedRows.push({ ...row, fresh: true });
  83. }
  84. const processedSeries = this.mergeGraphResults(newResults.series, seriesInState);
  85. const slice = -1000;
  86. const rows = processedRows.slice(slice);
  87. const series = processedSeries.slice(slice);
  88. return { ...newResults, rows, series };
  89. };
  90. private makeTimeSeriesList = (rawData: any[]) => {
  91. const dataList = getProcessedDataFrame(rawData);
  92. const dataProcessor = new DataProcessor({ xaxis: {}, aliasColors: [] }); // Hack before we use GraphSeriesXY instead
  93. const timeSeries = dataProcessor.getSeriesList({ dataList });
  94. return (timeSeries as any) as TimeSeries[]; // Hack before we use GraphSeriesXY instead
  95. };
  96. private isSameTimeSeries = (a: TimeSeries | TimeSeries2, b: TimeSeries | TimeSeries2) => {
  97. if (a.hasOwnProperty('id') && b.hasOwnProperty('id')) {
  98. const aValue = (a as TimeSeries2).id;
  99. const bValue = (b as TimeSeries2).id;
  100. if (aValue !== undefined && bValue !== undefined && aValue === bValue) {
  101. return true;
  102. }
  103. }
  104. if (a.hasOwnProperty('alias') && b.hasOwnProperty('alias')) {
  105. const aValue = (a as TimeSeries2).alias;
  106. const bValue = (b as TimeSeries2).alias;
  107. if (aValue !== undefined && bValue !== undefined && aValue === bValue) {
  108. return true;
  109. }
  110. }
  111. return false;
  112. };
  113. private mergeGraphResults = (
  114. newResults: TimeSeries[] | TimeSeries2[],
  115. prevResults: TimeSeries[] | TimeSeries2[]
  116. ): TimeSeries[] => {
  117. if (!prevResults || prevResults.length === 0 || this.replacePreviousResults) {
  118. return (newResults as any) as TimeSeries[]; // Hack before we use GraphSeriesXY instead
  119. }
  120. const results: TimeSeries[] = prevResults.slice() as TimeSeries[];
  121. // update existing results
  122. for (let index = 0; index < results.length; index++) {
  123. const prevResult = results[index];
  124. for (const newResult of newResults) {
  125. const isSame = this.isSameTimeSeries(prevResult, newResult);
  126. if (isSame) {
  127. prevResult.datapoints = prevResult.datapoints.concat(newResult.datapoints);
  128. break;
  129. }
  130. }
  131. }
  132. // add new results
  133. for (const newResult of newResults) {
  134. let isNew = true;
  135. for (const prevResult of results) {
  136. const isSame = this.isSameTimeSeries(prevResult, newResult);
  137. if (isSame) {
  138. isNew = false;
  139. break;
  140. }
  141. }
  142. if (isNew) {
  143. const timeSeries2Result = new TimeSeries2({ ...newResult });
  144. const result = (timeSeries2Result as any) as TimeSeries; // Hack before we use GraphSeriesXY instead
  145. results.push(result);
  146. }
  147. }
  148. return results;
  149. };
  150. }