loki: backend: add error-prop if loki parse error happened (#48860)
This commit is contained in:
@@ -39,12 +39,11 @@ const inputFrame: DataFrame = {
|
||||
{
|
||||
name: 'labels',
|
||||
type: FieldType.string,
|
||||
config: {
|
||||
custom: {
|
||||
json: true,
|
||||
},
|
||||
},
|
||||
values: new ArrayVector(['{ "level": "info", "code": "41🌙" }', '{ "level": "error", "code": "41🌙" }']),
|
||||
config: {},
|
||||
values: new ArrayVector([
|
||||
{ level: 'info', code: '41🌙' },
|
||||
{ level: 'error', code: '41🌙' },
|
||||
]),
|
||||
},
|
||||
{
|
||||
name: 'tsNs',
|
||||
@@ -157,4 +156,30 @@ describe('loki backendResultTransformer', () => {
|
||||
result.data[0].fields.filter((field: Field) => field.name === 'derived1' && field.type === 'string').length
|
||||
).toBe(1);
|
||||
});
|
||||
|
||||
it('handle loki parsing errors', () => {
|
||||
const clonedFrame = cloneDeep(inputFrame);
|
||||
clonedFrame.fields[2] = {
|
||||
name: 'labels',
|
||||
type: FieldType.string,
|
||||
config: {},
|
||||
values: new ArrayVector([
|
||||
{ level: 'info', code: '41🌙', __error__: 'LogfmtParserErr' },
|
||||
{ level: 'error', code: '41🌙' },
|
||||
]),
|
||||
};
|
||||
const response: DataQueryResponse = { data: [clonedFrame] };
|
||||
|
||||
const result = transformBackendResult(
|
||||
response,
|
||||
[
|
||||
{
|
||||
refId: 'A',
|
||||
expr: LOKI_EXPR,
|
||||
},
|
||||
],
|
||||
[]
|
||||
);
|
||||
expect(result.data[0]?.meta?.custom?.error).toBe('Error when parsing some of the logs');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,6 +3,7 @@ import { DataQueryResponse, DataFrame, isDataFrame, FieldType, QueryResultMeta }
|
||||
import { getDerivedFields } from './getDerivedFields';
|
||||
import { makeTableFrames } from './makeTableFrames';
|
||||
import { formatQuery, getHighlighterExpressionsFromQuery } from './query_utils';
|
||||
import { dataFrameHasLokiError } from './responseUtils';
|
||||
import { DerivedFieldConfig, LokiQuery, LokiQueryType } from './types';
|
||||
|
||||
function isMetricFrame(frame: DataFrame): boolean {
|
||||
@@ -25,14 +26,20 @@ function processStreamFrame(
|
||||
query: LokiQuery | undefined,
|
||||
derivedFieldConfigs: DerivedFieldConfig[]
|
||||
): DataFrame {
|
||||
const custom: Record<string, string> = {
|
||||
// used by logs_model
|
||||
lokiQueryStatKey: 'Summary: total bytes processed',
|
||||
};
|
||||
|
||||
if (dataFrameHasLokiError(frame)) {
|
||||
custom.error = 'Error when parsing some of the logs';
|
||||
}
|
||||
|
||||
const meta: QueryResultMeta = {
|
||||
preferredVisualisationType: 'logs',
|
||||
limit: query?.maxLines,
|
||||
searchWords: query !== undefined ? getHighlighterExpressionsFromQuery(formatQuery(query.expr)) : undefined,
|
||||
custom: {
|
||||
// used by logs_model
|
||||
lokiQueryStatKey: 'Summary: total bytes processed',
|
||||
},
|
||||
custom,
|
||||
};
|
||||
|
||||
const newFrame = setFrameMeta(frame, meta);
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import { cloneDeep } from 'lodash';
|
||||
|
||||
import { ArrayVector, DataFrame, FieldType } from '@grafana/data';
|
||||
|
||||
import { dataFrameHasLokiError } from './responseUtils';
|
||||
|
||||
const frame: DataFrame = {
|
||||
length: 1,
|
||||
fields: [
|
||||
{
|
||||
name: 'Time',
|
||||
config: {},
|
||||
type: FieldType.time,
|
||||
values: new ArrayVector([1]),
|
||||
},
|
||||
{
|
||||
name: 'labels',
|
||||
config: {},
|
||||
type: FieldType.other,
|
||||
values: new ArrayVector([{ level: 'info' }]),
|
||||
},
|
||||
{
|
||||
name: 'Line',
|
||||
config: {},
|
||||
type: FieldType.string,
|
||||
values: new ArrayVector(['line1']),
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
describe('dataframeHasParsingError', () => {
|
||||
it('handles frame with parsing error', () => {
|
||||
const input = cloneDeep(frame);
|
||||
input.fields[1].values = new ArrayVector([{ level: 'info', __error__: 'error' }]);
|
||||
expect(dataFrameHasLokiError(input)).toBe(true);
|
||||
});
|
||||
it('handles frame without parsing error', () => {
|
||||
const input = cloneDeep(frame);
|
||||
expect(dataFrameHasLokiError(input)).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,6 @@
|
||||
import { DataFrame, Labels } from '@grafana/data';
|
||||
|
||||
export function dataFrameHasLokiError(frame: DataFrame): boolean {
|
||||
const labelSets: Labels[] = frame.fields.find((f) => f.name === 'labels')?.values.toArray() ?? [];
|
||||
return labelSets.some((labels) => labels.__error__ !== undefined);
|
||||
}
|
||||
@@ -25,6 +25,7 @@ import TableModel from 'app/core/table_model';
|
||||
import { renderLegendFormat } from '../prometheus/legend';
|
||||
|
||||
import { formatQuery, getHighlighterExpressionsFromQuery } from './query_utils';
|
||||
import { dataFrameHasLokiError } from './responseUtils';
|
||||
import {
|
||||
LokiRangeQueryRequest,
|
||||
LokiResponse,
|
||||
@@ -346,7 +347,7 @@ export function lokiStreamsToDataFrames(
|
||||
const dataFrame = lokiStreamsToRawDataFrame(data, target.refId);
|
||||
enhanceDataFrame(dataFrame, config);
|
||||
|
||||
if (meta.custom && dataFrame.fields.some((f) => f.labels && Object.keys(f.labels).some((l) => l === '__error__'))) {
|
||||
if (meta.custom && dataFrameHasLokiError(dataFrame)) {
|
||||
meta.custom.error = 'Error when parsing some of the logs';
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user