mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
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:
committed by
kay delaney
parent
2fb45eeec8
commit
eecd8d1064
@@ -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 };
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user