Elasticsearch: Visualize logs in Explore (#17605)

* explore: try to use existing mode when switching datasource

* elasticsearch: initial explore logs support

* Elasticsearch: Adds ElasticsearchOptions type
Updates tests accordingly

* Elasticsearch: Adds typing to query method

* Elasticsearch: Makes maxConcurrentShardRequests optional

* Explore: Allows empty query for elasticsearch datasource

* Elasticsearch: Unifies ElasticsearchQuery interface definition
Removes check for context === 'explore'

* Elasticsearch: Removes context property from ElasticsearchQuery interface
Adds field property
Removes metricAggs property
Adds typing to metrics property

* Elasticsearch: Runs default 'empty' query when 'clear all' button is pressed

* Elasticsearch: Removes index property from ElasticsearchOptions interface

* Elasticsearch: Removes commented code from ElasticsearchQueryField.tsx

* Elasticsearch: Adds comment warning usage of for...in to elastic_response.ts

* Elasticsearch: adds tests related to log queries
This commit is contained in:
Marcus Efraimsson
2019-06-24 22:15:03 +02:00
committed by kay delaney
parent 2fb45eeec8
commit eecd8d1064
17 changed files with 617 additions and 64 deletions

View File

@@ -1,6 +1,8 @@
import _ from 'lodash';
import flatten from 'app/core/utils/flatten';
import * as queryDef from './query_def';
import TableModel from 'app/core/table_model';
import { SeriesData, DataQueryResponse, toSeriesData, FieldType } from '@grafana/ui';
export class ElasticResponse {
constructor(private targets, private response) {
@@ -410,4 +412,142 @@ export class ElasticResponse {
return { data: seriesList };
}
getLogs(logMessageField?: string, logLevelField?: string): DataQueryResponse {
const seriesData: SeriesData[] = [];
const docs: any[] = [];
for (let n = 0; n < this.response.responses.length; n++) {
const response = this.response.responses[n];
if (response.error) {
throw this.getErrorFromElasticResponse(this.response, response.error);
}
const hits = response.hits;
let propNames: string[] = [];
let propName, hit, doc, i;
for (i = 0; i < hits.hits.length; i++) {
hit = hits.hits[i];
const flattened = hit._source ? flatten(hit._source, null) : {};
doc = {};
doc[this.targets[0].timeField] = null;
doc = {
...doc,
_id: hit._id,
_type: hit._type,
_index: hit._index,
...flattened,
};
// Note: the order of for...in is arbitrary amd implementation dependant
// and should probably not be relied upon.
for (propName in hit.fields) {
if (propNames.indexOf(propName) === -1) {
propNames.push(propName);
}
doc[propName] = hit.fields[propName];
}
for (propName in doc) {
if (propNames.indexOf(propName) === -1) {
propNames.push(propName);
}
}
doc._source = { ...flattened };
docs.push(doc);
}
if (docs.length > 0) {
propNames = propNames.sort();
const series: SeriesData = {
fields: [
{
name: this.targets[0].timeField,
type: FieldType.time,
},
],
rows: [],
};
if (logMessageField) {
series.fields.push({
name: logMessageField,
type: FieldType.string,
});
} else {
series.fields.push({
name: '_source',
type: FieldType.string,
});
}
if (logLevelField) {
series.fields.push({
name: 'level',
type: FieldType.string,
});
}
for (const propName of propNames) {
if (propName === this.targets[0].timeField || propName === '_source') {
continue;
}
series.fields.push({
name: propName,
type: FieldType.string,
});
}
for (const doc of docs) {
const row: any[] = [];
row.push(doc[this.targets[0].timeField][0]);
if (logMessageField) {
row.push(doc[logMessageField] || '');
} else {
row.push(JSON.stringify(doc._source, null, 2));
}
if (logLevelField) {
row.push(doc[logLevelField] || '');
}
for (const propName of propNames) {
if (doc.hasOwnProperty(propName)) {
row.push(doc[propName]);
} else {
row.push(null);
}
}
series.rows.push(row);
}
seriesData.push(series);
}
if (response.aggregations) {
const aggregations = response.aggregations;
const target = this.targets[n];
const tmpSeriesList = [];
const table = new TableModel();
this.processBuckets(aggregations, target, tmpSeriesList, table, {}, 0);
this.trimDatapoints(tmpSeriesList, target);
this.nameSeries(tmpSeriesList, target);
for (let y = 0; y < tmpSeriesList.length; y++) {
const series = toSeriesData(tmpSeriesList[y]);
series.labels = {};
seriesData.push(series);
}
}
}
return { data: seriesData };
}
}