Skip to content

Commit

Permalink
[Metrics UI] Add endpoint for Metrics API (#81693) (#82095)
Browse files Browse the repository at this point in the history
* [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 <[email protected]>

Co-authored-by: Kibana Machine <[email protected]>
  • Loading branch information
simianhacker and kibanamachine authored Oct 30, 2020
1 parent fa253a1 commit 71234d2
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 2 deletions.
1 change: 1 addition & 0 deletions x-pack/plugins/infra/common/http_api/metrics_api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
2 changes: 2 additions & 0 deletions x-pack/plugins/infra/server/infra_server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -74,6 +75,7 @@ export const initInfraServer = (libs: InfraBackendLibs) => {
initLogEntriesSummaryHighlightsRoute(libs);
initLogEntriesItemRoute(libs);
initMetricExplorerRoute(libs);
initMetricsAPIRoute(libs);
initMetadataRoute(libs);
initInventoryMetaRoute(libs);
initLogSourceConfigurationRoutes(libs);
Expand Down
14 changes: 12 additions & 2 deletions x-pack/plugins/infra/server/lib/metrics/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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>> = [
{
Expand All @@ -35,6 +44,7 @@ export const query = async (
},
...(options.groupBy?.map((field) => ({ exists: { field } })) ?? []),
];

const params = {
allowNoIndices: true,
ignoreUnavailable: true,
Expand Down Expand Up @@ -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;
Expand Down
34 changes: 34 additions & 0 deletions x-pack/plugins/infra/server/lib/metrics/lib/calculate_interval.ts
Original file line number Diff line number Diff line change
@@ -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 changes: 50 additions & 0 deletions x-pack/plugins/infra/server/routes/metrics_api/index.ts
Original file line number Diff line number Diff line change
@@ -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,
});
}
}
);
};

0 comments on commit 71234d2

Please sign in to comment.