[Partial Results] Move inspector adapter integration into search source (#96241)

* Move inspector adapter integration into search source

* docs and ts

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Liza Katz 2021-04-09 18:29:15 +03:00 committed by GitHub
parent dfaf3ac8f5
commit b099a0bba2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
29 changed files with 205 additions and 234 deletions

View file

@ -19,6 +19,7 @@ export interface ISearchOptions
| [isRestore](./kibana-plugin-plugins-data-public.isearchoptions.isrestore.md) | <code>boolean</code> | Whether the session is restored (i.e. search requests should re-use the stored search IDs, rather than starting from scratch) |
| [isStored](./kibana-plugin-plugins-data-public.isearchoptions.isstored.md) | <code>boolean</code> | Whether the session is already saved (i.e. sent to background) |
| [legacyHitsTotal](./kibana-plugin-plugins-data-public.isearchoptions.legacyhitstotal.md) | <code>boolean</code> | Request the legacy format for the total number of hits. If sending <code>rest_total_hits_as_int</code> to something other than <code>true</code>, this should be set to <code>false</code>. |
| [requestResponder](./kibana-plugin-plugins-data-public.isearchoptions.requestresponder.md) | <code>RequestResponder</code> | |
| [sessionId](./kibana-plugin-plugins-data-public.isearchoptions.sessionid.md) | <code>string</code> | A session ID, grouping multiple search requests into a single session. |
| [strategy](./kibana-plugin-plugins-data-public.isearchoptions.strategy.md) | <code>string</code> | Use this option to force using a specific server side search strategy. Leave empty to use the default strategy. |

View file

@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) &gt; [ISearchOptions](./kibana-plugin-plugins-data-public.isearchoptions.md) &gt; [requestResponder](./kibana-plugin-plugins-data-public.isearchoptions.requestresponder.md)
## ISearchOptions.requestResponder property
<b>Signature:</b>
```typescript
requestResponder?: RequestResponder;
```

View file

@ -53,7 +53,6 @@ search: {
timeRange: import("../common").TimeRange | undefined;
} | undefined;
};
getRequestInspectorStats: typeof getRequestInspectorStats;
getResponseInspectorStats: typeof getResponseInspectorStats;
tabifyAggResponse: typeof tabifyAggResponse;
tabifyGetColumns: typeof tabifyGetColumns;

View file

@ -9,9 +9,9 @@ Returns body contents of the search request, often referred as query DSL.
<b>Signature:</b>
```typescript
getSearchRequestBody(): Promise<any>;
getSearchRequestBody(): any;
```
<b>Returns:</b>
`Promise<any>`
`any`

View file

@ -19,6 +19,7 @@ export interface ISearchOptions
| [isRestore](./kibana-plugin-plugins-data-server.isearchoptions.isrestore.md) | <code>boolean</code> | Whether the session is restored (i.e. search requests should re-use the stored search IDs, rather than starting from scratch) |
| [isStored](./kibana-plugin-plugins-data-server.isearchoptions.isstored.md) | <code>boolean</code> | Whether the session is already saved (i.e. sent to background) |
| [legacyHitsTotal](./kibana-plugin-plugins-data-server.isearchoptions.legacyhitstotal.md) | <code>boolean</code> | Request the legacy format for the total number of hits. If sending <code>rest_total_hits_as_int</code> to something other than <code>true</code>, this should be set to <code>false</code>. |
| [requestResponder](./kibana-plugin-plugins-data-server.isearchoptions.requestresponder.md) | <code>RequestResponder</code> | |
| [sessionId](./kibana-plugin-plugins-data-server.isearchoptions.sessionid.md) | <code>string</code> | A session ID, grouping multiple search requests into a single session. |
| [strategy](./kibana-plugin-plugins-data-server.isearchoptions.strategy.md) | <code>string</code> | Use this option to force using a specific server side search strategy. Leave empty to use the default strategy. |

View file

@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) &gt; [ISearchOptions](./kibana-plugin-plugins-data-server.isearchoptions.md) &gt; [requestResponder](./kibana-plugin-plugins-data-server.isearchoptions.requestresponder.md)
## ISearchOptions.requestResponder property
<b>Signature:</b>
```typescript
requestResponder?: RequestResponder;
```

View file

@ -36,8 +36,6 @@ search: {
toAbsoluteDates: typeof toAbsoluteDates;
calcAutoIntervalLessThan: typeof calcAutoIntervalLessThan;
};
getRequestInspectorStats: typeof getRequestInspectorStats;
getResponseInspectorStats: typeof getResponseInspectorStats;
tabifyAggResponse: typeof tabifyAggResponse;
tabifyGetColumns: typeof tabifyGetColumns;
}

View file

@ -204,8 +204,8 @@ export const SearchExamplesApp = ({
});
}
setRequest(await searchSource.getSearchRequestBody());
const res = await searchSource.fetch();
setRequest(searchSource.getSearchRequestBody());
const res = await searchSource.fetch$().toPromise();
setResponse(res);
const message = <EuiText>Searched {res.hits.total} documents.</EuiText>;

View file

@ -8,7 +8,6 @@
import { noop } from 'lodash';
import { i18n } from '@kbn/i18n';
import type { RequestAdapter } from 'src/plugins/inspector/common';
import { BucketAggType, IBucketAggConfig } from './bucket_agg_type';
import { BUCKET_TYPES } from './bucket_agg_types';
@ -21,7 +20,6 @@ import { aggTermsFnName } from './terms_fn';
import { AggConfigSerialized, BaseAggParams } from '../types';
import { KBN_FIELD_TYPES } from '../../../../common';
import { getRequestInspectorStats, getResponseInspectorStats } from '../../expressions';
import {
buildOtherBucketAgg,
@ -103,36 +101,28 @@ export const getTermsBucketAgg = () =>
nestedSearchSource.setField('aggs', filterAgg);
let request: ReturnType<RequestAdapter['start']> | undefined;
if (inspectorRequestAdapter) {
request = inspectorRequestAdapter.start(
i18n.translate('data.search.aggs.buckets.terms.otherBucketTitle', {
defaultMessage: 'Other bucket',
const requestResponder = inspectorRequestAdapter?.start(
i18n.translate('data.search.aggs.buckets.terms.otherBucketTitle', {
defaultMessage: 'Other bucket',
}),
{
description: i18n.translate('data.search.aggs.buckets.terms.otherBucketDescription', {
defaultMessage:
'This request counts the number of documents that fall ' +
'outside the criterion of the data buckets.',
}),
{
description: i18n.translate('data.search.aggs.buckets.terms.otherBucketDescription', {
defaultMessage:
'This request counts the number of documents that fall ' +
'outside the criterion of the data buckets.',
}),
searchSessionId,
}
);
nestedSearchSource.getSearchRequestBody().then((body) => {
request!.json(body);
});
request.stats(getRequestInspectorStats(nestedSearchSource));
}
searchSessionId,
}
);
const response = await nestedSearchSource
.fetch$({
abortSignal,
sessionId: searchSessionId,
requestResponder,
})
.toPromise();
const response = await nestedSearchSource.fetch({
abortSignal,
sessionId: searchSessionId,
});
if (request) {
request
.stats(getResponseInspectorStats(response, nestedSearchSource))
.ok({ json: response });
}
resp = mergeOtherBucketAggResponse(aggConfigs, resp, response, aggConfig, filterAgg());
}
if (aggConfig.params.missingBucket) {

View file

@ -133,7 +133,7 @@ describe('esaggs expression function - public', () => {
test('calls searchSource.fetch', async () => {
await handleRequest(mockParams);
const searchSource = await mockParams.searchSourceService.create();
expect(searchSource.fetch).toHaveBeenCalledWith({
expect(searchSource.fetch$).toHaveBeenCalledWith({
abortSignal: mockParams.abortSignal,
sessionId: mockParams.searchSessionId,
});

View file

@ -22,7 +22,6 @@ import {
import { IAggConfigs } from '../../aggs';
import { ISearchStartSearchSource } from '../../search_source';
import { tabifyAggResponse } from '../../tabify';
import { getRequestInspectorStats, getResponseInspectorStats } from '../utils';
/** @internal */
export interface RequestHandlerParams {
@ -41,6 +40,21 @@ export interface RequestHandlerParams {
getNow?: () => Date;
}
function getRequestMainResponder(inspectorAdapters: Adapters, searchSessionId?: string) {
return inspectorAdapters.requests?.start(
i18n.translate('data.functions.esaggs.inspector.dataRequest.title', {
defaultMessage: 'Data',
}),
{
description: i18n.translate('data.functions.esaggs.inspector.dataRequest.description', {
defaultMessage:
'This request queries Elasticsearch to fetch the data for the visualization.',
}),
searchSessionId,
}
);
}
export const handleRequest = async ({
abortSignal,
aggs,
@ -113,52 +127,19 @@ export const handleRequest = async ({
requestSearchSource.setField('filter', filters);
requestSearchSource.setField('query', query);
let request;
if (inspectorAdapters.requests) {
inspectorAdapters.requests.reset();
request = inspectorAdapters.requests.start(
i18n.translate('data.functions.esaggs.inspector.dataRequest.title', {
defaultMessage: 'Data',
}),
{
description: i18n.translate('data.functions.esaggs.inspector.dataRequest.description', {
defaultMessage:
'This request queries Elasticsearch to fetch the data for the visualization.',
}),
searchSessionId,
}
);
request.stats(getRequestInspectorStats(requestSearchSource));
}
inspectorAdapters.requests?.reset();
const requestResponder = getRequestMainResponder(inspectorAdapters, searchSessionId);
try {
const response = await requestSearchSource.fetch({
abortSignal,
sessionId: searchSessionId,
});
if (request) {
request.stats(getResponseInspectorStats(response, searchSource)).ok({ json: response });
}
(searchSource as any).rawResponse = response;
} catch (e) {
// Log any error during request to the inspector
if (request) {
request.error({ json: e });
}
throw e;
} finally {
// Add the request body no matter if things went fine or not
if (request) {
request.json(await requestSearchSource.getSearchRequestBody());
}
}
const response$ = await requestSearchSource.fetch$({
abortSignal,
sessionId: searchSessionId,
requestResponder,
});
// Note that rawResponse is not deeply cloned here, so downstream applications using courier
// must take care not to mutate it, or it could have unintended side effects, e.g. displaying
// response data incorrectly in the inspector.
let response = (searchSource as any).rawResponse;
let response = await response$.toPromise();
for (const agg of aggs.aggs) {
if (agg.enabled && typeof agg.type.postFlightRequest === 'function') {
response = await agg.type.postFlightRequest(

View file

@ -6,5 +6,4 @@
* Side Public License, v 1.
*/
export * from './courier_inspector_stats';
export * from './function_wrapper';

View file

@ -10,6 +10,7 @@ export { createSearchSource } from './create_search_source';
export { injectReferences } from './inject_references';
export { extractReferences } from './extract_references';
export { parseSearchSourceJSON } from './parse_json';
export { getResponseInspectorStats } from './inspect';
export * from './fetch';
export * from './legacy';
export * from './search_source';

View file

@ -0,0 +1,9 @@
/*
* 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.
*/
export * from './inspector_stats';

View file

@ -15,8 +15,8 @@
import { i18n } from '@kbn/i18n';
import type { estypes } from '@elastic/elasticsearch';
import { ISearchSource } from 'src/plugins/data/public';
import { RequestStatistics } from 'src/plugins/inspector/common';
import type { ISearchSource } from 'src/plugins/data/public';
import type { RequestStatistics } from 'src/plugins/inspector/common';
/** @public */
export function getRequestInspectorStats(searchSource: ISearchSource) {

View file

@ -125,7 +125,7 @@ describe('SearchSource', () => {
}),
} as unknown) as IndexPattern);
const request = await searchSource.getSearchRequestBody();
const request = searchSource.getSearchRequestBody();
expect(request.stored_fields).toEqual(['hello']);
expect(request.script_fields).toEqual({ world: {} });
expect(request.fields).toEqual(['@timestamp']);
@ -144,7 +144,7 @@ describe('SearchSource', () => {
searchSource.setField('fields', ['@timestamp']);
searchSource.setField('fieldsFromSource', ['foo']);
const request = await searchSource.getSearchRequestBody();
const request = searchSource.getSearchRequestBody();
expect(request).not.toHaveProperty('docvalue_fields');
});
@ -160,7 +160,7 @@ describe('SearchSource', () => {
// @ts-expect-error TS won't like using this field name, but technically it's possible.
searchSource.setField('docvalue_fields', ['world']);
const request = await searchSource.getSearchRequestBody();
const request = searchSource.getSearchRequestBody();
expect(request).toHaveProperty('docvalue_fields');
expect(request.docvalue_fields).toEqual(['world']);
});
@ -179,7 +179,7 @@ describe('SearchSource', () => {
searchSource.setField('fields', ['c']);
searchSource.setField('fieldsFromSource', ['a', 'b', 'd']);
const request = await searchSource.getSearchRequestBody();
const request = searchSource.getSearchRequestBody();
expect(request).toHaveProperty('docvalue_fields');
expect(request._source.includes).toEqual(['c', 'a', 'b', 'd']);
expect(request.docvalue_fields).toEqual([{ field: 'b', format: 'date_time' }]);
@ -202,7 +202,7 @@ describe('SearchSource', () => {
} as unknown) as IndexPattern);
searchSource.setField('fields', [{ field: 'hello', format: 'strict_date_time' }]);
const request = await searchSource.getSearchRequestBody();
const request = searchSource.getSearchRequestBody();
expect(request).toHaveProperty('fields');
expect(request.fields).toEqual([{ field: 'hello', format: 'strict_date_time' }]);
});
@ -218,7 +218,7 @@ describe('SearchSource', () => {
} as unknown) as IndexPattern);
searchSource.setField('fields', ['hello']);
const request = await searchSource.getSearchRequestBody();
const request = searchSource.getSearchRequestBody();
expect(request).toHaveProperty('fields');
expect(request.fields).toEqual([{ field: 'hello', format: 'date_time' }]);
});
@ -239,7 +239,7 @@ describe('SearchSource', () => {
} as unknown) as IndexPattern);
searchSource.setField('fields', [{ field: 'hello', a: 'a', c: 'c' }]);
const request = await searchSource.getSearchRequestBody();
const request = searchSource.getSearchRequestBody();
expect(request).toHaveProperty('fields');
expect(request.fields).toEqual([
{ field: 'hello', format: 'date_time', a: 'a', b: 'test', c: 'c' },
@ -258,7 +258,7 @@ describe('SearchSource', () => {
// @ts-expect-error TS won't like using this field name, but technically it's possible.
searchSource.setField('script_fields', { world: {} });
const request = await searchSource.getSearchRequestBody();
const request = searchSource.getSearchRequestBody();
expect(request).toHaveProperty('script_fields');
expect(request.script_fields).toEqual({
hello: {},
@ -277,7 +277,7 @@ describe('SearchSource', () => {
} as unknown) as IndexPattern);
searchSource.setField('fields', ['hello', 'a', { field: 'c' }]);
const request = await searchSource.getSearchRequestBody();
const request = searchSource.getSearchRequestBody();
expect(request.script_fields).toEqual({ hello: {} });
expect(request.stored_fields).toEqual(['a', 'c']);
});
@ -293,7 +293,7 @@ describe('SearchSource', () => {
} as unknown) as IndexPattern);
searchSource.setField('fields', ['hello', 'a', { foo: 'c' }]);
const request = await searchSource.getSearchRequestBody();
const request = searchSource.getSearchRequestBody();
expect(request.script_fields).toEqual({ hello: {} });
expect(request.stored_fields).toEqual(['a']);
});
@ -309,23 +309,23 @@ describe('SearchSource', () => {
} as unknown) as IndexPattern);
searchSource.setField('fieldsFromSource', ['hello', 'a']);
const request = await searchSource.getSearchRequestBody();
const request = searchSource.getSearchRequestBody();
expect(request.script_fields).toEqual({ hello: {} });
expect(request.stored_fields).toEqual(['a']);
});
test('defaults to * for stored fields when no fields are provided', async () => {
const requestA = await searchSource.getSearchRequestBody();
const requestA = searchSource.getSearchRequestBody();
expect(requestA.stored_fields).toEqual(['*']);
searchSource.setField('fields', ['*']);
const requestB = await searchSource.getSearchRequestBody();
const requestB = searchSource.getSearchRequestBody();
expect(requestB.stored_fields).toEqual(['*']);
});
test('defaults to * for stored fields when no fields are provided with fieldsFromSource', async () => {
searchSource.setField('fieldsFromSource', ['*']);
const request = await searchSource.getSearchRequestBody();
const request = searchSource.getSearchRequestBody();
expect(request.stored_fields).toEqual(['*']);
});
});
@ -343,7 +343,7 @@ describe('SearchSource', () => {
// @ts-expect-error Typings for excludes filters need to be fixed.
searchSource.setField('source', { excludes: ['exclude-*'] });
const request = await searchSource.getSearchRequestBody();
const request = searchSource.getSearchRequestBody();
expect(request.fields).toEqual(['@timestamp']);
});
@ -357,7 +357,7 @@ describe('SearchSource', () => {
}),
} as unknown) as IndexPattern);
const request = await searchSource.getSearchRequestBody();
const request = searchSource.getSearchRequestBody();
expect(request.fields).toEqual(['@timestamp']);
});
@ -372,7 +372,7 @@ describe('SearchSource', () => {
} as unknown) as IndexPattern);
searchSource.setField('fields', ['hello']);
const request = await searchSource.getSearchRequestBody();
const request = searchSource.getSearchRequestBody();
expect(request.script_fields).toEqual({ hello: {} });
});
@ -387,7 +387,7 @@ describe('SearchSource', () => {
} as unknown) as IndexPattern);
searchSource.setField('fields', ['hello', 'foo']);
const request = await searchSource.getSearchRequestBody();
const request = searchSource.getSearchRequestBody();
expect(request.fields).toEqual(['hello']);
});
@ -402,7 +402,7 @@ describe('SearchSource', () => {
} as unknown) as IndexPattern);
searchSource.setField('fields', ['*']);
const request = await searchSource.getSearchRequestBody();
const request = searchSource.getSearchRequestBody();
expect(request.fields).toEqual([{ field: 'field1' }, { field: 'field2' }]);
});
@ -417,7 +417,7 @@ describe('SearchSource', () => {
} as unknown) as IndexPattern);
searchSource.setField('fields', [{ field: '*', include_unmapped: 'true' }]);
const request = await searchSource.getSearchRequestBody();
const request = searchSource.getSearchRequestBody();
expect(request.fields).toEqual([{ field: 'field1' }, { field: 'field2' }]);
});
@ -432,7 +432,7 @@ describe('SearchSource', () => {
} as unknown) as IndexPattern);
searchSource.setField('fields', ['timestamp', '*']);
const request = await searchSource.getSearchRequestBody();
const request = searchSource.getSearchRequestBody();
expect(request.script_fields).toEqual({ hello: {}, world: {} });
});
});
@ -455,7 +455,7 @@ describe('SearchSource', () => {
'bar-b',
]);
const request = await searchSource.getSearchRequestBody();
const request = searchSource.getSearchRequestBody();
expect(request._source).toEqual({
includes: ['@timestamp', 'bar-b'],
});
@ -473,7 +473,7 @@ describe('SearchSource', () => {
} as unknown) as IndexPattern);
searchSource.setField('fields', ['hello', '@timestamp', 'foo-a', 'bar']);
const request = await searchSource.getSearchRequestBody();
const request = searchSource.getSearchRequestBody();
expect(request.fields).toEqual(['hello', '@timestamp', 'bar', 'date']);
expect(request.script_fields).toEqual({ hello: {} });
expect(request.stored_fields).toEqual(['@timestamp', 'bar']);
@ -498,7 +498,7 @@ describe('SearchSource', () => {
'runtime_field',
]);
const request = await searchSource.getSearchRequestBody();
const request = searchSource.getSearchRequestBody();
expect(request._source).toEqual({
includes: ['@timestamp', 'bar'],
});
@ -520,7 +520,7 @@ describe('SearchSource', () => {
searchSource.setField('fields', ['hello', '@timestamp', 'foo-a', 'bar']);
searchSource.setField('fieldsFromSource', ['foo-b', 'date', 'baz']);
const request = await searchSource.getSearchRequestBody();
const request = searchSource.getSearchRequestBody();
expect(request._source).toEqual({
includes: ['@timestamp', 'bar', 'date', 'baz'],
});
@ -546,7 +546,7 @@ describe('SearchSource', () => {
} as unknown) as IndexPattern);
searchSource.setField('fields', ['*']);
const request = await searchSource.getSearchRequestBody();
const request = searchSource.getSearchRequestBody();
expect(request.fields).toEqual([
'*',
{ field: '@timestamp', format: 'strict_date_optional_time_nanos' },
@ -574,7 +574,7 @@ describe('SearchSource', () => {
} as unknown) as IndexPattern);
searchSource.setField('fields', ['*']);
const request = await searchSource.getSearchRequestBody();
const request = searchSource.getSearchRequestBody();
expect(request.fields).toEqual([
{ field: 'foo-bar' },
{ field: 'field1' },
@ -592,14 +592,14 @@ describe('SearchSource', () => {
expect(searchSource.getField('source')).toBe(undefined);
searchSource.setField('index', indexPattern);
expect(searchSource.getField('index')).toBe(indexPattern);
const request = await searchSource.getSearchRequestBody();
const request = searchSource.getSearchRequestBody();
expect(request._source).toBe(mockSource);
});
test('removes created searchSource filter on removal', async () => {
searchSource.setField('index', indexPattern);
searchSource.setField('index', undefined);
const request = await searchSource.getSearchRequestBody();
const request = searchSource.getSearchRequestBody();
expect(request._source).toBe(undefined);
});
});
@ -609,7 +609,7 @@ describe('SearchSource', () => {
searchSource.setField('index', indexPattern);
searchSource.setField('index', indexPattern2);
expect(searchSource.getField('index')).toBe(indexPattern2);
const request = await searchSource.getSearchRequestBody();
const request = searchSource.getSearchRequestBody();
expect(request._source).toBe(mockSource2);
});
@ -617,7 +617,7 @@ describe('SearchSource', () => {
searchSource.setField('index', indexPattern);
searchSource.setField('index', indexPattern2);
searchSource.setField('index', undefined);
const request = await searchSource.getSearchRequestBody();
const request = searchSource.getSearchRequestBody();
expect(request._source).toBe(undefined);
});
});
@ -808,7 +808,7 @@ describe('SearchSource', () => {
docvalueFields: [],
}),
} as unknown) as IndexPattern);
const request = await searchSource.getSearchRequestBody();
const request = searchSource.getSearchRequestBody();
expect(request.stored_fields).toEqual(['geometry', 'prop1']);
expect(request.docvalue_fields).toEqual(['prop1']);
expect(request._source).toEqual(['geometry']);

