[Vega] Better error explanation for EsErrors and inspector now showing error responses (#112634)

* 🐛 Fix EsError not showing info

* 🐛 Record error response in the inspector

* 🏷️ Fix type issue

* 👌 Integrate feedback

* 👌 Integrated latest feedback

* 👌 i18n unknwon message

* 👌 Integrate feedback

* 🐛 Fix syntax error

* 🏷️ Fix type issue

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Marco Liberati 2021-09-23 10:54:31 +02:00 committed by GitHub
parent fa624567d6
commit 9dcacf77f7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 58 additions and 6 deletions

View file

@ -25,4 +25,31 @@ describe('EsError', () => {
expect(typeof esError.attributes).toEqual('object');
expect(esError.attributes).toEqual(error.attributes);
});
it('contains some explanation of the error in the message', () => {
// error taken from Vega's issue
const error = {
message:
'x_content_parse_exception: [x_content_parse_exception] Reason: [1:78] [date_histogram] failed to parse field [calendar_interval]',
statusCode: 400,
attributes: {
root_cause: [
{
type: 'x_content_parse_exception',
reason: '[1:78] [date_histogram] failed to parse field [calendar_interval]',
},
],
type: 'x_content_parse_exception',
reason: '[1:78] [date_histogram] failed to parse field [calendar_interval]',
caused_by: {
type: 'illegal_argument_exception',
reason: 'The supplied interval [2q] could not be parsed as a calendar interval.',
},
},
} as any;
const esError = new EsError(error);
expect(esError.message).toEqual(
'EsError: The supplied interval [2q] could not be parsed as a calendar interval.'
);
});
});

View file

@ -9,6 +9,7 @@
import React from 'react';
import { EuiCodeBlock, EuiSpacer } from '@elastic/eui';
import { ApplicationStart } from 'kibana/public';
import { i18n } from '@kbn/i18n';
import { KbnError } from '../../../../kibana_utils/common';
import { IEsError } from './types';
import { getRootCause } from './utils';
@ -17,7 +18,12 @@ export class EsError extends KbnError {
readonly attributes: IEsError['attributes'];
constructor(protected readonly err: IEsError) {
super('EsError');
super(
`EsError: ${
getRootCause(err)?.reason ||
i18n.translate('data.esError.unknownRootCause', { defaultMessage: 'unknown' })
}`
);
this.attributes = err.attributes;
}

View file

@ -5,8 +5,8 @@
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { FailedShard } from './types';
import type { ErrorCause } from '@elastic/elasticsearch/api/types';
import type { FailedShard, Reason } from './types';
import { KibanaServerError } from '../../../../kibana_utils/common';
export function getFailedShards(err: KibanaServerError<any>): FailedShard | undefined {
@ -15,6 +15,16 @@ export function getFailedShards(err: KibanaServerError<any>): FailedShard | unde
return failedShards ? failedShards[0] : undefined;
}
export function getRootCause(err: KibanaServerError) {
return getFailedShards(err)?.reason;
function getNestedCause(err: KibanaServerError | ErrorCause): Reason {
const attr = ((err as KibanaServerError).attributes || err) as ErrorCause;
const { type, reason, caused_by: causedBy } = attr;
if (causedBy) {
return getNestedCause(causedBy);
}
return { type, reason };
}
export function getRootCause(err: KibanaServerError) {
// Give shard failures priority, then try to get the error navigating nested objects
return getFailedShards(err)?.reason || getNestedCause(err);
}

View file

@ -95,7 +95,16 @@ export class SearchAPI {
}
)
.pipe(
tap((data) => this.inspectSearchResult(data, requestResponders[requestId])),
tap(
(data) => this.inspectSearchResult(data, requestResponders[requestId]),
(err) =>
this.inspectSearchResult(
{
rawResponse: err?.err,
},
requestResponders[requestId]
)
),
map((data) => ({
name: requestId,
rawResponse: data.rawResponse,