mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
Instrument vis_type_vislib, lens and vis_type_timeseries with execution context service (#105206) (#106117)
Co-authored-by: Josh Dover <1813008+joshdover@users.noreply.github.com> Co-authored-by: Mikhail Shustov <restrry@gmail.com> Co-authored-by: Josh Dover <1813008+joshdover@users.noreply.github.com>
This commit is contained in:
parent
dde965559d
commit
50d6106e56
69 changed files with 357 additions and 42 deletions
|
@ -16,4 +16,5 @@ export interface IExecutionContextContainer
|
|||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [toHeader](./kibana-plugin-core-public.iexecutioncontextcontainer.toheader.md) | <code>() => Record<string, string></code> | |
|
||||
| [toJSON](./kibana-plugin-core-public.iexecutioncontextcontainer.tojson.md) | <code>() => Readonly<KibanaExecutionContext></code> | |
|
||||
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [IExecutionContextContainer](./kibana-plugin-core-public.iexecutioncontextcontainer.md) > [toJSON](./kibana-plugin-core-public.iexecutioncontextcontainer.tojson.md)
|
||||
|
||||
## IExecutionContextContainer.toJSON property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
toJSON: () => Readonly<KibanaExecutionContext>;
|
||||
```
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
## KibanaExecutionContext.id property
|
||||
|
||||
unique value to indentify find the source
|
||||
unique value to identify the source
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ export interface KibanaExecutionContext
|
|||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [description](./kibana-plugin-core-public.kibanaexecutioncontext.description.md) | <code>string</code> | human readable description. For example, a vis title, action name |
|
||||
| [id](./kibana-plugin-core-public.kibanaexecutioncontext.id.md) | <code>string</code> | unique value to indentify find the source |
|
||||
| [id](./kibana-plugin-core-public.kibanaexecutioncontext.id.md) | <code>string</code> | unique value to identify the source |
|
||||
| [name](./kibana-plugin-core-public.kibanaexecutioncontext.name.md) | <code>string</code> | public name of a user-facing feature |
|
||||
| [type](./kibana-plugin-core-public.kibanaexecutioncontext.type.md) | <code>string</code> | Kibana application initated an operation. Can be narrowed to an enum later. |
|
||||
| [url](./kibana-plugin-core-public.kibanaexecutioncontext.url.md) | <code>string</code> | in browser - url to navigate to a current page, on server - endpoint path, for task: task SO url |
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
## KibanaExecutionContext.id property
|
||||
|
||||
unique value to indentify find the source
|
||||
unique value to identify the source
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ export interface KibanaExecutionContext
|
|||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [description](./kibana-plugin-core-server.kibanaexecutioncontext.description.md) | <code>string</code> | human readable description. For example, a vis title, action name |
|
||||
| [id](./kibana-plugin-core-server.kibanaexecutioncontext.id.md) | <code>string</code> | unique value to indentify find the source |
|
||||
| [id](./kibana-plugin-core-server.kibanaexecutioncontext.id.md) | <code>string</code> | unique value to identify the source |
|
||||
| [name](./kibana-plugin-core-server.kibanaexecutioncontext.name.md) | <code>string</code> | public name of a user-facing feature |
|
||||
| [type](./kibana-plugin-core-server.kibanaexecutioncontext.type.md) | <code>string</code> | Kibana application initated an operation. Can be narrowed to an enum later. |
|
||||
| [url](./kibana-plugin-core-server.kibanaexecutioncontext.url.md) | <code>string</code> | in browser - url to navigate to a current page, on server - endpoint path, for task: task SO url |
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [ISearchOptions](./kibana-plugin-plugins-data-public.isearchoptions.md) > [executionContext](./kibana-plugin-plugins-data-public.isearchoptions.executioncontext.md)
|
||||
|
||||
## ISearchOptions.executionContext property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
executionContext?: KibanaExecutionContext;
|
||||
```
|
|
@ -15,6 +15,7 @@ export interface ISearchOptions
|
|||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [abortSignal](./kibana-plugin-plugins-data-public.isearchoptions.abortsignal.md) | <code>AbortSignal</code> | An <code>AbortSignal</code> that allows the caller of <code>search</code> to abort a search request. |
|
||||
| [executionContext](./kibana-plugin-plugins-data-public.isearchoptions.executioncontext.md) | <code>KibanaExecutionContext</code> | |
|
||||
| [indexPattern](./kibana-plugin-plugins-data-public.isearchoptions.indexpattern.md) | <code>IndexPattern</code> | Index pattern reference is used for better error messages |
|
||||
| [inspector](./kibana-plugin-plugins-data-public.isearchoptions.inspector.md) | <code>IInspectorInfo</code> | Inspector integration options |
|
||||
| [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) |
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [ISearchOptions](./kibana-plugin-plugins-data-server.isearchoptions.md) > [executionContext](./kibana-plugin-plugins-data-server.isearchoptions.executioncontext.md)
|
||||
|
||||
## ISearchOptions.executionContext property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
executionContext?: KibanaExecutionContext;
|
||||
```
|
|
@ -15,6 +15,7 @@ export interface ISearchOptions
|
|||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [abortSignal](./kibana-plugin-plugins-data-server.isearchoptions.abortsignal.md) | <code>AbortSignal</code> | An <code>AbortSignal</code> that allows the caller of <code>search</code> to abort a search request. |
|
||||
| [executionContext](./kibana-plugin-plugins-data-server.isearchoptions.executioncontext.md) | <code>KibanaExecutionContext</code> | |
|
||||
| [indexPattern](./kibana-plugin-plugins-data-server.isearchoptions.indexpattern.md) | <code>IndexPattern</code> | Index pattern reference is used for better error messages |
|
||||
| [inspector](./kibana-plugin-plugins-data-server.isearchoptions.inspector.md) | <code>IInspectorInfo</code> | Inspector integration options |
|
||||
| [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) |
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-plugins-expressions-public](./kibana-plugin-plugins-expressions-public.md) > [ExecutionContext](./kibana-plugin-plugins-expressions-public.executioncontext.md) > [getExecutionContext](./kibana-plugin-plugins-expressions-public.executioncontext.getexecutioncontext.md)
|
||||
|
||||
## ExecutionContext.getExecutionContext property
|
||||
|
||||
Contains the meta-data about the source of the expression.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
getExecutionContext: () => IExecutionContextContainer | undefined;
|
||||
```
|
|
@ -17,6 +17,7 @@ export interface ExecutionContext<InspectorAdapters extends Adapters = Adapters,
|
|||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [abortSignal](./kibana-plugin-plugins-expressions-public.executioncontext.abortsignal.md) | <code>AbortSignal</code> | Adds ability to abort current execution. |
|
||||
| [getExecutionContext](./kibana-plugin-plugins-expressions-public.executioncontext.getexecutioncontext.md) | <code>() => IExecutionContextContainer | undefined</code> | Contains the meta-data about the source of the expression. |
|
||||
| [getKibanaRequest](./kibana-plugin-plugins-expressions-public.executioncontext.getkibanarequest.md) | <code>() => KibanaRequest</code> | Getter to retrieve the <code>KibanaRequest</code> object inside an expression function. Useful for functions which are running on the server and need to perform operations that are scoped to a specific user. |
|
||||
| [getSearchContext](./kibana-plugin-plugins-expressions-public.executioncontext.getsearchcontext.md) | <code>() => ExecutionContextSearch</code> | Get search context of the expression. |
|
||||
| [getSearchSessionId](./kibana-plugin-plugins-expressions-public.executioncontext.getsearchsessionid.md) | <code>() => string | undefined</code> | Search context in which expression should operate. |
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-plugins-expressions-public](./kibana-plugin-plugins-expressions-public.md) > [IExpressionLoaderParams](./kibana-plugin-plugins-expressions-public.iexpressionloaderparams.md) > [executionContext](./kibana-plugin-plugins-expressions-public.iexpressionloaderparams.executioncontext.md)
|
||||
|
||||
## IExpressionLoaderParams.executionContext property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
executionContext?: IExecutionContextContainer;
|
||||
```
|
|
@ -19,6 +19,7 @@ export interface IExpressionLoaderParams
|
|||
| [customRenderers](./kibana-plugin-plugins-expressions-public.iexpressionloaderparams.customrenderers.md) | <code>[]</code> | |
|
||||
| [debug](./kibana-plugin-plugins-expressions-public.iexpressionloaderparams.debug.md) | <code>boolean</code> | |
|
||||
| [disableCaching](./kibana-plugin-plugins-expressions-public.iexpressionloaderparams.disablecaching.md) | <code>boolean</code> | |
|
||||
| [executionContext](./kibana-plugin-plugins-expressions-public.iexpressionloaderparams.executioncontext.md) | <code>IExecutionContextContainer</code> | |
|
||||
| [hasCompatibleActions](./kibana-plugin-plugins-expressions-public.iexpressionloaderparams.hascompatibleactions.md) | <code>ExpressionRenderHandlerParams['hasCompatibleActions']</code> | |
|
||||
| [inspectorAdapters](./kibana-plugin-plugins-expressions-public.iexpressionloaderparams.inspectoradapters.md) | <code>Adapters</code> | |
|
||||
| [onRenderError](./kibana-plugin-plugins-expressions-public.iexpressionloaderparams.onrendererror.md) | <code>RenderErrorHandlerFnType</code> | |
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-plugins-expressions-server](./kibana-plugin-plugins-expressions-server.md) > [ExecutionContext](./kibana-plugin-plugins-expressions-server.executioncontext.md) > [getExecutionContext](./kibana-plugin-plugins-expressions-server.executioncontext.getexecutioncontext.md)
|
||||
|
||||
## ExecutionContext.getExecutionContext property
|
||||
|
||||
Contains the meta-data about the source of the expression.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
getExecutionContext: () => IExecutionContextContainer | undefined;
|
||||
```
|
|
@ -17,6 +17,7 @@ export interface ExecutionContext<InspectorAdapters extends Adapters = Adapters,
|
|||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [abortSignal](./kibana-plugin-plugins-expressions-server.executioncontext.abortsignal.md) | <code>AbortSignal</code> | Adds ability to abort current execution. |
|
||||
| [getExecutionContext](./kibana-plugin-plugins-expressions-server.executioncontext.getexecutioncontext.md) | <code>() => IExecutionContextContainer | undefined</code> | Contains the meta-data about the source of the expression. |
|
||||
| [getKibanaRequest](./kibana-plugin-plugins-expressions-server.executioncontext.getkibanarequest.md) | <code>() => KibanaRequest</code> | Getter to retrieve the <code>KibanaRequest</code> object inside an expression function. Useful for functions which are running on the server and need to perform operations that are scoped to a specific user. |
|
||||
| [getSearchContext](./kibana-plugin-plugins-expressions-server.executioncontext.getsearchcontext.md) | <code>() => ExecutionContextSearch</code> | Get search context of the expression. |
|
||||
| [getSearchSessionId](./kibana-plugin-plugins-expressions-server.executioncontext.getsearchsessionid.md) | <code>() => string | undefined</code> | Search context in which expression should operate. |
|
||||
|
|
|
@ -30,6 +30,7 @@ function enforceMaxLength(header: string): string {
|
|||
*/
|
||||
export interface IExecutionContextContainer {
|
||||
toHeader: () => Record<string, string>;
|
||||
toJSON: () => Readonly<KibanaExecutionContext>;
|
||||
}
|
||||
|
||||
export class ExecutionContextContainer implements IExecutionContextContainer {
|
||||
|
@ -42,7 +43,12 @@ export class ExecutionContextContainer implements IExecutionContextContainer {
|
|||
// escape content as the description property might contain non-ASCII symbols
|
||||
return enforceMaxLength(encodeURIComponent(value));
|
||||
}
|
||||
|
||||
toHeader() {
|
||||
return { [BAGGAGE_HEADER]: this.toString() };
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
return this.#context;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import type { ExecutionContextContainer } from './execution_context_container';
|
|||
const createContainerMock = () => {
|
||||
const mock: jest.Mocked<PublicMethodsOf<ExecutionContextContainer>> = {
|
||||
toHeader: jest.fn(),
|
||||
toJSON: jest.fn(),
|
||||
};
|
||||
return mock;
|
||||
};
|
||||
|
|
|
@ -186,16 +186,14 @@ export type {
|
|||
|
||||
export type { DeprecationsServiceStart, ResolveDeprecationResponse } from './deprecations';
|
||||
|
||||
export type {
|
||||
IExecutionContextContainer,
|
||||
ExecutionContextServiceStart,
|
||||
KibanaExecutionContext,
|
||||
} from './execution_context';
|
||||
export type { IExecutionContextContainer, ExecutionContextServiceStart } from './execution_context';
|
||||
|
||||
export type { MountPoint, UnmountCallback, PublicUiSettingsParams } from './types';
|
||||
|
||||
export { URL_MAX_LENGTH } from './core_app';
|
||||
|
||||
export type { KibanaExecutionContext } from './execution_context';
|
||||
|
||||
/**
|
||||
* Core services exposed to the `Plugin` setup lifecycle
|
||||
*
|
||||
|
|
|
@ -900,6 +900,8 @@ export interface IBasePath {
|
|||
export interface IExecutionContextContainer {
|
||||
// (undocumented)
|
||||
toHeader: () => Record<string, string>;
|
||||
// (undocumented)
|
||||
toJSON: () => Readonly<KibanaExecutionContext>;
|
||||
}
|
||||
|
||||
// @public
|
||||
|
|
|
@ -10,7 +10,11 @@ import { Buffer } from 'buffer';
|
|||
import { Readable } from 'stream';
|
||||
|
||||
import { RequestEvent, errors } from '@elastic/elasticsearch';
|
||||
import { TransportRequestParams, RequestBody } from '@elastic/elasticsearch/lib/Transport';
|
||||
import type {
|
||||
TransportRequestOptions,
|
||||
TransportRequestParams,
|
||||
RequestBody,
|
||||
} from '@elastic/elasticsearch/lib/Transport';
|
||||
|
||||
import { parseClientOptionsMock, ClientMock } from './configure_client.test.mocks';
|
||||
import { loggingSystemMock } from '../../logging/logging_system.mock';
|
||||
|
@ -39,12 +43,14 @@ const createApiResponse = <T>({
|
|||
headers = {},
|
||||
warnings = [],
|
||||
params,
|
||||
requestOptions = {},
|
||||
}: {
|
||||
body: T;
|
||||
statusCode?: number;
|
||||
headers?: Record<string, string>;
|
||||
warnings?: string[];
|
||||
params?: TransportRequestParams;
|
||||
requestOptions?: TransportRequestOptions;
|
||||
}): RequestEvent<T> => {
|
||||
return {
|
||||
body,
|
||||
|
@ -54,6 +60,7 @@ const createApiResponse = <T>({
|
|||
meta: {
|
||||
request: {
|
||||
params: params!,
|
||||
options: requestOptions,
|
||||
} as any,
|
||||
} as any,
|
||||
};
|
||||
|
@ -146,6 +153,7 @@ describe('configureClient', () => {
|
|||
"200
|
||||
GET /foo?hello=dolly
|
||||
{\\"seq_no_primary_term\\":true,\\"query\\":{\\"term\\":{\\"user\\":\\"kimchy\\"}}}",
|
||||
undefined,
|
||||
],
|
||||
]
|
||||
`);
|
||||
|
@ -170,6 +178,7 @@ describe('configureClient', () => {
|
|||
"200
|
||||
GET /foo?hello=dolly
|
||||
{\\"seq_no_primary_term\\":true,\\"query\\":{\\"term\\":{\\"user\\":\\"kimchy\\"}}}",
|
||||
undefined,
|
||||
],
|
||||
]
|
||||
`);
|
||||
|
@ -196,6 +205,7 @@ describe('configureClient', () => {
|
|||
"200
|
||||
GET /foo?hello=dolly
|
||||
[buffer]",
|
||||
undefined,
|
||||
],
|
||||
]
|
||||
`);
|
||||
|
@ -222,6 +232,7 @@ describe('configureClient', () => {
|
|||
"200
|
||||
GET /foo?hello=dolly
|
||||
[stream]",
|
||||
undefined,
|
||||
],
|
||||
]
|
||||
`);
|
||||
|
@ -238,6 +249,7 @@ describe('configureClient', () => {
|
|||
Array [
|
||||
"200
|
||||
GET /foo?hello=dolly",
|
||||
undefined,
|
||||
],
|
||||
]
|
||||
`);
|
||||
|
@ -263,6 +275,7 @@ describe('configureClient', () => {
|
|||
Array [
|
||||
"200
|
||||
GET /foo?city=M%C3%BCnich",
|
||||
undefined,
|
||||
],
|
||||
]
|
||||
`);
|
||||
|
@ -298,6 +311,7 @@ describe('configureClient', () => {
|
|||
"500
|
||||
GET /foo?hello=dolly
|
||||
{\\"seq_no_primary_term\\":true,\\"query\\":{\\"term\\":{\\"user\\":\\"kimchy\\"}}} [internal server error]: internal server error",
|
||||
undefined,
|
||||
],
|
||||
]
|
||||
`);
|
||||
|
@ -313,6 +327,7 @@ describe('configureClient', () => {
|
|||
Array [
|
||||
Array [
|
||||
"[TimeoutError]: message",
|
||||
undefined,
|
||||
],
|
||||
]
|
||||
`);
|
||||
|
@ -343,6 +358,7 @@ describe('configureClient', () => {
|
|||
Array [
|
||||
"400
|
||||
GET /_path?hello=dolly [illegal_argument_exception]: request [/_path] contains unrecognized parameter: [name]",
|
||||
undefined,
|
||||
],
|
||||
]
|
||||
`);
|
||||
|
@ -369,6 +385,7 @@ describe('configureClient', () => {
|
|||
Array [
|
||||
"400
|
||||
GET /_path [undefined]: Response Error",
|
||||
undefined,
|
||||
],
|
||||
]
|
||||
`);
|
||||
|
@ -391,10 +408,67 @@ describe('configureClient', () => {
|
|||
Array [
|
||||
"400
|
||||
GET /_path [undefined]: Response Error",
|
||||
undefined,
|
||||
],
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
it('adds meta information to logs', () => {
|
||||
const client = configureClient(createFakeConfig(), { logger, type: 'test', scoped: false });
|
||||
|
||||
let response = createApiResponse({
|
||||
statusCode: 400,
|
||||
headers: {},
|
||||
params: {
|
||||
method: 'GET',
|
||||
path: '/_path',
|
||||
},
|
||||
requestOptions: {
|
||||
opaqueId: 'opaque-id',
|
||||
},
|
||||
body: {
|
||||
error: {},
|
||||
},
|
||||
});
|
||||
client.emit('response', null, response);
|
||||
|
||||
expect(loggingSystemMock.collect(logger).debug[0][1]).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"http": Object {
|
||||
"request": Object {
|
||||
"id": "opaque-id",
|
||||
},
|
||||
},
|
||||
}
|
||||
`);
|
||||
|
||||
logger.debug.mockClear();
|
||||
|
||||
response = createApiResponse({
|
||||
statusCode: 400,
|
||||
headers: {},
|
||||
params: {
|
||||
method: 'GET',
|
||||
path: '/_path',
|
||||
},
|
||||
requestOptions: {
|
||||
opaqueId: 'opaque-id',
|
||||
},
|
||||
body: {} as any,
|
||||
});
|
||||
client.emit('response', new errors.ResponseError(response), response);
|
||||
|
||||
expect(loggingSystemMock.collect(logger).debug[0][1]).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"http": Object {
|
||||
"request": Object {
|
||||
"id": "opaque-id",
|
||||
},
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -98,10 +98,16 @@ function getResponseMessage(event: RequestEvent): string {
|
|||
const addLogging = (client: Client, logger: Logger) => {
|
||||
client.on('response', (error, event) => {
|
||||
if (event) {
|
||||
const opaqueId = event.meta.request.options.opaqueId;
|
||||
const meta = opaqueId
|
||||
? {
|
||||
http: { request: { id: event.meta.request.options.opaqueId } },
|
||||
}
|
||||
: undefined; // do not clutter logs if opaqueId is not present
|
||||
if (error) {
|
||||
logger.debug(getErrorMessage(error, event));
|
||||
logger.debug(getErrorMessage(error, event), meta);
|
||||
} else {
|
||||
logger.debug(getResponseMessage(event));
|
||||
logger.debug(getResponseMessage(event), meta);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -25,7 +25,7 @@ describe('KibanaExecutionContext', () => {
|
|||
};
|
||||
|
||||
const value = new ExecutionContextContainer(context).toString();
|
||||
expect(value).toMatchInlineSnapshot(`"1234-5678;kibana:test-type:42"`);
|
||||
expect(value).toMatchInlineSnapshot(`"1234-5678;kibana:test-type:test-name:42"`);
|
||||
});
|
||||
|
||||
it('returns a limited representation if optional properties are omitted', () => {
|
||||
|
@ -37,6 +37,20 @@ describe('KibanaExecutionContext', () => {
|
|||
expect(value).toMatchInlineSnapshot(`"1234-5678"`);
|
||||
});
|
||||
|
||||
it('returns an escaped string representation of provided execution contextStringified', () => {
|
||||
const context: KibanaServerExecutionContext = {
|
||||
id: 'Visualization☺漢字',
|
||||
type: 'test-type',
|
||||
name: 'test-name',
|
||||
requestId: '1234-5678',
|
||||
};
|
||||
|
||||
const value = new ExecutionContextContainer(context).toString();
|
||||
expect(value).toMatchInlineSnapshot(
|
||||
`"1234-5678;kibana:test-type:test-name:Visualization%E2%98%BA%E6%BC%A2%E5%AD%97"`
|
||||
);
|
||||
});
|
||||
|
||||
it('trims a string representation of provided execution context if it is bigger max allowed size', () => {
|
||||
expect(
|
||||
new Blob([
|
||||
|
|
|
@ -57,7 +57,13 @@ export class ExecutionContextContainer implements IExecutionContextContainer {
|
|||
}
|
||||
toString(): string {
|
||||
const ctx = this.#context;
|
||||
const contextStringified = ctx.type && ctx.id ? `kibana:${ctx.type}:${ctx.id}` : '';
|
||||
const contextStringified =
|
||||
ctx.type && ctx.id && ctx.name
|
||||
? // id may contain non-ASCII symbols
|
||||
`kibana:${encodeURIComponent(ctx.type)}:${encodeURIComponent(
|
||||
ctx.name
|
||||
)}:${encodeURIComponent(ctx.id)}`
|
||||
: '';
|
||||
const result = contextStringified ? `${ctx.requestId};${contextStringified}` : ctx.requestId;
|
||||
return enforceMaxLength(result);
|
||||
}
|
||||
|
|
|
@ -11,14 +11,17 @@ import {
|
|||
InternalExecutionContextSetup,
|
||||
} from './execution_context_service';
|
||||
import { mockCoreContext } from '../core_context.mock';
|
||||
import { loggingSystemMock } from '../logging/logging_system.mock';
|
||||
|
||||
const delay = (ms: number = 100) => new Promise((resolve) => setTimeout(resolve, ms));
|
||||
describe('ExecutionContextService', () => {
|
||||
describe('setup', () => {
|
||||
let service: InternalExecutionContextSetup;
|
||||
const core = mockCoreContext.create();
|
||||
core.configService.atPath.mockReturnValue(new BehaviorSubject({ enabled: true }));
|
||||
let core: ReturnType<typeof mockCoreContext.create>;
|
||||
|
||||
beforeEach(() => {
|
||||
core = mockCoreContext.create();
|
||||
core.configService.atPath.mockReturnValue(new BehaviorSubject({ enabled: true }));
|
||||
service = new ExecutionContextService(core).setup();
|
||||
});
|
||||
|
||||
|
@ -82,6 +85,19 @@ describe('ExecutionContextService', () => {
|
|||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('emits context to the logs when "set" is called', async () => {
|
||||
service.set({
|
||||
requestId: '0000',
|
||||
});
|
||||
expect(loggingSystemMock.collect(core.logger).debug).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Array [
|
||||
"stored the execution context: {\\"requestId\\":\\"0000\\"}",
|
||||
],
|
||||
]
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('config', () => {
|
||||
|
|
|
@ -119,7 +119,7 @@ export class ExecutionContextService
|
|||
// we have to use enterWith since Hapi lifecycle model is built on event emitters.
|
||||
// therefore if we wrapped request handler in asyncLocalStorage.run(), we would lose context in other lifecycles.
|
||||
this.asyncLocalStorage.enterWith(contextContainer);
|
||||
this.log.trace(`stored the execution context: ${contextContainer.toJSON()}`);
|
||||
this.log.debug(`stored the execution context: ${JSON.stringify(contextContainer)}`);
|
||||
}
|
||||
|
||||
private reset() {
|
||||
|
|
|
@ -435,7 +435,7 @@ describe('trace', () => {
|
|||
.expect(200);
|
||||
|
||||
const header = response.body['x-opaque-id'];
|
||||
expect(header).toContain('kibana:test-type:42');
|
||||
expect(header).toContain('kibana:test-type:test-name:42');
|
||||
});
|
||||
|
||||
it('propagates context to Elasticsearch unscoped client', async () => {
|
||||
|
@ -456,7 +456,7 @@ describe('trace', () => {
|
|||
.expect(200);
|
||||
|
||||
const header = response.body['x-opaque-id'];
|
||||
expect(header).toContain('kibana:test-type:42');
|
||||
expect(header).toContain('kibana:test-type:test-name:42');
|
||||
});
|
||||
|
||||
it('a repeat call overwrites the old context', async () => {
|
||||
|
@ -484,7 +484,7 @@ describe('trace', () => {
|
|||
.expect(200);
|
||||
|
||||
const header = response.body['x-opaque-id'];
|
||||
expect(header).toContain('kibana:new-type:41');
|
||||
expect(header).toContain('kibana:new-type:new-name:41');
|
||||
});
|
||||
|
||||
it('does not affect "x-opaque-id" set by user', async () => {
|
||||
|
@ -507,7 +507,7 @@ describe('trace', () => {
|
|||
.expect(200);
|
||||
|
||||
const header = response.body['x-opaque-id'];
|
||||
expect(header).toBe('my-opaque-id;kibana:test-type:42');
|
||||
expect(header).toBe('my-opaque-id;kibana:test-type:test-name:42');
|
||||
});
|
||||
|
||||
it('does not break on non-ASCII characters within execution context', async () => {
|
||||
|
@ -536,7 +536,7 @@ describe('trace', () => {
|
|||
.expect(200);
|
||||
|
||||
const header = response.body['x-opaque-id'];
|
||||
expect(header).toBe('my-opaque-id;kibana:test-type:42');
|
||||
expect(header).toBe('my-opaque-id;kibana:test-type:test-name:42');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -81,8 +81,6 @@ export type {
|
|||
import type { ExecutionContextSetup, ExecutionContextStart } from './execution_context';
|
||||
|
||||
export type {
|
||||
ExecutionContextSetup,
|
||||
ExecutionContextStart,
|
||||
IExecutionContextContainer,
|
||||
KibanaServerExecutionContext,
|
||||
KibanaExecutionContext,
|
||||
|
@ -551,6 +549,8 @@ export type {
|
|||
CapabilitiesSetup,
|
||||
CapabilitiesStart,
|
||||
ContextSetup,
|
||||
ExecutionContextSetup,
|
||||
ExecutionContextStart,
|
||||
HttpResources,
|
||||
PluginsServiceSetup,
|
||||
PluginsServiceStart,
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
*/
|
||||
|
||||
/** @public */
|
||||
|
||||
export interface KibanaExecutionContext {
|
||||
/**
|
||||
* Kibana application initated an operation.
|
||||
* Can be narrowed to an enum later.
|
||||
* */
|
||||
readonly type: string; // 'visualization' | 'actions' | 'server' | ..;
|
||||
/** public name of a user-facing feature */
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { KibanaExecutionContext } from 'src/core/public';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { defer } from 'rxjs';
|
||||
import { map, switchMap } from 'rxjs/operators';
|
||||
|
@ -32,6 +32,7 @@ export interface RequestHandlerParams {
|
|||
timeFields?: string[];
|
||||
timeRange?: TimeRange;
|
||||
getNow?: () => Date;
|
||||
executionContext?: KibanaExecutionContext;
|
||||
}
|
||||
|
||||
export const handleRequest = ({
|
||||
|
@ -47,6 +48,7 @@ export const handleRequest = ({
|
|||
timeFields,
|
||||
timeRange,
|
||||
getNow,
|
||||
executionContext,
|
||||
}: RequestHandlerParams) => {
|
||||
return defer(async () => {
|
||||
const forceNow = getNow?.();
|
||||
|
@ -122,6 +124,7 @@ export const handleRequest = ({
|
|||
'This request queries Elasticsearch to fetch the data for the visualization.',
|
||||
}),
|
||||
},
|
||||
executionContext,
|
||||
})
|
||||
.pipe(
|
||||
map(({ rawResponse: response }) => {
|
||||
|
|
|
@ -18,6 +18,7 @@ describe('interpreter/functions#field', () => {
|
|||
context = {
|
||||
getSearchContext: () => ({}),
|
||||
getSearchSessionId: () => undefined,
|
||||
getExecutionContext: () => undefined,
|
||||
types: {},
|
||||
variables: {},
|
||||
abortSignal: {} as any,
|
||||
|
|
|
@ -37,6 +37,7 @@ describe('interpreter/functions#kibana', () => {
|
|||
context = {
|
||||
getSearchContext: () => search,
|
||||
getSearchSessionId: () => undefined,
|
||||
getExecutionContext: () => undefined,
|
||||
types: {},
|
||||
variables: {},
|
||||
abortSignal: {} as any,
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { ExpressionValueBoxed } from 'src/plugins/expressions/common';
|
||||
import { Filter } from '../../es_query';
|
||||
import { Query, TimeRange } from '../../query';
|
||||
|
|
|
@ -21,6 +21,7 @@ describe('interpreter/functions#kql', () => {
|
|||
context = {
|
||||
getSearchContext: () => ({}),
|
||||
getSearchSessionId: () => undefined,
|
||||
getExecutionContext: () => undefined,
|
||||
types: {},
|
||||
variables: {},
|
||||
abortSignal: {} as any,
|
||||
|
|
|
@ -21,6 +21,7 @@ describe('interpreter/functions#lucene', () => {
|
|||
context = {
|
||||
getSearchContext: () => ({}),
|
||||
getSearchSessionId: () => undefined,
|
||||
getExecutionContext: () => undefined,
|
||||
types: {},
|
||||
variables: {},
|
||||
abortSignal: {} as any,
|
||||
|
|
|
@ -18,6 +18,7 @@ describe('interpreter/functions#range', () => {
|
|||
context = {
|
||||
getSearchContext: () => ({}),
|
||||
getSearchSessionId: () => undefined,
|
||||
getExecutionContext: () => undefined,
|
||||
types: {},
|
||||
variables: {},
|
||||
abortSignal: {} as any,
|
||||
|
|
|
@ -21,6 +21,7 @@ describe('interpreter/functions#timerange', () => {
|
|||
context = {
|
||||
getSearchContext: () => ({}),
|
||||
getSearchSessionId: () => undefined,
|
||||
getExecutionContext: () => undefined,
|
||||
types: {},
|
||||
variables: {},
|
||||
abortSignal: {} as any,
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { KibanaExecutionContext } from 'src/core/public';
|
||||
import { Observable } from 'rxjs';
|
||||
import { IEsSearchRequest, IEsSearchResponse, IndexPattern } from '..';
|
||||
import type { RequestAdapter } from '../../../inspector/common';
|
||||
|
@ -134,6 +134,8 @@ export interface ISearchOptions {
|
|||
* Inspector integration options
|
||||
*/
|
||||
inspector?: IInspectorInfo;
|
||||
|
||||
executionContext?: KibanaExecutionContext;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -142,5 +144,5 @@ export interface ISearchOptions {
|
|||
*/
|
||||
export type ISearchOptionsSerializable = Pick<
|
||||
ISearchOptions,
|
||||
'strategy' | 'legacyHitsTotal' | 'sessionId' | 'isStored' | 'isRestore'
|
||||
'strategy' | 'legacyHitsTotal' | 'sessionId' | 'isStored' | 'isRestore' | 'executionContext'
|
||||
>;
|
||||
|
|
|
@ -54,6 +54,7 @@ import { IStorageWrapper } from 'src/plugins/kibana_utils/public';
|
|||
import { IUiSettingsClient } from 'src/core/public';
|
||||
import { JsonValue } from '@kbn/common-utils';
|
||||
import { KibanaClient } from '@elastic/elasticsearch/api/kibana';
|
||||
import { KibanaExecutionContext } from 'src/core/public';
|
||||
import { Location } from 'history';
|
||||
import { LocationDescriptorObject } from 'history';
|
||||
import { Logger } from '@kbn/logging';
|
||||
|
@ -1759,6 +1760,8 @@ export type ISearchGeneric = <SearchStrategyRequest extends IKibanaSearchRequest
|
|||
// @public (undocumented)
|
||||
export interface ISearchOptions {
|
||||
abortSignal?: AbortSignal;
|
||||
// (undocumented)
|
||||
executionContext?: KibanaExecutionContext;
|
||||
indexPattern?: IndexPattern;
|
||||
// Warning: (ae-forgotten-export) The symbol "IInspectorInfo" needs to be exported by the entry point index.d.ts
|
||||
inspector?: IInspectorInfo;
|
||||
|
|
|
@ -57,6 +57,7 @@ describe('esaggs expression function - public', () => {
|
|||
abortSignal: (jest.fn() as unknown) as jest.Mocked<AbortSignal>,
|
||||
getSearchContext: jest.fn(),
|
||||
getSearchSessionId: jest.fn().mockReturnValue('abc123'),
|
||||
getExecutionContext: jest.fn(),
|
||||
inspectorAdapters: jest.fn(),
|
||||
variables: {},
|
||||
types: {},
|
||||
|
|
|
@ -37,7 +37,7 @@ export function getFunctionDefinition({
|
|||
}) {
|
||||
return (): EsaggsExpressionFunctionDefinition => ({
|
||||
...getEsaggsMeta(),
|
||||
fn(input, args, { inspectorAdapters, abortSignal, getSearchSessionId }) {
|
||||
fn(input, args, { inspectorAdapters, abortSignal, getSearchSessionId, getExecutionContext }) {
|
||||
return defer(async () => {
|
||||
const { aggs, indexPatterns, searchSource, getNow } = await getStartDependencies();
|
||||
|
||||
|
@ -64,6 +64,7 @@ export function getFunctionDefinition({
|
|||
timeFields: args.timeFields,
|
||||
timeRange: get(input, 'timeRange', undefined),
|
||||
getNow,
|
||||
executionContext: getExecutionContext()?.toJSON(),
|
||||
})
|
||||
)
|
||||
);
|
||||
|
|
|
@ -188,6 +188,9 @@ export class SearchInterceptor {
|
|||
serializableOptions.legacyHitsTotal = combined.legacyHitsTotal;
|
||||
if (combined.strategy !== undefined) serializableOptions.strategy = combined.strategy;
|
||||
if (combined.isStored !== undefined) serializableOptions.isStored = combined.isStored;
|
||||
if (combined.executionContext !== undefined) {
|
||||
serializableOptions.executionContext = combined.executionContext;
|
||||
}
|
||||
|
||||
return serializableOptions;
|
||||
}
|
||||
|
|
|
@ -59,6 +59,7 @@ describe('esaggs expression function - server', () => {
|
|||
getKibanaRequest: jest.fn().mockReturnValue({ id: 'hi' } as KibanaRequest),
|
||||
getSearchContext: jest.fn(),
|
||||
getSearchSessionId: jest.fn().mockReturnValue('abc123'),
|
||||
getExecutionContext: jest.fn(),
|
||||
inspectorAdapters: jest.fn(),
|
||||
variables: {},
|
||||
types: {},
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
import { catchError, first } from 'rxjs/operators';
|
||||
import { BfetchServerSetup } from 'src/plugins/bfetch/server';
|
||||
import type { ExecutionContextSetup } from 'src/core/server';
|
||||
import {
|
||||
IKibanaSearchRequest,
|
||||
IKibanaSearchResponse,
|
||||
|
@ -17,7 +18,8 @@ import { ISearchStart } from '../types';
|
|||
|
||||
export function registerBsearchRoute(
|
||||
bfetch: BfetchServerSetup,
|
||||
getScoped: ISearchStart['asScoped']
|
||||
getScoped: ISearchStart['asScoped'],
|
||||
executionContextService: ExecutionContextSetup
|
||||
): void {
|
||||
bfetch.addBatchProcessingRoute<
|
||||
{ request: IKibanaSearchRequest; options?: ISearchOptionsSerializable },
|
||||
|
@ -30,8 +32,11 @@ export function registerBsearchRoute(
|
|||
*/
|
||||
onBatchItem: async ({ request: requestData, options }) => {
|
||||
const search = getScoped(request);
|
||||
const { executionContext, ...restOptions } = options || {};
|
||||
if (executionContext) executionContextService.set(executionContext);
|
||||
|
||||
return search
|
||||
.search(requestData, options)
|
||||
.search(requestData, restOptions)
|
||||
.pipe(
|
||||
first(),
|
||||
catchError((err) => {
|
||||
|
|
|
@ -158,7 +158,11 @@ export class SearchService implements Plugin<ISearchSetup, ISearchStart> {
|
|||
|
||||
this.registerSearchStrategy(EQL_SEARCH_STRATEGY, eqlSearchStrategyProvider(this.logger));
|
||||
|
||||
registerBsearchRoute(bfetch, (request: KibanaRequest) => this.asScoped(request));
|
||||
registerBsearchRoute(
|
||||
bfetch,
|
||||
(request: KibanaRequest) => this.asScoped(request),
|
||||
core.executionContext
|
||||
);
|
||||
|
||||
core.savedObjects.registerType(searchTelemetry);
|
||||
if (usageCollection) {
|
||||
|
|
|
@ -39,6 +39,7 @@ import { ISearchSource } from 'src/plugins/data/public';
|
|||
import { IUiSettingsClient } from 'src/core/server';
|
||||
import { IUiSettingsClient as IUiSettingsClient_3 } from 'kibana/server';
|
||||
import { JsonValue } from '@kbn/common-utils';
|
||||
import { KibanaExecutionContext } from 'src/core/public';
|
||||
import { KibanaRequest } from 'src/core/server';
|
||||
import { KibanaRequest as KibanaRequest_2 } from 'kibana/server';
|
||||
import { Logger } from 'src/core/server';
|
||||
|
@ -1020,6 +1021,8 @@ export interface IScopedSearchClient extends ISearchClient {
|
|||
// @public (undocumented)
|
||||
export interface ISearchOptions {
|
||||
abortSignal?: AbortSignal;
|
||||
// (undocumented)
|
||||
executionContext?: KibanaExecutionContext;
|
||||
indexPattern?: IndexPattern;
|
||||
// Warning: (ae-forgotten-export) The symbol "IInspectorInfo" needs to be exported by the entry point index.d.ts
|
||||
inspector?: IInspectorInfo;
|
||||
|
|
|
@ -213,6 +213,7 @@ export class Execution<
|
|||
},
|
||||
isSyncColorsEnabled: () => execution.params.syncColors,
|
||||
...(execution.params as any).extraContext,
|
||||
getExecutionContext: () => execution.params.executionContext,
|
||||
};
|
||||
|
||||
this.result = this.input$.pipe(
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
|
||||
import type { KibanaRequest } from 'src/core/server';
|
||||
import type { IExecutionContextContainer } from 'src/core/public';
|
||||
|
||||
import { ExpressionType, SerializableState } from '../expression_types';
|
||||
import { Adapters, RequestAdapter } from '../../../inspector/common';
|
||||
|
@ -62,6 +63,11 @@ export interface ExecutionContext<
|
|||
* Returns the state (true|false) of the sync colors across panels switch.
|
||||
*/
|
||||
isSyncColorsEnabled?: () => boolean;
|
||||
|
||||
/**
|
||||
* Contains the meta-data about the source of the expression.
|
||||
*/
|
||||
getExecutionContext: () => IExecutionContextContainer | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -28,6 +28,7 @@ describe('expression_functions', () => {
|
|||
context = {
|
||||
getSearchContext: () => ({} as any),
|
||||
getSearchSessionId: () => undefined,
|
||||
getExecutionContext: () => undefined,
|
||||
types: {},
|
||||
variables: { theme: themeProps },
|
||||
abortSignal: {} as any,
|
||||
|
|
|
@ -21,6 +21,7 @@ describe('expression_functions', () => {
|
|||
context = {
|
||||
getSearchContext: () => input,
|
||||
getSearchSessionId: () => undefined,
|
||||
getExecutionContext: () => undefined,
|
||||
types: {},
|
||||
variables: { test: 1 },
|
||||
abortSignal: {} as any,
|
||||
|
|
|
@ -24,6 +24,7 @@ describe('expression_functions', () => {
|
|||
context = {
|
||||
getSearchContext: () => input,
|
||||
getSearchSessionId: () => undefined,
|
||||
getExecutionContext: () => undefined,
|
||||
types: {},
|
||||
variables: { test: 1 },
|
||||
abortSignal: {} as any,
|
||||
|
|
|
@ -14,6 +14,7 @@ export const createMockExecutionContext = <ExtraContext extends object = object>
|
|||
const executionContext: ExecutionContext = {
|
||||
getSearchContext: jest.fn(),
|
||||
getSearchSessionId: jest.fn(),
|
||||
getExecutionContext: jest.fn(),
|
||||
variables: {},
|
||||
types: {},
|
||||
abortSignal: {
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
import { Observable } from 'rxjs';
|
||||
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
|
||||
import type { KibanaRequest } from 'src/core/server';
|
||||
import type { IExecutionContextContainer } from 'src/core/public';
|
||||
|
||||
import { Executor } from '../executor';
|
||||
import { AnyExpressionRenderDefinition, ExpressionRendererRegistry } from '../expression_renderers';
|
||||
|
@ -78,6 +79,8 @@ export interface ExpressionExecutionParams {
|
|||
syncColors?: boolean;
|
||||
|
||||
inspectorAdapters?: Adapters;
|
||||
|
||||
executionContext?: IExecutionContextContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -140,6 +140,7 @@ export class ExpressionLoader {
|
|||
searchSessionId: params.searchSessionId,
|
||||
debug: params.debug,
|
||||
syncColors: params.syncColors,
|
||||
executionContext: params.executionContext,
|
||||
});
|
||||
this.subscription = this.execution
|
||||
.getData()
|
||||
|
@ -185,6 +186,8 @@ export class ExpressionLoader {
|
|||
|
||||
this.params.inspectorAdapters = (params.inspectorAdapters ||
|
||||
this.execution?.inspect()) as Adapters;
|
||||
|
||||
this.params.executionContext = params.executionContext;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import { CoreStart } from 'src/core/public';
|
|||
import { Ensure } from '@kbn/utility-types';
|
||||
import { EnvironmentMode } from '@kbn/config';
|
||||
import { EventEmitter } from 'events';
|
||||
import { IExecutionContextContainer } from 'src/core/public';
|
||||
import { KibanaRequest } from 'src/core/server';
|
||||
import { Observable } from 'rxjs';
|
||||
import { ObservableLike } from '@kbn/utility-types';
|
||||
|
@ -138,6 +139,7 @@ export type ExecutionContainer<Output = ExpressionValue> = StateContainer<Execut
|
|||
// @public
|
||||
export interface ExecutionContext<InspectorAdapters extends Adapters = Adapters, ExecutionContextSearch extends SerializableState_2 = SerializableState_2> {
|
||||
abortSignal: AbortSignal;
|
||||
getExecutionContext: () => IExecutionContextContainer | undefined;
|
||||
getKibanaRequest?: () => KibanaRequest;
|
||||
getSearchContext: () => ExecutionContextSearch;
|
||||
getSearchSessionId: () => string | undefined;
|
||||
|
@ -901,6 +903,8 @@ export interface IExpressionLoaderParams {
|
|||
// (undocumented)
|
||||
disableCaching?: boolean;
|
||||
// (undocumented)
|
||||
executionContext?: IExecutionContextContainer;
|
||||
// (undocumented)
|
||||
hasCompatibleActions?: ExpressionRenderHandlerParams['hasCompatibleActions'];
|
||||
// (undocumented)
|
||||
inspectorAdapters?: Adapters;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { IExecutionContextContainer } from 'src/core/public';
|
||||
import { Adapters } from '../../../inspector/public';
|
||||
import {
|
||||
IInterpreterRenderHandlers,
|
||||
|
@ -48,6 +48,7 @@ export interface IExpressionLoaderParams {
|
|||
renderMode?: RenderMode;
|
||||
syncColors?: boolean;
|
||||
hasCompatibleActions?: ExpressionRenderHandlerParams['hasCompatibleActions'];
|
||||
executionContext?: IExecutionContextContainer;
|
||||
|
||||
/**
|
||||
* The flag to toggle on emitting partial results.
|
||||
|
|
|
@ -8,6 +8,7 @@ import { CoreSetup } from 'src/core/server';
|
|||
import { CoreStart } from 'src/core/server';
|
||||
import { Ensure } from '@kbn/utility-types';
|
||||
import { EventEmitter } from 'events';
|
||||
import { IExecutionContextContainer } from 'src/core/public';
|
||||
import { KibanaRequest } from 'src/core/server';
|
||||
import { Observable } from 'rxjs';
|
||||
import { ObservableLike } from '@kbn/utility-types';
|
||||
|
@ -136,6 +137,7 @@ export type ExecutionContainer<Output = ExpressionValue> = StateContainer<Execut
|
|||
// @public
|
||||
export interface ExecutionContext<InspectorAdapters extends Adapters = Adapters, ExecutionContextSearch extends SerializableState_2 = SerializableState_2> {
|
||||
abortSignal: AbortSignal;
|
||||
getExecutionContext: () => IExecutionContextContainer | undefined;
|
||||
getKibanaRequest?: () => KibanaRequest;
|
||||
getSearchContext: () => ExecutionContextSearch;
|
||||
getSearchSessionId: () => string | undefined;
|
||||
|
|
|
@ -54,7 +54,7 @@ export const createMetricsFn = (): TimeseriesExpressionFunctionDefinition => ({
|
|||
help: '',
|
||||
},
|
||||
},
|
||||
async fn(input, args, { getSearchSessionId, isSyncColorsEnabled }) {
|
||||
async fn(input, args, { getSearchSessionId, isSyncColorsEnabled, getExecutionContext }) {
|
||||
const visParams: TimeseriesVisParams = JSON.parse(args.params);
|
||||
const uiState = JSON.parse(args.uiState);
|
||||
const syncColors = isSyncColorsEnabled?.() ?? false;
|
||||
|
@ -64,6 +64,7 @@ export const createMetricsFn = (): TimeseriesExpressionFunctionDefinition => ({
|
|||
visParams,
|
||||
uiState,
|
||||
searchSessionId: getSearchSessionId(),
|
||||
executionContext: getExecutionContext(),
|
||||
});
|
||||
|
||||
return {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { IExecutionContextContainer } from 'src/core/public';
|
||||
import { getTimezone } from './application/lib/get_timezone';
|
||||
import { getUISettings, getDataStart, getCoreStart } from './services';
|
||||
import { ROUTES } from '../common/constants';
|
||||
|
@ -19,6 +19,7 @@ interface MetricsRequestHandlerParams {
|
|||
uiState: Record<string, any>;
|
||||
visParams: TimeseriesVisParams;
|
||||
searchSessionId?: string;
|
||||
executionContext?: IExecutionContextContainer;
|
||||
}
|
||||
|
||||
export const metricsRequestHandler = async ({
|
||||
|
@ -26,6 +27,7 @@ export const metricsRequestHandler = async ({
|
|||
uiState,
|
||||
visParams,
|
||||
searchSessionId,
|
||||
executionContext,
|
||||
}: MetricsRequestHandlerParams): Promise<TimeseriesVisData | {}> => {
|
||||
const config = getUISettings();
|
||||
const data = getDataStart();
|
||||
|
@ -60,6 +62,7 @@ export const metricsRequestHandler = async ({
|
|||
searchSession: searchSessionOptions,
|
||||
}),
|
||||
}),
|
||||
context: executionContext,
|
||||
});
|
||||
} finally {
|
||||
if (untrackSearch && dataSearch.session.isCurrentSession(searchSessionId)) {
|
||||
|
|
|
@ -391,6 +391,13 @@ export class VisualizeEmbeddable
|
|||
syncColors: this.input.syncColors,
|
||||
uiState: this.vis.uiState,
|
||||
inspectorAdapters: this.inspectorAdapters,
|
||||
executionContext: this.deps.start().core.executionContext.create({
|
||||
type: 'visualization',
|
||||
name: this.vis.type.name,
|
||||
id: this.vis.id ?? 'an_unsaved_vis',
|
||||
description: this.vis.title ?? this.vis.type.title,
|
||||
url: this.output.editUrl,
|
||||
}),
|
||||
};
|
||||
if (this.abortController) {
|
||||
this.abortController.abort();
|
||||
|
|
|
@ -59,7 +59,10 @@ interface VisualizationAttributes extends SavedObjectAttributes {
|
|||
|
||||
export interface VisualizeEmbeddableFactoryDeps {
|
||||
start: StartServicesGetter<
|
||||
Pick<VisualizationsStartDeps, 'inspector' | 'embeddable' | 'savedObjectsClient'>
|
||||
Pick<
|
||||
VisualizationsStartDeps,
|
||||
'inspector' | 'embeddable' | 'savedObjectsClient' | 'executionContext'
|
||||
>
|
||||
>;
|
||||
}
|
||||
|
||||
|
|
|
@ -64,6 +64,7 @@ const createInstance = async () => {
|
|||
getAttributeService: jest.fn(),
|
||||
savedObjectsClient: coreMock.createStart().savedObjects.client,
|
||||
savedObjects: savedObjectsPluginMock.createStartContract(),
|
||||
executionContext: coreMock.createStart().executionContext,
|
||||
});
|
||||
|
||||
return {
|
||||
|
|
|
@ -53,6 +53,7 @@ import type {
|
|||
Plugin,
|
||||
ApplicationStart,
|
||||
SavedObjectsClientContract,
|
||||
ExecutionContextServiceStart,
|
||||
} from '../../../core/public';
|
||||
import type { UsageCollectionSetup } from '../../usage_collection/public';
|
||||
import type { UiActionsStart } from '../../ui_actions/public';
|
||||
|
@ -102,6 +103,7 @@ export interface VisualizationsStartDeps {
|
|||
getAttributeService: EmbeddableStart['getAttributeService'];
|
||||
savedObjects: SavedObjectsStart;
|
||||
savedObjectsClient: SavedObjectsClientContract;
|
||||
executionContext: ExecutionContextServiceStart;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -26,10 +26,10 @@ export default function ({ getService, getPageObjects }: PluginFunctionalProvide
|
|||
const coreStart = window._coreProvider.start.core;
|
||||
|
||||
const context = coreStart.executionContext.create({
|
||||
type: 'execution_context_app',
|
||||
name: 'Execution context app',
|
||||
id: '42',
|
||||
type: 'visualization',
|
||||
name: 'execution_context_app',
|
||||
// add a non-ASCII symbols to make sure it doesn't break the context propagation mechanism
|
||||
id: 'Visualization☺漢字',
|
||||
description: 'какое-то странное описание',
|
||||
});
|
||||
|
||||
|
@ -39,7 +39,9 @@ export default function ({ getService, getPageObjects }: PluginFunctionalProvide
|
|||
|
||||
return result['x-opaque-id'];
|
||||
})
|
||||
).to.contain('kibana:execution_context_app:42');
|
||||
).to.contain(
|
||||
'kibana:visualization:execution_context_app:Visualization%E2%98%BA%E6%BC%A2%E5%AD%97'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -128,6 +128,7 @@ describe('embeddable', () => {
|
|||
},
|
||||
errors: undefined,
|
||||
}),
|
||||
executionContext: coreMock.createStart().executionContext,
|
||||
},
|
||||
{
|
||||
timeRange: {
|
||||
|
@ -167,6 +168,7 @@ describe('embeddable', () => {
|
|||
},
|
||||
errors: undefined,
|
||||
}),
|
||||
executionContext: coreMock.createStart().executionContext,
|
||||
},
|
||||
{
|
||||
timeRange: {
|
||||
|
@ -210,6 +212,7 @@ describe('embeddable', () => {
|
|||
},
|
||||
errors: [{ shortMessage: '', longMessage: 'my validation error' }],
|
||||
}),
|
||||
executionContext: coreMock.createStart().executionContext,
|
||||
},
|
||||
{} as LensEmbeddableInput
|
||||
);
|
||||
|
@ -253,6 +256,7 @@ describe('embeddable', () => {
|
|||
},
|
||||
errors: undefined,
|
||||
}),
|
||||
executionContext: coreMock.createStart().executionContext,
|
||||
},
|
||||
{} as LensEmbeddableInput
|
||||
);
|
||||
|
@ -291,6 +295,7 @@ describe('embeddable', () => {
|
|||
},
|
||||
errors: undefined,
|
||||
}),
|
||||
executionContext: coreMock.createStart().executionContext,
|
||||
},
|
||||
{ id: '123' } as LensEmbeddableInput
|
||||
);
|
||||
|
@ -332,6 +337,7 @@ describe('embeddable', () => {
|
|||
},
|
||||
errors: undefined,
|
||||
}),
|
||||
executionContext: coreMock.createStart().executionContext,
|
||||
},
|
||||
{ id: '123' } as LensEmbeddableInput
|
||||
);
|
||||
|
@ -380,6 +386,7 @@ describe('embeddable', () => {
|
|||
},
|
||||
errors: undefined,
|
||||
}),
|
||||
executionContext: coreMock.createStart().executionContext,
|
||||
},
|
||||
{ id: '123' } as LensEmbeddableInput
|
||||
);
|
||||
|
@ -426,6 +433,7 @@ describe('embeddable', () => {
|
|||
},
|
||||
errors: undefined,
|
||||
}),
|
||||
executionContext: coreMock.createStart().executionContext,
|
||||
},
|
||||
{ id: '123' } as LensEmbeddableInput
|
||||
);
|
||||
|
@ -479,6 +487,7 @@ describe('embeddable', () => {
|
|||
},
|
||||
errors: undefined,
|
||||
}),
|
||||
executionContext: coreMock.createStart().executionContext,
|
||||
},
|
||||
input
|
||||
);
|
||||
|
@ -532,6 +541,7 @@ describe('embeddable', () => {
|
|||
},
|
||||
errors: undefined,
|
||||
}),
|
||||
executionContext: coreMock.createStart().executionContext,
|
||||
},
|
||||
input
|
||||
);
|
||||
|
@ -584,6 +594,7 @@ describe('embeddable', () => {
|
|||
},
|
||||
errors: undefined,
|
||||
}),
|
||||
executionContext: coreMock.createStart().executionContext,
|
||||
},
|
||||
input
|
||||
);
|
||||
|
@ -625,6 +636,7 @@ describe('embeddable', () => {
|
|||
},
|
||||
errors: undefined,
|
||||
}),
|
||||
executionContext: coreMock.createStart().executionContext,
|
||||
},
|
||||
{ id: '123' } as LensEmbeddableInput
|
||||
);
|
||||
|
@ -666,6 +678,7 @@ describe('embeddable', () => {
|
|||
},
|
||||
errors: undefined,
|
||||
}),
|
||||
executionContext: coreMock.createStart().executionContext,
|
||||
},
|
||||
{ id: '123' } as LensEmbeddableInput
|
||||
);
|
||||
|
@ -707,6 +720,7 @@ describe('embeddable', () => {
|
|||
},
|
||||
errors: undefined,
|
||||
}),
|
||||
executionContext: coreMock.createStart().executionContext,
|
||||
},
|
||||
{ id: '123', timeRange, query, filters } as LensEmbeddableInput
|
||||
);
|
||||
|
@ -763,6 +777,7 @@ describe('embeddable', () => {
|
|||
},
|
||||
errors: undefined,
|
||||
}),
|
||||
executionContext: coreMock.createStart().executionContext,
|
||||
},
|
||||
({ id: '123', onLoad } as unknown) as LensEmbeddableInput
|
||||
);
|
||||
|
@ -835,6 +850,7 @@ describe('embeddable', () => {
|
|||
},
|
||||
errors: undefined,
|
||||
}),
|
||||
executionContext: coreMock.createStart().executionContext,
|
||||
},
|
||||
({ id: '123', onFilter } as unknown) as LensEmbeddableInput
|
||||
);
|
||||
|
@ -882,6 +898,7 @@ describe('embeddable', () => {
|
|||
},
|
||||
errors: undefined,
|
||||
}),
|
||||
executionContext: coreMock.createStart().executionContext,
|
||||
},
|
||||
({ id: '123', onBrushEnd } as unknown) as LensEmbeddableInput
|
||||
);
|
||||
|
@ -929,6 +946,7 @@ describe('embeddable', () => {
|
|||
},
|
||||
errors: undefined,
|
||||
}),
|
||||
executionContext: coreMock.createStart().executionContext,
|
||||
},
|
||||
({ id: '123', onTableRowClick } as unknown) as LensEmbeddableInput
|
||||
);
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
import { isEqual, uniqBy } from 'lodash';
|
||||
import React from 'react';
|
||||
import { render, unmountComponentAtNode } from 'react-dom';
|
||||
import type { ExecutionContextServiceStart } from 'src/core/public';
|
||||
import {
|
||||
ExecutionContextSearch,
|
||||
Filter,
|
||||
|
@ -98,6 +99,7 @@ export interface LensEmbeddableDeps {
|
|||
getTriggerCompatibleActions?: UiActionsStart['getTriggerCompatibleActions'];
|
||||
capabilities: { canSaveVisualizations: boolean; canSaveDashboards: boolean };
|
||||
usageCollection?: UsageCollectionSetup;
|
||||
executionContext: ExecutionContextServiceStart;
|
||||
}
|
||||
|
||||
export class Embeddable
|
||||
|
@ -323,7 +325,15 @@ export class Embeddable
|
|||
if (this.input.onLoad) {
|
||||
this.input.onLoad(true);
|
||||
}
|
||||
const executionContext = this.deps.executionContext.create({
|
||||
type: 'lens',
|
||||
name: this.savedVis.visualizationType ?? '',
|
||||
description: this.savedVis.title ?? this.savedVis.description ?? '',
|
||||
id: this.id,
|
||||
url: this.output.editUrl,
|
||||
});
|
||||
const input = this.getInput();
|
||||
|
||||
render(
|
||||
<ExpressionWrapper
|
||||
ExpressionRenderer={this.expressionRenderer}
|
||||
|
@ -339,6 +349,7 @@ export class Embeddable
|
|||
hasCompatibleActions={this.hasCompatibleActions}
|
||||
className={input.className}
|
||||
style={input.style}
|
||||
executionContext={executionContext}
|
||||
canEdit={this.getIsEditable() && input.viewMode === 'edit'}
|
||||
onRuntimeError={() => {
|
||||
this.logError('runtime');
|
||||
|
|
|
@ -5,7 +5,12 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { Capabilities, HttpSetup, SavedObjectReference } from 'kibana/public';
|
||||
import type {
|
||||
Capabilities,
|
||||
HttpSetup,
|
||||
SavedObjectReference,
|
||||
ExecutionContextServiceStart,
|
||||
} from 'kibana/public';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { RecursiveReadonly } from '@kbn/utility-types';
|
||||
import { Ast } from '@kbn/interpreter/target/common';
|
||||
|
@ -33,6 +38,7 @@ export interface LensEmbeddableStartServices {
|
|||
indexPatternService: IndexPatternsContract;
|
||||
uiActions?: UiActionsStart;
|
||||
usageCollection?: UsageCollectionSetup;
|
||||
executionContext: ExecutionContextServiceStart;
|
||||
documentToExpression: (
|
||||
doc: Document
|
||||
) => Promise<{ ast: Ast | null; errors: ErrorMessage[] | undefined }>;
|
||||
|
@ -87,6 +93,7 @@ export class EmbeddableFactory implements EmbeddableFactoryDefinition {
|
|||
indexPatternService,
|
||||
capabilities,
|
||||
usageCollection,
|
||||
executionContext,
|
||||
} = await this.getStartServices();
|
||||
|
||||
const { Embeddable } = await import('../async_services');
|
||||
|
@ -106,6 +113,7 @@ export class EmbeddableFactory implements EmbeddableFactoryDefinition {
|
|||
canSaveVisualizations: Boolean(capabilities.visualize.save),
|
||||
},
|
||||
usageCollection,
|
||||
executionContext,
|
||||
},
|
||||
input,
|
||||
parent
|
||||
|
|
|
@ -14,6 +14,7 @@ import {
|
|||
ReactExpressionRendererType,
|
||||
ReactExpressionRendererProps,
|
||||
} from 'src/plugins/expressions/public';
|
||||
import type { IExecutionContextContainer } from 'src/core/public';
|
||||
import { ExecutionContextSearch } from 'src/plugins/data/public';
|
||||
import { DefaultInspectorAdapters, RenderMode } from 'src/plugins/expressions';
|
||||
import classNames from 'classnames';
|
||||
|
@ -39,6 +40,7 @@ export interface ExpressionWrapperProps {
|
|||
className?: string;
|
||||
canEdit: boolean;
|
||||
onRuntimeError: () => void;
|
||||
executionContext?: IExecutionContextContainer;
|
||||
}
|
||||
|
||||
interface VisualizationErrorProps {
|
||||
|
@ -108,6 +110,7 @@ export function ExpressionWrapper({
|
|||
errors,
|
||||
canEdit,
|
||||
onRuntimeError,
|
||||
executionContext,
|
||||
}: ExpressionWrapperProps) {
|
||||
return (
|
||||
<I18nProvider>
|
||||
|
@ -125,6 +128,7 @@ export function ExpressionWrapper({
|
|||
onData$={onData$}
|
||||
renderMode={renderMode}
|
||||
syncColors={syncColors}
|
||||
executionContext={executionContext}
|
||||
renderError={(errorMessage, error) => {
|
||||
onRuntimeError();
|
||||
return (
|
||||
|
|
|
@ -177,6 +177,7 @@ export class LensPlugin {
|
|||
attributeService: await this.attributeService!(),
|
||||
capabilities: coreStart.application.capabilities,
|
||||
coreHttp: coreStart.http,
|
||||
executionContext: coreStart.executionContext,
|
||||
timefilter: deps.data.query.timefilter.timefilter,
|
||||
expressionRenderer: deps.expressions.ReactExpressionRenderer,
|
||||
documentToExpression: this.editorFrameService!.documentToExpression,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue