Skip to content

Commit

Permalink
[APM] Wrap Elasticsearch client errors (#91125) (#91608)
Browse files Browse the repository at this point in the history
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>

Co-authored-by: Dario Gieselaar <dario.gieselaar@elastic.co>
  • Loading branch information
kibanamachine and dgieselaar authored Feb 17, 2021
1 parent 8ffca46 commit 46b73b5
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
*/

import { ElasticsearchClient, Logger } from 'kibana/server';
import { unwrapEsResponse } from '../../../../../observability/server';
import { ResponseError } from '@elastic/elasticsearch/lib/errors';
import {
unwrapEsResponse,
WrappedElasticsearchClientError,
} from '../../../../../observability/server';
import { rangeFilter } from '../../../../common/utils/range_filter';
import { ESSearchResponse } from '../../../../../../typings/elasticsearch';
import { Annotation as ESAnnotation } from '../../../../../observability/common/annotations';
Expand Down Expand Up @@ -72,15 +76,22 @@ export function getStoredAnnotations({
} catch (error) {
// index is only created when an annotation has been indexed,
// so we should handle this error gracefully
if (error.body?.error?.type === 'index_not_found_exception') {
return [];
}
if (
error instanceof WrappedElasticsearchClientError &&
error.originalError instanceof ResponseError
) {
const type = error.originalError.body.error.type;

if (type === 'index_not_found_exception') {
return [];
}

if (error.body?.error?.type === 'security_exception') {
logger.warn(
`Unable to get stored annotations due to a security exception. Please make sure that the user has 'indices:data/read/search' permissions for ${annotationsClient.index}`
);
return [];
if (type === 'security_exception') {
logger.warn(
`Unable to get stored annotations due to a security exception. Please make sure that the user has 'indices:data/read/search' permissions for ${annotationsClient.index}`
);
return [];
}
}

throw error;
Expand Down
3 changes: 2 additions & 1 deletion x-pack/plugins/observability/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { PluginInitializerContext } from 'src/core/server';
import { ObservabilityPlugin, ObservabilityPluginSetup } from './plugin';
import { createOrUpdateIndex, MappingsDefinition } from './utils/create_or_update_index';
import { ScopedAnnotationsClient } from './lib/annotations/bootstrap_annotations';
import { unwrapEsResponse } from './utils/unwrap_es_response';
import { unwrapEsResponse, WrappedElasticsearchClientError } from './utils/unwrap_es_response';

export const config = {
schema: schema.object({
Expand All @@ -33,4 +33,5 @@ export {
ObservabilityPluginSetup,
ScopedAnnotationsClient,
unwrapEsResponse,
WrappedElasticsearchClientError,
};
38 changes: 36 additions & 2 deletions x-pack/plugins/observability/server/utils/unwrap_es_response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,45 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { ElasticsearchClientError, ResponseError } from '@elastic/elasticsearch/lib/errors';
import type { UnwrapPromise } from '@kbn/utility-types';
import { inspect } from 'util';

export class WrappedElasticsearchClientError extends Error {
originalError: ElasticsearchClientError;
constructor(originalError: ElasticsearchClientError) {
super(originalError.message);

const stack = this.stack;

this.originalError = originalError;

if (originalError instanceof ResponseError) {
// make sure ES response body is visible when logged to the console
// @ts-expect-error
this.stack = {
valueOf() {
const value = stack?.valueOf() ?? '';
return value;
},
toString() {
const value =
stack?.toString() +
`\nResponse: ${inspect(originalError.meta.body, { depth: null })}\n`;
return value;
},
};
}
}
}

export function unwrapEsResponse<T extends Promise<{ body: any }>>(
responsePromise: T
): Promise<UnwrapPromise<T>['body']> {
return responsePromise.then((res) => res.body);
return responsePromise
.then((res) => res.body)
.catch((err) => {
// make sure stacktrace is relative to where client was called
throw new WrappedElasticsearchClientError(err);
});
}

0 comments on commit 46b73b5

Please sign in to comment.