[Logs UI] Versioning for Logs related APIs (#158710)

## 📓  Summary

Closes #157324 
Closes #159275 
Closes #159303 

This work converts the APIs related to the Logs UI feature into
versioned APIs using the new [Kibana versioned
router](https://docs.elastic.dev/kibana-dev-docs/versioning-http-apis#4-adhere-to-the-http-versioning-specification).

The converted APIs are the following, where each endpoint now is set to
version `1`:
-
[log_views](https://github.com/elastic/kibana/tree/main/x-pack/plugins/infra/server/routes/log_views)
-
[log_entries](https://github.com/elastic/kibana/tree/main/x-pack/plugins/infra/server/routes/log_entries)
-
[log_analysis](https://github.com/elastic/kibana/tree/main/x-pack/plugins/infra/server/routes/log_analysis)
-
[log_alerts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/infra/server/routes/log_alerts)

The PR also includes moving the interfaces and runtime types relatives
to each endpoint's group into the recommended practices for [versioning
interfaces](https://docs.elastic.dev/kibana-dev-docs/versioning-interfaces).

## 🧪 Testing

- Navigate to the Logs UI settings page and verify the log view is
correctly retrieved and can be successfully updated.
- Navigate to the Logs stream page and verify the stream entries are
retrieved and rendered.
- Navigate to the Anomalies and Categories pages page and verify the
anomalies entries are retrieved and rendered correctly.
- Create a Log threshold alert and verify the chart preview data are
correctly retrieved and shown.

---------

Co-authored-by: Marco Antonio Ghiani <marcoantonio.ghiani@elastic.co>
Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Marco Antonio Ghiani 2023-06-08 15:43:46 +02:00 committed by GitHub
parent 4f6784339f
commit e3fddf38f7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
70 changed files with 1003 additions and 860 deletions

View file

@ -5,12 +5,9 @@
* 2.0.
*/
export * from './log_analysis';
export * from './metadata_api';
export * from './log_entries';
export * from './metrics_explorer';
export * from './metrics_api';
export * from './log_alerts';
export * from './snapshot_api';
export * from './host_details';
export * from './infra';
@ -20,4 +17,9 @@ export * from './infra';
*/
export * from './latest';
export * as inventoryViewsV1 from './inventory_views/v1';
export * as logAlertsV1 from './log_alerts/v1';
export * as logAnalysisResultsV1 from './log_analysis/results/v1';
export * as logAnalysisValidationV1 from './log_analysis/validation/v1';
export * as logEntriesV1 from './log_entries/v1';
export * as logViewsV1 from './log_views/v1';
export * as metricsExplorerViewsV1 from './metrics_explorer_views/v1';

View file

@ -6,4 +6,9 @@
*/
export * from './inventory_views/v1';
export * from './log_alerts/v1';
export * from './log_analysis/results/v1';
export * from './log_analysis/validation/v1';
export * from './log_entries/v1';
export * from './log_views/v1';
export * from './metrics_explorer_views/v1';

View file

@ -12,8 +12,8 @@ import {
timeUnitRT,
timeSizeRT,
groupByRT,
} from '../../alerting/logs/log_threshold/types';
import { persistedLogViewReferenceRT } from '../../log_views';
} from '../../../alerting/logs/log_threshold/types';
import { persistedLogViewReferenceRT } from '../../../log_views';
export const LOG_ALERTS_CHART_PREVIEW_DATA_PATH = '/api/infra/log_alerts/chart_preview_data';

View file

@ -7,15 +7,15 @@
import * as rt from 'io-ts';
import { persistedLogViewReferenceRT } from '../../../log_views';
import { timeRangeRT, routeTimingMetadataRT } from '../../shared';
import { persistedLogViewReferenceRT } from '../../../../log_views';
import { timeRangeRT, routeTimingMetadataRT } from '../../../shared';
import {
logEntryAnomalyRT,
logEntryAnomalyDatasetsRT,
anomaliesSortRT,
paginationRT,
paginationCursorRT,
} from '../../../log_analysis';
} from '../../../../log_analysis';
export const LOG_ANALYSIS_GET_LOG_ENTRY_ANOMALIES_PATH =
'/api/infra/log_analysis/results/log_entry_anomalies';

View file

@ -6,14 +6,14 @@
*/
import * as rt from 'io-ts';
import { persistedLogViewReferenceRT } from '../../../log_views';
import { persistedLogViewReferenceRT } from '../../../../log_views';
import {
badRequestErrorRT,
forbiddenErrorRT,
timeRangeRT,
routeTimingMetadataRT,
} from '../../shared';
} from '../../../shared';
export const LOG_ANALYSIS_GET_LOG_ENTRY_ANOMALIES_DATASETS_PATH =
'/api/infra/log_analysis/results/log_entry_anomalies_datasets';

View file

@ -7,15 +7,15 @@
import * as rt from 'io-ts';
import { persistedLogViewReferenceRT } from '../../../log_views';
import { persistedLogViewReferenceRT } from '../../../../log_views';
import {
badRequestErrorRT,
forbiddenErrorRT,
timeRangeRT,
routeTimingMetadataRT,
} from '../../shared';
} from '../../../shared';
import { logEntryCategoryRT, categoriesSortRT } from '../../../log_analysis';
import { logEntryCategoryRT, categoriesSortRT } from '../../../../log_analysis';
export const LOG_ANALYSIS_GET_LOG_ENTRY_CATEGORIES_PATH =
'/api/infra/log_analysis/results/log_entry_categories';

View file

@ -12,8 +12,8 @@ import {
forbiddenErrorRT,
timeRangeRT,
routeTimingMetadataRT,
} from '../../shared';
import { persistedLogViewReferenceRT } from '../../../log_views';
} from '../../../shared';
import { persistedLogViewReferenceRT } from '../../../../log_views';
export const LOG_ANALYSIS_GET_LOG_ENTRY_CATEGORY_DATASETS_PATH =
'/api/infra/log_analysis/results/log_entry_category_datasets';

View file

@ -7,7 +7,7 @@
import * as rt from 'io-ts';
import { timeRangeRT, routeTimingMetadataRT } from '../../shared';
import { timeRangeRT, routeTimingMetadataRT } from '../../../shared';
export const LOG_ANALYSIS_GET_LATEST_LOG_ENTRY_CATEGORY_DATASETS_STATS_PATH =
'/api/infra/log_analysis/results/latest_log_entry_category_datasets_stats';

View file

@ -7,14 +7,14 @@
import * as rt from 'io-ts';
import { persistedLogViewReferenceRT } from '../../../log_views';
import { persistedLogViewReferenceRT } from '../../../../log_views';
import {
badRequestErrorRT,
forbiddenErrorRT,
timeRangeRT,
routeTimingMetadataRT,
} from '../../shared';
import { logEntryContextRT } from '../../../log_entry';
} from '../../../shared';
import { logEntryContextRT } from '../../../../log_entry';
export const LOG_ANALYSIS_GET_LOG_ENTRY_CATEGORY_EXAMPLES_PATH =
'/api/infra/log_analysis/results/log_entry_category_examples';

View file

