Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Logs UI] Register Logs UI Locators #155156

Merged
Show file tree
Hide file tree
Changes from 39 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
dcafc0a
[Logs UI] Register Logs UI Locators
mohamedhamed-ahmed Apr 18, 2023
96beae3
Added Tests and some code refactoring
mohamedhamed-ahmed Apr 24, 2023
491ae2b
Resolve Conflicts
mohamedhamed-ahmed Apr 24, 2023
be89547
Allow defining time range in locators
mohamedhamed-ahmed Apr 24, 2023
47ec73a
Code Refactoring
mohamedhamed-ahmed Apr 24, 2023
37044d0
Code Refactoring
mohamedhamed-ahmed Apr 24, 2023
f33bd7c
Merge branch 'main' of https://github.com/elastic/kibana into 104855-…
mohamedhamed-ahmed Apr 24, 2023
1a8c68a
Merge branch 'main' of https://github.com/elastic/kibana into 104855-…
mohamedhamed-ahmed Apr 25, 2023
f600d36
Merge branch 'main' of https://github.com/elastic/kibana into 104855-…
mohamedhamed-ahmed Apr 25, 2023
0887034
Merge branch 'main' of https://github.com/elastic/kibana into 104855-…
mohamedhamed-ahmed Apr 25, 2023
d93c5c9
Code Refactoring
mohamedhamed-ahmed Apr 25, 2023
10eeddd
Remove unused references
mohamedhamed-ahmed Apr 25, 2023
470c441
Awaited on import to lower bundle size
mohamedhamed-ahmed Apr 25, 2023
8fae828
Code Refactoring
mohamedhamed-ahmed Apr 25, 2023
5a16193
Added redirection to discover in serverless
mohamedhamed-ahmed Apr 25, 2023
69d0f6a
Fix Tests
mohamedhamed-ahmed Apr 25, 2023
2e88f65
change from and to to be timeRange
mohamedhamed-ahmed Apr 25, 2023
1bee11b
Update discover redirection to support query params
mohamedhamed-ahmed Apr 25, 2023
b038085
bug fix
mohamedhamed-ahmed Apr 25, 2023
a546606
Merge Main
mohamedhamed-ahmed Apr 26, 2023
2647b58
Code Refactoring
mohamedhamed-ahmed Apr 26, 2023
877a9ee
Code Refactoring
mohamedhamed-ahmed Apr 26, 2023
ec50509
Fix bundle size
mohamedhamed-ahmed Apr 26, 2023
be33b45
Added support to redirection in serverless
mohamedhamed-ahmed Apr 28, 2023
c3cf1dc
Merge branch 'main' of https://github.com/elastic/kibana into 104855-…
mohamedhamed-ahmed Apr 28, 2023
d5e3554
reverted missed code
mohamedhamed-ahmed Apr 28, 2023
120b8f8
Merge branch 'main' of https://github.com/elastic/kibana into 104855-…
mohamedhamed-ahmed May 8, 2023
e382fc8
Fix Review Comments
mohamedhamed-ahmed May 8, 2023
8351cf8
Bug Fix
mohamedhamed-ahmed May 8, 2023
455abc4
Use dynamic import
mohamedhamed-ahmed May 8, 2023
9904a03
Merge branch 'main' of https://github.com/elastic/kibana into 104855-…
mohamedhamed-ahmed May 9, 2023
55f2d5e
Code Refactoring and fixing comments
mohamedhamed-ahmed May 9, 2023
b6374fc
Merge branch 'main' of https://github.com/elastic/kibana into 104855-…
mohamedhamed-ahmed May 10, 2023
6cde016
Merge branch 'main' of https://github.com/elastic/kibana into 104855-…
mohamedhamed-ahmed May 15, 2023
5d99d46
Code Refactoring and fixing comments
mohamedhamed-ahmed May 15, 2023
311517d
Remove unused translations
mohamedhamed-ahmed May 15, 2023
09ed682
Code Refactoring
mohamedhamed-ahmed May 16, 2023
6bcbfa4
Code Refactoring
mohamedhamed-ahmed May 16, 2023
485f00d
Remove unused reference
mohamedhamed-ahmed May 16, 2023
ebeabc3
Merge Main
mohamedhamed-ahmed May 17, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions x-pack/plugins/infra/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,6 @@ export const TIEBREAKER_FIELD = '_doc';
export const HOST_FIELD = 'host.name';
export const CONTAINER_FIELD = 'container.id';
export const POD_FIELD = 'kubernetes.pod.uid';

