[Metrics UI] Add endpoint for Metrics API (#81693)
* [Metrics UI] Add endpoint for Metrics API * Adding the ability to caculate the interval based on a module * fixing types Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
2a38461817
commit
eedf0673d3
|
@ -30,6 +30,7 @@ export const MetricsAPIRequestRT = rt.intersection([
|
|||
}),
|
||||
rt.partial({
|
||||
groupBy: rt.array(groupByRT),
|
||||
modules: rt.array(rt.string),
|
||||
afterKey: rt.union([rt.null, afterKeyObjectRT]),
|
||||
limit: rt.union([rt.number, rt.null, rt.undefined]),
|
||||
filters: rt.array(rt.object),
|
||||
|
|
|
@ -25,6 +25,7 @@ import {
|
|||
import { initGetK8sAnomaliesRoute } from './routes/infra_ml';
|
||||
import { initGetHostsAnomaliesRoute } from './routes/infra_ml';
|
||||
import { initMetricExplorerRoute } from './routes/metrics_explorer';
|
||||
import { initMetricsAPIRoute } from './routes/metrics_api';
|
||||
import { initMetadataRoute } from './routes/metadata';
|
||||
import { initSnapshotRoute } from './routes/snapshot';
|
||||
import { initNodeDetailsRoute } from './routes/node_details';
|
||||
|
@ -74,6 +75,7 @@ export const initInfraServer = (libs: InfraBackendLibs) => {
|
|||
initLogEntriesSummaryHighlightsRoute(libs);
|
||||
initLogEntriesItemRoute(libs);
|
||||
initMetricExplorerRoute(libs);
|
||||
initMetricsAPIRoute(libs);
|
||||
initMetadataRoute(libs);
|
||||
initInventoryMetaRoute(libs);
|
||||
initLogSourceConfigurationRoutes(libs);
|
||||
|
|
|
@ -17,11 +17,20 @@ import { EMPTY_RESPONSE } from './constants';
|
|||
import { createAggregations } from './lib/create_aggregations';
|
||||
import { convertHistogramBucketsToTimeseries } from './lib/convert_histogram_buckets_to_timeseries';
|
||||
import { calculateBucketSize } from './lib/calculate_bucket_size';
|
||||
import { calculatedInterval } from './lib/calculate_interval';
|
||||
|
||||
export const query = async (
|
||||
search: ESSearchClient,
|
||||
options: MetricsAPIRequest
|
||||
rawOptions: MetricsAPIRequest
|
||||
): Promise<MetricsAPIResponse> => {
|
||||
const interval = await calculatedInterval(search, rawOptions);
|
||||
const options = {
|
||||
...rawOptions,
|
||||
timerange: {
|
||||
...rawOptions.timerange,
|
||||
interval,
|
||||
},
|
||||
};
|
||||
const hasGroupBy = Array.isArray(options.groupBy) && options.groupBy.length > 0;
|
||||
const filter: Array<Record<string, any>> = [
|
||||
{
|
||||
|
@ -35,6 +44,7 @@ export const query = async (
|
|||
},
|
||||
...(options.groupBy?.map((field) => ({ exists: { field } })) ?? []),
|
||||
];
|
||||
|
||||
const params = {
|
||||
allowNoIndices: true,
|
||||
ignoreUnavailable: true,
|
||||
|
@ -70,7 +80,7 @@ export const query = async (
|
|||
throw new Error('Aggregations should be present.');
|
||||
}
|
||||
|
||||
const { bucketSize } = calculateBucketSize(options.timerange);
|
||||
const { bucketSize } = calculateBucketSize({ ...options.timerange, interval });
|
||||
|
||||
if (hasGroupBy && GroupingResponseRT.is(response.aggregations)) {
|
||||
const { groupings } = response.aggregations;
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { isArray, isNumber } from 'lodash';
|
||||
import { MetricsAPIRequest } from '../../../../common/http_api';
|
||||
import { ESSearchClient } from '../types';
|
||||
import { calculateMetricInterval } from '../../../utils/calculate_metric_interval';
|
||||
|
||||
export const calculatedInterval = async (search: ESSearchClient, options: MetricsAPIRequest) => {
|
||||
const useModuleInterval =
|
||||
options.timerange.interval === 'modules' &&
|
||||
isArray(options.modules) &&
|
||||
options.modules.length > 0;
|
||||
|
||||
const calcualatedInterval = useModuleInterval
|
||||
? await calculateMetricInterval(
|
||||
search,
|
||||
{
|
||||
indexPattern: options.indexPattern,
|
||||
timestampField: options.timerange.field,
|
||||
timerange: { from: options.timerange.from, to: options.timerange.to },
|
||||
},
|
||||
options.modules
|
||||
)
|
||||
: false;
|
||||
|
||||
const defaultInterval =
|
||||
options.timerange.interval === 'modules' ? 'auto' : options.timerange.interval;
|
||||
|
||||
return isNumber(calcualatedInterval) ? `>=${calcualatedInterval}s` : defaultInterval;
|
||||
};
|
50
x-pack/plugins/infra/server/routes/metrics_api/index.ts
Normal file
50
x-pack/plugins/infra/server/routes/metrics_api/index.ts
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import Boom from 'boom';
|
||||
import { pipe } from 'fp-ts/lib/pipeable';
|
||||
import { fold } from 'fp-ts/lib/Either';
|
||||
import { identity } from 'fp-ts/lib/function';
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import { InfraBackendLibs } from '../../lib/infra_types';
|
||||
import { throwErrors } from '../../../common/runtime_types';
|
||||
import { createSearchClient } from '../../lib/create_search_client';
|
||||
import { query } from '../../lib/metrics';
|
||||
import { MetricsAPIRequestRT, MetricsAPIResponseRT } from '../../../common/http_api';
|
||||
|
||||
const escapeHatch = schema.object({}, { unknowns: 'allow' });
|
||||
|
||||
export const initMetricsAPIRoute = (libs: InfraBackendLibs) => {
|
||||
const { framework } = libs;
|
||||
framework.registerRoute(
|
||||
{
|
||||
method: 'post',
|
||||
path: '/api/infra/metrics_api',
|
||||
validate: {
|
||||
body: escapeHatch,
|
||||
},
|
||||
},
|
||||
async (requestContext, request, response) => {
|
||||
try {
|
||||
const options = pipe(
|
||||
MetricsAPIRequestRT.decode(request.body),
|
||||
fold(throwErrors(Boom.badRequest), identity)
|
||||
);
|
||||
|
||||
const client = createSearchClient(requestContext, framework);
|
||||
const metricsApiResponse = await query(client, options);
|
||||
|
||||
return response.ok({
|
||||
body: MetricsAPIResponseRT.encode(metricsApiResponse),
|
||||
});
|
||||
} catch (error) {
|
||||
return response.internalError({
|
||||
body: error.message,
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
Loading…
Reference in a new issue