@ -6,14 +6,14 @@
*/
import * as rt from 'io-ts';
import { persistedLogViewReferenceRT } from '../../../log_views';
import { logEntryExampleRT } from '../../../log_analysis';
import { persistedLogViewReferenceRT } from '../../../../log_views';
import { logEntryExampleRT } from '../../../../log_analysis';
import {
badRequestErrorRT,
forbiddenErrorRT,
timeRangeRT,
routeTimingMetadataRT,
} from '../../shared';
} from '../../../shared';
export const LOG_ANALYSIS_GET_LOG_ENTRY_RATE_EXAMPLES_PATH =
'/api/infra/log_analysis/results/log_entry_examples';
@ -48,7 +48,7 @@ export type GetLogEntryExamplesRequestPayload = rt.TypeOf<
* response
*/
export const getLogEntryExamplesSuccessReponsePayloadRT = rt.intersection([
export const getLogEntryExamplesSuccessResponsePayloadRT = rt.intersection([
rt.type({
data: rt.type({
examples: rt.array(logEntryExampleRT),
@ -60,11 +60,11 @@ export const getLogEntryExamplesSuccessReponsePayloadRT = rt.intersection([
]);
export type GetLogEntryExamplesSuccessReponsePayload = rt.TypeOf<
typeof getLogEntryExamplesSuccessReponsePayloadRT
typeof getLogEntryExamplesSuccessResponsePayloadRT
>;
export const getLogEntryExamplesResponsePayloadRT = rt.union([
getLogEntryExamplesSuccessReponsePayloadRT,
getLogEntryExamplesSuccessResponsePayloadRT,
badRequestErrorRT,
forbiddenErrorRT,
]);

View file

@ -6,7 +6,7 @@
*/
import * as rt from 'io-ts';
import { mappingRuntimeFieldRT } from '../../shared/es_request';
import { mappingRuntimeFieldRT } from '../../../shared/es_request';
export const LOG_ANALYSIS_VALIDATE_INDICES_PATH =
'/api/infra/log_analysis/validation/log_entry_rate_indices';

View file

@ -6,9 +6,9 @@
*/
import * as rt from 'io-ts';
import { logEntryCursorRT, logEntryRT } from '../../log_entry';
import { logViewColumnConfigurationRT } from '../../log_views';
import { logViewReferenceRT } from '../../log_views';
import { logEntryCursorRT, logEntryRT } from '../../../log_entry';
import { logViewColumnConfigurationRT } from '../../../log_views';
import { logViewReferenceRT } from '../../../log_views';
export const LOG_ENTRIES_HIGHLIGHTS_PATH = '/api/log_entries/highlights';

View file

@ -6,7 +6,7 @@
*/
import * as rt from 'io-ts';
import { logViewReferenceRT } from '../../log_views';
import { logViewReferenceRT } from '../../../log_views';
export const LOG_ENTRIES_SUMMARY_PATH = '/api/log_entries/summary';

View file

@ -6,7 +6,7 @@
*/
import * as rt from 'io-ts';
import { logEntryCursorRT } from '../../log_entry';
import { logEntryCursorRT } from '../../../log_entry';
import { logEntriesSummaryRequestRT, logEntriesSummaryBucketRT } from './summary';
export const LOG_ENTRIES_SUMMARY_HIGHLIGHTS_PATH = '/api/log_entries/summary_highlights';

View file

@ -6,5 +6,3 @@
*/
export { getLogViewUrl, LOG_VIEW_URL } from './common';
export * from './get_log_view';
export * from './put_log_view';

View file

@ -6,13 +6,15 @@
*/
import * as rt from 'io-ts';
import { logViewRT } from '../../log_views';
import { logViewRT } from '../../../log_views';
export const getLogViewRequestParamsRT = rt.type({
// the id of the log view
logViewId: rt.string,
});
export type GetLogViewRequestParams = rt.TypeOf<typeof getLogViewRequestParamsRT>;
export const getLogViewResponsePayloadRT = rt.type({
data: logViewRT,
});

View file

@ -5,5 +5,5 @@
* 2.0.
*/
export * from './results';
export * from './validation';
export * from './get_log_view';
export * from './put_log_view';

View file

@ -6,7 +6,7 @@
*/
import * as rt from 'io-ts';
import { logViewAttributesRT, logViewRT } from '../../log_views';
import { logViewAttributesRT, logViewRT } from '../../../log_views';
export const putLogViewRequestParamsRT = rt.type({
logViewId: rt.string,
@ -15,6 +15,7 @@ export const putLogViewRequestParamsRT = rt.type({
export const putLogViewRequestPayloadRT = rt.type({
attributes: rt.partial(logViewAttributesRT.type.props),
});
export type PutLogViewRequestPayload = rt.TypeOf<typeof putLogViewRequestPayloadRT>;
export const putLogViewResponsePayloadRT = rt.type({

View file

@ -46,7 +46,7 @@ import { Color, colorTransformer } from '../../../../../common/color_palette';
import {
GetLogAlertsChartPreviewDataAlertParamsSubset,
getLogAlertsChartPreviewDataAlertParamsSubsetRT,
} from '../../../../../common/http_api/log_alerts';
} from '../../../../../common/http_api';
import { useChartPreviewData } from './hooks/use_chart_preview_data';
import { decodeOrThrow } from '../../../../../common/runtime_types';
import { useKibanaTimeZoneSetting } from '../../../../hooks/use_kibana_time_zone_setting';

View file

@ -5,21 +5,21 @@
* 2.0.
*/
import { useState, useMemo } from 'react';
import { HttpHandler } from '@kbn/core/public';
import { useKibana } from '@kbn/kibana-react-plugin/public';
import { useMemo, useState } from 'react';
import { isRatioRule } from '../../../../../../common/alerting/logs/log_threshold';
import { PersistedLogViewReference } from '../../../../../../common/log_views';
import { ExecutionTimeRange } from '../../../../../types';
import { useTrackedPromise } from '../../../../../utils/use_tracked_promise';
import {
GetLogAlertsChartPreviewDataAlertParamsSubset,
getLogAlertsChartPreviewDataRequestPayloadRT,
GetLogAlertsChartPreviewDataSuccessResponsePayload,
getLogAlertsChartPreviewDataSuccessResponsePayloadRT,
getLogAlertsChartPreviewDataRequestPayloadRT,
LOG_ALERTS_CHART_PREVIEW_DATA_PATH,
} from '../../../../../../common/http_api';
import { PersistedLogViewReference } from '../../../../../../common/log_views';
import { decodeOrThrow } from '../../../../../../common/runtime_types';
import { GetLogAlertsChartPreviewDataAlertParamsSubset } from '../../../../../../common/http_api/log_alerts';
import { ExecutionTimeRange } from '../../../../../types';
import { useTrackedPromise } from '../../../../../utils/use_tracked_promise';
interface Options {
logViewReference: PersistedLogViewReference;
@ -147,6 +147,7 @@ export const callGetChartPreviewDataAPI = async (
},
})
),
version: '1',
});
return decodeOrThrow(getLogAlertsChartPreviewDataSuccessResponsePayloadRT)(response);

View file

@ -21,7 +21,7 @@ import {
ISearchOptions,
} from '@kbn/data-plugin/public';
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
import { getLogViewResponsePayloadRT } from '../../../common/http_api/log_views';
import { getLogViewResponsePayloadRT } from '../../../common/http_api';
import { defaultLogViewAttributes } from '../../../common/log_views';
import {
LogEntriesSearchResponsePayload,

View file

@ -42,6 +42,7 @@ export const callGetLatestCategoriesDatasetsStatsAPI = async (
},
})
),
version: '1',
});
return decodeOrThrow(getLatestLogEntryCategoryDatasetsStatsSuccessResponsePayloadRT)(response);

View file

@ -37,6 +37,7 @@ export const callValidateDatasetsAPI = async (requestArgs: RequestArgs, fetch: H
},
})
),
version: '1',
});
return decodeOrThrow(validateLogEntryDatasetsResponsePayloadRT)(response);

View file

@ -31,6 +31,7 @@ export const callValidateIndicesAPI = async (requestArgs: RequestArgs, fetch: Ht
// @ts-expect-error TODO: fix after elasticsearch-js bump
validationIndicesRequestPayloadRT.encode({ data: { indices, fields, runtimeMappings } })
),
version: '1',
});
return decodeOrThrow(validationIndicesResponsePayloadRT)(response);

View file

@ -10,7 +10,7 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
import {
ValidateLogEntryDatasetsResponsePayload,
ValidationIndicesResponsePayload,
} from '../../../../common/http_api/log_analysis';
} from '../../../../common/http_api';
import { DatasetFilter } from '../../../../common/log_analysis';
import { DeleteJobsResponsePayload } from './api/ml_cleanup';
import { FetchJobStatusResponsePayload } from './api/ml_get_jobs_summary_api';

View file

@ -23,6 +23,7 @@ export const fetchLogEntriesHighlights = async (
const response = await fetch(LOG_ENTRIES_HIGHLIGHTS_PATH, {
method: 'POST',
body: JSON.stringify(logEntriesHighlightsRequestRT.encode(requestArgs)),
version: '1',
});
return decodeOrThrow(logEntriesHighlightsResponseRT)(response);

View file

@ -22,6 +22,7 @@ export const fetchLogSummaryHighlights = async (
const response = await fetch(LOG_ENTRIES_SUMMARY_HIGHLIGHTS_PATH, {
method: 'POST',
body: JSON.stringify(logEntriesSummaryHighlightsRequestRT.encode(requestArgs)),
version: '1',
});
return decodeOrThrow(logEntriesSummaryHighlightsResponseRT)(response);

View file

@ -22,6 +22,7 @@ export const fetchLogSummary = async (
const response = await fetch(LOG_ENTRIES_SUMMARY_PATH, {
method: 'POST',
body: JSON.stringify(logEntriesSummaryRequestRT.encode(requestArgs)),
version: '1',
});
return decodeOrThrow(logEntriesSummaryResponseRT)(response);

View file

@ -9,7 +9,7 @@ import { HttpHandler } from '@kbn/core/public';
import {
ValidateLogEntryDatasetsResponsePayload,
ValidationIndicesResponsePayload,
} from '../../../common/http_api/log_analysis';
} from '../../../common/http_api';
import { DeleteJobsResponsePayload } from './api/ml_cleanup';
import { FetchJobStatusResponsePayload } from './api/ml_get_jobs_summary_api';
import { GetMlModuleResponsePayload } from './api/ml_get_module';

View file

@ -12,7 +12,7 @@ import {
getLogEntryCategoryDatasetsRequestPayloadRT,
getLogEntryCategoryDatasetsSuccessReponsePayloadRT,
LOG_ANALYSIS_GET_LOG_ENTRY_CATEGORY_DATASETS_PATH,
} from '../../../../../common/http_api/log_analysis';
} from '../../../../../common/http_api';
import { decodeOrThrow } from '../../../../../common/runtime_types';
interface RequestArgs {
@ -40,6 +40,7 @@ export const callGetLogEntryCategoryDatasetsAPI = async (
},
})
),
version: '1',
});
return decodeOrThrow(getLogEntryCategoryDatasetsSuccessReponsePayloadRT)(response);

View file

@ -12,7 +12,7 @@ import {
getLogEntryCategoryExamplesRequestPayloadRT,
getLogEntryCategoryExamplesSuccessReponsePayloadRT,
LOG_ANALYSIS_GET_LOG_ENTRY_CATEGORY_EXAMPLES_PATH,
} from '../../../../../common/http_api/log_analysis';
} from '../../../../../common/http_api';
import { decodeOrThrow } from '../../../../../common/runtime_types';
interface RequestArgs {
@ -44,6 +44,7 @@ export const callGetLogEntryCategoryExamplesAPI = async (
},
})
),
version: '1',
});
return decodeOrThrow(getLogEntryCategoryExamplesSuccessReponsePayloadRT)(response);

View file

@ -12,7 +12,7 @@ import {
getLogEntryCategoriesRequestPayloadRT,
getLogEntryCategoriesSuccessReponsePayloadRT,
LOG_ANALYSIS_GET_LOG_ENTRY_CATEGORIES_PATH,
} from '../../../../../common/http_api/log_analysis';
} from '../../../../../common/http_api';
import { CategoriesSort } from '../../../../../common/log_analysis';
import { decodeOrThrow } from '../../../../../common/runtime_types';
@ -66,6 +66,7 @@ export const callGetTopLogEntryCategoriesAPI = async (
},
})
),
version: '1',
});
return decodeOrThrow(getLogEntryCategoriesSuccessReponsePayloadRT)(response);

View file

@ -11,7 +11,7 @@ import { PersistedLogViewReference } from '../../../../common/log_views';
import {
GetLogEntryCategoriesSuccessResponsePayload,
GetLogEntryCategoryDatasetsSuccessResponsePayload,
} from '../../../../common/http_api/log_analysis';
} from '../../../../common/http_api';
import { CategoriesSort } from '../../../../common/log_analysis';
import { useTrackedPromise, CanceledPromiseError } from '../../../utils/use_tracked_promise';
import { callGetTopLogEntryCategoriesAPI } from './service_calls/get_top_log_entry_categories';

View file

@ -11,7 +11,7 @@ import {
getLogEntryAnomaliesRequestPayloadRT,
getLogEntryAnomaliesSuccessReponsePayloadRT,
LOG_ANALYSIS_GET_LOG_ENTRY_ANOMALIES_PATH,
} from '../../../../../common/http_api/log_analysis';
} from '../../../../../common/http_api';
import { decodeOrThrow } from '../../../../../common/runtime_types';
import { AnomaliesSort, Pagination } from '../../../../../common/log_analysis';
@ -42,6 +42,7 @@ export const callGetLogEntryAnomaliesAPI = async (requestArgs: RequestArgs, fetc
},
})
),
version: '1',
});
return decodeOrThrow(getLogEntryAnomaliesSuccessReponsePayloadRT)(response);

View file

@ -12,7 +12,7 @@ import {
getLogEntryAnomaliesDatasetsRequestPayloadRT,
getLogEntryAnomaliesDatasetsSuccessReponsePayloadRT,
LOG_ANALYSIS_GET_LOG_ENTRY_ANOMALIES_DATASETS_PATH,
} from '../../../../../common/http_api/log_analysis';
} from '../../../../../common/http_api';
interface RequestArgs {
logViewReference: PersistedLogViewReference;
@ -38,6 +38,7 @@ export const callGetLogEntryAnomaliesDatasetsAPI = async (
},
})
),
version: '1',
});
return decodeOrThrow(getLogEntryAnomaliesDatasetsSuccessReponsePayloadRT)(response);

View file

@ -10,9 +10,9 @@ import { PersistedLogViewReference } from '../../../../../common/log_views';
import {
getLogEntryExamplesRequestPayloadRT,
getLogEntryExamplesSuccessReponsePayloadRT,
getLogEntryExamplesSuccessResponsePayloadRT,
LOG_ANALYSIS_GET_LOG_ENTRY_RATE_EXAMPLES_PATH,
} from '../../../../../common/http_api/log_analysis';
} from '../../../../../common/http_api';
import { decodeOrThrow } from '../../../../../common/runtime_types';
interface RequestArgs {
@ -42,7 +42,8 @@ export const callGetLogEntryExamplesAPI = async (requestArgs: RequestArgs, fetch
},
})
),
version: '1',
});
return decodeOrThrow(getLogEntryExamplesSuccessReponsePayloadRT)(response);
return decodeOrThrow(getLogEntryExamplesSuccessResponsePayloadRT)(response);
};

View file

@ -11,7 +11,7 @@ import { PersistedLogViewReference } from '../../../../common/log_views';
import { useTrackedPromise, CanceledPromiseError } from '../../../utils/use_tracked_promise';
import { callGetLogEntryAnomaliesAPI } from './service_calls/get_log_entry_anomalies';
import { callGetLogEntryAnomaliesDatasetsAPI } from './service_calls/get_log_entry_anomalies_datasets';
import { GetLogEntryAnomaliesDatasetsSuccessResponsePayload } from '../../../../common/http_api/log_analysis';
import { GetLogEntryAnomaliesDatasetsSuccessResponsePayload } from '../../../../common/http_api';
import {
AnomaliesSort,
Pagination,

View file

@ -10,11 +10,8 @@ import { HttpStart } from '@kbn/core/public';
import { ISearchGeneric } from '@kbn/data-plugin/public';
import { DataViewsContract } from '@kbn/data-views-plugin/public';
import { lastValueFrom } from 'rxjs';
import {
getLogViewResponsePayloadRT,
getLogViewUrl,
putLogViewRequestPayloadRT,
} from '../../../common/http_api/log_views';
import { getLogViewResponsePayloadRT, putLogViewRequestPayloadRT } from '../../../common/http_api';
import { getLogViewUrl } from '../../../common/http_api/log_views';
import {
FetchLogViewError,
FetchLogViewStatusError,
@ -48,9 +45,11 @@ export class LogViewsClient implements ILogViewsClient {
}
const { logViewId } = logViewReference;
const response = await this.http.get(getLogViewUrl(logViewId)).catch((error) => {
throw new FetchLogViewError(`Failed to fetch log view "${logViewId}": ${error}`);
});
const response = await this.http
.get(getLogViewUrl(logViewId), { version: '1' })
.catch((error) => {
throw new FetchLogViewError(`Failed to fetch log view "${logViewId}": ${error}`);
});
const { data } = decodeOrThrow(
getLogViewResponsePayloadRT,
@ -133,6 +132,7 @@ export class LogViewsClient implements ILogViewsClient {
body: JSON.stringify(
putLogViewRequestPayloadRT.encode({ attributes: logViewAttributes })
),
version: '1',
})
.catch((error) => {
throw new PutLogViewError(`Failed to write log view "${logViewId}": ${error}`);

View file

@ -24,6 +24,7 @@ import { PluginSetupContract as AlertingPluginContract } from '@kbn/alerting-plu
import { MlPluginSetup } from '@kbn/ml-plugin/server';
import { RuleRegistryPluginSetupContract } from '@kbn/rule-registry-plugin/server';
import { ObservabilityPluginSetup } from '@kbn/observability-plugin/server';
import { VersionedRouteConfig } from '@kbn/core-http-server';
export interface InfraServerPluginSetupDeps {
alerting: AlertingPluginContract;
@ -173,3 +174,7 @@ export interface InfraFieldDef {
export type InfraRouteConfig<Params, Query, Body, Method extends RouteMethod> = {
method: RouteMethod;
} & RouteConfig<Params, Query, Body, Method>;
export type InfraVersionedRouteConfig<Method extends RouteMethod> = {
method: RouteMethod;
} & VersionedRouteConfig<Method>;

View file

@ -24,6 +24,7 @@ import {
InfraRouteConfig,
InfraServerPluginSetupDeps,
InfraServerPluginStartDeps,
InfraVersionedRouteConfig,
} from './adapter_types';
interface FrozenIndexParams {
@ -78,6 +79,37 @@ export class KibanaFramework {
}
}
public registerVersionedRoute<Method extends RouteMethod = any>(
config: InfraVersionedRouteConfig<Method>
) {
const defaultOptions = {
tags: ['access:infra'],
};
const routeConfig = {
access: config.access,
path: config.path,
// Currently we have no use of custom options beyond tags, this can be extended
// beyond defaultOptions if it's needed.
options: defaultOptions,
};
switch (config.method) {
case 'get':
return this.router.versioned.get(routeConfig);
case 'post':
return this.router.versioned.post(routeConfig);
case 'delete':
return this.router.versioned.delete(routeConfig);
case 'put':
return this.router.versioned.put(routeConfig);
case 'patch':
return this.router.versioned.patch(routeConfig);
default:
throw new RangeError(
`#registerVersionedRoute: "${config.method}" is not an accepted method`
);
}
}
callWithRequest<Hit = {}, Aggregation = undefined>(
requestContext: InfraPluginRequestHandlerContext,
endpoint: 'search',

View file

@ -18,7 +18,7 @@ import {
GetLogAlertsChartPreviewDataAlertParamsSubset,
Point,
Series,
} from '../../../../common/http_api/log_alerts';
} from '../../../../common/http_api';
import { ResolvedLogView } from '../../../../common/log_views';
import { decodeOrThrow } from '../../../../common/runtime_types';
import type { InfraPluginRequestHandlerContext } from '../../../types';

View file

@ -6,12 +6,9 @@
*/
import Boom from '@hapi/boom';
import { logAlertsV1 } from '../../../common/http_api';
import { InfraBackendLibs } from '../../lib/infra_types';
import {
LOG_ALERTS_CHART_PREVIEW_DATA_PATH,
getLogAlertsChartPreviewDataSuccessResponsePayloadRT,
getLogAlertsChartPreviewDataRequestPayloadRT,
} from '../../../common/http_api/log_alerts/chart_preview_data';
import { createValidationFunction } from '../../../common/runtime_types';
import { getChartPreviewData } from '../../lib/alerting/log_threshold/log_threshold_chart_preview';
@ -19,49 +16,58 @@ export const initGetLogAlertsChartPreviewDataRoute = ({
framework,
getStartServices,
}: Pick<InfraBackendLibs, 'framework' | 'getStartServices'>) => {
framework.registerRoute(
{
framework
.registerVersionedRoute({
access: 'internal',
method: 'post',
path: LOG_ALERTS_CHART_PREVIEW_DATA_PATH,
validate: {
body: createValidationFunction(getLogAlertsChartPreviewDataRequestPayloadRT),
},
},
framework.router.handleLegacyErrors(async (requestContext, request, response) => {
const {
data: { logView, buckets, alertParams, executionTimeRange },
} = request.body;
const [, , { logViews }] = await getStartServices();
const resolvedLogView = await logViews.getScopedClient(request).getResolvedLogView(logView);
try {
const { series } = await getChartPreviewData(
requestContext,
resolvedLogView,
framework.callWithRequest,
alertParams,
buckets,
executionTimeRange
);
return response.ok({
body: getLogAlertsChartPreviewDataSuccessResponsePayloadRT.encode({
data: { series },
}),
});
} catch (error) {
if (Boom.isBoom(error)) {
throw error;
}
return response.customError({
statusCode: error.statusCode ?? 500,
body: {
message: error.message ?? 'An unexpected error occurred',
},
});
}
path: logAlertsV1.LOG_ALERTS_CHART_PREVIEW_DATA_PATH,
})
);
.addVersion(
{
version: '1',
validate: {
request: {
body: createValidationFunction(
logAlertsV1.getLogAlertsChartPreviewDataRequestPayloadRT
),
},
},
},
framework.router.handleLegacyErrors(async (requestContext, request, response) => {
const {
data: { logView, buckets, alertParams, executionTimeRange },
} = request.body;
const [, , { logViews }] = await getStartServices();
const resolvedLogView = await logViews.getScopedClient(request).getResolvedLogView(logView);
try {
const { series } = await getChartPreviewData(
requestContext,
resolvedLogView,
framework.callWithRequest,
alertParams,
buckets,
executionTimeRange
);
return response.ok({
body: logAlertsV1.getLogAlertsChartPreviewDataSuccessResponsePayloadRT.encode({
data: { series },
}),
});
} catch (error) {
if (Boom.isBoom(error)) {
throw error;
}
return response.customError({
statusCode: error.statusCode ?? 500,
body: {
message: error.message ?? 'An unexpected error occurred',
},
});
}
})
);
};

View file

@ -6,13 +6,9 @@
*/
import Boom from '@hapi/boom';
import { logAnalysisResultsV1 } from '../../../../common/http_api';
import { InfraBackendLibs } from '../../../lib/infra_types';
import {
LOG_ANALYSIS_GET_LOG_ENTRY_ANOMALIES_PATH,
getLogEntryAnomaliesSuccessReponsePayloadRT,
getLogEntryAnomaliesRequestPayloadRT,
GetLogEntryAnomaliesRequestPayload,
} from '../../../../common/http_api/log_analysis';
import { AnomaliesSort, Pagination } from '../../../../common/log_analysis';
import { createValidationFunction } from '../../../../common/runtime_types';
import { assertHasInfraMlPlugins } from '../../../utils/request_context';
@ -20,83 +16,94 @@ import { getLogEntryAnomalies } from '../../../lib/log_analysis';
import { isMlPrivilegesError } from '../../../lib/log_analysis/errors';
export const initGetLogEntryAnomaliesRoute = ({ framework }: InfraBackendLibs) => {
framework.registerRoute(
{
framework
.registerVersionedRoute({
access: 'internal',
method: 'post',
path: LOG_ANALYSIS_GET_LOG_ENTRY_ANOMALIES_PATH,
validate: {
body: createValidationFunction(getLogEntryAnomaliesRequestPayloadRT),
},
},
framework.router.handleLegacyErrors(async (requestContext, request, response) => {
const {
data: {
logView,
timeRange: { startTime, endTime },
sort: sortParam,
pagination: paginationParam,
datasets,
path: logAnalysisResultsV1.LOG_ANALYSIS_GET_LOG_ENTRY_ANOMALIES_PATH,
})
.addVersion(
{
version: '1',
validate: {
request: {
body: createValidationFunction(
logAnalysisResultsV1.getLogEntryAnomaliesRequestPayloadRT
),
},
},
} = request.body;
const { sort, pagination } = getSortAndPagination(sortParam, paginationParam);
try {
const infraMlContext = await assertHasInfraMlPlugins(requestContext);
},
framework.router.handleLegacyErrors(async (requestContext, request, response) => {
const {
data: logEntryAnomalies,
paginationCursors,
hasMoreEntries,
timing,
} = await getLogEntryAnomalies(
infraMlContext,
logView,
startTime,
endTime,
sort,
pagination,
datasets
);
data: {
logView,
timeRange: { startTime, endTime },
sort: sortParam,
pagination: paginationParam,
datasets,
},
} = request.body;
return response.ok({
body: getLogEntryAnomaliesSuccessReponsePayloadRT.encode({
data: {
anomalies: logEntryAnomalies,
hasMoreEntries,
paginationCursors,
},
const { sort, pagination } = getSortAndPagination(sortParam, paginationParam);
try {
const infraMlContext = await assertHasInfraMlPlugins(requestContext);
const {
data: logEntryAnomalies,
paginationCursors,
hasMoreEntries,
timing,
}),
});
} catch (error) {
if (Boom.isBoom(error)) {
throw error;
}
} = await getLogEntryAnomalies(
infraMlContext,
logView,
startTime,
endTime,
sort,
pagination,
datasets
);
return response.ok({
body: logAnalysisResultsV1.getLogEntryAnomaliesSuccessReponsePayloadRT.encode({
data: {
anomalies: logEntryAnomalies,
hasMoreEntries,
paginationCursors,
},
timing,
}),
});
} catch (error) {
if (Boom.isBoom(error)) {
throw error;
}
if (isMlPrivilegesError(error)) {
return response.customError({
statusCode: 403,
body: {
message: error.message,
},
});
}
if (isMlPrivilegesError(error)) {
return response.customError({
statusCode: 403,
statusCode: error.statusCode ?? 500,
body: {
message: error.message,
message: error.message ?? 'An unexpected error occurred',
},
});
}
return response.customError({
statusCode: error.statusCode ?? 500,
body: {
message: error.message ?? 'An unexpected error occurred',
},
});
}
})
);
})
);
};
const getSortAndPagination = (
sort: Partial<GetLogEntryAnomaliesRequestPayload['data']['sort']> = {},
pagination: Partial<GetLogEntryAnomaliesRequestPayload['data']['pagination']> = {}
sort: Partial<logAnalysisResultsV1.GetLogEntryAnomaliesRequestPayload['data']['sort']> = {},
pagination: Partial<
logAnalysisResultsV1.GetLogEntryAnomaliesRequestPayload['data']['pagination']
> = {}
): {
sort: AnomaliesSort;
pagination: Pagination;

View file

@ -6,11 +6,8 @@
*/
import Boom from '@hapi/boom';
import {
getLogEntryAnomaliesDatasetsRequestPayloadRT,
getLogEntryAnomaliesDatasetsSuccessReponsePayloadRT,
LOG_ANALYSIS_GET_LOG_ENTRY_ANOMALIES_DATASETS_PATH,
} from '../../../../common/http_api/log_analysis';
import { logAnalysisResultsV1 } from '../../../../common/http_api';
import { createValidationFunction } from '../../../../common/runtime_types';
import type { InfraBackendLibs } from '../../../lib/infra_types';
import { getLogEntryAnomaliesDatasets } from '../../../lib/log_analysis';
@ -18,61 +15,70 @@ import { assertHasInfraMlPlugins } from '../../../utils/request_context';
import { isMlPrivilegesError } from '../../../lib/log_analysis/errors';
export const initGetLogEntryAnomaliesDatasetsRoute = ({ framework }: InfraBackendLibs) => {
framework.registerRoute(
{
framework
.registerVersionedRoute({
access: 'internal',
method: 'post',
path: LOG_ANALYSIS_GET_LOG_ENTRY_ANOMALIES_DATASETS_PATH,
validate: {
body: createValidationFunction(getLogEntryAnomaliesDatasetsRequestPayloadRT),
},
},
framework.router.handleLegacyErrors(async (requestContext, request, response) => {
const {
data: {
logView,
timeRange: { startTime, endTime },
path: logAnalysisResultsV1.LOG_ANALYSIS_GET_LOG_ENTRY_ANOMALIES_DATASETS_PATH,
})
.addVersion(
{
version: '1',
validate: {
request: {
body: createValidationFunction(
logAnalysisResultsV1.getLogEntryAnomaliesDatasetsRequestPayloadRT
),
},
},
} = request.body;
},
framework.router.handleLegacyErrors(async (requestContext, request, response) => {
const {
data: {
logView,
timeRange: { startTime, endTime },
},
} = request.body;
try {
const infraMlContext = await assertHasInfraMlPlugins(requestContext);
try {
const infraMlContext = await assertHasInfraMlPlugins(requestContext);
const { datasets, timing } = await getLogEntryAnomaliesDatasets(
{ infra: await infraMlContext.infra },
logView,
startTime,
endTime
);
const { datasets, timing } = await getLogEntryAnomaliesDatasets(
{ infra: await infraMlContext.infra },
logView,
startTime,
endTime
);
return response.ok({
body: getLogEntryAnomaliesDatasetsSuccessReponsePayloadRT.encode({
data: {
datasets,
},
timing,
}),
});
} catch (error) {
if (Boom.isBoom(error)) {
throw error;
}
return response.ok({
body: logAnalysisResultsV1.getLogEntryAnomaliesDatasetsSuccessReponsePayloadRT.encode({
data: {
datasets,
},
timing,
}),
});
} catch (error) {
if (Boom.isBoom(error)) {
throw error;
}
if (isMlPrivilegesError(error)) {
return response.customError({
statusCode: 403,
body: {
message: error.message,
},
});
}
if (isMlPrivilegesError(error)) {
return response.customError({
statusCode: 403,
statusCode: error.statusCode ?? 500,
body: {
message: error.message,
message: error.message ?? 'An unexpected error occurred',
},
});
}
return response.customError({
statusCode: error.statusCode ?? 500,
body: {
message: error.message ?? 'An unexpected error occurred',
},
});
}
})
);
})
);
};

View file

@ -6,11 +6,8 @@
*/
import Boom from '@hapi/boom';
import {
getLogEntryCategoriesRequestPayloadRT,
getLogEntryCategoriesSuccessReponsePayloadRT,
LOG_ANALYSIS_GET_LOG_ENTRY_CATEGORIES_PATH,
} from '../../../../common/http_api/log_analysis';
import { logAnalysisResultsV1 } from '../../../../common/http_api';
import { createValidationFunction } from '../../../../common/runtime_types';
import type { InfraBackendLibs } from '../../../lib/infra_types';
import { getTopLogEntryCategories } from '../../../lib/log_analysis';
@ -18,74 +15,83 @@ import { assertHasInfraMlPlugins } from '../../../utils/request_context';
import { isMlPrivilegesError } from '../../../lib/log_analysis/errors';
export const initGetLogEntryCategoriesRoute = ({ framework }: InfraBackendLibs) => {
framework.registerRoute(
{
framework
.registerVersionedRoute({
access: 'internal',
method: 'post',
path: LOG_ANALYSIS_GET_LOG_ENTRY_CATEGORIES_PATH,
validate: {
body: createValidationFunction(getLogEntryCategoriesRequestPayloadRT),
},
},
framework.router.handleLegacyErrors(async (requestContext, request, response) => {
const {
data: {
categoryCount,
histograms,
logView,
timeRange: { startTime, endTime },
datasets,
sort,
path: logAnalysisResultsV1.LOG_ANALYSIS_GET_LOG_ENTRY_CATEGORIES_PATH,
})
.addVersion(
{
version: '1',
validate: {
request: {
body: createValidationFunction(
logAnalysisResultsV1.getLogEntryCategoriesRequestPayloadRT
),
},
},
} = request.body;
},
framework.router.handleLegacyErrors(async (requestContext, request, response) => {
const {
data: {
categoryCount,
histograms,
logView,
timeRange: { startTime, endTime },
datasets,
sort,
},
} = request.body;
try {
const infraMlContext = await assertHasInfraMlPlugins(requestContext);
try {
const infraMlContext = await assertHasInfraMlPlugins(requestContext);
const { data: topLogEntryCategories, timing } = await getTopLogEntryCategories(
{ infra: await infraMlContext.infra },
logView,
startTime,
endTime,
categoryCount,
datasets ?? [],
histograms.map((histogram) => ({
bucketCount: histogram.bucketCount,
endTime: histogram.timeRange.endTime,
id: histogram.id,
startTime: histogram.timeRange.startTime,
})),
sort
);
const { data: topLogEntryCategories, timing } = await getTopLogEntryCategories(
{ infra: await infraMlContext.infra },
logView,
startTime,
endTime,
categoryCount,
datasets ?? [],
histograms.map((histogram) => ({
bucketCount: histogram.bucketCount,
endTime: histogram.timeRange.endTime,
id: histogram.id,
startTime: histogram.timeRange.startTime,
})),
sort
);
return response.ok({
body: getLogEntryCategoriesSuccessReponsePayloadRT.encode({
data: {
categories: topLogEntryCategories,
},
timing,
}),
});
} catch (error) {
if (Boom.isBoom(error)) {
throw error;
}
return response.ok({
body: logAnalysisResultsV1.getLogEntryCategoriesSuccessReponsePayloadRT.encode({
data: {
categories: topLogEntryCategories,
},
timing,
}),
});
} catch (error) {
if (Boom.isBoom(error)) {
throw error;
}
if (isMlPrivilegesError(error)) {
return response.customError({
statusCode: 403,
body: {
message: error.message,
},
});
}
if (isMlPrivilegesError(error)) {
return response.customError({
statusCode: 403,
statusCode: error.statusCode ?? 500,
body: {
message: error.message,
message: error.message ?? 'An unexpected error occurred',
},
});
}
return response.customError({
statusCode: error.statusCode ?? 500,
body: {
message: error.message ?? 'An unexpected error occurred',
},
});
}
})
);
})
);
};

View file

@ -6,11 +6,8 @@
*/
import Boom from '@hapi/boom';
import {
getLogEntryCategoryDatasetsRequestPayloadRT,
getLogEntryCategoryDatasetsSuccessReponsePayloadRT,
LOG_ANALYSIS_GET_LOG_ENTRY_CATEGORY_DATASETS_PATH,
} from '../../../../common/http_api/log_analysis';
import { logAnalysisResultsV1 } from '../../../../common/http_api';
import { createValidationFunction } from '../../../../common/runtime_types';
import type { InfraBackendLibs } from '../../../lib/infra_types';
import { getLogEntryCategoryDatasets } from '../../../lib/log_analysis';
@ -18,61 +15,70 @@ import { assertHasInfraMlPlugins } from '../../../utils/request_context';
import { isMlPrivilegesError } from '../../../lib/log_analysis/errors';
export const initGetLogEntryCategoryDatasetsRoute = ({ framework }: InfraBackendLibs) => {
framework.registerRoute(
{
framework
.registerVersionedRoute({
access: 'internal',
method: 'post',
path: LOG_ANALYSIS_GET_LOG_ENTRY_CATEGORY_DATASETS_PATH,
validate: {
body: createValidationFunction(getLogEntryCategoryDatasetsRequestPayloadRT),
},
},
framework.router.handleLegacyErrors(async (requestContext, request, response) => {
const {
data: {
logView,
timeRange: { startTime, endTime },
path: logAnalysisResultsV1.LOG_ANALYSIS_GET_LOG_ENTRY_CATEGORY_DATASETS_PATH,
})
.addVersion(
{
version: '1',
validate: {
request: {
body: createValidationFunction(
logAnalysisResultsV1.getLogEntryCategoryDatasetsRequestPayloadRT
),
},
},
} = request.body;
},
framework.router.handleLegacyErrors(async (requestContext, request, response) => {
const {
data: {
logView,
timeRange: { startTime, endTime },
},
} = request.body;
try {
const infraMlContext = await assertHasInfraMlPlugins(requestContext);
try {
const infraMlContext = await assertHasInfraMlPlugins(requestContext);
const { data: logEntryCategoryDatasets, timing } = await getLogEntryCategoryDatasets(
{ infra: await infraMlContext.infra },
logView,
startTime,
endTime
);
const { data: logEntryCategoryDatasets, timing } = await getLogEntryCategoryDatasets(
{ infra: await infraMlContext.infra },
logView,
startTime,
endTime
);
return response.ok({
body: getLogEntryCategoryDatasetsSuccessReponsePayloadRT.encode({
data: {
datasets: logEntryCategoryDatasets,
},
timing,
}),
});
} catch (error) {
if (Boom.isBoom(error)) {
throw error;
}
return response.ok({
body: logAnalysisResultsV1.getLogEntryCategoryDatasetsSuccessReponsePayloadRT.encode({
data: {
datasets: logEntryCategoryDatasets,
},
timing,
}),
});
} catch (error) {
if (Boom.isBoom(error)) {
throw error;
}
if (isMlPrivilegesError(error)) {
return response.customError({
statusCode: 403,
body: {
message: error.message,
},
});
}
if (isMlPrivilegesError(error)) {
return response.customError({
statusCode: 403,
statusCode: error.statusCode ?? 500,
body: {
message: error.message,
message: error.message ?? 'An unexpected error occurred',
},
});
}
return response.customError({
statusCode: error.statusCode ?? 500,
body: {
message: error.message ?? 'An unexpected error occurred',
},
});
}
})
);
})
);
};

View file

@ -6,11 +6,8 @@
*/
import Boom from '@hapi/boom';
import {
getLatestLogEntryCategoryDatasetsStatsRequestPayloadRT,
getLatestLogEntryCategoryDatasetsStatsSuccessResponsePayloadRT,
LOG_ANALYSIS_GET_LATEST_LOG_ENTRY_CATEGORY_DATASETS_STATS_PATH,
} from '../../../../common/http_api/log_analysis';
import { logAnalysisResultsV1 } from '../../../../common/http_api';
import { createValidationFunction } from '../../../../common/runtime_types';
import type { InfraBackendLibs } from '../../../lib/infra_types';
import { getLatestLogEntriesCategoriesDatasetsStats } from '../../../lib/log_analysis';
@ -18,63 +15,74 @@ import { isMlPrivilegesError } from '../../../lib/log_analysis/errors';
import { assertHasInfraMlPlugins } from '../../../utils/request_context';
export const initGetLogEntryCategoryDatasetsStatsRoute = ({ framework }: InfraBackendLibs) => {
framework.registerRoute(
{
framework
.registerVersionedRoute({
access: 'internal',
method: 'post',
path: LOG_ANALYSIS_GET_LATEST_LOG_ENTRY_CATEGORY_DATASETS_STATS_PATH,
validate: {
body: createValidationFunction(getLatestLogEntryCategoryDatasetsStatsRequestPayloadRT),
},
},
framework.router.handleLegacyErrors(async (requestContext, request, response) => {
const {
data: {
jobIds,
timeRange: { startTime, endTime },
includeCategorizerStatuses,
path: logAnalysisResultsV1.LOG_ANALYSIS_GET_LATEST_LOG_ENTRY_CATEGORY_DATASETS_STATS_PATH,
})
.addVersion(
{
version: '1',
validate: {
request: {
body: createValidationFunction(
logAnalysisResultsV1.getLatestLogEntryCategoryDatasetsStatsRequestPayloadRT
),
},
},
} = request.body;
},
framework.router.handleLegacyErrors(async (requestContext, request, response) => {
const {
data: {
jobIds,
timeRange: { startTime, endTime },
includeCategorizerStatuses,
},
} = request.body;
try {
const infraMlContext = await assertHasInfraMlPlugins(requestContext);
try {
const infraMlContext = await assertHasInfraMlPlugins(requestContext);
const { data: datasetStats, timing } = await getLatestLogEntriesCategoriesDatasetsStats(
{ infra: await infraMlContext.infra },
jobIds,
startTime,
endTime,
includeCategorizerStatuses
);
const { data: datasetStats, timing } = await getLatestLogEntriesCategoriesDatasetsStats(
{ infra: await infraMlContext.infra },
jobIds,
startTime,
endTime,
includeCategorizerStatuses
);
return response.ok({
body: getLatestLogEntryCategoryDatasetsStatsSuccessResponsePayloadRT.encode({
data: {
datasetStats,
},
timing,
}),
});
} catch (error) {
if (Boom.isBoom(error)) {
throw error;
}
return response.ok({
body: logAnalysisResultsV1.getLatestLogEntryCategoryDatasetsStatsSuccessResponsePayloadRT.encode(
{
data: {
datasetStats,
},
timing,
}
),
});
} catch (error) {
if (Boom.isBoom(error)) {
throw error;
}
if (isMlPrivilegesError(error)) {
return response.customError({
statusCode: 403,
body: {
message: error.message,
},
});
}
if (isMlPrivilegesError(error)) {
return response.customError({
statusCode: 403,
statusCode: error.statusCode ?? 500,
body: {
message: error.message,
message: error.message ?? 'An unexpected error occurred',
},
});
}
return response.customError({
statusCode: error.statusCode ?? 500,
body: {
message: error.message ?? 'An unexpected error occurred',
},
});
}
})
);
})
);
};

View file

@ -6,11 +6,8 @@
*/
import Boom from '@hapi/boom';
import {
getLogEntryCategoryExamplesRequestPayloadRT,
getLogEntryCategoryExamplesSuccessReponsePayloadRT,
LOG_ANALYSIS_GET_LOG_ENTRY_CATEGORY_EXAMPLES_PATH,
} from '../../../../common/http_api/log_analysis';
import { logAnalysisResultsV1 } from '../../../../common/http_api';
import { createValidationFunction } from '../../../../common/runtime_types';
import type { InfraBackendLibs } from '../../../lib/infra_types';
import { getLogEntryCategoryExamples } from '../../../lib/log_analysis';
@ -21,69 +18,78 @@ export const initGetLogEntryCategoryExamplesRoute = ({
framework,
getStartServices,
}: Pick<InfraBackendLibs, 'framework' | 'getStartServices'>) => {
framework.registerRoute(
{
framework
.registerVersionedRoute({
access: 'internal',
method: 'post',
path: LOG_ANALYSIS_GET_LOG_ENTRY_CATEGORY_EXAMPLES_PATH,
validate: {
body: createValidationFunction(getLogEntryCategoryExamplesRequestPayloadRT),
},
},
framework.router.handleLegacyErrors(async (requestContext, request, response) => {
const {
data: {
categoryId,
exampleCount,
logView,
timeRange: { startTime, endTime },
path: logAnalysisResultsV1.LOG_ANALYSIS_GET_LOG_ENTRY_CATEGORY_EXAMPLES_PATH,
})
.addVersion(
{
version: '1',
validate: {
request: {
body: createValidationFunction(
logAnalysisResultsV1.getLogEntryCategoryExamplesRequestPayloadRT
),
},
},
} = request.body;
},
framework.router.handleLegacyErrors(async (requestContext, request, response) => {
const {
data: {
categoryId,
exampleCount,
logView,
timeRange: { startTime, endTime },
},
} = request.body;
const [, , { logViews }] = await getStartServices();
const resolvedLogView = await logViews.getScopedClient(request).getResolvedLogView(logView);
const [, , { logViews }] = await getStartServices();
const resolvedLogView = await logViews.getScopedClient(request).getResolvedLogView(logView);
try {
const infraMlContext = await assertHasInfraMlPlugins(requestContext);
try {
const infraMlContext = await assertHasInfraMlPlugins(requestContext);
const { data: logEntryCategoryExamples, timing } = await getLogEntryCategoryExamples(
{ infra: await infraMlContext.infra, core: await infraMlContext.core },
logView,
startTime,
endTime,
categoryId,
exampleCount,
resolvedLogView
);
const { data: logEntryCategoryExamples, timing } = await getLogEntryCategoryExamples(
{ infra: await infraMlContext.infra, core: await infraMlContext.core },
logView,
startTime,
endTime,
categoryId,
exampleCount,
resolvedLogView
);
return response.ok({
body: getLogEntryCategoryExamplesSuccessReponsePayloadRT.encode({
data: {
examples: logEntryCategoryExamples,
},
timing,
}),
});
} catch (error) {
if (Boom.isBoom(error)) {
throw error;
}
return response.ok({
body: logAnalysisResultsV1.getLogEntryCategoryExamplesSuccessReponsePayloadRT.encode({
data: {
examples: logEntryCategoryExamples,
},
timing,
}),
});
} catch (error) {
if (Boom.isBoom(error)) {
throw error;
}
if (isMlPrivilegesError(error)) {
return response.customError({
statusCode: 403,
body: {
message: error.message,
},
});
}
if (isMlPrivilegesError(error)) {
return response.customError({
statusCode: 403,
statusCode: error.statusCode ?? 500,
body: {
message: error.message,
message: error.message ?? 'An unexpected error occurred',
},
});
}
return response.customError({
statusCode: error.statusCode ?? 500,
body: {
message: error.message ?? 'An unexpected error occurred',
},
});
}
})
);
})
);
};

View file

@ -6,11 +6,8 @@
*/
import Boom from '@hapi/boom';
import {
getLogEntryExamplesRequestPayloadRT,
getLogEntryExamplesSuccessReponsePayloadRT,
LOG_ANALYSIS_GET_LOG_ENTRY_RATE_EXAMPLES_PATH,
} from '../../../../common/http_api/log_analysis';
import { logAnalysisResultsV1 } from '../../../../common/http_api';
import { createValidationFunction } from '../../../../common/runtime_types';
import { InfraBackendLibs } from '../../../lib/infra_types';
import { getLogEntryExamples } from '../../../lib/log_analysis';
@ -21,72 +18,81 @@ export const initGetLogEntryExamplesRoute = ({
framework,
getStartServices,
}: Pick<InfraBackendLibs, 'framework' | 'getStartServices'>) => {
framework.registerRoute(
{
framework
.registerVersionedRoute({
access: 'internal',
method: 'post',
path: LOG_ANALYSIS_GET_LOG_ENTRY_RATE_EXAMPLES_PATH,
validate: {
body: createValidationFunction(getLogEntryExamplesRequestPayloadRT),
},
},
framework.router.handleLegacyErrors(async (requestContext, request, response) => {
const {
data: {
dataset,
exampleCount,
logView,
timeRange: { startTime, endTime },
categoryId,
path: logAnalysisResultsV1.LOG_ANALYSIS_GET_LOG_ENTRY_RATE_EXAMPLES_PATH,
})
.addVersion(
{
version: '1',
validate: {
request: {
body: createValidationFunction(
logAnalysisResultsV1.getLogEntryExamplesRequestPayloadRT
),
},
},
} = request.body;
},
framework.router.handleLegacyErrors(async (requestContext, request, response) => {
const {
data: {
dataset,
exampleCount,
logView,
timeRange: { startTime, endTime },
categoryId,
},
} = request.body;
const [, , { logViews }] = await getStartServices();
const resolvedLogView = await logViews.getScopedClient(request).getResolvedLogView(logView);
const [, , { logViews }] = await getStartServices();
const resolvedLogView = await logViews.getScopedClient(request).getResolvedLogView(logView);
try {
const infraMlContext = await assertHasInfraMlPlugins(requestContext);
try {
const infraMlContext = await assertHasInfraMlPlugins(requestContext);
const { data: logEntryExamples, timing } = await getLogEntryExamples(
infraMlContext,
logView,
startTime,
endTime,
dataset,
exampleCount,
resolvedLogView,
framework.callWithRequest,
categoryId
);
const { data: logEntryExamples, timing } = await getLogEntryExamples(
infraMlContext,
logView,
startTime,
endTime,
dataset,
exampleCount,
resolvedLogView,
framework.callWithRequest,
categoryId
);
return response.ok({
body: getLogEntryExamplesSuccessReponsePayloadRT.encode({
data: {
examples: logEntryExamples,
},
timing,
}),
});
} catch (error) {
if (Boom.isBoom(error)) {
throw error;
}
return response.ok({
body: logAnalysisResultsV1.getLogEntryExamplesSuccessResponsePayloadRT.encode({
data: {
examples: logEntryExamples,
},
timing,
}),
});
} catch (error) {
if (Boom.isBoom(error)) {
throw error;
}
if (isMlPrivilegesError(error)) {
return response.customError({
statusCode: 403,
body: {
message: error.message,
},
});
}
if (isMlPrivilegesError(error)) {
return response.customError({
statusCode: 403,
statusCode: error.statusCode ?? 500,
body: {
message: error.message,
message: error.message ?? 'An unexpected error occurred',
},
});
}
return response.customError({
statusCode: error.statusCode ?? 500,
body: {
message: error.message ?? 'An unexpected error occurred',
},
});
}
})
);
})
);
};

View file

@ -9,65 +9,72 @@ import Boom from '@hapi/boom';
import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
import { InfraBackendLibs } from '../../../lib/infra_types';
import {
LOG_ANALYSIS_VALIDATE_DATASETS_PATH,
validateLogEntryDatasetsRequestPayloadRT,
validateLogEntryDatasetsResponsePayloadRT,
} from '../../../../common/http_api';
import { createValidationFunction } from '../../../../common/runtime_types';
import { logAnalysisValidationV1 } from '../../../../common/http_api';
export const initValidateLogAnalysisDatasetsRoute = ({
framework,
logEntries,
}: InfraBackendLibs) => {
framework.registerRoute(
{
framework
.registerVersionedRoute({
access: 'internal',
method: 'post',
path: LOG_ANALYSIS_VALIDATE_DATASETS_PATH,
validate: {
body: createValidationFunction(validateLogEntryDatasetsRequestPayloadRT),
},
},
framework.router.handleLegacyErrors(async (requestContext, request, response) => {
try {
const {
data: { indices, timestampField, startTime, endTime, runtimeMappings },
} = request.body;
const datasets = await Promise.all(
indices.map(async (indexName) => {
const indexDatasets = await logEntries.getLogEntryDatasets(
requestContext,
timestampField,
indexName,
startTime,
endTime,
runtimeMappings as estypes.MappingRuntimeFields
);
return {
indexName,
datasets: indexDatasets,
};
})
);
return response.ok({
body: validateLogEntryDatasetsResponsePayloadRT.encode({ data: { datasets } }),
});
} catch (error) {
if (Boom.isBoom(error)) {
throw error;
}
return response.customError({
statusCode: error.statusCode ?? 500,
body: {
message: error.message ?? 'An unexpected error occurred',
},
});
}
path: logAnalysisValidationV1.LOG_ANALYSIS_VALIDATE_DATASETS_PATH,
})
);
.addVersion(
{
version: '1',
validate: {
request: {
body: createValidationFunction(
logAnalysisValidationV1.validateLogEntryDatasetsRequestPayloadRT
),
},
},
},
framework.router.handleLegacyErrors(async (requestContext, request, response) => {
try {
const {
data: { indices, timestampField, startTime, endTime, runtimeMappings },
} = request.body;
const datasets = await Promise.all(
indices.map(async (indexName) => {
const indexDatasets = await logEntries.getLogEntryDatasets(
requestContext,
timestampField,
indexName,
startTime,
endTime,
runtimeMappings as estypes.MappingRuntimeFields
);
return {
indexName,
datasets: indexDatasets,
};
})
);
return response.ok({
body: logAnalysisValidationV1.validateLogEntryDatasetsResponsePayloadRT.encode({
data: { datasets },
}),
});
} catch (error) {
if (Boom.isBoom(error)) {
throw error;
}
return response.customError({
statusCode: error.statusCode ?? 500,
body: {
message: error.message ?? 'An unexpected error occurred',
},
});
}
})
);
};

View file

@ -12,83 +12,85 @@ 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 {
LOG_ANALYSIS_VALIDATE_INDICES_PATH,
validationIndicesRequestPayloadRT,
validationIndicesResponsePayloadRT,
ValidationIndicesError,
} from '../../../../common/http_api';
import { throwErrors } from '../../../../common/runtime_types';
import { logAnalysisValidationV1 } from '../../../../common/http_api';
const escapeHatch = schema.object({}, { unknowns: 'allow' });
export const initValidateLogAnalysisIndicesRoute = ({ framework }: InfraBackendLibs) => {
framework.registerRoute(
{
framework
.registerVersionedRoute({
access: 'internal',
method: 'post',
path: LOG_ANALYSIS_VALIDATE_INDICES_PATH,
validate: { body: escapeHatch },
},
async (requestContext, request, response) => {
const payload = pipe(
validationIndicesRequestPayloadRT.decode(request.body),
fold(throwErrors(Boom.badRequest), identity)
);
path: logAnalysisValidationV1.LOG_ANALYSIS_VALIDATE_INDICES_PATH,
})
.addVersion(
{
version: '1',
validate: { request: { body: escapeHatch } },
},
async (requestContext, request, response) => {
const payload = pipe(
logAnalysisValidationV1.validationIndicesRequestPayloadRT.decode(request.body),
fold(throwErrors(Boom.badRequest), identity)
);
const { fields, indices, runtimeMappings } = payload.data;
const errors: ValidationIndicesError[] = [];
const { fields, indices, runtimeMappings } = payload.data;
const errors: logAnalysisValidationV1.ValidationIndicesError[] = [];
// Query each pattern individually, to map correctly the errors
await Promise.all(
indices.map(async (index) => {
const fieldCaps = await (
await requestContext.core
).elasticsearch.client.asCurrentUser.fieldCaps({
allow_no_indices: true,
fields: fields.map((field) => field.name),
ignore_unavailable: true,
index,
body: {
runtime_mappings: runtimeMappings,
},
});
if (fieldCaps.indices.length === 0) {
errors.push({
error: 'INDEX_NOT_FOUND',
// Query each pattern individually, to map correctly the errors
await Promise.all(
indices.map(async (index) => {
const fieldCaps = await (
await requestContext.core
).elasticsearch.client.asCurrentUser.fieldCaps({
allow_no_indices: true,
fields: fields.map((field) => field.name),
ignore_unavailable: true,
index,
body: {
runtime_mappings: runtimeMappings,
},
});
return;
}
fields.forEach(({ name: fieldName, validTypes }) => {
const fieldMetadata = fieldCaps.fields[fieldName];
if (fieldMetadata === undefined) {
if (fieldCaps.indices.length === 0) {
errors.push({
error: 'FIELD_NOT_FOUND',
error: 'INDEX_NOT_FOUND',
index,
field: fieldName,
});
} else {
const fieldTypes = Object.keys(fieldMetadata);
return;
}
if (!fieldTypes.every((fieldType) => validTypes.includes(fieldType))) {
fields.forEach(({ name: fieldName, validTypes }) => {
const fieldMetadata = fieldCaps.fields[fieldName];
if (fieldMetadata === undefined) {
errors.push({
error: `FIELD_NOT_VALID`,
error: 'FIELD_NOT_FOUND',
index,
field: fieldName,
});
}
}
});
})
);
} else {
const fieldTypes = Object.keys(fieldMetadata);
return response.ok({
body: validationIndicesResponsePayloadRT.encode({ data: { errors } }),
});
}
);
if (!fieldTypes.every((fieldType) => validTypes.includes(fieldType))) {
errors.push({
error: `FIELD_NOT_VALID`,
index,
field: fieldName,
});
}
}
});
})
);
return response.ok({
body: logAnalysisValidationV1.validationIndicesResponsePayloadRT.encode({
data: { errors },
}),
});
}
);
};

View file

@ -12,90 +12,92 @@ import { fold } from 'fp-ts/lib/Either';
import { identity } from 'fp-ts/lib/function';
import { schema } from '@kbn/config-schema';
import { logEntriesV1 } from '../../../common/http_api';
import { throwErrors } from '../../../common/runtime_types';
import { InfraBackendLibs } from '../../lib/infra_types';
import {
LOG_ENTRIES_HIGHLIGHTS_PATH,
logEntriesHighlightsRequestRT,
logEntriesHighlightsResponseRT,
} from '../../../common/http_api/log_entries';
import { parseFilterQuery } from '../../utils/serialized_query';
import { LogEntriesParams } from '../../lib/domains/log_entries_domain';
const escapeHatch = schema.object({}, { unknowns: 'allow' });
export const initLogEntriesHighlightsRoute = ({ framework, logEntries }: InfraBackendLibs) => {
framework.registerRoute(
{
framework
.registerVersionedRoute({
access: 'internal',
method: 'post',
path: LOG_ENTRIES_HIGHLIGHTS_PATH,
validate: { body: escapeHatch },
},
async (requestContext, request, response) => {
const payload = pipe(
logEntriesHighlightsRequestRT.decode(request.body),
fold(throwErrors(Boom.badRequest), identity)
);
const { startTimestamp, endTimestamp, logView, query, size, highlightTerms } = payload;
let entriesPerHighlightTerm;
if ('center' in payload) {
entriesPerHighlightTerm = await Promise.all(
highlightTerms.map((highlightTerm) =>
logEntries.getLogEntriesAround(requestContext, logView, {
startTimestamp,
endTimestamp,
query: parseFilterQuery(query),
center: payload.center,
size,
highlightTerm,
})
)
path: logEntriesV1.LOG_ENTRIES_HIGHLIGHTS_PATH,
})
.addVersion(
{
version: '1',
validate: { request: { body: escapeHatch } },
},
async (requestContext, request, response) => {
const payload = pipe(
logEntriesV1.logEntriesHighlightsRequestRT.decode(request.body),
fold(throwErrors(Boom.badRequest), identity)
);
} else {
let cursor: LogEntriesParams['cursor'];
if ('before' in payload) {
cursor = { before: payload.before };
} else if ('after' in payload) {
cursor = { after: payload.after };
const { startTimestamp, endTimestamp, logView, query, size, highlightTerms } = payload;
let entriesPerHighlightTerm;
if ('center' in payload) {
entriesPerHighlightTerm = await Promise.all(
highlightTerms.map((highlightTerm) =>
logEntries.getLogEntriesAround(requestContext, logView, {
startTimestamp,
endTimestamp,
query: parseFilterQuery(query),
center: payload.center,
size,
highlightTerm,
})
)
);
} else {
let cursor: LogEntriesParams['cursor'];
if ('before' in payload) {
cursor = { before: payload.before };
} else if ('after' in payload) {
cursor = { after: payload.after };
}
entriesPerHighlightTerm = await Promise.all(
highlightTerms.map((highlightTerm) =>
logEntries.getLogEntries(requestContext, logView, {
startTimestamp,
endTimestamp,
query: parseFilterQuery(query),
cursor,
size,
highlightTerm,
})
)
);
}
entriesPerHighlightTerm = await Promise.all(
highlightTerms.map((highlightTerm) =>
logEntries.getLogEntries(requestContext, logView, {
startTimestamp,
endTimestamp,
query: parseFilterQuery(query),
cursor,
size,
highlightTerm,
})
)
);
}
return response.ok({
body: logEntriesHighlightsResponseRT.encode({
data: entriesPerHighlightTerm.map(({ entries }) => {
if (entries.length > 0) {
return {
entries,
topCursor: entries[0].cursor,
bottomCursor: entries[entries.length - 1].cursor,
};
} else {
return {
entries,
topCursor: null,
bottomCursor: null,
};
}
return response.ok({
body: logEntriesV1.logEntriesHighlightsResponseRT.encode({
data: entriesPerHighlightTerm.map(({ entries }) => {
if (entries.length > 0) {
return {
entries,
topCursor: entries[0].cursor,
bottomCursor: entries[entries.length - 1].cursor,
};
} else {
return {
entries,
topCursor: null,
bottomCursor: null,
};
}
}),
}),
}),
});
}
);
});
}
);
};

View file

@ -12,53 +12,55 @@ import { fold } from 'fp-ts/lib/Either';
import { identity } from 'fp-ts/lib/function';
import { schema } from '@kbn/config-schema';
import { logEntriesV1 } from '../../../common/http_api';
import { throwErrors } from '../../../common/runtime_types';
import { InfraBackendLibs } from '../../lib/infra_types';
import {
LOG_ENTRIES_SUMMARY_PATH,
logEntriesSummaryRequestRT,
logEntriesSummaryResponseRT,
} from '../../../common/http_api/log_entries';
import { parseFilterQuery } from '../../utils/serialized_query';
import { UsageCollector } from '../../usage/usage_collector';
const escapeHatch = schema.object({}, { unknowns: 'allow' });
export const initLogEntriesSummaryRoute = ({ framework, logEntries }: InfraBackendLibs) => {
framework.registerRoute(
{
framework
.registerVersionedRoute({
access: 'internal',
method: 'post',
path: LOG_ENTRIES_SUMMARY_PATH,
validate: { body: escapeHatch },
},
async (requestContext, request, response) => {
const payload = pipe(
logEntriesSummaryRequestRT.decode(request.body),
fold(throwErrors(Boom.badRequest), identity)
);
const { logView, startTimestamp, endTimestamp, bucketSize, query } = payload;
path: logEntriesV1.LOG_ENTRIES_SUMMARY_PATH,
})
.addVersion(
{
version: '1',
validate: { request: { body: escapeHatch } },
},
async (requestContext, request, response) => {
const payload = pipe(
logEntriesV1.logEntriesSummaryRequestRT.decode(request.body),
fold(throwErrors(Boom.badRequest), identity)
);
const { logView, startTimestamp, endTimestamp, bucketSize, query } = payload;
const buckets = await logEntries.getLogSummaryBucketsBetween(
requestContext,
logView,
startTimestamp,
endTimestamp,
bucketSize,
parseFilterQuery(query)
);
const buckets = await logEntries.getLogSummaryBucketsBetween(
requestContext,
logView,
startTimestamp,
endTimestamp,
bucketSize,
parseFilterQuery(query)
);
UsageCollector.countLogs();
UsageCollector.countLogs();
return response.ok({
body: logEntriesSummaryResponseRT.encode({
data: {
start: startTimestamp,
end: endTimestamp,
buckets,
},
}),
});
}
);
return response.ok({
body: logEntriesV1.logEntriesSummaryResponseRT.encode({
data: {
start: startTimestamp,
end: endTimestamp,
buckets,
},
}),
});
}
);
};

View file

@ -12,14 +12,11 @@ import { fold } from 'fp-ts/lib/Either';
import { identity } from 'fp-ts/lib/function';
import { schema } from '@kbn/config-schema';
import { logEntriesV1 } from '../../../common/http_api';
import { throwErrors } from '../../../common/runtime_types';
import { InfraBackendLibs } from '../../lib/infra_types';
import {
LOG_ENTRIES_SUMMARY_HIGHLIGHTS_PATH,
logEntriesSummaryHighlightsRequestRT,
logEntriesSummaryHighlightsResponseRT,
} from '../../../common/http_api/log_entries';
import { parseFilterQuery } from '../../utils/serialized_query';
const escapeHatch = schema.object({}, { unknowns: 'allow' });
@ -28,38 +25,44 @@ export const initLogEntriesSummaryHighlightsRoute = ({
framework,
logEntries,
}: InfraBackendLibs) => {
framework.registerRoute(
{
framework
.registerVersionedRoute({
access: 'internal',
method: 'post',
path: LOG_ENTRIES_SUMMARY_HIGHLIGHTS_PATH,
validate: { body: escapeHatch },
},
async (requestContext, request, response) => {
const payload = pipe(
logEntriesSummaryHighlightsRequestRT.decode(request.body),
fold(throwErrors(Boom.badRequest), identity)
);
const { logView, startTimestamp, endTimestamp, bucketSize, query, highlightTerms } = payload;
path: logEntriesV1.LOG_ENTRIES_SUMMARY_HIGHLIGHTS_PATH,
})
.addVersion(
{
version: '1',
validate: { request: { body: escapeHatch } },
},
async (requestContext, request, response) => {
const payload = pipe(
logEntriesV1.logEntriesSummaryHighlightsRequestRT.decode(request.body),
fold(throwErrors(Boom.badRequest), identity)
);
const { logView, startTimestamp, endTimestamp, bucketSize, query, highlightTerms } =
payload;
const bucketsPerHighlightTerm = await logEntries.getLogSummaryHighlightBucketsBetween(
requestContext,
logView,
startTimestamp,
endTimestamp,
bucketSize,
highlightTerms,
parseFilterQuery(query)
);
const bucketsPerHighlightTerm = await logEntries.getLogSummaryHighlightBucketsBetween(
requestContext,
logView,
startTimestamp,
endTimestamp,
bucketSize,
highlightTerms,
parseFilterQuery(query)
);
return response.ok({
body: logEntriesSummaryHighlightsResponseRT.encode({
data: bucketsPerHighlightTerm.map((buckets) => ({
start: startTimestamp,
end: endTimestamp,
buckets,
})),
}),
});
}
);
return response.ok({
body: logEntriesV1.logEntriesSummaryHighlightsResponseRT.encode({
data: bucketsPerHighlightTerm.map((buckets) => ({
start: startTimestamp,
end: endTimestamp,
buckets,
})),
}),
});
}
);
};

View file

@ -5,11 +5,8 @@
* 2.0.
*/
import {
getLogViewRequestParamsRT,
getLogViewResponsePayloadRT,
LOG_VIEW_URL,
} from '../../../common/http_api/log_views';
import { logViewsV1 } from '../../../common/http_api';
import { LOG_VIEW_URL } from '../../../common/http_api/log_views';
import { createValidationFunction } from '../../../common/runtime_types';
import type { KibanaFramework } from '../../lib/adapters/framework/kibana_framework_adapter';
import type { InfraPluginStartServicesAccessor } from '../../types';
@ -21,35 +18,42 @@ export const initGetLogViewRoute = ({
framework: KibanaFramework;
getStartServices: InfraPluginStartServicesAccessor;
}) => {
framework.registerRoute(
{
framework
.registerVersionedRoute({
access: 'internal',
method: 'get',
path: LOG_VIEW_URL,
validate: {
params: createValidationFunction(getLogViewRequestParamsRT),
},
},
async (_requestContext, request, response) => {
const { logViewId } = request.params;
const { logViews } = (await getStartServices())[2];
const logViewsClient = logViews.getScopedClient(request);
try {
const logView = await logViewsClient.getLogView(logViewId);
return response.ok({
body: getLogViewResponsePayloadRT.encode({
data: logView,
}),
});
} catch (error) {
return response.customError({
statusCode: error.statusCode ?? 500,
body: {
message: error.message ?? 'An unexpected error occurred',
})
.addVersion(
{
version: '1',
validate: {
request: {
params: createValidationFunction(logViewsV1.getLogViewRequestParamsRT),
},
});
},
},
async (_requestContext, request, response) => {
const { logViewId } = request.params;
const { logViews } = (await getStartServices())[2];
const logViewsClient = logViews.getScopedClient(request);
try {
const logView = await logViewsClient.getLogView(logViewId);
return response.ok({
body: logViewsV1.getLogViewResponsePayloadRT.encode({
data: logView,
}),
});
} catch (error) {
return response.customError({
statusCode: error.statusCode ?? 500,
body: {
message: error.message ?? 'An unexpected error occurred',
},
});
}
}
}
);
);
};

View file

@ -5,12 +5,8 @@
* 2.0.
*/
import {
LOG_VIEW_URL,
putLogViewRequestParamsRT,
putLogViewRequestPayloadRT,
putLogViewResponsePayloadRT,
} from '../../../common/http_api/log_views';
import { logViewsV1 } from '../../../common/http_api';
import { LOG_VIEW_URL } from '../../../common/http_api/log_views';
import { createValidationFunction } from '../../../common/runtime_types';
import type { KibanaFramework } from '../../lib/adapters/framework/kibana_framework_adapter';
import type { InfraPluginStartServicesAccessor } from '../../types';
@ -22,37 +18,44 @@ export const initPutLogViewRoute = ({
framework: KibanaFramework;
getStartServices: InfraPluginStartServicesAccessor;
}) => {
framework.registerRoute(
{
framework
.registerVersionedRoute({
access: 'internal',
method: 'put',
path: LOG_VIEW_URL,
validate: {
params: createValidationFunction(putLogViewRequestParamsRT),
body: createValidationFunction(putLogViewRequestPayloadRT),
},
},
async (_requestContext, request, response) => {
const { logViewId } = request.params;
const { attributes } = request.body;
const { logViews } = (await getStartServices())[2];
const logViewsClient = logViews.getScopedClient(request);
try {
const logView = await logViewsClient.putLogView(logViewId, attributes);
return response.ok({
body: putLogViewResponsePayloadRT.encode({
data: logView,
}),
});
} catch (error) {
return response.customError({
statusCode: error.statusCode ?? 500,
body: {
message: error.message ?? 'An unexpected error occurred',
})
.addVersion(
{
version: '1',
validate: {
request: {
params: createValidationFunction(logViewsV1.putLogViewRequestParamsRT),
body: createValidationFunction(logViewsV1.putLogViewRequestPayloadRT),
},
});
},
},
async (_requestContext, request, response) => {
const { logViewId } = request.params;
const { attributes } = request.body;
const { logViews } = (await getStartServices())[2];
const logViewsClient = logViews.getScopedClient(request);
try {
const logView = await logViewsClient.putLogView(logViewId, attributes);
return response.ok({
body: logViewsV1.putLogViewResponsePayloadRT.encode({
data: logView,
}),
});
} catch (error) {
return response.customError({
statusCode: error.statusCode ?? 500,
body: {
message: error.message ?? 'An unexpected error occurred',
},
});
}
}
}
);
);
};

View file

@ -64,6 +64,7 @@
"@kbn/observability-shared-plugin",
"@kbn/ui-theme",
"@kbn/ml-anomaly-utils",
"@kbn/core-http-server",
],
"exclude": ["target/**/*"]
}

View file

@ -10,7 +10,7 @@ import {
LOG_ANALYSIS_VALIDATE_DATASETS_PATH,
validateLogEntryDatasetsRequestPayloadRT,
validateLogEntryDatasetsResponsePayloadRT,
} from '@kbn/infra-plugin/common/http_api/log_analysis/validation/datasets';
} from '@kbn/infra-plugin/common/http_api';
import { decodeOrThrow } from '@kbn/infra-plugin/common/runtime_types';
import { FtrProviderContext } from '../../ftr_provider_context';
@ -31,6 +31,7 @@ export default function ({ getService }: FtrProviderContext) {
.post(LOG_ANALYSIS_VALIDATE_DATASETS_PATH)
.set({
'kbn-xsrf': 'some-xsrf-token',
'Elastic-Api-Version': '1',
})
.send(
validateLogEntryDatasetsRequestPayloadRT.encode({

View file

@ -32,6 +32,7 @@ const KEY_AFTER_END = {
const COMMON_HEADERS = {
'kbn-xsrf': 'some-xsrf-token',
'Elastic-Api-Version': '1',
};
export default function ({ getService }: FtrProviderContext) {

View file

@ -19,7 +19,7 @@ import {
LOG_ENTRIES_SUMMARY_PATH,
logEntriesSummaryRequestRT,
logEntriesSummaryResponseRT,
} from '@kbn/infra-plugin/common/http_api/log_entries';
} from '@kbn/infra-plugin/common/http_api';
import { FtrProviderContext } from '../../ftr_provider_context';
@ -28,6 +28,7 @@ const LATEST_TIME_WITH_DATA = new Date('2018-10-17T19:57:21.611Z').valueOf();
const COMMON_HEADERS = {
'kbn-xsrf': 'some-xsrf-token',
'Elastic-Api-Version': '1',
};
export default function ({ getService }: FtrProviderContext) {

View file

@ -7,11 +7,11 @@
import {
getLogViewResponsePayloadRT,
getLogViewUrl,
PutLogViewRequestPayload,
putLogViewRequestPayloadRT,
putLogViewResponsePayloadRT,
} from '@kbn/infra-plugin/common/http_api/log_views';
} from '@kbn/infra-plugin/common/http_api';
import { getLogViewUrl } from '@kbn/infra-plugin/common/http_api/log_views';
import { decodeOrThrow } from '@kbn/infra-plugin/common/runtime_types';
import { FtrProviderContext } from '../ftr_provider_context';
@ -24,6 +24,7 @@ export function InfraLogViewsServiceProvider({ getService }: FtrProviderContext)
.get(getLogViewUrl(logViewId))
.set({
'kbn-xsrf': 'some-xsrf-token',
'Elastic-Api-Version': '1',
})
.send();
@ -40,6 +41,7 @@ export function InfraLogViewsServiceProvider({ getService }: FtrProviderContext)
.put(getLogViewUrl(logViewId))
.set({
'kbn-xsrf': 'some-xsrf-token',
'Elastic-Api-Version': '1',
})
.send(putLogViewRequestPayloadRT.encode(payload));

View file

@ -23,7 +23,6 @@ const timepickerFormat = 'MMM D, YYYY @ HH:mm:ss.SSS';
const tableEntries = [
{
title: 'demo-stack-apache-01',
os: '-',
cpuUsage: '1.2%',
diskLatency: '1.6 ms',
rx: '0 bit/s',
@ -33,7 +32,6 @@ const tableEntries = [
},
{
title: 'demo-stack-client-01',
os: '-',
cpuUsage: '0.5%',
diskLatency: '8.7 ms',
rx: '0 bit/s',
@ -43,7 +41,6 @@ const tableEntries = [
},
{
title: 'demo-stack-haproxy-01',
os: '-',
cpuUsage: '0.8%',
diskLatency: '7 ms',
rx: '0 bit/s',
@ -53,7 +50,6 @@ const tableEntries = [
},
{
title: 'demo-stack-mysql-01',
os: '-',
cpuUsage: '0.9%',
diskLatency: '6.6 ms',
rx: '0 bit/s',
@ -63,7 +59,6 @@ const tableEntries = [
},
{
title: 'demo-stack-nginx-01',
os: '-',
cpuUsage: '0.8%',
diskLatency: '5.7 ms',
rx: '0 bit/s',
@ -73,7 +68,6 @@ const tableEntries = [
},
{
title: 'demo-stack-redis-01',
os: '-',
cpuUsage: '0.8%',
diskLatency: '6.3 ms',
rx: '0 bit/s',

View file

@ -90,11 +90,11 @@ export function InfraHostsViewProvider({ getService }: FtrProviderContext) {
const cells = await row.findAllByCssSelector('[data-test-subj*="hostsView-tableRow-"]');
// Retrieve content for each cell
const [title, os, cpuUsage, diskLatency, rx, tx, memoryTotal, memory] = await Promise.all(
const [title, cpuUsage, diskLatency, rx, tx, memoryTotal, memory] = await Promise.all(
cells.map((cell) => this.getHostsCellContent(cell))
);
return { title, os, cpuUsage, diskLatency, rx, tx, memoryTotal, memory };
return { title, cpuUsage, diskLatency, rx, tx, memoryTotal, memory };
},
async getHostsCellContent(cell: WebElementWrapper) {
@ -285,7 +285,7 @@ export function InfraHostsViewProvider({ getService }: FtrProviderContext) {
// Sorting
getDiskLatencyHeader() {
return testSubjects.find('tableHeaderCell_diskLatency_4');
return testSubjects.find('tableHeaderCell_diskLatency_3');
},
getTitleHeader() {

View file

@ -6,7 +6,10 @@
*/
import expect from '@kbn/expect';
import { GET_TOTAL_IO_BYTES_ROUTE } from '@kbn/session-view-plugin/common/constants';
import {
CURRENT_API_VERSION,
GET_TOTAL_IO_BYTES_ROUTE,
} from '@kbn/session-view-plugin/common/constants';
import { FtrProviderContext } from '../../common/ftr_provider_context';
const MOCK_INDEX = 'logs-endpoint.events.process*';
@ -20,6 +23,13 @@ export default function getTotalIOBytesTests({ getService }: FtrProviderContext)
const supertest = getService('supertest');
const esArchiver = getService('esArchiver');
function getTestRoute() {
return supertest
.get(GET_TOTAL_IO_BYTES_ROUTE)
.set('kbn-xsrf', 'foo')
.set('Elastic-Api-Version', CURRENT_API_VERSION);
}
describe(`Session view - ${GET_TOTAL_IO_BYTES_ROUTE} - with a basic license`, () => {
before(async () => {
await esArchiver.load('x-pack/test/functional/es_archives/session_view/process_events');
@ -32,7 +42,7 @@ export default function getTotalIOBytesTests({ getService }: FtrProviderContext)
});
it(`${GET_TOTAL_IO_BYTES_ROUTE} returns a page of IO events`, async () => {
const response = await supertest.get(GET_TOTAL_IO_BYTES_ROUTE).set('kbn-xsrf', 'foo').query({
const response = await getTestRoute().query({
index: MOCK_INDEX,
sessionEntityId: MOCK_SESSION_ENTITY_ID,
sessionStartTime: MOCK_SESSION_START_TIME,
@ -42,7 +52,7 @@ export default function getTotalIOBytesTests({ getService }: FtrProviderContext)
});
it(`${GET_TOTAL_IO_BYTES_ROUTE} returns 0 for invalid query`, async () => {
const response = await supertest.get(GET_TOTAL_IO_BYTES_ROUTE).set('kbn-xsrf', 'foo').query({
const response = await getTestRoute().query({
index: MOCK_INDEX,
sessionStartTime: MOCK_SESSION_START_TIME,
sessionEntityId: 'xyz',

View file

@ -54,8 +54,7 @@ export default function processEventsTests({ getService }: FtrProviderContext) {
.set('Elastic-Api-Version', CURRENT_API_VERSION);
}
// Failing: See https://github.com/elastic/kibana/issues/159275
describe.skip(`Session view - ${PROCESS_EVENTS_ROUTE} - with a basic license`, () => {
describe(`Session view - ${PROCESS_EVENTS_ROUTE} - with a basic license`, () => {
describe(`using typical process event data`, () => {
before(async () => {
await esArchiver.load('x-pack/test/functional/es_archives/session_view/process_events');
@ -144,6 +143,7 @@ export default function processEventsTests({ getService }: FtrProviderContext) {
.get(`${PROCESS_EVENTS_ROUTE}`)
.auth(username, password)
.set('kbn-xsrf', 'true')
.set('Elastic-Api-Version', CURRENT_API_VERSION)
.query({
index: MOCK_INDEX,
sessionEntityId: MOCK_SESSION_ENTITY_ID,
@ -167,6 +167,7 @@ export default function processEventsTests({ getService }: FtrProviderContext) {
.get(`${PROCESS_EVENTS_ROUTE}`)
.auth(username, password)
.set('kbn-xsrf', 'true')
.set('Elastic-Api-Version', CURRENT_API_VERSION)
.query({
index: MOCK_INDEX,
sessionEntityId: MOCK_SESSION_ENTITY_ID,