mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Elasticsearch: remove usages of any (#69575)
* Elasticsearch: remove usages of any
* Elasticsearch: check for filter type when accessing field aggs
* Elasticsearch: use type guards instead of checking types
* Use unknown for isPrimitive function
* Add deprecation notice
* Remove unused type
* Fix bug in "isPrimitive" function
* Remove unused import
* Revert "Fix bug in "isPrimitive" function"
This reverts commit 27f9874cce
.
This commit is contained in:
parent
cb7e18938b
commit
a75752b085
@ -3877,23 +3877,7 @@ exports[`better eslint`] = {
|
|||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "3"],
|
[0, 0, 0, "Unexpected any. Specify a different type.", "3"],
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "4"],
|
[0, 0, 0, "Unexpected any. Specify a different type.", "4"],
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "5"],
|
[0, 0, 0, "Unexpected any. Specify a different type.", "5"],
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "6"],
|
[0, 0, 0, "Unexpected any. Specify a different type.", "6"]
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "7"],
|
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "8"],
|
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "9"],
|
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "10"],
|
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "11"],
|
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "12"],
|
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "13"],
|
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "14"],
|
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "15"],
|
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "16"],
|
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "17"],
|
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "18"],
|
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "19"],
|
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "20"],
|
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "21"],
|
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "22"]
|
|
||||||
],
|
],
|
||||||
"public/app/plugins/datasource/elasticsearch/hooks/useStatelessReducer.ts:5381": [
|
"public/app/plugins/datasource/elasticsearch/hooks/useStatelessReducer.ts:5381": [
|
||||||
[0, 0, 0, "Do not use any type assertions.", "0"]
|
[0, 0, 0, "Do not use any type assertions.", "0"]
|
||||||
|
@ -51,6 +51,7 @@ import {
|
|||||||
isPipelineAggregationWithMultipleBucketPaths,
|
isPipelineAggregationWithMultipleBucketPaths,
|
||||||
} from './components/QueryEditor/MetricAggregationsEditor/aggregations';
|
} from './components/QueryEditor/MetricAggregationsEditor/aggregations';
|
||||||
import { metricAggregationConfig } from './components/QueryEditor/MetricAggregationsEditor/utils';
|
import { metricAggregationConfig } from './components/QueryEditor/MetricAggregationsEditor/utils';
|
||||||
|
import { isMetricAggregationWithMeta } from './guards';
|
||||||
import { trackAnnotationQuery, trackQuery } from './tracking';
|
import { trackAnnotationQuery, trackQuery } from './tracking';
|
||||||
import {
|
import {
|
||||||
Logs,
|
Logs,
|
||||||
@ -60,6 +61,8 @@ import {
|
|||||||
ElasticsearchQuery,
|
ElasticsearchQuery,
|
||||||
TermsQuery,
|
TermsQuery,
|
||||||
Interval,
|
Interval,
|
||||||
|
ElasticsearchAnnotationQuery,
|
||||||
|
RangeMap,
|
||||||
} from './types';
|
} from './types';
|
||||||
import { getScriptValue, isSupportedVersion, unsupportedVersionMessage } from './utils';
|
import { getScriptValue, isSupportedVersion, unsupportedVersionMessage } from './utils';
|
||||||
|
|
||||||
@ -233,17 +236,7 @@ export class ElasticDatasource
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private prepareAnnotationRequest(options: {
|
private prepareAnnotationRequest(options: { annotation: ElasticsearchAnnotationQuery; range: TimeRange }) {
|
||||||
annotation: {
|
|
||||||
target: ElasticsearchQuery;
|
|
||||||
timeField?: string;
|
|
||||||
timeEndField?: string;
|
|
||||||
titleField?: string;
|
|
||||||
query?: string;
|
|
||||||
index?: string;
|
|
||||||
};
|
|
||||||
range: TimeRange;
|
|
||||||
}) {
|
|
||||||
const annotation = options.annotation;
|
const annotation = options.annotation;
|
||||||
const timeField = annotation.timeField || '@timestamp';
|
const timeField = annotation.timeField || '@timestamp';
|
||||||
const timeEndField = annotation.timeEndField || null;
|
const timeEndField = annotation.timeEndField || null;
|
||||||
@ -260,7 +253,7 @@ export class ElasticDatasource
|
|||||||
const queryString = annotation.query ?? annotation.target?.query ?? '';
|
const queryString = annotation.query ?? annotation.target?.query ?? '';
|
||||||
|
|
||||||
const dateRanges = [];
|
const dateRanges = [];
|
||||||
const rangeStart: any = {};
|
const rangeStart: RangeMap = {};
|
||||||
rangeStart[timeField] = {
|
rangeStart[timeField] = {
|
||||||
from: options.range.from.valueOf(),
|
from: options.range.from.valueOf(),
|
||||||
to: options.range.to.valueOf(),
|
to: options.range.to.valueOf(),
|
||||||
@ -269,7 +262,7 @@ export class ElasticDatasource
|
|||||||
dateRanges.push({ range: rangeStart });
|
dateRanges.push({ range: rangeStart });
|
||||||
|
|
||||||
if (timeEndField) {
|
if (timeEndField) {
|
||||||
const rangeEnd: any = {};
|
const rangeEnd: RangeMap = {};
|
||||||
rangeEnd[timeEndField] = {
|
rangeEnd[timeEndField] = {
|
||||||
from: options.range.from.valueOf(),
|
from: options.range.from.valueOf(),
|
||||||
to: options.range.to.valueOf(),
|
to: options.range.to.valueOf(),
|
||||||
@ -279,7 +272,9 @@ export class ElasticDatasource
|
|||||||
}
|
}
|
||||||
|
|
||||||
const queryInterpolated = this.interpolateLuceneQuery(queryString);
|
const queryInterpolated = this.interpolateLuceneQuery(queryString);
|
||||||
const query: any = {
|
const query: {
|
||||||
|
bool: { filter: Array<Record<string, Record<string, string | number | Array<{ range: RangeMap }>>>> };
|
||||||
|
} = {
|
||||||
bool: {
|
bool: {
|
||||||
filter: [
|
filter: [
|
||||||
{
|
{
|
||||||
@ -299,12 +294,12 @@ export class ElasticDatasource
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const data: any = {
|
const data = {
|
||||||
query,
|
query,
|
||||||
size: 10000,
|
size: 10000,
|
||||||
};
|
};
|
||||||
|
|
||||||
const header: any = {
|
const header: Record<string, string | string[] | boolean> = {
|
||||||
search_type: 'query_then_fetch',
|
search_type: 'query_then_fetch',
|
||||||
ignore_unavailable: true,
|
ignore_unavailable: true,
|
||||||
};
|
};
|
||||||
@ -322,17 +317,8 @@ export class ElasticDatasource
|
|||||||
}
|
}
|
||||||
|
|
||||||
private processHitsToAnnotationEvents(
|
private processHitsToAnnotationEvents(
|
||||||
annotation: {
|
annotation: ElasticsearchAnnotationQuery,
|
||||||
target: ElasticsearchQuery;
|
hits: Array<Record<string, string | number | Record<string | number, string | number>>>
|
||||||
timeField?: string;
|
|
||||||
titleField?: string;
|
|
||||||
timeEndField?: string;
|
|
||||||
query?: string;
|
|
||||||
tagsField?: string;
|
|
||||||
textField?: string;
|
|
||||||
index?: string;
|
|
||||||
},
|
|
||||||
hits: Array<{ [key: string]: any }>
|
|
||||||
) {
|
) {
|
||||||
const timeField = annotation.timeField || '@timestamp';
|
const timeField = annotation.timeField || '@timestamp';
|
||||||
const timeEndField = annotation.timeEndField || null;
|
const timeEndField = annotation.timeEndField || null;
|
||||||
@ -340,7 +326,7 @@ export class ElasticDatasource
|
|||||||
const tagsField = annotation.tagsField || null;
|
const tagsField = annotation.tagsField || null;
|
||||||
const list: AnnotationEvent[] = [];
|
const list: AnnotationEvent[] = [];
|
||||||
|
|
||||||
const getFieldFromSource = (source: any, fieldName: any) => {
|
const getFieldFromSource = (source: any, fieldName: string | null) => {
|
||||||
if (!fieldName) {
|
if (!fieldName) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -363,7 +349,7 @@ export class ElasticDatasource
|
|||||||
let time = getFieldFromSource(source, timeField);
|
let time = getFieldFromSource(source, timeField);
|
||||||
if (typeof hits[i].fields !== 'undefined') {
|
if (typeof hits[i].fields !== 'undefined') {
|
||||||
const fields = hits[i].fields;
|
const fields = hits[i].fields;
|
||||||
if (isString(fields[timeField]) || isNumber(fields[timeField])) {
|
if (typeof fields === 'object' && (isString(fields[timeField]) || isNumber(fields[timeField]))) {
|
||||||
time = fields[timeField];
|
time = fields[timeField];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -419,7 +405,7 @@ export class ElasticDatasource
|
|||||||
return lastValueFrom(
|
return lastValueFrom(
|
||||||
this.getFields(['date']).pipe(
|
this.getFields(['date']).pipe(
|
||||||
mergeMap((dateFields) => {
|
mergeMap((dateFields) => {
|
||||||
const timeField: any = find(dateFields, { text: this.timeField });
|
const timeField = find(dateFields, { text: this.timeField });
|
||||||
if (!timeField) {
|
if (!timeField) {
|
||||||
return of({
|
return of({
|
||||||
status: 'error',
|
status: 'error',
|
||||||
@ -437,8 +423,8 @@ export class ElasticDatasource
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getQueryHeader(searchType: any, timeFrom?: DateTime, timeTo?: DateTime): string {
|
getQueryHeader(searchType: string, timeFrom?: DateTime, timeTo?: DateTime): string {
|
||||||
const queryHeader: any = {
|
const queryHeader = {
|
||||||
search_type: searchType,
|
search_type: searchType,
|
||||||
ignore_unavailable: true,
|
ignore_unavailable: true,
|
||||||
index: this.indexPattern.getIndexList(timeFrom, timeTo),
|
index: this.indexPattern.getIndexList(timeFrom, timeTo),
|
||||||
@ -680,8 +666,8 @@ export class ElasticDatasource
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Store subfield names: [system, process, cpu, total] -> system.process.cpu.total
|
// Store subfield names: [system, process, cpu, total] -> system.process.cpu.total
|
||||||
const fieldNameParts: any = [];
|
const fieldNameParts: string[] = [];
|
||||||
const fields: any = {};
|
const fields: Record<string, { text: string; type: string }> = {};
|
||||||
|
|
||||||
function getFieldsRecursively(obj: any) {
|
function getFieldsRecursively(obj: any) {
|
||||||
for (const key in obj) {
|
for (const key in obj) {
|
||||||
@ -778,7 +764,7 @@ export class ElasticDatasource
|
|||||||
return ('_msearch?' + searchParams.toString()).replace(/\?$/, '');
|
return ('_msearch?' + searchParams.toString()).replace(/\?$/, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
metricFindQuery(query: string, options?: any): Promise<MetricFindValue[]> {
|
metricFindQuery(query: string, options?: { range: TimeRange }): Promise<MetricFindValue[]> {
|
||||||
const range = options?.range;
|
const range = options?.range;
|
||||||
const parsedQuery = JSON.parse(query);
|
const parsedQuery = JSON.parse(query);
|
||||||
if (query) {
|
if (query) {
|
||||||
@ -801,36 +787,48 @@ export class ElasticDatasource
|
|||||||
return lastValueFrom(this.getFields());
|
return lastValueFrom(this.getFields());
|
||||||
}
|
}
|
||||||
|
|
||||||
getTagValues(options: any) {
|
getTagValues(options: { key: string }) {
|
||||||
const range = this.timeSrv.timeRange();
|
const range = this.timeSrv.timeRange();
|
||||||
return lastValueFrom(this.getTerms({ field: options.key }, range));
|
return lastValueFrom(this.getTerms({ field: options.key }, range));
|
||||||
}
|
}
|
||||||
|
|
||||||
targetContainsTemplate(target: any) {
|
targetContainsTemplate(target: ElasticsearchQuery) {
|
||||||
if (this.templateSrv.containsTemplate(target.query) || this.templateSrv.containsTemplate(target.alias)) {
|
if (this.templateSrv.containsTemplate(target.query) || this.templateSrv.containsTemplate(target.alias)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (target.bucketAggs) {
|
||||||
for (const bucketAgg of target.bucketAggs) {
|
for (const bucketAgg of target.bucketAggs) {
|
||||||
if (this.templateSrv.containsTemplate(bucketAgg.field) || this.objectContainsTemplate(bucketAgg.settings)) {
|
if (isBucketAggregationWithField(bucketAgg) && this.templateSrv.containsTemplate(bucketAgg.field)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (this.objectContainsTemplate(bucketAgg.settings)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (target.metrics) {
|
||||||
for (const metric of target.metrics) {
|
for (const metric of target.metrics) {
|
||||||
if (
|
if (!isMetricAggregationWithField(metric)) {
|
||||||
this.templateSrv.containsTemplate(metric.field) ||
|
continue;
|
||||||
this.objectContainsTemplate(metric.settings) ||
|
}
|
||||||
this.objectContainsTemplate(metric.meta)
|
if (metric.field && this.templateSrv.containsTemplate(metric.field)) {
|
||||||
) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (metric.settings && this.objectContainsTemplate(metric.settings)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (isMetricAggregationWithMeta(metric) && this.objectContainsTemplate(metric.meta)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private isPrimitive(obj: any) {
|
private isPrimitive(obj: unknown) {
|
||||||
if (obj === null || obj === undefined) {
|
if (obj === null || obj === undefined) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
23
public/app/plugins/datasource/elasticsearch/guards.test.ts
Normal file
23
public/app/plugins/datasource/elasticsearch/guards.test.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { Count, ExtendedStats } from './dataquery.gen';
|
||||||
|
import { isMetricAggregationWithMeta } from './guards';
|
||||||
|
|
||||||
|
describe('Type guards', () => {
|
||||||
|
test('Identifies metrics with meta attribute', () => {
|
||||||
|
const metric: ExtendedStats = {
|
||||||
|
id: 'test',
|
||||||
|
type: 'extended_stats',
|
||||||
|
meta: {
|
||||||
|
test: 'test',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
expect(isMetricAggregationWithMeta(metric)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Identifies metrics without meta attribute', () => {
|
||||||
|
const metric: Count = {
|
||||||
|
id: 'test',
|
||||||
|
type: 'count',
|
||||||
|
};
|
||||||
|
expect(isMetricAggregationWithMeta(metric)).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
8
public/app/plugins/datasource/elasticsearch/guards.ts
Normal file
8
public/app/plugins/datasource/elasticsearch/guards.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { ExtendedStats, MetricAggregation } from './dataquery.gen';
|
||||||
|
|
||||||
|
export function isMetricAggregationWithMeta(metric: MetricAggregation): metric is ExtendedStats {
|
||||||
|
if (!metric || typeof metric !== 'object') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return 'meta' in metric;
|
||||||
|
}
|
@ -4,7 +4,7 @@ import { variableRegex } from 'app/features/variables/utils';
|
|||||||
|
|
||||||
import { REF_ID_STARTER_LOG_VOLUME } from './datasource';
|
import { REF_ID_STARTER_LOG_VOLUME } from './datasource';
|
||||||
import pluginJson from './plugin.json';
|
import pluginJson from './plugin.json';
|
||||||
import { ElasticsearchQuery } from './types';
|
import { ElasticsearchAnnotationQuery, ElasticsearchQuery } from './types';
|
||||||
|
|
||||||
type ElasticSearchOnDashboardLoadedTrackingEvent = {
|
type ElasticSearchOnDashboardLoadedTrackingEvent = {
|
||||||
grafana_version?: string;
|
grafana_version?: string;
|
||||||
@ -141,16 +141,7 @@ export function trackQuery(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function trackAnnotationQuery(annotation: {
|
export function trackAnnotationQuery(annotation: ElasticsearchAnnotationQuery): void {
|
||||||
target: ElasticsearchQuery;
|
|
||||||
timeField?: string;
|
|
||||||
timeEndField?: string;
|
|
||||||
query?: string;
|
|
||||||
tagsField?: string;
|
|
||||||
textField?: string;
|
|
||||||
index?: string;
|
|
||||||
[key: string]: unknown;
|
|
||||||
}): void {
|
|
||||||
reportInteraction('grafana_elasticsearch_annotation_query_executed', {
|
reportInteraction('grafana_elasticsearch_annotation_query_executed', {
|
||||||
grafana_version: config.buildInfo.version,
|
grafana_version: config.buildInfo.version,
|
||||||
has_target_query: !!annotation.target?.query,
|
has_target_query: !!annotation.target?.query,
|
||||||
|
@ -14,6 +14,7 @@ import {
|
|||||||
MovingAverage as SchemaMovingAverage,
|
MovingAverage as SchemaMovingAverage,
|
||||||
BucketAggregation,
|
BucketAggregation,
|
||||||
Logs as SchemaLogs,
|
Logs as SchemaLogs,
|
||||||
|
Elasticsearch,
|
||||||
} from './dataquery.gen';
|
} from './dataquery.gen';
|
||||||
|
|
||||||
export * from './dataquery.gen';
|
export * from './dataquery.gen';
|
||||||
@ -121,3 +122,17 @@ export type DataLinkConfig = {
|
|||||||
urlDisplayLabel?: string;
|
urlDisplayLabel?: string;
|
||||||
datasourceUid?: string;
|
datasourceUid?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export interface ElasticsearchAnnotationQuery {
|
||||||
|
target: Elasticsearch;
|
||||||
|
timeField?: string;
|
||||||
|
titleField?: string;
|
||||||
|
timeEndField?: string;
|
||||||
|
query?: string;
|
||||||
|
tagsField?: string;
|
||||||
|
textField?: string;
|
||||||
|
// @deprecated index is deprecated and will be removed in the future
|
||||||
|
index?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type RangeMap = Record<string, { from: number; to: number; format: string }>;
|
||||||
|
Loading…
Reference in New Issue
Block a user