From d0b149bdad0cde8009998fa1df590386eb9e6ee5 Mon Sep 17 00:00:00 2001 From: "grafana-delivery-bot[bot]" <132647405+grafana-delivery-bot[bot]@users.noreply.github.com> Date: Tue, 8 Aug 2023 12:30:21 +0200 Subject: [PATCH] [v10.1.x] Logs: Fix displaying the wrong field as body (#73037) Logs: Fix displaying the wrong field as body (#73025) * fix displaying the wrong field as body * fix test * fix `getFirstFieldOfType` with non-present type (cherry picked from commit 533fae4c603293149b41e2a4d411e3f90388c44f) Co-authored-by: Sven Grossmann --- .../src/dataframe/FieldCache.test.ts | 18 +++++++++++++ .../grafana-data/src/dataframe/FieldCache.ts | 2 +- .../explore/Logs/LogsMetaRow.test.tsx | 21 ++++++++++++++-- public/app/features/logs/legacyLogsFrame.ts | 4 +-- public/app/features/logs/logsFrame.test.ts | 25 +++++++++++++++++++ 5 files changed, 65 insertions(+), 5 deletions(-) diff --git a/packages/grafana-data/src/dataframe/FieldCache.test.ts b/packages/grafana-data/src/dataframe/FieldCache.test.ts index b5f5b861b64..8af5aff66e2 100644 --- a/packages/grafana-data/src/dataframe/FieldCache.test.ts +++ b/packages/grafana-data/src/dataframe/FieldCache.test.ts @@ -100,4 +100,22 @@ describe('FieldCache', () => { expect(field!.index).toEqual(2); }); }); + + describe('getFirstFieldOfType', () => { + let fieldCache: FieldCache; + beforeEach(() => { + const frame = toDataFrame({ + fields: [ + { name: 'time', type: FieldType.time, values: [100, 200, 300] }, + { name: 'value', type: FieldType.number, values: [1, 2, 3] }, + ], + }); + fieldCache = new FieldCache(frame); + }); + + it('should return undefined if type is not present', () => { + const field = fieldCache.getFirstFieldOfType(FieldType.string); + expect(field).toBeUndefined(); + }); + }); }); diff --git a/packages/grafana-data/src/dataframe/FieldCache.ts b/packages/grafana-data/src/dataframe/FieldCache.ts index 2834d47af13..9653be2426d 100644 --- a/packages/grafana-data/src/dataframe/FieldCache.ts +++ b/packages/grafana-data/src/dataframe/FieldCache.ts @@ -59,7 +59,7 @@ export class FieldCache { getFirstFieldOfType(type: FieldType, includeHidden = false): FieldWithIndex | undefined { const fields = this.fieldByType[type]; - const firstField = fields.find((field) => includeHidden || !field.config.custom?.hidden); + const firstField = fields?.find((field) => includeHidden || !field.config.custom?.hidden); return firstField; } diff --git a/public/app/features/explore/Logs/LogsMetaRow.test.tsx b/public/app/features/explore/Logs/LogsMetaRow.test.tsx index d367e9d358c..9e506d6b61f 100644 --- a/public/app/features/explore/Logs/LogsMetaRow.test.tsx +++ b/public/app/features/explore/Logs/LogsMetaRow.test.tsx @@ -3,7 +3,7 @@ import userEvent from '@testing-library/user-event'; import saveAs from 'file-saver'; import React, { ComponentProps } from 'react'; -import { LogLevel, LogsDedupStrategy, MutableDataFrame } from '@grafana/data'; +import { FieldType, LogLevel, LogsDedupStrategy, toDataFrame } from '@grafana/data'; import { MAX_CHARACTERS } from '../../logs/components/LogRowMessage'; import { logRowsToReadableJson } from '../../logs/utils'; @@ -150,7 +150,24 @@ describe('LogsMetaRow', () => { { rowIndex: 1, entryFieldIndex: 0, - dataFrame: new MutableDataFrame(), + dataFrame: toDataFrame({ + name: 'logs', + fields: [ + { + name: 'time', + type: FieldType.time, + values: ['1970-01-01T00:00:00Z'], + }, + { + name: 'message', + type: FieldType.string, + values: ['INFO 1'], + labels: { + foo: 'bar', + }, + }, + ], + }), entry: 'test entry', hasAnsi: false, hasUnescapedContent: false, diff --git a/public/app/features/logs/legacyLogsFrame.ts b/public/app/features/logs/legacyLogsFrame.ts index 0d91ee7cc4c..0c016cf6df3 100644 --- a/public/app/features/logs/legacyLogsFrame.ts +++ b/public/app/features/logs/legacyLogsFrame.ts @@ -34,8 +34,8 @@ function makeLabelsGetter( export function parseLegacyLogsFrame(frame: DataFrame): LogsFrame | null { const cache = new FieldCache(frame); - const timeField = cache.getFields(FieldType.time)[0]; - const bodyField = cache.getFields(FieldType.string)[0]; + const timeField = cache.getFirstFieldOfType(FieldType.time); + const bodyField = cache.getFirstFieldOfType(FieldType.string); // these two are mandatory if (timeField === undefined || bodyField === undefined) { diff --git a/public/app/features/logs/logsFrame.test.ts b/public/app/features/logs/logsFrame.test.ts index dad2a75254e..b6f491ad6c2 100644 --- a/public/app/features/logs/logsFrame.test.ts +++ b/public/app/features/logs/logsFrame.test.ts @@ -186,6 +186,31 @@ describe('parseLogsFrame should parse different logs-dataframe formats', () => { expect(result!.getAttributes()).toBeNull(); expect(result?.extraFields).toStrictEqual([]); }); + + it('should parse an old-style frame with a hidden string field', () => { + const time = makeTime('Time', [1687185711795, 1687185711995]); + const hidden = makeString('Hidden', ['hidden1', 'hidden2']); + const line = makeString('Line', ['line1', 'line2']); + + hidden.config.custom = { + hidden: true, + }; + + const result = parseLogsFrame({ + fields: [time, hidden, line], + length: 2, + }); + + expect(result).not.toBeNull(); + + expect(result!.timeField.values[0]).toBe(time.values[0]); + expect(result!.bodyField.values[0]).toBe(line.values[0]); + expect(result!.severityField).toBeNull(); + expect(result!.idField).toBeNull(); + expect(result!.timeNanosecondField).toBeNull(); + expect(result!.getAttributesAsLabels()).toBeNull(); + expect(result!.getAttributes()).toBeNull(); + }); }); describe('attributesToLabels', () => {