grafana/public/app/plugins/datasource/loki/makeTableFrames.ts
Gábor Farkas 1cad35ea67
loki: backend mode: support all query types (#45619)
* loki: backend mode: support all query types

* loki: backend: adjust vector-parsing field-names

* loki: backend: no interval for streams-dataframes

* loki: backend: enable more query types

* better variable name

* removed unnecessary code

* improve frame-processing

* more unit tests

* improved code

Co-authored-by: Ivana Huckova <30407135+ivanahuckova@users.noreply.github.com>

* remove unused code

Co-authored-by: Ivana Huckova <30407135+ivanahuckova@users.noreply.github.com>

* simplify code

Co-authored-by: Ivana Huckova <30407135+ivanahuckova@users.noreply.github.com>

* lint fix

Co-authored-by: Ivana Huckova <30407135+ivanahuckova@users.noreply.github.com>
2022-02-25 09:14:17 +01:00

76 lines
2.5 KiB
TypeScript

import { DataFrame, Field, FieldType, ArrayVector } from '@grafana/data';
import { groupBy } from 'lodash';
export function makeTableFrames(instantMetricFrames: DataFrame[]): DataFrame[] {
// first we remove frames that have no refId
// (we will group them by refId, so we need it to be set)
const framesWithRefId = instantMetricFrames.filter((f) => f.refId !== undefined);
const framesByRefId = groupBy(framesWithRefId, (frame) => frame.refId);
return Object.entries(framesByRefId).map(([refId, frames]) => makeTableFrame(frames, refId));
}
type NumberField = Field<number, ArrayVector<number>>;
type StringField = Field<string, ArrayVector<string>>;
function makeTableFrame(instantMetricFrames: DataFrame[], refId: string): DataFrame {
const tableTimeField: NumberField = { name: 'Time', config: {}, values: new ArrayVector(), type: FieldType.time };
const tableValueField: NumberField = {
name: `Value #${refId}`,
config: {},
values: new ArrayVector(),
type: FieldType.number,
};
// Sort metric labels, create columns for them and record their index
const allLabelNames = new Set(
instantMetricFrames.map((frame) => frame.fields.map((field) => Object.keys(field.labels ?? {})).flat()).flat()
);
const sortedLabelNames = Array.from(allLabelNames).sort();
const labelFields: StringField[] = sortedLabelNames.map((labelName) => ({
name: labelName,
config: { filterable: true },
values: new ArrayVector(),
type: FieldType.string,
}));
instantMetricFrames.forEach((frame) => {
const timeField = frame.fields.find((field) => field.type === FieldType.time);
const valueField = frame.fields.find((field) => field.type === FieldType.number);
if (timeField == null || valueField == null) {
return;
}
const timeArray = timeField.values.toArray();
const valueArray = valueField.values.toArray();
for (let x of timeArray) {
tableTimeField.values.add(x);
}
for (let x of valueArray) {
tableValueField.values.add(x);
}
const labels = valueField.labels ?? {};
for (let f of labelFields) {
const text = labels[f.name] ?? '';
// we insert the labels as many times as we have values
for (let i = 0; i < valueArray.length; i++) {
f.values.add(text);
}
}
});
return {
fields: [tableTimeField, ...labelFields, tableValueField],
refId,
meta: { preferredVisualisationType: 'table' },
length: tableTimeField.values.length,
};
}