mirror of
https://github.com/grafana/grafana.git
synced 2025-02-13 00:55:47 -06:00
* WIP: intial commit * Switch: Adds tooltip * Refactor: Adds props to LogsPanelEditor * Refactor: Moves LogRowContextProvider to grafana/ui * Refactor: Moves LogRowContext and Alert to grafana/ui * Refactor: Moves LogLabelStats to grafana/ui * Refactor: Moves LogLabels and LogLabel to grafana/ui * Refactor: Moves LogMessageAnsi and ansicolor to grafana/ui * Refactor: Moves calculateFieldStats, LogsParsers and getParser to grafana/data * Refactor: Moves findHighlightChunksInText to grafana/data * Refactor: Moves LogRow to grafana/ui * Refactor: Moving ExploreGraphPanel to grafana/ui * Refactor: Copies Logs to grafana/ui * Refactor: Moves ToggleButtonGroup to grafana/ui * Refactor: Adds Logs to LogsPanel * Refactor: Moves styles to emotion * Feature: Adds LogsRows * Refactor: Introduces render limit * Styles: Moves styles to emotion * Styles: Moves styles to emotion * Styles: Moves styles to emotion * Styles: Moves styles to emotion * Refactor: Adds sorting to LogsPanelEditor * Tests: Adds tests for sorting * Refactor: Changes according to PR comments * Refactor: Changes according to PR comments * Refactor: Moves Logs and ExploreGraphPanel out of grafana/ui * Fix: Shows the Show context label again
182 lines
5.5 KiB
TypeScript
182 lines
5.5 KiB
TypeScript
import { DataQueryResponse, DataQueryResponseData } from '@grafana/ui';
|
|
|
|
import {
|
|
TableData,
|
|
isTableData,
|
|
LogsModel,
|
|
toDataFrame,
|
|
guessFieldTypes,
|
|
TimeSeries,
|
|
GraphSeriesXY,
|
|
LoadingState,
|
|
} from '@grafana/data';
|
|
|
|
import { ExploreItemState, ExploreMode } from 'app/types/explore';
|
|
import { getProcessedDataFrames } from 'app/features/dashboard/state/PanelQueryState';
|
|
import TableModel, { mergeTablesIntoModel } from 'app/core/table_model';
|
|
import { sortLogsResult, refreshIntervalToSortOrder } from 'app/core/utils/explore';
|
|
import { dataFrameToLogsModel } from 'app/core/logs_model';
|
|
import { getGraphSeriesModel } from 'app/plugins/panel/graph2/getGraphSeriesModel';
|
|
|
|
export class ResultProcessor {
|
|
private rawData: DataQueryResponseData[] = [];
|
|
private metrics: TimeSeries[] = [];
|
|
private tables: TableData[] = [];
|
|
|
|
constructor(
|
|
private state: ExploreItemState,
|
|
private replacePreviousResults: boolean,
|
|
result?: DataQueryResponse | DataQueryResponseData[]
|
|
) {
|
|
if (result && result.hasOwnProperty('data')) {
|
|
this.rawData = (result as DataQueryResponse).data;
|
|
} else {
|
|
this.rawData = (result as DataQueryResponseData[]) || [];
|
|
}
|
|
|
|
if (this.state.mode !== ExploreMode.Metrics) {
|
|
return;
|
|
}
|
|
|
|
for (let index = 0; index < this.rawData.length; index++) {
|
|
const res: any = this.rawData[index];
|
|
const isTable = isTableData(res);
|
|
if (isTable) {
|
|
this.tables.push(res);
|
|
} else {
|
|
this.metrics.push(res);
|
|
}
|
|
}
|
|
}
|
|
|
|
getRawData = (): any[] => {
|
|
return this.rawData;
|
|
};
|
|
|
|
getGraphResult = (): GraphSeriesXY[] => {
|
|
if (this.state.mode !== ExploreMode.Metrics) {
|
|
return [];
|
|
}
|
|
|
|
const newResults = this.createGraphSeries(this.metrics);
|
|
return this.mergeGraphResults(newResults, this.state.graphResult);
|
|
};
|
|
|
|
getTableResult = (): TableModel => {
|
|
if (this.state.mode !== ExploreMode.Metrics) {
|
|
return new TableModel();
|
|
}
|
|
|
|
const prevTableResults: any[] | TableModel = this.state.tableResult || [];
|
|
const tablesToMerge = this.replacePreviousResults ? this.tables : [].concat(prevTableResults, this.tables);
|
|
|
|
return mergeTablesIntoModel(new TableModel(), ...tablesToMerge);
|
|
};
|
|
|
|
getLogsResult = (): LogsModel => {
|
|
if (this.state.mode !== ExploreMode.Logs) {
|
|
return null;
|
|
}
|
|
const graphInterval = this.state.queryIntervals.intervalMs;
|
|
const dataFrame = this.rawData.map(result => guessFieldTypes(toDataFrame(result)));
|
|
const newResults = this.rawData ? dataFrameToLogsModel(dataFrame, graphInterval) : null;
|
|
const sortOrder = refreshIntervalToSortOrder(this.state.refreshInterval);
|
|
const sortedNewResults = sortLogsResult(newResults, sortOrder);
|
|
|
|
if (this.replacePreviousResults) {
|
|
const slice = 1000;
|
|
const rows = sortedNewResults.rows.slice(0, slice);
|
|
const series = sortedNewResults.series;
|
|
|
|
return { ...sortedNewResults, rows, series };
|
|
}
|
|
|
|
const prevLogsResult: LogsModel = this.state.logsResult || { hasUniqueLabels: false, rows: [] };
|
|
const sortedLogResult = sortLogsResult(prevLogsResult, sortOrder);
|
|
const rowsInState = sortedLogResult.rows;
|
|
const seriesInState = sortedLogResult.series || [];
|
|
|
|
const processedRows = [];
|
|
for (const row of rowsInState) {
|
|
processedRows.push({ ...row, fresh: false });
|
|
}
|
|
for (const row of sortedNewResults.rows) {
|
|
processedRows.push({ ...row, fresh: true });
|
|
}
|
|
|
|
const processedSeries = this.mergeGraphResults(sortedNewResults.series, seriesInState);
|
|
|
|
const slice = -1000;
|
|
const rows = processedRows.slice(slice);
|
|
const series = processedSeries.slice(slice);
|
|
|
|
return { ...sortedNewResults, rows, series };
|
|
};
|
|
|
|
private createGraphSeries = (rawData: any[]) => {
|
|
const dataFrames = getProcessedDataFrames(rawData);
|
|
const graphSeries = getGraphSeriesModel(
|
|
{ series: dataFrames, state: LoadingState.Done },
|
|
{},
|
|
{ showBars: false, showLines: true, showPoints: false },
|
|
{
|
|
asTable: false,
|
|
isVisible: true,
|
|
placement: 'under',
|
|
}
|
|
);
|
|
|
|
return graphSeries;
|
|
};
|
|
|
|
private isSameGraphSeries = (a: GraphSeriesXY, b: GraphSeriesXY) => {
|
|
if (a.hasOwnProperty('label') && b.hasOwnProperty('label')) {
|
|
const aValue = a.label;
|
|
const bValue = b.label;
|
|
if (aValue !== undefined && bValue !== undefined && aValue === bValue) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
};
|
|
|
|
private mergeGraphResults = (newResults: GraphSeriesXY[], prevResults: GraphSeriesXY[]): GraphSeriesXY[] => {
|
|
if (!prevResults || prevResults.length === 0 || this.replacePreviousResults) {
|
|
return newResults; // Hack before we use GraphSeriesXY instead
|
|
}
|
|
|
|
const results: GraphSeriesXY[] = prevResults.slice() as GraphSeriesXY[];
|
|
|
|
// update existing results
|
|
for (let index = 0; index < results.length; index++) {
|
|
const prevResult = results[index];
|
|
for (const newResult of newResults) {
|
|
const isSame = this.isSameGraphSeries(prevResult, newResult);
|
|
|
|
if (isSame) {
|
|
prevResult.data = prevResult.data.concat(newResult.data);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// add new results
|
|
for (const newResult of newResults) {
|
|
let isNew = true;
|
|
for (const prevResult of results) {
|
|
const isSame = this.isSameGraphSeries(prevResult, newResult);
|
|
if (isSame) {
|
|
isNew = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (isNew) {
|
|
results.push(newResult);
|
|
}
|
|
}
|
|
return results;
|
|
};
|
|
}
|