View file

@ -60,7 +60,7 @@
import { setWith } from '@elastic/safer-lodash-set';
import { uniqueId, keyBy, pick, difference, isFunction, isEqual, uniqWith, isObject } from 'lodash';
import { map, switchMap, tap } from 'rxjs/operators';
import { catchError, finalize, map, switchMap, tap } from 'rxjs/operators';
import { defer, from } from 'rxjs';
import { normalizeSortRequest } from './normalize_sort_request';
import { fieldWildcardFilter } from '../../../../kibana_utils/common';
@ -73,6 +73,7 @@ import type {
SearchSourceFields,
} from './types';
import { FetchHandlers, RequestFailure, getSearchParamsFromRequest, SearchRequest } from './fetch';
import { getRequestInspectorStats, getResponseInspectorStats } from './inspect';
import { getEsQueryConfig, buildEsQuery, Filter, UI_SETTINGS } from '../../../common';
import { getHighlightRequest } from '../../../common/field_formats';
@ -256,6 +257,9 @@ export class SearchSource {
fetch$(options: ISearchOptions = {}) {
const { getConfig } = this.dependencies;
return defer(() => this.requestIsStarting(options)).pipe(
tap(() => {
options.requestResponder?.stats(getRequestInspectorStats(this));
}),
switchMap(() => {
const searchRequest = this.flatten();
this.history = [searchRequest];
@ -271,7 +275,17 @@ export class SearchSource {
// TODO: Remove casting when https://github.com/elastic/elasticsearch-js/issues/1287 is resolved
if ((response as any).error) {
throw new RequestFailure(null, response);
} else {
options.requestResponder?.stats(getResponseInspectorStats(response, this));
options.requestResponder?.ok({ json: response });
}
}),
catchError((e) => {
options.requestResponder?.error({ json: e });
throw e;
}),
finalize(() => {
options.requestResponder?.json(this.getSearchRequestBody());
})
);
}
@ -298,9 +312,8 @@ export class SearchSource {
/**
* Returns body contents of the search request, often referred as query DSL.
*/
async getSearchRequestBody() {
const searchRequest = await this.flatten();
return searchRequest.body;
getSearchRequestBody() {
return this.flatten().body;
}
/**

View file

@ -9,6 +9,7 @@
import { Observable } from 'rxjs';
import { IEsSearchRequest, IEsSearchResponse } from './es_search';
import { IndexPattern } from '..';
import type { RequestResponder } from '../../../inspector/common';
export type ISearchGeneric = <
SearchStrategyRequest extends IKibanaSearchRequest = IEsSearchRequest,
@ -118,6 +119,8 @@ export interface ISearchOptions {
*/
indexPattern?: IndexPattern;
requestResponder?: RequestResponder;
}
/**

View file

@ -314,8 +314,6 @@ import {
boundsDescendingRaw,
getNumberHistogramIntervalByDatatableColumn,
getDateHistogramMetaDataByDatatableColumn,
// expressions utils
getRequestInspectorStats,
getResponseInspectorStats,
// tabify
tabifyAggResponse,
@ -428,7 +426,6 @@ export const search = {
getNumberHistogramIntervalByDatatableColumn,
getDateHistogramMetaDataByDatatableColumn,
},
getRequestInspectorStats,
getResponseInspectorStats,
tabifyAggResponse,
tabifyGetColumns,

View file

@ -1676,6 +1676,10 @@ export interface ISearchOptions {
isRestore?: boolean;
isStored?: boolean;
legacyHitsTotal?: boolean;
// Warning: (ae-forgotten-export) The symbol "RequestResponder" needs to be exported by the entry point index.d.ts
//
// (undocumented)
requestResponder?: RequestResponder;
sessionId?: string;
strategy?: string;
}
@ -2298,7 +2302,6 @@ export const search: {
timeRange: import("../common").TimeRange | undefined;
} | undefined;
};
getRequestInspectorStats: typeof getRequestInspectorStats;
getResponseInspectorStats: typeof getResponseInspectorStats;
tabifyAggResponse: typeof tabifyAggResponse;
tabifyGetColumns: typeof tabifyGetColumns;
@ -2434,7 +2437,7 @@ export class SearchSource {
getId(): string;
getOwnField<K extends keyof SearchSourceFields>(field: K): SearchSourceFields[K];
getParent(): SearchSource | undefined;
getSearchRequestBody(): Promise<any>;
getSearchRequestBody(): any;
getSerializedFields(recurse?: boolean): SearchSourceFields;
// Warning: (ae-incompatible-release-tags) The symbol "history" is marked as @public, but its signature references "SearchRequest" which is marked as @internal
//
@ -2712,21 +2715,20 @@ export interface WaitUntilNextSessionCompletesOptions {
// src/plugins/data/public/index.ts:238:27 - (ae-forgotten-export) The symbol "validateIndexPattern" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/index.ts:238:27 - (ae-forgotten-export) The symbol "flattenHitWrapper" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/index.ts:238:27 - (ae-forgotten-export) The symbol "formatHitProvider" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/index.ts:406:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/index.ts:406:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/index.ts:406:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/index.ts:406:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/index.ts:408:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/index.ts:409:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/index.ts:418:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/index.ts:419:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/index.ts:420:1 - (ae-forgotten-export) The symbol "Ipv4Address" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/index.ts:421:1 - (ae-forgotten-export) The symbol "isDateHistogramBucketAggConfig" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/index.ts:425:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/index.ts:426:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/index.ts:429:1 - (ae-forgotten-export) The symbol "parseInterval" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/index.ts:430:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/index.ts:433:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/index.ts:404:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/index.ts:404:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/index.ts:404:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/index.ts:406:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/index.ts:407:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/index.ts:416:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/index.ts:417:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/index.ts:418:1 - (ae-forgotten-export) The symbol "Ipv4Address" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/index.ts:419:1 - (ae-forgotten-export) The symbol "isDateHistogramBucketAggConfig" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/index.ts:423:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/index.ts:424:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/index.ts:427:1 - (ae-forgotten-export) The symbol "parseInterval" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/index.ts:428:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/index.ts:431:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/query/state_sync/connect_to_query_state.ts:34:5 - (ae-forgotten-export) The symbol "FilterStateStore" needs to be exported by the entry point index.d.ts
// src/plugins/data/public/search/session/session_service.ts:56:5 - (ae-forgotten-export) The symbol "UrlGeneratorStateMapping" needs to be exported by the entry point index.d.ts

View file

@ -176,9 +176,6 @@ import {
parseEsInterval,
parseInterval,
toAbsoluteDates,
// expressions utils
getRequestInspectorStats,
getResponseInspectorStats,
// tabify
tabifyAggResponse,
tabifyGetColumns,
@ -263,8 +260,6 @@ export const search = {
toAbsoluteDates,
calcAutoIntervalLessThan,
},
getRequestInspectorStats,
getResponseInspectorStats,
tabifyAggResponse,
tabifyGetColumns,
};

View file

@ -56,7 +56,6 @@ import { PublicMethodsOf } from '@kbn/utility-types';
import { RecursiveReadonly } from '@kbn/utility-types';
import { RequestAdapter } from 'src/plugins/inspector/common';
import { RequestHandlerContext } from 'src/core/server';
import { RequestStatistics } from 'src/plugins/inspector/common';
import { SavedObject } from 'kibana/server';
import { SavedObject as SavedObject_2 } from 'src/core/server';
import { SavedObjectsClientContract } from 'src/core/server';
@ -1002,6 +1001,10 @@ export interface ISearchOptions {
isRestore?: boolean;
isStored?: boolean;
legacyHitsTotal?: boolean;
// Warning: (ae-forgotten-export) The symbol "RequestResponder" needs to be exported by the entry point index.d.ts
//
// (undocumented)
requestResponder?: RequestResponder;
sessionId?: string;
strategy?: string;
}
@ -1327,8 +1330,6 @@ export const search: {
toAbsoluteDates: typeof toAbsoluteDates;
calcAutoIntervalLessThan: typeof calcAutoIntervalLessThan;
};
getRequestInspectorStats: typeof getRequestInspectorStats;
getResponseInspectorStats: typeof getResponseInspectorStats;
tabifyAggResponse: typeof tabifyAggResponse;
tabifyGetColumns: typeof tabifyGetColumns;
};
@ -1510,20 +1511,18 @@ export function usageProvider(core: CoreSetup_2): SearchUsage;
// src/plugins/data/server/index.ts:101:26 - (ae-forgotten-export) The symbol "HistogramFormat" needs to be exported by the entry point index.d.ts
// src/plugins/data/server/index.ts:128:27 - (ae-forgotten-export) The symbol "isFilterable" needs to be exported by the entry point index.d.ts
// src/plugins/data/server/index.ts:128:27 - (ae-forgotten-export) The symbol "isNestedField" needs to be exported by the entry point index.d.ts
// src/plugins/data/server/index.ts:244:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts
// src/plugins/data/server/index.ts:244:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts
// src/plugins/data/server/index.ts:244:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts
// src/plugins/data/server/index.ts:244:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts
// src/plugins/data/server/index.ts:246:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts
// src/plugins/data/server/index.ts:247:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts
// src/plugins/data/server/index.ts:256:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts
// src/plugins/data/server/index.ts:257:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts
// src/plugins/data/server/index.ts:258:1 - (ae-forgotten-export) The symbol "Ipv4Address" needs to be exported by the entry point index.d.ts
// src/plugins/data/server/index.ts:262:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts
// src/plugins/data/server/index.ts:263:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts
// src/plugins/data/server/index.ts:267:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts
// src/plugins/data/server/index.ts:270:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts
// src/plugins/data/server/index.ts:271:1 - (ae-forgotten-export) The symbol "calcAutoIntervalLessThan" needs to be exported by the entry point index.d.ts
// src/plugins/data/server/index.ts:241:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts
// src/plugins/data/server/index.ts:241:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts
// src/plugins/data/server/index.ts:243:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts
// src/plugins/data/server/index.ts:244:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts
// src/plugins/data/server/index.ts:253:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts
// src/plugins/data/server/index.ts:254:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts
// src/plugins/data/server/index.ts:255:1 - (ae-forgotten-export) The symbol "Ipv4Address" needs to be exported by the entry point index.d.ts
// src/plugins/data/server/index.ts:259:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts
// src/plugins/data/server/index.ts:260:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts
// src/plugins/data/server/index.ts:264:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts
// src/plugins/data/server/index.ts:267:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts
// src/plugins/data/server/index.ts:268:1 - (ae-forgotten-export) The symbol "calcAutoIntervalLessThan" needs to be exported by the entry point index.d.ts
// src/plugins/data/server/plugin.ts:81:74 - (ae-forgotten-export) The symbol "DataEnhancements" needs to be exported by the entry point index.d.ts
// src/plugins/data/server/search/types.ts:114:5 - (ae-forgotten-export) The symbol "ISearchStartSearchSource" needs to be exported by the entry point index.d.ts

View file

@ -25,8 +25,6 @@ import { discoverResponseHandler } from './response_handler';
import {
getAngularModule,
getHeaderActionMenuMounter,
getRequestInspectorStats,
getResponseInspectorStats,
getServices,
getUrlTracker,
redirectWhenMissing,
@ -153,7 +151,6 @@ function discoverController($route, $scope) {
const subscriptions = new Subscription();
const refetch$ = new Subject();
let inspectorRequest;
let isChangingIndexPattern = false;
const savedSearch = $route.current.locals.savedObjects.savedSearch;
const persistentSearchSource = savedSearch.searchSource;
@ -417,12 +414,14 @@ function discoverController($route, $scope) {
$scope.fetchStatus = fetchStatuses.LOADING;
$scope.resultState = getResultState($scope.fetchStatus, $scope.rows);
logInspectorRequest({ searchSessionId });
return $scope.volatileSearchSource
.fetch({
.fetch$({
abortSignal: abortController.signal,
sessionId: searchSessionId,
requestResponder: getRequestResponder({ searchSessionId }),
})
.toPromise()
.then(onResults)
.catch((error) => {
// If the request was aborted then no need to surface this error in the UI
@ -439,10 +438,6 @@ function discoverController($route, $scope) {
};
function onResults(resp) {
inspectorRequest
.stats(getResponseInspectorStats(resp, $scope.volatileSearchSource))
.ok({ json: resp });
if (getTimeField() && !$scope.state.hideChart) {
const tabifiedData = tabifyAggResponse($scope.opts.chartAggConfigs, resp);
$scope.volatileSearchSource.rawResponse = resp;
@ -463,7 +458,7 @@ function discoverController($route, $scope) {
$scope.fetchStatus = fetchStatuses.COMPLETE;
}
function logInspectorRequest({ searchSessionId = null } = { searchSessionId: null }) {
function getRequestResponder({ searchSessionId = null } = { searchSessionId: null }) {
inspectorAdapters.requests.reset();
const title = i18n.translate('discover.inspectorRequestDataTitle', {
defaultMessage: 'data',
@ -471,11 +466,7 @@ function discoverController($route, $scope) {
const description = i18n.translate('discover.inspectorRequestDescription', {
defaultMessage: 'This request queries Elasticsearch to fetch the data for the search.',
});
inspectorRequest = inspectorAdapters.requests.start(title, { description, searchSessionId });
inspectorRequest.stats(getRequestInspectorStats($scope.volatileSearchSource));
$scope.volatileSearchSource.getSearchRequestBody().then((body) => {
inspectorRequest.json(body);
});
return inspectorAdapters.requests.start(title, { description, searchSessionId });
}
$scope.resetQuery = function () {

View file

@ -29,13 +29,7 @@ import searchTemplateGrid from './search_template_datagrid.html';
import { ISearchEmbeddable, SearchInput, SearchOutput } from './types';
import { SortOrder } from '../angular/doc_table/components/table_header/helpers';
import { getSortForSearchSource } from '../angular/doc_table';
import {
getRequestInspectorStats,
getResponseInspectorStats,
getServices,
IndexPattern,
ISearchSource,
} from '../../kibana_services';
import { getServices, IndexPattern, ISearchSource } from '../../kibana_services';
import { SEARCH_EMBEDDABLE_TYPE } from './constants';
import { SavedSearch } from '../..';
import {
@ -330,14 +324,11 @@ export class SearchEmbeddable
defaultMessage: 'This request queries Elasticsearch to fetch the data for the search.',
});
const inspectorRequest = this.inspectorAdapters.requests!.start(title, {
const requestResponder = this.inspectorAdapters.requests!.start(title, {
description,
searchSessionId,
});
inspectorRequest.stats(getRequestInspectorStats(searchSource));
searchSource.getSearchRequestBody().then((body: Record<string, unknown>) => {
inspectorRequest.json(body);
});
this.searchScope.$apply(() => {
this.searchScope!.isLoading = true;
});
@ -345,15 +336,15 @@ export class SearchEmbeddable
try {
// Make the request
const resp = await searchSource.fetch({
abortSignal: this.abortController.signal,
sessionId: searchSessionId,
});
const resp = await searchSource
.fetch$({
abortSignal: this.abortController.signal,
sessionId: searchSessionId,
requestResponder,
})
.toPromise();
this.updateOutput({ loading: false, error: undefined });
// Log response to inspector
inspectorRequest.stats(getResponseInspectorStats(resp, searchSource)).ok({ json: resp });
// Apply the changes to the angular scope
this.searchScope.$apply(() => {
this.searchScope!.hits = resp.hits.hits;

View file

@ -88,7 +88,7 @@ export const [getScopedHistory, setScopedHistory] = createGetterSetter<ScopedHis
'scopedHistory'
);
export const { getRequestInspectorStats, getResponseInspectorStats, tabifyAggResponse } = search;
export const { tabifyAggResponse } = search;
export { unhashUrl, redirectWhenMissing } from '../../kibana_utils/public';
export { formatMsg, formatStack, subscribeWithScope } from '../../kibana_legacy/public';

View file

@ -436,7 +436,7 @@ export class ESGeoGridSource extends AbstractESAggSource implements ITiledSingle
null // needs to be stripped server-side
);
const dsl = await searchSource.getSearchRequestBody();
const dsl = searchSource.getSearchRequestBody();
const risonDsl = rison.encode(dsl);

View file

@ -706,7 +706,7 @@ export class ESSearchSource extends AbstractESSource implements ITiledSingleLaye
searchSource.setField('sort', this._buildEsSort());
}
const dsl = await searchSource.getSearchRequestBody();
const dsl = searchSource.getSearchRequestBody();
const risonDsl = rison.encode(dsl);
const mvtUrlServicePath = getHttp().basePath.prepend(

View file

@ -19,7 +19,6 @@ import { createExtentFilter } from '../../../../common/elasticsearch_util';
import { copyPersistentState } from '../../../reducers/copy_persistent_state';
import { DataRequestAbortError } from '../../util/data_request';
import { expandToTileBoundaries } from '../../../../common/geo_tile_utils';
import { search } from '../../../../../../../src/plugins/data/public';
import { IVectorSource } from '../vector_source';
import { TimeRange } from '../../../../../../../src/plugins/data/common';
import {
@ -35,10 +34,7 @@ import { IVectorStyle } from '../../styles/vector/vector_style';
import { IDynamicStyleProperty } from '../../styles/vector/properties/dynamic_style_property';
import { IField } from '../../fields/field';
import { FieldFormatter } from '../../../../common/constants';
import {
Adapters,
RequestResponder,
} from '../../../../../../../src/plugins/inspector/common/adapters';
import { Adapters } from '../../../../../../../src/plugins/inspector/common/adapters';
import { isValidStringConfig } from '../../util/valid_string_config';
export function isSearchSourceAbortError(error: Error) {
@ -171,40 +167,23 @@ export class AbstractESSource extends AbstractVectorSource implements IESSource
const abortController = new AbortController();
registerCancelCallback(() => abortController.abort());
const inspectorAdapters = this.getInspectorAdapters();
let inspectorRequest: RequestResponder | undefined;
if (inspectorAdapters?.requests) {
inspectorRequest = inspectorAdapters.requests.start(requestName, {
id: requestId,
description: requestDescription,
searchSessionId,
});
}
const requestResponder = this.getInspectorAdapters()?.requests?.start(requestName, {
id: requestId,
description: requestDescription,
searchSessionId,
});
let resp;
try {
if (inspectorRequest) {
const requestStats = search.getRequestInspectorStats(searchSource);
inspectorRequest.stats(requestStats);
searchSource.getSearchRequestBody().then((body) => {
if (inspectorRequest) {
inspectorRequest.json(body);
}
});
}
resp = await searchSource.fetch({
abortSignal: abortController.signal,
sessionId: searchSessionId,
legacyHitsTotal: false,
});
if (inspectorRequest) {
const responseStats = search.getResponseInspectorStats(resp, searchSource);
inspectorRequest.stats(responseStats).ok({ json: resp });
}
resp = await searchSource
.fetch$({
abortSignal: abortController.signal,
sessionId: searchSessionId,
legacyHitsTotal: false,
requestResponder,
})
.toPromise();
} catch (error) {
if (inspectorRequest) {
inspectorRequest.error(error);
}
if (isSearchSourceAbortError(error)) {
throw new DataRequestAbortError();
}

View file

@ -79,7 +79,7 @@ export class CsvGenerator {
searchSource: ISearchSource,
scrollSettings: CsvExportSettings['scroll']
) {
const searchBody = await searchSource.getSearchRequestBody();
const searchBody = searchSource.getSearchRequestBody();
this.logger.debug(`executing search request`);
const searchParams = {
params: {