ResultProcessor.ts 5.8 KB

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