Logs: Fix unresponsive log lines if duplicate ids in Elasticsearch (#68569)

* Logs: Fix duplicate uids by appending series refIds

* Fix id generation in loki live streams to be consistent

* Update public/app/core/logsModel.ts

Co-authored-by: Sven Grossmann <sven.grossmann@grafana.com>

* Fix test

---------

Co-authored-by: Sven Grossmann <sven.grossmann@grafana.com>
This commit is contained in:
Ivana Huckova
2023-05-17 16:28:25 +03:00
committed by GitHub
co-authored by Sven Grossmann
parent fcef387151
commit ee9620e4e0
11 changed files with 138 additions and 85 deletions
+59 -7
View File
@@ -299,6 +299,7 @@ describe('dataFrameToLogsModel', () => {
meta: {
limit: 1000,
},
refId: 'A',
}),
];
const logsModel = dataFrameToLogsModel(series, 1);
@@ -310,14 +311,14 @@ describe('dataFrameToLogsModel', () => {
labels: { filename: '/var/log/grafana/grafana.log', job: 'grafana' },
logLevel: 'info',
uniqueLabels: {},
uid: 'foo',
uid: 'A_foo',
},
{
entry: 't=2019-04-26T16:42:50+0200 lvl=eror msg="new token…t unhashed token=56d9fdc5c8b7400bd51b060eea8ca9d7',
labels: { filename: '/var/log/grafana/grafana.log', job: 'grafana' },
logLevel: 'error',
uniqueLabels: {},
uid: 'bar',
uid: 'A_bar',
},
]);
@@ -439,6 +440,7 @@ describe('dataFrameToLogsModel', () => {
frameType: 'LabeledTimeValues',
},
},
refId: 'A',
}),
];
const logsModel = dataFrameToLogsModel(series, 1);
@@ -450,14 +452,14 @@ describe('dataFrameToLogsModel', () => {
labels: { filename: '/var/log/grafana/grafana.log', job: 'grafana' },
logLevel: 'info',
uniqueLabels: {},
uid: 'foo',
uid: 'A_foo',
},
{
entry: 't=2019-04-26T16:42:50+0200 lvl=eror msg="new token…t unhashed token=56d9fdc5c8b7400bd51b060eea8ca9d7',
labels: { filename: '/var/log/grafana/grafana.log', job: 'grafana' },
logLevel: 'error',
uniqueLabels: {},
uid: 'bar',
uid: 'A_bar',
},
]);
@@ -583,6 +585,7 @@ describe('dataFrameToLogsModel', () => {
error: 'Error when parsing some of the logs',
},
},
refId: 'A',
}),
];
const logsModel = dataFrameToLogsModel(series, 1);
@@ -594,14 +597,14 @@ describe('dataFrameToLogsModel', () => {
labels: { filename: '/var/log/grafana/grafana.log', job: 'grafana', __error__: 'Failed while parsing' },
logLevel: 'info',
uniqueLabels: {},
uid: 'foo',
uid: 'A_foo',
},
{
entry: 't=2019-04-26T16:42:50+0200 lvl=eror msg="new token…t unhashed token=56d9fdc5c8b7400bd51b060eea8ca9d7',
labels: { filename: '/var/log/grafana/grafana.log', job: 'grafana', __error__: 'Failed while parsing' },
logLevel: 'error',
uniqueLabels: {},
uid: 'bar',
uid: 'A_bar',
},
]);
@@ -658,6 +661,54 @@ describe('dataFrameToLogsModel', () => {
]);
});
it('given multiple series with duplicate results it should return unique uids', () => {
const series: DataFrame[] = [
toDataFrame({
refId: 'A',
fields: [
{
name: 'ts',
type: FieldType.time,
values: ['1970-01-01T00:00:01Z'],
},
{
name: 'line',
type: FieldType.string,
values: ['WARN boooo'],
},
{
name: 'id',
type: FieldType.string,
values: ['duplicate_uid'],
},
],
}),
toDataFrame({
refId: 'B',
fields: [
{
name: 'ts',
type: FieldType.time,
values: ['1970-01-01T00:00:01Z'],
},
{
name: 'line',
type: FieldType.string,
values: ['WARN boooo'],
},
{
name: 'id',
type: FieldType.string,
values: ['duplicate_uid'],
},
],
}),
];
const logsModel = dataFrameToLogsModel(series, 1);
const uids = logsModel.rows.map((row) => row.uid);
expect(uids).toEqual(['A_duplicate_uid', 'B_duplicate_uid']);
});
it('given multiple series with unique times should return expected logs model', () => {
const series: DataFrame[] = [
toDataFrame({
@@ -916,6 +967,7 @@ describe('dataFrameToLogsModel', () => {
it('should fallback to row index if no id', () => {
const series: DataFrame[] = [
toDataFrame({
refId: 'A',
labels: { foo: 'bar' },
fields: [
{
@@ -932,7 +984,7 @@ describe('dataFrameToLogsModel', () => {
}),
];
const logsModel = dataFrameToLogsModel(series, 1);
expect(logsModel.rows[0].uid).toBe('0');
expect(logsModel.rows[0].uid).toBe('A_0');
});
});
+2 -1
View File
@@ -459,7 +459,8 @@ export function logSeriesToLogsModel(logSeries: DataFrame[], queries: DataQuery[
entry,
raw: message,
labels: labels || {},
uid: idField ? idField.values[j] : j.toString(),
// prepend refId to uid to make it unique across all series in a case when series contain duplicates
uid: `${series.refId}_${idField ? idField.values[j] : j.toString()}`,
datasourceType,
});
}
@@ -52,7 +52,7 @@ describe('Live Stream Tests', () => {
const last = { ...view.get(view.length - 1) };
expect(last).toEqual({
Time: '2019-08-28T20:50:40.118Z',
id: '25d81461-a66f-53ff-98d5-e39515af4735_A',
id: 'A_25d81461-a66f-53ff-98d5-e39515af4735',
Line: 'Kittens',
});
},
@@ -63,12 +63,12 @@ describe('loki result transformer', () => {
data.refId = 'C';
ResultTransformer.appendResponseToBufferedData(tailResponse, data);
expect(data.get(0).id).toEqual('75e72b25-8589-5f99-8d10-ccb5eb27c1b4_C');
expect(data.get(1).id).toEqual('75e72b25-8589-5f99-8d10-ccb5eb27c1b4_1_C');
expect(data.get(2).id).toEqual('3ca99d6b-3ab5-5970-93c0-eb3c9449088e_C');
expect(data.get(3).id).toEqual('ec9bea1d-70cb-556c-8519-d5d6ae18c004_C');
expect(data.get(4).id).toEqual('75e72b25-8589-5f99-8d10-ccb5eb27c1b4_2_C');
expect(data.get(5).id).toEqual('3ca99d6b-3ab5-5970-93c0-eb3c9449088e_1_C');
expect(data.get(0).id).toEqual('C_75e72b25-8589-5f99-8d10-ccb5eb27c1b4');
expect(data.get(1).id).toEqual('C_75e72b25-8589-5f99-8d10-ccb5eb27c1b4_1');
expect(data.get(2).id).toEqual('C_3ca99d6b-3ab5-5970-93c0-eb3c9449088e');
expect(data.get(3).id).toEqual('C_ec9bea1d-70cb-556c-8519-d5d6ae18c004');
expect(data.get(4).id).toEqual('C_75e72b25-8589-5f99-8d10-ccb5eb27c1b4_2');
expect(data.get(5).id).toEqual('C_3ca99d6b-3ab5-5970-93c0-eb3c9449088e_1');
});
});
});
@@ -69,7 +69,7 @@ function createUid(
}
// Return unique id
if (refId) {
return `${id}_${refId}`;
return `${refId}_${id}`;
}
return id;
}