Commit 373e8696 by Besart Berisha Committed by GitHub

Explore: show meta data when available (#25798)

* Return valid metadata even if data is empty

* Make sure fields is not accessed when there is no data

* Meta Info should depend only on meta data

* Refactor condition for better reading

* Change data to empty array for better condition handling

* Remove unecessary checks

* Add test for showing metaData even when data is empty
parent 7a11ed91
......@@ -8,7 +8,7 @@ import {
MutableDataFrame,
toDataFrame,
} from '@grafana/data';
import { dataFrameToLogsModel, dedupLogRows, getSeriesProperties } from './logs_model';
import { dataFrameToLogsModel, dedupLogRows, getSeriesProperties, logSeriesToLogsModel } from './logs_model';
describe('dedupLogRows()', () => {
test('should return rows as is when dedup is set to none', () => {
......@@ -596,6 +596,37 @@ describe('dataFrameToLogsModel', () => {
});
});
describe('logSeriesToLogsModel', () => {
it('should return correct metaData even if the data is empty', () => {
const logSeries: DataFrame[] = [
{
fields: [],
length: 0,
refId: 'A',
meta: {
searchWords: ['test'],
limit: 1000,
stats: [{ displayName: 'Summary: total bytes processed', value: 97048, unit: 'decbytes' }],
custom: { lokiQueryStatKey: 'Summary: total bytes processed' },
preferredVisualisationType: 'logs',
},
},
];
const metaData = {
hasUniqueLabels: false,
meta: [
{ label: 'Limit', value: '1000 (0 returned)', kind: 1 },
{ label: 'Total bytes processed', value: '97 kB', kind: 1 },
],
rows: [],
};
expect(logSeriesToLogsModel(logSeries)).toMatchObject(metaData);
});
});
describe('getSeriesProperties()', () => {
it('sets a minimum bucket size', () => {
const result = getSeriesProperties([], 2, undefined, 3, 123);
......
......@@ -269,7 +269,7 @@ function separateLogsAndMetrics(dataFrames: DataFrame[]) {
const logSeries: DataFrame[] = [];
for (const dataFrame of dataFrames) {
if (isLogsData(dataFrame)) {
if (isLogsData(dataFrame) || !dataFrame.fields.length) {
logSeries.push(dataFrame);
continue;
}
......@@ -303,23 +303,29 @@ export function logSeriesToLogsModel(logSeries: DataFrame[]): LogsModel | undefi
const allLabels: Labels[] = [];
// Find the fields we care about and collect all labels
const allSeries: LogFields[] = logSeries.map(series => {
const fieldCache = new FieldCache(series);
const stringField = fieldCache.getFirstFieldOfType(FieldType.string);
if (stringField?.labels) {
allLabels.push(stringField.labels);
}
return {
series,
timeField: fieldCache.getFirstFieldOfType(FieldType.time),
timeNanosecondField: fieldCache.hasFieldWithNameAndType('tsNs', FieldType.time)
? fieldCache.getFieldByName('tsNs')
: undefined,
stringField,
logLevelField: fieldCache.getFieldByName('level'),
idField: getIdField(fieldCache),
} as LogFields;
});
let allSeries: LogFields[] = [];
if (hasFields(logSeries)) {
allSeries = logSeries.map(series => {
const fieldCache = new FieldCache(series);
const stringField = fieldCache.getFirstFieldOfType(FieldType.string);
if (stringField?.labels) {
allLabels.push(stringField.labels);
}
return {
series,
timeField: fieldCache.getFirstFieldOfType(FieldType.time),
timeNanosecondField: fieldCache.hasFieldWithNameAndType('tsNs', FieldType.time)
? fieldCache.getFieldByName('tsNs')
: undefined,
stringField,
logLevelField: fieldCache.getFieldByName('level'),
idField: getIdField(fieldCache),
} as LogFields;
});
}
const commonLabels = allLabels.length > 0 ? findCommonLabels(allLabels) : {};
......@@ -445,6 +451,10 @@ export function logSeriesToLogsModel(logSeries: DataFrame[]): LogsModel | undefi
};
}
function hasFields(logSeries: DataFrame[]): boolean {
return logSeries.some(series => series.fields.length);
}
function getIdField(fieldCache: FieldCache): FieldWithIndex | undefined {
const idFieldNames = ['id'];
for (const fieldName of idFieldNames) {
......
......@@ -171,9 +171,11 @@ export function getProcessedDataFrames(results?: DataQueryResponseData[]): DataF
for (const result of results) {
const dataFrame = guessFieldTypes(toDataFrame(result));
// clear out the cached info
for (const field of dataFrame.fields) {
field.state = null;
if (dataFrame.fields && dataFrame.fields.length) {
// clear out the cached info
for (const field of dataFrame.fields) {
field.state = null;
}
}
dataFrames.push(dataFrame);
......
......@@ -225,7 +225,7 @@ export class Logs extends PureComponent<Props, State> {
</div>
</div>
{hasData && meta && (
{meta && (
<MetaInfoText
metaItems={meta.map(item => {
return {
......
......@@ -312,22 +312,36 @@ export function lokiStreamsToDataframes(
lokiQueryStatKey: 'Summary: total bytes processed',
};
const meta: QueryResultMeta = {
searchWords: getHighlighterExpressionsFromQuery(formatQuery(target.expr)),
limit,
stats,
custom,
preferredVisualisationType: 'logs',
};
const series: DataFrame[] = data.map(stream => {
const dataFrame = lokiStreamResultToDataFrame(stream, reverse);
enhanceDataFrame(dataFrame, config);
return {
...dataFrame,
refId: target.refId,
meta: {
searchWords: getHighlighterExpressionsFromQuery(formatQuery(target.expr)),
limit,
stats,
custom,
preferredVisualisationType: 'logs',
},
meta,
};
});
if (stats.length && !data.length) {
return [
{
fields: [],
length: 0,
refId: target.refId,
meta,
},
];
}
return series;
}
......
......@@ -107,8 +107,9 @@ export class TablePanel extends Component<Props> {
const { data, height, width } = this.props;
const count = data.series?.length;
const hasFields = data.series[0]?.fields.length;
if (!count || count < 1) {
if (!count || !hasFields) {
return <div>No data</div>;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment