Skip to content

Commit

Permalink
[ML] Moves shared code to @kbn/ml-error-utils. (#155372)
Browse files Browse the repository at this point in the history
- Moves code from `x-pack/plugins/ml/common/util/errors` that was shared
via `x-pack/plugins/ml/public/shared.ts` to `@kbn/ml-error-utils`.
- `data_visualizer` and `aiops` plugins now use that package instead of
code duplication.
  • Loading branch information
walterra authored Apr 22, 2023
1 parent 1bbaa5a commit d6d933a
Show file tree
Hide file tree
Showing 91 changed files with 449 additions and 611 deletions.
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,7 @@ src/plugins/maps_ems @elastic/kibana-gis
x-pack/plugins/maps @elastic/kibana-gis
x-pack/packages/ml/agg_utils @elastic/ml-ui
x-pack/packages/ml/date_picker @elastic/ml-ui
x-pack/packages/ml/error_utils @elastic/ml-ui
x-pack/packages/ml/is_defined @elastic/ml-ui
x-pack/packages/ml/is_populated_object @elastic/ml-ui
x-pack/packages/ml/local_storage @elastic/ml-ui
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,7 @@
"@kbn/maps-plugin": "link:x-pack/plugins/maps",
"@kbn/ml-agg-utils": "link:x-pack/packages/ml/agg_utils",
"@kbn/ml-date-picker": "link:x-pack/packages/ml/date_picker",
"@kbn/ml-error-utils": "link:x-pack/packages/ml/error_utils",
"@kbn/ml-is-defined": "link:x-pack/packages/ml/is_defined",
"@kbn/ml-is-populated-object": "link:x-pack/packages/ml/is_populated_object",
"@kbn/ml-local-storage": "link:x-pack/packages/ml/local_storage",
Expand Down
2 changes: 2 additions & 0 deletions tsconfig.base.json
Original file line number Diff line number Diff line change
Expand Up @@ -904,6 +904,8 @@
"@kbn/ml-agg-utils/*": ["x-pack/packages/ml/agg_utils/*"],
"@kbn/ml-date-picker": ["x-pack/packages/ml/date_picker"],
"@kbn/ml-date-picker/*": ["x-pack/packages/ml/date_picker/*"],
"@kbn/ml-error-utils": ["x-pack/packages/ml/error_utils"],
"@kbn/ml-error-utils/*": ["x-pack/packages/ml/error_utils/*"],
"@kbn/ml-is-defined": ["x-pack/packages/ml/is_defined"],
"@kbn/ml-is-defined/*": ["x-pack/packages/ml/is_defined/*"],
"@kbn/ml-is-populated-object": ["x-pack/packages/ml/is_populated_object"],
Expand Down
3 changes: 3 additions & 0 deletions x-pack/packages/ml/error_utils/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# @kbn/ml-error-utils

Empty package generated by @kbn/generate
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,17 @@
* 2.0.
*/

export { MLRequestFailure } from './request_error';
export { extractErrorMessage, extractErrorProperties } from './process_errors';
export { MLRequestFailure } from './src/request_error';
export { extractErrorMessage, extractErrorProperties } from './src/process_errors';
export type {
ErrorType,
ErrorMessage,
EsErrorBody,
EsErrorRootCause,
MLErrorObject,
MLHttpFetchError,
MLHttpFetchErrorBase,
MLResponseError,
} from './types';
export { isBoomError, isErrorString, isEsErrorBody, isMLResponseError } from './types';
QueryErrorMessage,
} from './src/types';
export { isBoomError, isErrorString, isEsErrorBody, isMLResponseError } from './src/types';
12 changes: 12 additions & 0 deletions x-pack/packages/ml/error_utils/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

module.exports = {
preset: '@kbn/test',
rootDir: '../../../..',
roots: ['<rootDir>/x-pack/packages/ml/error_utils'],
};
5 changes: 5 additions & 0 deletions x-pack/packages/ml/error_utils/kibana.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"type": "shared-common",
"id": "@kbn/ml-error-utils",
"owner": "@elastic/ml-ui"
}
6 changes: 6 additions & 0 deletions x-pack/packages/ml/error_utils/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "@kbn/ml-error-utils",
"private": true,
"version": "1.0.0",
"license": "Elastic License 2.0"
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@

import Boom from '@hapi/boom';

import { extractErrorMessage, MLHttpFetchError, EsErrorBody } from '.';
import { extractErrorMessage } from './process_errors';
import { type MLHttpFetchError, type EsErrorBody } from './types';

describe('ML - error message utils', () => {
describe('extractErrorMessage', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,19 @@ import {
isMLResponseError,
} from './types';

/**
* Extract properties of the error object from within the response error
* coming from Kibana, Elasticsearch, and our own ML messages.
*
* @param {ErrorType} error
* @returns {MLErrorObject}
*/
export const extractErrorProperties = (error: ErrorType): MLErrorObject => {
// extract properties of the error object from within the response error
// coming from Kibana, Elasticsearch, and our own ML messages

// some responses contain raw es errors as part of a bulk response
// e.g. if some jobs fail the action in a bulk request
if (isEsErrorBody(error)) {
return {
message: error.error.reason,
message: error.error.reason ?? '',
statusCode: error.status,
fullError: error,
};
Expand Down Expand Up @@ -79,7 +83,7 @@ export const extractErrorProperties = (error: ErrorType): MLErrorObject => {
typeof error.body.attributes.body.error.root_cause[0] === 'object' &&
isPopulatedObject(error.body.attributes.body.error.root_cause[0], ['script'])
) {
errObj.causedBy = error.body.attributes.body.error.root_cause[0].script;
errObj.causedBy = error.body.attributes.body.error.root_cause[0].script as string;
errObj.message += `: '${error.body.attributes.body.error.root_cause[0].script}'`;
}
return errObj;
Expand All @@ -103,8 +107,14 @@ export const extractErrorProperties = (error: ErrorType): MLErrorObject => {
};
};

/**
* Extract only the error message within the response error
* coming from Kibana, Elasticsearch, and our own ML messages.
*
* @param {ErrorType} error
* @returns {string}
*/
export const extractErrorMessage = (error: ErrorType): string => {
// extract only the error message within the response error coming from Kibana, Elasticsearch, and our own ML messages
const errorObj = extractErrorProperties(error);
return errorObj.message;
};
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,22 @@

import { MLErrorObject, ErrorType } from './types';

/**
* ML Request Failure
*
* @export
* @class MLRequestFailure
* @typedef {MLRequestFailure}
* @extends {Error}
*/
export class MLRequestFailure extends Error {
/**
* Creates an instance of MLRequestFailure.
*
* @constructor
* @param {MLErrorObject} error
* @param {ErrorType} resp
*/
constructor(error: MLErrorObject, resp: ErrorType) {
super(error.message);
Object.setPrototypeOf(this, new.target.prototype);
Expand Down
196 changes: 196 additions & 0 deletions x-pack/packages/ml/error_utils/src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import type Boom from '@hapi/boom';

import * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';

import type { IHttpFetchError } from '@kbn/core-http-browser';
import { isPopulatedObject } from '@kbn/ml-is-populated-object';

/**
* Short hand type of estypes.ErrorCause.
* @typedef {EsErrorRootCause}
*/
export type EsErrorRootCause = estypes.ErrorCause;

/**
* Short hand type of estypes.ErrorResponseBase.
* @typedef {EsErrorBody}
*/
export type EsErrorBody = estypes.ErrorResponseBase;

/**
* ML Response error
* @export
* @interface MLResponseError
* @typedef {MLResponseError}
*/
export interface MLResponseError {
/**
* statusCode
* @type {number}
*/
statusCode: number;
/**
* error
* @type {string}
*/
error: string;
/**
* message
* @type {string}
*/
message: string;
/**
* Optional attributes
* @type {?{
body: EsErrorBody;
}}
*/
attributes?: {
body: EsErrorBody;
};
}

/**
* Interface holding error message
* @export
* @interface ErrorMessage
* @typedef {ErrorMessage}
*/
export interface ErrorMessage {
/**
* message
* @type {string}
*/
message: string;
}

/**
* To be used for client side errors related to search query bars.
*/
export interface QueryErrorMessage extends ErrorMessage {
/**
* query
* @type {string}
*/
query: string;
}

/**
* ML Error Object
* @export
* @interface MLErrorObject
* @typedef {MLErrorObject}
*/
export interface MLErrorObject {
/**
* Optional causedBy
* @type {?string}
*/
causedBy?: string;
/**
* message
* @type {string}
*/
message: string;
/**
* Optional statusCode
* @type {?number}
*/
statusCode?: number;
/**
* Optional fullError
* @type {?EsErrorBody}
*/
fullError?: EsErrorBody;
}

/**
* MLHttpFetchErrorBase
* @export
* @interface MLHttpFetchErrorBase
* @typedef {MLHttpFetchErrorBase}
* @template T
* @extends {IHttpFetchError<T>}
*/
export interface MLHttpFetchErrorBase<T> extends IHttpFetchError<T> {
/**
* body
* @type {T}
*/
body: T;
}

/**
* MLHttpFetchError
* @export
* @typedef {MLHttpFetchError}
*/
export type MLHttpFetchError = MLHttpFetchErrorBase<MLResponseError>;

/**
* Union type of error types
* @export
* @typedef {ErrorType}
*/
export type ErrorType = MLHttpFetchError | EsErrorBody | Boom.Boom | string | undefined;

/**
* Type guard to check if error is of type EsErrorBody
* @export
* @param {unknown} error
* @returns {error is EsErrorBody}
*/
export function isEsErrorBody(error: unknown): error is EsErrorBody {
return isPopulatedObject(error, ['error']) && isPopulatedObject(error.error, ['reason']);
}

/**
* Type guard to check if error is a string.
* @export
* @param {unknown} error
* @returns {error is string}
*/
export function isErrorString(error: unknown): error is string {
return typeof error === 'string';
}

/**
* Type guard to check if error is of type ErrorMessage.
* @export
* @param {unknown} error
* @returns {error is ErrorMessage}
*/
export function isErrorMessage(error: unknown): error is ErrorMessage {
return isPopulatedObject(error, ['message']) && typeof error.message === 'string';
}

/**
* Type guard to check if error is of type MLResponseError.
* @export
* @param {unknown} error
* @returns {error is MLResponseError}
*/
export function isMLResponseError(error: unknown): error is MLResponseError {
return (
isPopulatedObject(error, ['body']) &&
isPopulatedObject(error.body, ['message']) &&
'message' in error.body
);
}

/**
* Type guard to check if error is of type Boom.
* @export
* @param {unknown} error
* @returns {error is Boom.Boom}
*/
export function isBoomError(error: unknown): error is Boom.Boom {
return isPopulatedObject(error, ['isBoom']) && error.isBoom === true;
}
22 changes: 22 additions & 0 deletions x-pack/packages/ml/error_utils/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"extends": "../../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "target/types",
"types": [
"jest",
"node",
"react"
]
},
"include": [
"**/*.ts",
"**/*.tsx",
],
"exclude": [
"target/**/*"
],
"kbn_references": [
"@kbn/ml-is-populated-object",
"@kbn/core-http-browser",
]
}
Loading

0 comments on commit d6d933a

Please sign in to comment.