[Logs UI] <LogStream /> as a kibana embeddable (#88618)

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Alejandro Fernández Gómez 2021-02-01 14:48:30 +01:00 committed by GitHub
parent fb19aab307
commit 53637d0158
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 169 additions and 10 deletions

View file

@ -34,7 +34,7 @@ pageLoadAssetSize:
indexLifecycleManagement: 107090
indexManagement: 140608
indexPatternManagement: 154222
infra: 197873
infra: 204800
fleet: 415829
ingestPipelines: 58003
inputControlVis: 172675

View file

@ -6,7 +6,7 @@
"features",
"usageCollection",
"spaces",
"embeddable",
"data",
"dataEnhanced",
"visTypeTimeseries",

View file

@ -0,0 +1,7 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
export * from './log_stream';

View file

@ -5,9 +5,9 @@
*/
import React from 'react';
import type { LogStreamProps } from './';
import type { LogStreamProps } from './log_stream';
const LazyLogStream = React.lazy(() => import('./'));
const LazyLogStream = React.lazy(() => import('./log_stream'));
export const LazyLogStreamWrapper: React.FC<LogStreamProps> = (props) => (
<React.Suspense fallback={<div />}>

View file

@ -17,6 +17,7 @@ import { useLogStream } from '../../containers/logs/log_stream';
import { ScrollableLogTextStreamView } from '../logging/log_text_stream';
import { LogColumnRenderConfiguration } from '../../utils/log_column_render_configuration';
import { JsonValue } from '../../../../../../src/plugins/kibana_utils/common';
import { Query } from '../../../../../../src/plugins/data/common';
const PAGE_THRESHOLD = 2;
@ -55,7 +56,7 @@ export interface LogStreamProps {
sourceId?: string;
startTimestamp: number;
endTimestamp: number;
query?: string;
query?: string | Query;
center?: LogEntryCursor;
highlight?: string;
height?: string | number;

View file

@ -0,0 +1,91 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import React from 'react';
import ReactDOM from 'react-dom';
import { CoreStart } from 'kibana/public';
import { I18nProvider } from '@kbn/i18n/react';
import { KibanaContextProvider } from '../../../../../../src/plugins/kibana_react/public';
import { EuiThemeProvider } from '../../../../../../src/plugins/kibana_react/common';
import { Query, TimeRange } from '../../../../../../src/plugins/data/public';
import {
Embeddable,
EmbeddableInput,
IContainer,
} from '../../../../../../src/plugins/embeddable/public';
import { datemathToEpochMillis } from '../../utils/datemath';
import { LazyLogStreamWrapper } from './lazy_log_stream_wrapper';
export const LOG_STREAM_EMBEDDABLE = 'LOG_STREAM_EMBEDDABLE';
export interface LogStreamEmbeddableInput extends EmbeddableInput {
timeRange: TimeRange;
query: Query;
}
export class LogStreamEmbeddable extends Embeddable<LogStreamEmbeddableInput> {
public readonly type = LOG_STREAM_EMBEDDABLE;
private node?: HTMLElement;
constructor(
private services: CoreStart,
initialInput: LogStreamEmbeddableInput,
parent?: IContainer
) {
super(initialInput, {}, parent);
}
public render(node: HTMLElement) {
if (this.node) {
ReactDOM.unmountComponentAtNode(this.node);
}
this.node = node;
this.renderComponent();
}
public reload() {
this.renderComponent();
}
public destroy() {
super.destroy();
if (this.node) {
ReactDOM.unmountComponentAtNode(this.node);
}
}
private renderComponent() {
if (!this.node) {
return;
}
const startTimestamp = datemathToEpochMillis(this.input.timeRange.from);
const endTimestamp = datemathToEpochMillis(this.input.timeRange.to);
if (!startTimestamp || !endTimestamp) {
return;
}
ReactDOM.render(
<I18nProvider>
<EuiThemeProvider>
<KibanaContextProvider services={this.services}>
<div style={{ width: '100%' }}>
<LazyLogStreamWrapper
startTimestamp={startTimestamp}
endTimestamp={endTimestamp}
height="100%"
query={this.input.query}
/>
</div>
</KibanaContextProvider>
</EuiThemeProvider>
</I18nProvider>,
this.node
);
}
}

View file

@ -0,0 +1,37 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { CoreStart } from 'kibana/public';
import {
EmbeddableFactoryDefinition,
IContainer,
} from '../../../../../../src/plugins/embeddable/public';
import {
LogStreamEmbeddable,
LOG_STREAM_EMBEDDABLE,
LogStreamEmbeddableInput,
} from './log_stream_embeddable';
export class LogStreamEmbeddableFactoryDefinition
implements EmbeddableFactoryDefinition<LogStreamEmbeddableInput> {
public readonly type = LOG_STREAM_EMBEDDABLE;
constructor(private getCoreServices: () => Promise<CoreStart>) {}
public async isEditable() {
const { application } = await this.getCoreServices();
return application.capabilities.logs.save as boolean;
}
public async create(initialInput: LogStreamEmbeddableInput, parent?: IContainer) {
const services = await this.getCoreServices();
return new LogStreamEmbeddable(services, initialInput, parent);
}
public getDisplayName() {
return 'Log stream';
}
}

View file

@ -7,7 +7,7 @@
import { useMemo, useEffect } from 'react';
import useSetState from 'react-use/lib/useSetState';
import usePrevious from 'react-use/lib/usePrevious';
import { esKuery } from '../../../../../../../src/plugins/data/public';
import { esKuery, esQuery, Query } from '../../../../../../../src/plugins/data/public';
import { fetchLogEntries } from '../log_entries/api/fetch_log_entries';
import { useTrackedPromise } from '../../../utils/use_tracked_promise';
import { LogEntryCursor, LogEntry } from '../../../../common/log_entry';
@ -18,7 +18,7 @@ interface LogStreamProps {
sourceId: string;
startTimestamp: number;
endTimestamp: number;
query?: string;
query?: string | Query;
center?: LogEntryCursor;
columns?: LogSourceConfigurationProperties['logColumns'];
}
@ -84,9 +84,21 @@ export function useLogStream({
}, [prevEndTimestamp, endTimestamp, setState]);
const parsedQuery = useMemo(() => {
return query
? JSON.stringify(esKuery.toElasticsearchQuery(esKuery.fromKueryExpression(query)))
: null;
if (!query) {
return null;
}
let q;
if (typeof query === 'string') {
q = esKuery.toElasticsearchQuery(esKuery.fromKueryExpression(query));
} else if (query.language === 'kuery') {
q = esKuery.toElasticsearchQuery(esKuery.fromKueryExpression(query.query as string));
} else if (query.language === 'lucene') {
q = esQuery.luceneStringToDsl(query.query as string);
}
return JSON.stringify(q);
}, [query]);
// Callbacks

View file

@ -19,6 +19,8 @@ import {
} from './types';
import { getLogsHasDataFetcher, getLogsOverviewDataFetcher } from './utils/logs_overview_fetchers';
import { createMetricsHasData, createMetricsFetchData } from './metrics_overview_fetchers';
import { LOG_STREAM_EMBEDDABLE } from './components/log_stream/log_stream_embeddable';
import { LogStreamEmbeddableFactoryDefinition } from './components/log_stream/log_stream_embeddable_factory';
export class Plugin implements InfraClientPluginClass {
constructor(_context: PluginInitializerContext) {}
@ -46,6 +48,13 @@ export class Plugin implements InfraClientPluginClass {
});
}
const getCoreServices = async () => (await core.getStartServices())[0];
pluginsSetup.embeddable.registerEmbeddableFactory(
LOG_STREAM_EMBEDDABLE,
new LogStreamEmbeddableFactoryDefinition(getCoreServices)
);
core.application.register({
id: 'logs',
title: i18n.translate('xpack.infra.logs.pluginTitle', {

View file

@ -7,6 +7,7 @@
import type { CoreSetup, CoreStart, Plugin as PluginClass } from 'kibana/public';
import type { DataPublicPluginStart } from '../../../../src/plugins/data/public';
import type { HomePublicPluginSetup } from '../../../../src/plugins/home/public';
import type { EmbeddableSetup } from '../../../../src/plugins/embeddable/public';
import type {
UsageCollectionSetup,
UsageCollectionStart,
@ -33,6 +34,7 @@ export interface InfraClientSetupDeps {
observability: ObservabilityPluginSetup;
triggersActionsUi: TriggersAndActionsUIPublicPluginSetup;
usageCollection: UsageCollectionSetup;
embeddable: EmbeddableSetup;
}
export interface InfraClientStartDeps {