Explore: Prevent empty Elasticsearch logs query responses from hiding the logs panel (#40217)

* remove return value from addPreferredVisualisationType

* Elasticsearch: send empty series instead when no data is received for a query
This commit is contained in:
Giordano Ricci 2021-10-12 13:59:28 +01:00 committed by GitHub
parent ea0c1006f5
commit b0391d4933
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 105 additions and 67 deletions

View File

@ -489,7 +489,7 @@ export class ElasticResponse {
return this.processResponseToDataFrames(true, logMessageField, logLevelField); return this.processResponseToDataFrames(true, logMessageField, logLevelField);
} }
processResponseToDataFrames( private processResponseToDataFrames(
isLogsRequest: boolean, isLogsRequest: boolean,
logMessageField?: string, logMessageField?: string,
logLevelField?: string logLevelField?: string
@ -501,16 +501,22 @@ export class ElasticResponse {
throw this.getErrorFromElasticResponse(this.response, response.error); throw this.getErrorFromElasticResponse(this.response, response.error);
} }
if (response.hits && response.hits.hits.length > 0) { if (response.hits) {
const { propNames, docs } = flattenHits(response.hits.hits); const { propNames, docs } = flattenHits(response.hits.hits);
if (docs.length > 0) {
let series = createEmptyDataFrame( const series = docs.length
? createEmptyDataFrame(
propNames.map(toNameTypePair(docs)), propNames.map(toNameTypePair(docs)),
this.targets[0].timeField!,
isLogsRequest, isLogsRequest,
this.targets[0].timeField,
logMessageField, logMessageField,
logLevelField logLevelField
); )
: createEmptyDataFrame([], isLogsRequest);
if (isLogsRequest) {
addPreferredVisualisationType(series, 'logs');
}
// Add a row for each document // Add a row for each document
for (const doc of docs) { for (const doc of docs) {
@ -552,14 +558,11 @@ export class ElasticResponse {
} }
series.add(doc); series.add(doc);
} }
if (isLogsRequest) {
series = addPreferredVisualisationType(series, 'logs');
}
const target = this.targets[n]; const target = this.targets[n];
series.refId = target.refId; series.refId = target.refId;
dataFrame.push(series); dataFrame.push(series);
} }
}
if (response.aggregations) { if (response.aggregations) {
const aggregations = response.aggregations; const aggregations = response.aggregations;
@ -582,7 +585,7 @@ export class ElasticResponse {
// When log results, show aggregations only in graph. Log fields are then going to be shown in table. // When log results, show aggregations only in graph. Log fields are then going to be shown in table.
if (isLogsRequest) { if (isLogsRequest) {
series = addPreferredVisualisationType(series, 'graph'); addPreferredVisualisationType(series, 'graph');
} }
series.refId = target.refId; series.refId = target.refId;
@ -690,13 +693,14 @@ const flattenHits = (hits: Doc[]): { docs: Array<Record<string, any>>; propNames
*/ */
const createEmptyDataFrame = ( const createEmptyDataFrame = (
props: Array<[string, FieldType]>, props: Array<[string, FieldType]>,
timeField: string,
isLogsRequest: boolean, isLogsRequest: boolean,
timeField?: string,
logMessageField?: string, logMessageField?: string,
logLevelField?: string logLevelField?: string
): MutableDataFrame => { ): MutableDataFrame => {
const series = new MutableDataFrame({ fields: [] }); const series = new MutableDataFrame({ fields: [] });
if (timeField) {
series.addField({ series.addField({
config: { config: {
filterable: true, filterable: true,
@ -704,6 +708,7 @@ const createEmptyDataFrame = (
name: timeField, name: timeField,
type: FieldType.time, type: FieldType.time,
}); });
}
if (logMessageField) { if (logMessageField) {
series.addField({ series.addField({
@ -756,8 +761,6 @@ const addPreferredVisualisationType = (series: any, type: PreferredVisualisation
: (s.meta = { : (s.meta = {
preferredVisualisationType: type, preferredVisualisationType: type,
}); });
return s;
}; };
const toNameTypePair = (docs: Array<Record<string, any>>) => (propName: string): [string, FieldType] => [ const toNameTypePair = (docs: Array<Record<string, any>>) => (propName: string): [string, FieldType] => [

View File

@ -1432,4 +1432,39 @@ describe('ElasticResponse', () => {
expect(fields).toContainEqual({ name: 'message', type: 'string' }); expect(fields).toContainEqual({ name: 'message', type: 'string' });
}); });
}); });
describe('logs query with empty response', () => {
const targets: ElasticsearchQuery[] = [
{
refId: 'A',
metrics: [{ type: 'logs', id: '2' }],
bucketAggs: [{ type: 'date_histogram', settings: { interval: 'auto' }, id: '1' }],
key: 'Q-1561369883389-0.7611823271062786-0',
query: 'hello AND message',
timeField: '@timestamp',
},
];
const response = {
responses: [
{
hits: { hits: [] },
aggregations: {
'1': {
buckets: [
{ key_as_string: '1633676760000', key: 1633676760000, doc_count: 0 },
{ key_as_string: '1633676770000', key: 1633676770000, doc_count: 0 },
{ key_as_string: '1633676780000', key: 1633676780000, doc_count: 0 },
],
},
},
status: 200,
},
],
};
it('should return histogram aggregation and documents', () => {
const result = new ElasticResponse(targets, response).getLogs('message', 'level');
expect(result.data.length).toBe(2);
});
});
}); });