export const DISCOVER_APP_TARGET = 'discover';
export const LOGS_APP_TARGET = 'logs-ui';
91 changes: 8 additions & 83 deletions x-pack/plugins/infra/public/apps/discover_app.tsx
Copy link
Contributor Author

@mohamedhamed-ahmed mohamedhamed-ahmed Apr 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added the logic to the locator

Original file line number Diff line number Diff line change
Expand Up @@ -4,95 +4,16 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { interpret } from 'xstate';
import type { DiscoverStart } from '@kbn/discover-plugin/public';
import { createKbnUrlStateStorage } from '@kbn/kibana-utils-plugin/public';
import { AppMountParameters, CoreStart } from '@kbn/core/public';
import type { InfraClientStartDeps, InfraClientStartExports } from '../types';
import type { LogViewColumnConfiguration, ResolvedLogView } from '../../common/log_views';
import {
createLogViewStateMachine,
DEFAULT_LOG_VIEW,
initializeFromUrl,
} from '../observability_logs/log_view_state';
import { MESSAGE_FIELD, TIMESTAMP_FIELD } from '../../common/constants';
import type { AppMountParameters, CoreStart } from '@kbn/core/public';
import type { InfraClientStartExports } from '../types';
import { getLogViewReferenceFromUrl } from '../observability_logs/log_view_state';

export const renderApp = (
core: CoreStart,
plugins: InfraClientStartDeps,
pluginStart: InfraClientStartExports,
params: AppMountParameters
) => {
const { discover } = plugins;
const { logViews } = pluginStart;

const machine = createLogViewStateMachine({
initialContext: { logViewReference: DEFAULT_LOG_VIEW },
logViews: logViews.client,
initializeFromUrl: createInitializeFromUrl(core, params),
});

const service = interpret(machine)
.onTransition((state) => {
if (
state.matches('checkingStatus') ||
state.matches('resolvedPersistedLogView') ||
state.matches('resolvedInlineLogView')
) {
return redirectToDiscover(discover, state.context.resolvedLogView);
} else if (
state.matches('loadingFailed') ||
state.matches('resolutionFailed') ||
state.matches('checkingStatusFailed')
) {
return redirectToDiscover(discover);
}
})
.start();

return () => {
// Stop machine interpreter after navigation
service.stop();
};
};

const redirectToDiscover = (discover: DiscoverStart, resolvedLogView?: ResolvedLogView) => {
const navigationOptions = { replace: true };

if (!resolvedLogView) {
return discover.locator?.navigate({}, navigationOptions);
}

const columns = parseColumns(resolvedLogView.columns);
const dataViewSpec = resolvedLogView.dataViewReference.toSpec();

return discover.locator?.navigate(
{
columns,
dataViewId: dataViewSpec.id,
dataViewSpec,
},
navigationOptions
);
};

/**
* Helpers
*/

const parseColumns = (columns: ResolvedLogView['columns']) => {
return columns.map(getColumnValue).filter(Boolean) as string[];
};

const getColumnValue = (column: LogViewColumnConfiguration) => {
if ('messageColumn' in column) return MESSAGE_FIELD;
if ('timestampColumn' in column) return TIMESTAMP_FIELD;
if ('fieldColumn' in column) return column.fieldColumn.field;

return null;
};

const createInitializeFromUrl = (core: CoreStart, params: AppMountParameters) => {
const toastsService = core.notifications.toasts;

const urlStateStorage = createKbnUrlStateStorage({
Expand All @@ -101,5 +22,9 @@ const createInitializeFromUrl = (core: CoreStart, params: AppMountParameters) =>
useHashQuery: false,
});

return initializeFromUrl({ toastsService, urlStateStorage });
const logView = getLogViewReferenceFromUrl({ toastsService, urlStateStorage });

pluginStart.locators.logsLocator.navigate({ ...(logView ? { logView } : {}) }, { replace: true });

return () => true;
};
25 changes: 25 additions & 0 deletions x-pack/plugins/infra/public/locators/discover_logs_locator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { LocatorDefinition, LocatorPublic } from '@kbn/share-plugin/public';
import type { LogsLocatorDependencies, LogsLocatorParams } from './logs_locator';

const DISCOVER_LOGS_LOCATOR_ID = 'DISCOVER_LOGS_LOCATOR';

export type DiscoverLogsLocator = LocatorPublic<LogsLocatorParams>;

export class DiscoverLogsLocatorDefinition implements LocatorDefinition<LogsLocatorParams> {
public readonly id = DISCOVER_LOGS_LOCATOR_ID;

constructor(protected readonly deps: LogsLocatorDependencies) {}

public readonly getLocation = async (params: LogsLocatorParams) => {
const { getLocationToDiscover } = await import('./helpers');

return getLocationToDiscover({ core: this.deps.core, ...params });
};
}
33 changes: 33 additions & 0 deletions x-pack/plugins/infra/public/locators/discover_node_logs_locator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { LocatorDefinition, LocatorPublic } from '@kbn/share-plugin/public';
import type { NodeLogsLocatorDependencies, NodeLogsLocatorParams } from './node_logs_locator';

const DISCOVER_NODE_LOGS_LOCATOR_ID = 'DISCOVER_NODE_LOGS_LOCATOR';

export type DiscoverNodeLogsLocator = LocatorPublic<NodeLogsLocatorParams>;

export class DiscoverNodeLogsLocatorDefinition implements LocatorDefinition<NodeLogsLocatorParams> {
public readonly id = DISCOVER_NODE_LOGS_LOCATOR_ID;

constructor(protected readonly deps: NodeLogsLocatorDependencies) {}

public readonly getLocation = async (params: NodeLogsLocatorParams) => {
const { createNodeLogsQuery, getLocationToDiscover } = await import('./helpers');

const { timeRange, logView } = params;
const query = createNodeLogsQuery(params);

return getLocationToDiscover({
core: this.deps.core,
timeRange,
filter: query,
logView,
});
};
}
151 changes: 151 additions & 0 deletions x-pack/plugins/infra/public/locators/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { interpret } from 'xstate';
import { waitFor } from 'xstate/lib/waitFor';
import { flowRight } from 'lodash';
import type { DiscoverAppLocatorParams } from '@kbn/discover-plugin/common';
import type { DiscoverStart } from '@kbn/discover-plugin/public';
import { findInventoryFields } from '../../common/inventory_models';
import { MESSAGE_FIELD, TIMESTAMP_FIELD } from '../../common/constants';
import {
createLogViewStateMachine,
DEFAULT_LOG_VIEW,
replaceLogViewInQueryString,
} from '../observability_logs/log_view_state';
import { replaceLogFilterInQueryString } from '../observability_logs/log_stream_query_state';
import { replaceLogPositionInQueryString } from '../observability_logs/log_stream_position_state/src/url_state_storage_service';
import type { TimeRange } from '../../common/time';
import type { LogsLocatorParams } from './logs_locator';
import type { InfraClientCoreSetup } from '../types';
import type {
LogViewColumnConfiguration,
LogViewReference,
ResolvedLogView,
} from '../../common/log_views';
import type { NodeLogsLocatorParams } from './node_logs_locator';

interface LocationToDiscoverParams {
core: InfraClientCoreSetup;
timeRange?: TimeRange;
filter?: string;
logView?: LogViewReference;
}

