Skip to content

Commit

Permalink
[Logs UI] <LogStream /> as a kibana embeddable (#88618)
Browse files Browse the repository at this point in the history
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
Alejandro Fernández Gómez and kibanamachine committed Feb 1, 2021
1 parent fb19aab commit 53637d0
Show file tree
Hide file tree
Showing 10 changed files with 169 additions and 10 deletions.
2 changes: 1 addition & 1 deletion packages/kbn-optimizer/limits.yml
Expand Up @@ -34,7 +34,7 @@ pageLoadAssetSize:
indexLifecycleManagement: 107090
indexManagement: 140608
indexPatternManagement: 154222
infra: 197873
infra: 204800
fleet: 415829
ingestPipelines: 58003
inputControlVis: 172675
Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugins/infra/kibana.json
Expand Up @@ -6,7 +6,7 @@
"features",
"usageCollection",
"spaces",

"embeddable",
"data",
"dataEnhanced",
"visTypeTimeseries",
Expand Down
7 changes: 7 additions & 0 deletions x-pack/plugins/infra/public/components/log_stream/index.ts
@@ -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';
Expand Up @@ -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 />}>
Expand Down
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand Down
@@ -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
);
}
}
@@ -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';
}
}
22 changes: 17 additions & 5 deletions x-pack/plugins/infra/public/containers/logs/log_stream/index.ts
Expand Up @@ -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';
Expand All @@ -18,7 +18,7 @@ interface LogStreamProps {
sourceId: string;
startTimestamp: number;
endTimestamp: number;
query?: string;
query?: string | Query;
center?: LogEntryCursor;
columns?: LogSourceConfigurationProperties['logColumns'];
}
Expand Down Expand Up @@ -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
Expand Down
9 changes: 9 additions & 0 deletions x-pack/plugins/infra/public/plugin.ts
Expand Up @@ -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) {}
Expand Down Expand Up @@ -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', {
Expand Down
2 changes: 2 additions & 0 deletions x-pack/plugins/infra/public/types.ts
Expand Up @@ -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,
Expand All @@ -33,6 +34,7 @@ export interface InfraClientSetupDeps {
observability: ObservabilityPluginSetup;
triggersActionsUi: TriggersAndActionsUIPublicPluginSetup;
usageCollection: UsageCollectionSetup;
embeddable: EmbeddableSetup;
}

export interface InfraClientStartDeps {
Expand Down

0 comments on commit 53637d0

Please sign in to comment.