ResultProcessor.ts 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  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. if (this.replacePreviousResults) {
  63. return newResults;
  64. }
  65. const prevLogsResult: LogsModel = this.state.logsResult || { hasUniqueLabels: false, rows: [] };
  66. const sortedLogResult = sortLogsResult(prevLogsResult, this.state.refreshInterval);
  67. const rowsInState = sortedLogResult.rows;
  68. const seriesInState = sortedLogResult.series || [];
  69. const processedRows = [];
  70. for (const row of rowsInState) {
  71. processedRows.push({ ...row, fresh: false });
  72. }
  73. for (const row of newResults.rows) {
  74. processedRows.push({ ...row, fresh: true });
  75. }
  76. const processedSeries = this.mergeGraphResults(newResults.series, seriesInState);
  77. const slice = -1000;
  78. const rows = processedRows.slice(slice);
  79. const series = processedSeries.slice(slice);
  80. return { ...newResults, rows, series };
  81. };
  82. private makeTimeSeriesList = (rawData: any[]) => {
  83. const dataList = getProcessedDataFrame(rawData);
  84. const dataProcessor = new DataProcessor({ xaxis: {}, aliasColors: [] }); // Hack before we use GraphSeriesXY instead
  85. const timeSeries = dataProcessor.getSeriesList({ dataList });
  86. return (timeSeries as any) as TimeSeries[]; // Hack before we use GraphSeriesXY instead
  87. };
  88. private isSameTimeSeries = (a: TimeSeries | TimeSeries2, b: TimeSeries | TimeSeries2) => {
  89. if (a.hasOwnProperty('id') && b.hasOwnProperty('id')) {
  90. const aValue = (a as TimeSeries2).id;
  91. const bValue = (b as TimeSeries2).id;
  92. if (aValue !== undefined && bValue !== undefined && aValue === bValue) {
  93. return true;
  94. }
  95. }
  96. if (a.hasOwnProperty('alias') && b.hasOwnProperty('alias')) {
  97. const aValue = (a as TimeSeries2).alias;
  98. const bValue = (b as TimeSeries2).alias;
  99. if (aValue !== undefined && bValue !== undefined && aValue === bValue) {
  100. return true;
  101. }
  102. }
  103. return false;
  104. };
  105. private mergeGraphResults = (
  106. newResults: TimeSeries[] | TimeSeries2[],
  107. prevResults: TimeSeries[] | TimeSeries2[]
  108. ): TimeSeries[] => {
  109. if (!prevResults || prevResults.length === 0 || this.replacePreviousResults) {
  110. return (newResults as any) as TimeSeries[]; // Hack before we use GraphSeriesXY instead
  111. }
  112. const results: TimeSeries[] = prevResults.slice() as TimeSeries[];
  113. // update existing results
  114. for (let index = 0; index < results.length; index++) {
  115. const prevResult = results[index];
  116. for (const newResult of newResults) {
  117. const isSame = this.isSameTimeSeries(prevResult, newResult);
  118. if (isSame) {
  119. prevResult.datapoints = prevResult.datapoints.concat(newResult.datapoints);
  120. break;
  121. }
  122. }
  123. }
  124. // add new results
  125. for (const newResult of newResults) {
  126. let isNew = true;
  127. for (const prevResult of results) {
  128. const isSame = this.isSameTimeSeries(prevResult, newResult);
  129. if (isSame) {
  130. isNew = false;
  131. break;
  132. }
  133. }
  134. if (isNew) {
  135. const timeSeries2Result = new TimeSeries2({ ...newResult });
  136. const result = (timeSeries2Result as any) as TimeSeries; // Hack before we use GraphSeriesXY instead
  137. results.push(result);
  138. }
  139. }
  140. return results;
  141. };
  142. }