diff --git a/src/core/server/elasticsearch/client/configure_client.ts b/src/core/server/elasticsearch/client/configure_client.ts index a295d2a53d1a7..3800858d6a601 100644 --- a/src/core/server/elasticsearch/client/configure_client.ts +++ b/src/core/server/elasticsearch/client/configure_client.ts @@ -15,9 +15,13 @@ import type { import { Logger } from '../../logging'; import { parseClientOptions, ElasticsearchClientConfig } from './client_config'; import { instrumentEsQueryAndDeprecationLogger } from './log_query_and_deprecation'; +import { patchElasticsearchClient } from './patch_client'; const noop = () => undefined; +// Apply ES client patches on module load +patchElasticsearchClient(); + export const configureClient = ( config: ElasticsearchClientConfig, { diff --git a/src/core/server/elasticsearch/client/patch_client.ts b/src/core/server/elasticsearch/client/patch_client.ts new file mode 100644 index 0000000000000..75ea5db91b2e3 --- /dev/null +++ b/src/core/server/elasticsearch/client/patch_client.ts @@ -0,0 +1,20 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { errors } from '@elastic/elasticsearch'; + +export const patchElasticsearchClient = () => { + const baseErrorPrototype = errors.ElasticsearchClientError.prototype; + // @ts-expect-error + baseErrorPrototype.toJSON = function () { + return { + name: this.name, + message: this.message, + }; + }; +}; diff --git a/src/core/server/elasticsearch/integration_tests/errors.test.ts b/src/core/server/elasticsearch/integration_tests/errors.test.ts new file mode 100644 index 0000000000000..42508050ffa79 --- /dev/null +++ b/src/core/server/elasticsearch/integration_tests/errors.test.ts @@ -0,0 +1,49 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { + createTestServers, + type TestElasticsearchUtils, + type TestKibanaUtils, +} from '../../../test_helpers/kbn_server'; + +describe('elasticsearch clients errors', () => { + let esServer: TestElasticsearchUtils; + let kibanaServer: TestKibanaUtils; + + beforeAll(async () => { + const { startES, startKibana } = createTestServers({ + adjustTimeout: jest.setTimeout, + }); + + esServer = await startES(); + kibanaServer = await startKibana(); + }); + + afterAll(async () => { + await kibanaServer.stop(); + await esServer.stop(); + }); + + it('has the proper JSON representation', async () => { + const esClient = kibanaServer.coreStart.elasticsearch.client.asInternalUser; + + try { + await esClient.search({ + index: '.kibana', + // @ts-expect-error yes this is invalid + query: { someInvalidQuery: { foo: 'bar' } }, + }); + expect('should have thrown').toEqual('but it did not'); + } catch (e) { + const stringifiedError = JSON.stringify(e); + expect(stringifiedError).not.toContain('headers'); + expect(stringifiedError).not.toContain('authorization'); + } + }); +});