export const createNodeLogsQuery = (params: NodeLogsLocatorParams) => {
const { nodeType, nodeId, filter } = params;

const nodeFilter = `${findInventoryFields(nodeType).id}: ${nodeId}`;
const query = filter ? `(${nodeFilter}) and (${filter})` : nodeFilter;

return query;
};

export const createSearchString = ({
time,
timeRange,
filter = '',
logView = DEFAULT_LOG_VIEW,
}: LogsLocatorParams) => {
return flowRight(
replaceLogFilterInQueryString({ language: 'kuery', query: filter }, time, timeRange),
replaceLogPositionInQueryString(time),
replaceLogViewInQueryString(logView)
)('');
};

export const getLocationToDiscover = async ({
core,
timeRange,
filter,
logView,
}: LocationToDiscoverParams) => {
const [, plugins, pluginStart] = await core.getStartServices();
const { discover } = plugins;
const { logViews } = pluginStart;

const machine = createLogViewStateMachine({
initialContext: { logViewReference: logView || DEFAULT_LOG_VIEW },
logViews: logViews.client,
});

const discoverParams: DiscoverAppLocatorParams = {
...(timeRange ? { from: timeRange.startTime, to: timeRange.endTime } : {}),
...(filter
? {
query: {
language: 'kuery',
query: filter,
},
}
: {}),
};

let discoverLocation;

const service = interpret(machine).start();
const doneState = await waitFor(
service,
(state) =>
state.matches('checkingStatus') ||
state.matches('resolvedPersistedLogView') ||
state.matches('resolvedInlineLogView') ||
state.matches('loadingFailed') ||
state.matches('resolutionFailed') ||
state.matches('checkingStatusFailed')
);

service.stop();

if ('resolvedLogView' in doneState.context) {
discoverLocation = await constructDiscoverLocation(
discover,
discoverParams,
doneState.context.resolvedLogView
);
} else {
discoverLocation = await constructDiscoverLocation(discover, discoverParams);
}

if (!discoverLocation) {
throw new Error('Discover location not found');
}

return discoverLocation;
};

const constructDiscoverLocation = async (
discover: DiscoverStart,
discoverParams: DiscoverAppLocatorParams,
resolvedLogView?: ResolvedLogView
) => {
if (!resolvedLogView) {
return await discover.locator?.getLocation(discoverParams);
}

const columns = parseColumns(resolvedLogView.columns);
const dataViewSpec = resolvedLogView.dataViewReference.toSpec();

return await discover.locator?.getLocation({
...discoverParams,
columns,
dataViewId: dataViewSpec.id,
dataViewSpec,
});
};

const parseColumns = (columns: ResolvedLogView['columns']) => {
return columns.map(getColumnValue).filter(Boolean) as string[];
};

const getColumnValue = (column: LogViewColumnConfiguration) => {
if ('messageColumn' in column) return MESSAGE_FIELD;
if ('timestampColumn' in column) return TIMESTAMP_FIELD;
if ('fieldColumn' in column) return column.fieldColumn.field;

return null;
};
21 changes: 21 additions & 0 deletions x-pack/plugins/infra/public/locators/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import type { DiscoverLogsLocator } from './discover_logs_locator';
import type { DiscoverNodeLogsLocator } from './discover_node_logs_locator';
import type { LogsLocator } from './logs_locator';
import type { NodeLogsLocator } from './node_logs_locator';

export * from './discover_logs_locator';
export * from './discover_node_logs_locator';
export * from './logs_locator';
export * from './node_logs_locator';

export interface InfraLocators {
logsLocator: LogsLocator | DiscoverLogsLocator;
nodeLogsLocator: NodeLogsLocator | DiscoverNodeLogsLocator;
}
14 changes: 14 additions & 0 deletions x-pack/plugins/infra/public/locators/locators.mock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { sharePluginMock } from '@kbn/share-plugin/public/mocks';
import type { InfraLocators } from '.';

export const createLocatorMock = (): jest.Mocked<InfraLocators> => ({
logsLocator: sharePluginMock.createLocator(),
nodeLogsLocator: sharePluginMock.createLocator(),
});
Loading