diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/instance_actions_menu/index.tsx b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/instance_actions_menu/index.tsx index 450c5ec061971..ff88e61fd5132 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/instance_actions_menu/index.tsx +++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/instance_actions_menu/index.tsx @@ -19,10 +19,7 @@ import { AllDatasetsLocatorParams, ALL_DATASETS_LOCATOR_ID, } from '@kbn/deeplinks-observability/locators'; -import { - NODE_LOGS_LOCATOR_ID, - NodeLogsLocatorParams, -} from '@kbn/logs-shared-plugin/common'; +import { getLogsLocatorsFromUrlService } from '@kbn/logs-shared-plugin/common'; import { isJavaAgentName } from '../../../../../../common/agent_name'; import { SERVICE_NODE_NAME } from '../../../../../../common/es_fields/apm'; import { useApmPluginContext } from '../../../../../context/apm_plugin/use_apm_plugin_context'; @@ -63,8 +60,7 @@ export function InstanceActionsMenu({ const allDatasetsLocator = share.url.locators.get( ALL_DATASETS_LOCATOR_ID )!; - const nodeLogsLocator = - share.url.locators.get(NODE_LOGS_LOCATOR_ID)!; + const { nodeLogsLocator } = getLogsLocatorsFromUrlService(share.url); if (isPending(status)) { return ( diff --git a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/instance_actions_menu/menu_sections.ts b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/instance_actions_menu/menu_sections.ts index 8401cc6bbc744..3f258ea089a15 100644 --- a/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/instance_actions_menu/menu_sections.ts +++ b/x-pack/plugins/apm/public/components/app/service_overview/service_overview_instances_table/instance_actions_menu/menu_sections.ts @@ -8,10 +8,10 @@ import { i18n } from '@kbn/i18n'; import { IBasePath } from '@kbn/core/public'; import moment from 'moment'; -import type { LocatorPublic } from '@kbn/share-plugin/public'; import { AllDatasetsLocatorParams } from '@kbn/deeplinks-observability/locators'; +import type { LocatorPublic } from '@kbn/share-plugin/public'; import { NodeLogsLocatorParams } from '@kbn/logs-shared-plugin/common'; -import { getNodeLogsHref } from '../../../../shared/links/observability_logs_link'; +import { findInventoryFields } from '@kbn/metrics-data-access-plugin/common'; import { APIReturnType } from '../../../../../services/rest/create_call_apm_api'; import { getInfraHref } from '../../../../shared/links/infra_link'; import { @@ -58,20 +58,17 @@ export function getMenuSections({ : undefined; const infraMetricsQuery = getInfraMetricsQuery(instanceDetails['@timestamp']); - const podLogsHref = getNodeLogsHref( - 'pod', - podId!, + const podLogsHref = nodeLogsLocator.getRedirectUrl({ + nodeField: findInventoryFields('pod').id, + nodeId: podId!, time, - allDatasetsLocator, - nodeLogsLocator - ); - const containerLogsHref = getNodeLogsHref( - 'container', - containerId!, + }); + + const containerLogsHref = nodeLogsLocator.getRedirectUrl({ + nodeField: findInventoryFields('container').id, + nodeId: containerId!, time, - allDatasetsLocator, - nodeLogsLocator - ); + }); const podActions: Action[] = [ { diff --git a/x-pack/plugins/apm/public/components/shared/links/observability_logs_link.ts b/x-pack/plugins/apm/public/components/shared/links/observability_logs_link.ts deleted file mode 100644 index 72ae29960942e..0000000000000 --- a/x-pack/plugins/apm/public/components/shared/links/observability_logs_link.ts +++ /dev/null @@ -1,89 +0,0 @@ -/* - * 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 { - LogsLocatorParams, - NodeLogsLocatorParams, -} from '@kbn/logs-shared-plugin/common'; -import { AllDatasetsLocatorParams } from '@kbn/deeplinks-observability/locators'; -import { LocatorPublic } from '@kbn/share-plugin/common'; -import moment from 'moment'; -import { DurationInputObject } from 'moment'; - -type NodeType = 'host' | 'pod' | 'container'; - -const NodeTypeMapping: Record = { - host: 'host.name', - container: 'container.id', - pod: 'kubernetes.pod.uid', -}; - -export const getNodeLogsHref = ( - nodeType: NodeType, - id: string, - time: number | undefined, - allDatasetsLocator: LocatorPublic, - infraNodeLocator?: LocatorPublic -): string => { - if (infraNodeLocator) - return infraNodeLocator?.getRedirectUrl({ - nodeId: id!, - nodeType, - time, - }); - - return allDatasetsLocator.getRedirectUrl({ - query: getNodeQuery(nodeType, id), - ...(time - ? { - timeRange: { - from: getTimeRangeStartFromTime(time), - to: getTimeRangeEndFromTime(time), - }, - } - : {}), - }); -}; - -export const getTraceLogsHref = ( - traceId: string, - time: number | undefined, - allDatasetsLocator: LocatorPublic, - infraLogsLocator: LocatorPublic -): string => { - const query = `trace.id:"${traceId}" OR (not trace.id:* AND "${traceId}")`; - - if (infraLogsLocator) - return infraLogsLocator.getRedirectUrl({ - filter: query, - time, - }); - - return allDatasetsLocator.getRedirectUrl({ - query: { language: 'kuery', query }, - ...(time - ? { - timeRange: { - from: getTimeRangeStartFromTime(time), - to: getTimeRangeEndFromTime(time), - }, - } - : {}), - }); -}; - -const getNodeQuery = (type: NodeType, id: string) => { - return { language: 'kuery', query: `${NodeTypeMapping[type]}: ${id}` }; -}; - -const defaultTimeRangeFromPositionOffset: DurationInputObject = { hours: 1 }; - -const getTimeRangeStartFromTime = (time: number): string => - moment(time).subtract(defaultTimeRangeFromPositionOffset).toISOString(); - -const getTimeRangeEndFromTime = (time: number): string => - moment(time).add(defaultTimeRangeFromPositionOffset).toISOString(); diff --git a/x-pack/plugins/apm/public/components/shared/transaction_action_menu/sections.test.ts b/x-pack/plugins/apm/public/components/shared/transaction_action_menu/sections.test.ts index 7d7a720f27cfc..dd1cfa389453f 100644 --- a/x-pack/plugins/apm/public/components/shared/transaction_action_menu/sections.test.ts +++ b/x-pack/plugins/apm/public/components/shared/transaction_action_menu/sections.test.ts @@ -7,11 +7,6 @@ import { createMemoryHistory } from 'history'; import { IBasePath } from '@kbn/core/public'; -import { LocatorPublic } from '@kbn/share-plugin/common'; -import { - LogsLocatorParams, - NodeLogsLocatorParams, -} from '@kbn/logs-shared-plugin/common'; import { Transaction } from '../../../../typings/es_schemas/ui/transaction'; import { getSections } from './sections'; import { @@ -19,7 +14,7 @@ import { ApmRouter, } from '../../routing/apm_route_config'; import { - infraLocatorsMock, + logsLocatorsMock, observabilityLogExplorerLocatorsMock, } from '../../../context/apm_plugin/mock_apm_plugin_context'; @@ -30,11 +25,11 @@ const apmRouter = { } as ApmRouter; const { allDatasetsLocator } = observabilityLogExplorerLocatorsMock; -const { nodeLogsLocator, logsLocator } = infraLocatorsMock; +const { nodeLogsLocator, traceLogsLocator } = logsLocatorsMock; -const expectInfraLocatorsToBeCalled = () => { +const expectLogsLocatorsToBeCalled = () => { expect(nodeLogsLocator.getRedirectUrl).toBeCalledTimes(3); - expect(logsLocator.getRedirectUrl).toBeCalledTimes(1); + expect(traceLogsLocator.getRedirectUrl).toBeCalledTimes(1); }; describe('Transaction action menu', () => { @@ -70,9 +65,7 @@ describe('Transaction action menu', () => { location, apmRouter, allDatasetsLocator, - logsLocator: logsLocator as unknown as LocatorPublic, - nodeLogsLocator: - nodeLogsLocator as unknown as LocatorPublic, + logsLocators: logsLocatorsMock, infraLinksAvailable: false, rangeFrom: 'now-24h', rangeTo: 'now', @@ -121,7 +114,7 @@ describe('Transaction action menu', () => { }, ], ]); - expectInfraLocatorsToBeCalled(); + expectLogsLocatorsToBeCalled(); }); it('shows pod and required sections only', () => { @@ -138,10 +131,8 @@ describe('Transaction action menu', () => { basePath, location, apmRouter, - logsLocator: logsLocator as unknown as LocatorPublic, - nodeLogsLocator: - nodeLogsLocator as unknown as LocatorPublic, allDatasetsLocator, + logsLocators: logsLocatorsMock, infraLinksAvailable: true, rangeFrom: 'now-24h', rangeTo: 'now', @@ -209,7 +200,7 @@ describe('Transaction action menu', () => { }, ], ]); - expectInfraLocatorsToBeCalled(); + expectLogsLocatorsToBeCalled(); }); it('shows host and required sections only', () => { @@ -226,10 +217,8 @@ describe('Transaction action menu', () => { basePath, location, apmRouter, - logsLocator: logsLocator as unknown as LocatorPublic, - nodeLogsLocator: - nodeLogsLocator as unknown as LocatorPublic, allDatasetsLocator, + logsLocators: logsLocatorsMock, infraLinksAvailable: true, rangeFrom: 'now-24h', rangeTo: 'now', @@ -296,6 +285,6 @@ describe('Transaction action menu', () => { }, ], ]); - expectInfraLocatorsToBeCalled(); + expectLogsLocatorsToBeCalled(); }); }); diff --git a/x-pack/plugins/apm/public/components/shared/transaction_action_menu/sections.ts b/x-pack/plugins/apm/public/components/shared/transaction_action_menu/sections.ts index 09f742ad1254e..398a657d06714 100644 --- a/x-pack/plugins/apm/public/components/shared/transaction_action_menu/sections.ts +++ b/x-pack/plugins/apm/public/components/shared/transaction_action_menu/sections.ts @@ -11,10 +11,8 @@ import { IBasePath } from '@kbn/core/public'; import { isEmpty, pickBy } from 'lodash'; import moment from 'moment'; import url from 'url'; -import { - LogsLocatorParams, - NodeLogsLocatorParams, -} from '@kbn/logs-shared-plugin/common'; +import type { getLogsLocatorsFromUrlService } from '@kbn/logs-shared-plugin/common'; +import { findInventoryFields } from '@kbn/metrics-data-access-plugin/common'; import { LocatorPublic } from '@kbn/share-plugin/common'; import { AllDatasetsLocatorParams } from '@kbn/deeplinks-observability/locators'; import type { ProfilingLocators } from '@kbn/observability-shared-plugin/public'; @@ -27,10 +25,6 @@ import { fromQuery } from '../links/url_helpers'; import { SectionRecord, getNonEmptySections, Action } from './sections_helper'; import { HOST_NAME, TRACE_ID } from '../../../../common/es_fields/apm'; import { ApmRouter } from '../../routing/apm_route_config'; -import { - getNodeLogsHref, - getTraceLogsHref, -} from '../links/observability_logs_link'; function getInfraMetricsQuery(transaction: Transaction) { const timestamp = new Date(transaction['@timestamp']).getTime(); @@ -53,8 +47,7 @@ export const getSections = ({ rangeTo, environment, allDatasetsLocator, - logsLocator, - nodeLogsLocator, + logsLocators, dataViewId, }: { transaction?: Transaction; @@ -67,8 +60,7 @@ export const getSections = ({ rangeTo: string; environment: Environment; allDatasetsLocator: LocatorPublic; - logsLocator: LocatorPublic; - nodeLogsLocator: LocatorPublic; + logsLocators: ReturnType; dataViewId?: string; }) => { if (!transaction) return []; @@ -95,33 +87,26 @@ export const getSections = ({ }); // Logs hrefs - const podLogsHref = getNodeLogsHref( - 'pod', - podId!, + const podLogsHref = logsLocators.nodeLogsLocator.getRedirectUrl({ + nodeField: findInventoryFields('pod').id, + nodeId: podId!, time, - allDatasetsLocator, - nodeLogsLocator - ); - const containerLogsHref = getNodeLogsHref( - 'container', - containerId!, + }); + const containerLogsHref = logsLocators.nodeLogsLocator.getRedirectUrl({ + nodeField: findInventoryFields('container').id, + nodeId: containerId!, time, - allDatasetsLocator, - nodeLogsLocator - ); - const hostLogsHref = getNodeLogsHref( - 'host', - hostName!, + }); + const hostLogsHref = logsLocators.nodeLogsLocator.getRedirectUrl({ + nodeField: findInventoryFields('host').id, + nodeId: hostName!, time, - allDatasetsLocator, - nodeLogsLocator - ); - const traceLogsHref = getTraceLogsHref( - transaction.trace.id!, + }); + + const traceLogsHref = logsLocators.traceLogsLocator.getRedirectUrl({ + traceId: transaction.trace.id!, time, - allDatasetsLocator, - logsLocator - ); + }); const podActions: Action[] = [ { diff --git a/x-pack/plugins/apm/public/components/shared/transaction_action_menu/transaction_action_menu.test.tsx b/x-pack/plugins/apm/public/components/shared/transaction_action_menu/transaction_action_menu.test.tsx index be78efeb870ee..ce9d81a52eb32 100644 --- a/x-pack/plugins/apm/public/components/shared/transaction_action_menu/transaction_action_menu.test.tsx +++ b/x-pack/plugins/apm/public/components/shared/transaction_action_menu/transaction_action_menu.test.tsx @@ -13,13 +13,14 @@ import { License } from '@kbn/licensing-plugin/common/license'; import { LOGS_LOCATOR_ID, NODE_LOGS_LOCATOR_ID, + TRACE_LOGS_LOCATOR_ID, } from '@kbn/logs-shared-plugin/common'; import { Transaction } from '../../../../typings/es_schemas/ui/transaction'; import { ApmPluginContextValue } from '../../../context/apm_plugin/apm_plugin_context'; import { mockApmPluginContextValue, MockApmPluginContextWrapper, - infraLocatorsMock, + logsLocatorsMock, } from '../../../context/apm_plugin/mock_apm_plugin_context'; import { LicenseContext } from '../../../context/license/license_context'; import * as hooks from '../../../hooks/use_fetcher'; @@ -43,11 +44,15 @@ const apmContextMock = { locators: { get: (id: string) => { if (id === LOGS_LOCATOR_ID) { - return infraLocatorsMock.logsLocator; + return logsLocatorsMock.logsLocator; } if (id === NODE_LOGS_LOCATOR_ID) { - return infraLocatorsMock.nodeLogsLocator; + return logsLocatorsMock.nodeLogsLocator; + } + + if (id === TRACE_LOGS_LOCATOR_ID) { + return logsLocatorsMock.traceLogsLocator; } }, }, @@ -102,9 +107,9 @@ const renderTransaction = async (transaction: Record) => { return rendered; }; -const expectInfraLocatorsToBeCalled = () => { - expect(infraLocatorsMock.nodeLogsLocator.getRedirectUrl).toBeCalled(); - expect(infraLocatorsMock.logsLocator.getRedirectUrl).toBeCalled(); +const expectLogsLocatorsToBeCalled = () => { + expect(logsLocatorsMock.nodeLogsLocator.getRedirectUrl).toBeCalled(); + expect(logsLocatorsMock.traceLogsLocator.getRedirectUrl).toBeCalled(); }; let useAdHocApmDataViewSpy: jest.SpyInstance; @@ -144,10 +149,10 @@ describe('TransactionActionMenu ', () => { expect(findByText('View transaction in Discover')).not.toBeNull(); }); - it('should call infra locators getRedirectUrl function', async () => { + it('should call logs locators getRedirectUrl function', async () => { await renderTransaction(Transactions.transactionWithMinimalData); - expectInfraLocatorsToBeCalled(); + expectLogsLocatorsToBeCalled(); }); describe('when there is no pod id', () => { @@ -169,10 +174,10 @@ describe('TransactionActionMenu ', () => { }); describe('when there is a pod id', () => { - it('should call infra locators getRedirectUrl function', async () => { + it('should call logs locators getRedirectUrl function', async () => { await renderTransaction(Transactions.transactionWithKubernetesData); - expectInfraLocatorsToBeCalled(); + expectLogsLocatorsToBeCalled(); }); it('renders the pod metrics link', async () => { @@ -206,11 +211,11 @@ describe('TransactionActionMenu ', () => { }); }); - describe('should call infra locators getRedirectUrl function', () => { + describe('should call logs locators getRedirectUrl function', () => { it('renders the Container logs link', async () => { await renderTransaction(Transactions.transactionWithContainerData); - expectInfraLocatorsToBeCalled(); + expectLogsLocatorsToBeCalled(); }); it('renders the Container metrics link', async () => { @@ -245,10 +250,10 @@ describe('TransactionActionMenu ', () => { }); describe('when there is a hostname', () => { - it('should call infra locators getRedirectUrl function', async () => { + it('should call logs locators getRedirectUrl function', async () => { await renderTransaction(Transactions.transactionWithHostData); - expectInfraLocatorsToBeCalled(); + expectLogsLocatorsToBeCalled(); }); it('renders the Host metrics link', async () => { diff --git a/x-pack/plugins/apm/public/components/shared/transaction_action_menu/transaction_action_menu.tsx b/x-pack/plugins/apm/public/components/shared/transaction_action_menu/transaction_action_menu.tsx index 21cfea70c4e31..fe3cd90222ef4 100644 --- a/x-pack/plugins/apm/public/components/shared/transaction_action_menu/transaction_action_menu.tsx +++ b/x-pack/plugins/apm/public/components/shared/transaction_action_menu/transaction_action_menu.tsx @@ -25,13 +25,8 @@ import { AllDatasetsLocatorParams, ALL_DATASETS_LOCATOR_ID, } from '@kbn/deeplinks-observability/locators'; -import { - LOGS_LOCATOR_ID, - LogsLocatorParams, - NODE_LOGS_LOCATOR_ID, - NodeLogsLocatorParams, -} from '@kbn/logs-shared-plugin/common'; import type { ProfilingLocators } from '@kbn/observability-shared-plugin/public'; +import { getLogsLocatorsFromUrlService } from '@kbn/logs-shared-plugin/common'; import { useAnyOfApmParams } from '../../../hooks/use_apm_params'; import { ApmFeatureFlagName } from '../../../../common/apm_feature_flags'; import { Transaction } from '../../../../typings/es_schemas/ui/transaction'; @@ -144,10 +139,7 @@ function ActionMenuSections({ const allDatasetsLocator = share.url.locators.get( ALL_DATASETS_LOCATOR_ID )!; - const logsLocator = - share.url.locators.get(LOGS_LOCATOR_ID)!; - const nodeLogsLocator = - share.url.locators.get(NODE_LOGS_LOCATOR_ID)!; + const logsLocators = getLogsLocatorsFromUrlService(share.url); const infraLinksAvailable = useApmFeatureFlag( ApmFeatureFlagName.InfraUiAvailable @@ -173,8 +165,7 @@ function ActionMenuSections({ rangeTo, environment, allDatasetsLocator, - logsLocator, - nodeLogsLocator, + logsLocators, dataViewId: dataView?.id, }); diff --git a/x-pack/plugins/apm/public/context/apm_plugin/mock_apm_plugin_context.tsx b/x-pack/plugins/apm/public/context/apm_plugin/mock_apm_plugin_context.tsx index 61710babd1dac..f6f45a273de45 100644 --- a/x-pack/plugins/apm/public/context/apm_plugin/mock_apm_plugin_context.tsx +++ b/x-pack/plugins/apm/public/context/apm_plugin/mock_apm_plugin_context.tsx @@ -13,6 +13,11 @@ import { merge } from 'lodash'; import { coreMock } from '@kbn/core/public/mocks'; import { UrlService } from '@kbn/share-plugin/common/url_service'; import { createObservabilityRuleTypeRegistryMock } from '@kbn/observability-plugin/public'; +import { + LogsLocatorParams, + NodeLogsLocatorParams, + TraceLogsLocatorParams, +} from '@kbn/logs-shared-plugin/common'; import { UI_SETTINGS } from '@kbn/data-plugin/common'; import { MlLocatorDefinition } from '@kbn/ml-plugin/public'; import { enableComparisonByDefault } from '@kbn/observability-plugin/public'; @@ -131,9 +136,10 @@ export const observabilityLogExplorerLocatorsMock = { singleDatasetLocator: sharePluginMock.createLocator(), }; -export const infraLocatorsMock = { - nodeLogsLocator: sharePluginMock.createLocator(), - logsLocator: sharePluginMock.createLocator(), +export const logsLocatorsMock = { + logsLocator: sharePluginMock.createLocator(), + nodeLogsLocator: sharePluginMock.createLocator(), + traceLogsLocator: sharePluginMock.createLocator(), }; const mockCorePlugins = { diff --git a/x-pack/plugins/infra/common/locators/helpers.ts b/x-pack/plugins/infra/common/locators/helpers.ts index 582499407bb40..d067ea15e7ebe 100644 --- a/x-pack/plugins/infra/common/locators/helpers.ts +++ b/x-pack/plugins/infra/common/locators/helpers.ts @@ -13,10 +13,8 @@ import { LogViewReference, ResolvedLogView, LogsLocatorParams, - NodeLogsLocatorParams, } from '@kbn/logs-shared-plugin/common'; import { flowRight } from 'lodash'; -import { findInventoryFields } from '@kbn/metrics-data-access-plugin/common'; import type { InfraClientCoreSetup } from '../../public/types'; import { MESSAGE_FIELD, TIMESTAMP_FIELD } from '../constants'; import type { TimeRange } from '../time'; @@ -33,15 +31,6 @@ interface LocationToDiscoverParams { 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, diff --git a/x-pack/plugins/infra/common/locators/index.ts b/x-pack/plugins/infra/common/locators/index.ts index d84c42a6dc21e..914334d2df97c 100644 --- a/x-pack/plugins/infra/common/locators/index.ts +++ b/x-pack/plugins/infra/common/locators/index.ts @@ -5,13 +5,13 @@ * 2.0. */ -import type { LogsLocator } from './logs_locator'; -import type { NodeLogsLocator } from './node_logs_locator'; +import type { InfraLogsLocator } from './logs_locator'; +import type { InfraNodeLogsLocator } from './node_logs_locator'; export * from './logs_locator'; export * from './node_logs_locator'; export interface InfraLocators { - logsLocator: LogsLocator; - nodeLogsLocator: NodeLogsLocator; + logsLocator?: InfraLogsLocator; + nodeLogsLocator?: InfraNodeLogsLocator; } diff --git a/x-pack/plugins/infra/common/locators/locators.test.ts b/x-pack/plugins/infra/common/locators/locators.test.ts index 607fd41b1bab6..7996380e3268b 100644 --- a/x-pack/plugins/infra/common/locators/locators.test.ts +++ b/x-pack/plugins/infra/common/locators/locators.test.ts @@ -6,8 +6,8 @@ */ import { v4 as uuidv4 } from 'uuid'; -import { LogsLocatorDefinition, LogsLocatorDependencies } from './logs_locator'; -import { NodeLogsLocatorDefinition } from './node_logs_locator'; +import { InfraLogsLocatorDefinition, InfraLogsLocatorDependencies } from './logs_locator'; +import { InfraNodeLogsLocatorDefinition } from './node_logs_locator'; import { coreMock } from '@kbn/core/public/mocks'; import { findInventoryFields } from '@kbn/metrics-data-access-plugin/common'; import moment from 'moment'; @@ -19,11 +19,11 @@ import { } from '@kbn/logs-shared-plugin/common'; const setupLogsLocator = async () => { - const deps: LogsLocatorDependencies = { + const deps: InfraLogsLocatorDependencies = { core: coreMock.createSetup(), }; - const logsLocator = new LogsLocatorDefinition(deps); - const nodeLogsLocator = new NodeLogsLocatorDefinition(deps); + const logsLocator = new InfraLogsLocatorDefinition(deps); + const nodeLogsLocator = new InfraNodeLogsLocatorDefinition(deps); return { logsLocator, @@ -33,8 +33,9 @@ const setupLogsLocator = async () => { describe('Infra Locators', () => { const APP_ID = 'logs'; - const nodeType = 'host'; const FILTER_QUERY = 'trace.id:1234'; + const nodeType = 'host'; + const nodeField = findInventoryFields(nodeType).id; const nodeId = uuidv4(); const time = 1550671089404; const from = 1676815089000; @@ -124,7 +125,7 @@ describe('Infra Locators', () => { it('should create a link to Node Logs with no state', async () => { const params: NodeLogsLocatorParams = { nodeId, - nodeType, + nodeField, time, }; const { nodeLogsLocator } = await setupLogsLocator(); @@ -139,7 +140,7 @@ describe('Infra Locators', () => { it('should allow specifying specific logPosition', async () => { const params: NodeLogsLocatorParams = { nodeId, - nodeType, + nodeField, time, }; const { nodeLogsLocator } = await setupLogsLocator(); @@ -152,7 +153,7 @@ describe('Infra Locators', () => { it('should allow specifying specific filter', async () => { const params: NodeLogsLocatorParams = { nodeId, - nodeType, + nodeField, time, filter: FILTER_QUERY, }; @@ -166,7 +167,7 @@ describe('Infra Locators', () => { it('should allow specifying specific view id', async () => { const params: NodeLogsLocatorParams = { nodeId, - nodeType, + nodeField, time, logView: { ...DEFAULT_LOG_VIEW, logViewId: 'test' }, }; @@ -180,7 +181,7 @@ describe('Infra Locators', () => { it('should allow specifying specific time range', async () => { const params: NodeLogsLocatorParams = { nodeId, - nodeType, + nodeField, time, from, to, @@ -196,7 +197,7 @@ describe('Infra Locators', () => { it('should return correct structured url', async () => { const params: NodeLogsLocatorParams = { nodeId, - nodeType, + nodeField, time, logView: DEFAULT_LOG_VIEW, filter: FILTER_QUERY, @@ -237,7 +238,7 @@ const constructLogPosition = (time: number = 1550671089404) => { }; const constructLogFilter = ({ - nodeType, + nodeField, nodeId, filter, timeRange, @@ -246,7 +247,7 @@ const constructLogFilter = ({ let finalFilter = filter || ''; if (nodeId) { - const nodeFilter = `${findInventoryFields(nodeType!).id}: ${nodeId}`; + const nodeFilter = `${nodeField}: ${nodeId}`; finalFilter = filter ? `(${nodeFilter}) and (${filter})` : nodeFilter; } diff --git a/x-pack/plugins/infra/common/locators/logs_locator.ts b/x-pack/plugins/infra/common/locators/logs_locator.ts index e481c0d53d390..952a6b4704aea 100644 --- a/x-pack/plugins/infra/common/locators/logs_locator.ts +++ b/x-pack/plugins/infra/common/locators/logs_locator.ts @@ -6,19 +6,19 @@ */ import type { LocatorDefinition, LocatorPublic } from '@kbn/share-plugin/public'; -import { LOGS_LOCATOR_ID, LogsLocatorParams } from '@kbn/logs-shared-plugin/common'; +import { INFRA_LOGS_LOCATOR_ID, LogsLocatorParams } from '@kbn/logs-shared-plugin/common'; import type { InfraClientCoreSetup } from '../../public/types'; -export type LogsLocator = LocatorPublic; +export type InfraLogsLocator = LocatorPublic; -export interface LogsLocatorDependencies { +export interface InfraLogsLocatorDependencies { core: InfraClientCoreSetup; } -export class LogsLocatorDefinition implements LocatorDefinition { - public readonly id = LOGS_LOCATOR_ID; +export class InfraLogsLocatorDefinition implements LocatorDefinition { + public readonly id = INFRA_LOGS_LOCATOR_ID; - constructor(protected readonly deps: LogsLocatorDependencies) {} + constructor(protected readonly deps: InfraLogsLocatorDependencies) {} public readonly getLocation = async (params: LogsLocatorParams) => { const { createSearchString } = await import('./helpers'); diff --git a/x-pack/plugins/infra/common/locators/node_logs_locator.ts b/x-pack/plugins/infra/common/locators/node_logs_locator.ts index c8c53ec69292e..d5bfe4d7ac936 100644 --- a/x-pack/plugins/infra/common/locators/node_logs_locator.ts +++ b/x-pack/plugins/infra/common/locators/node_logs_locator.ts @@ -6,20 +6,24 @@ */ import type { LocatorDefinition, LocatorPublic } from '@kbn/share-plugin/public'; -import { NODE_LOGS_LOCATOR_ID, NodeLogsLocatorParams } from '@kbn/logs-shared-plugin/common'; -import type { LogsLocatorDependencies } from './logs_locator'; +import { + INFRA_NODE_LOGS_LOCATOR_ID, + NodeLogsLocatorParams, + createNodeLogsQuery, +} from '@kbn/logs-shared-plugin/common'; +import type { InfraLogsLocatorDependencies } from './logs_locator'; -export type NodeLogsLocator = LocatorPublic; +export type InfraNodeLogsLocator = LocatorPublic; -export type NodeLogsLocatorDependencies = LogsLocatorDependencies; +export type InfraNodeLogsLocatorDependencies = InfraLogsLocatorDependencies; -export class NodeLogsLocatorDefinition implements LocatorDefinition { - public readonly id = NODE_LOGS_LOCATOR_ID; +export class InfraNodeLogsLocatorDefinition implements LocatorDefinition { + public readonly id = INFRA_NODE_LOGS_LOCATOR_ID; - constructor(protected readonly deps: NodeLogsLocatorDependencies) {} + constructor(protected readonly deps: InfraNodeLogsLocatorDependencies) {} public readonly getLocation = async (params: NodeLogsLocatorParams) => { - const { createNodeLogsQuery, createSearchString } = await import('./helpers'); + const { createSearchString } = await import('./helpers'); const query = createNodeLogsQuery(params); diff --git a/x-pack/plugins/infra/public/alerting/log_threshold/log_threshold_rule_type.tsx b/x-pack/plugins/infra/public/alerting/log_threshold/log_threshold_rule_type.tsx index 1f2e8731a85df..f87558de360b7 100644 --- a/x-pack/plugins/infra/public/alerting/log_threshold/log_threshold_rule_type.tsx +++ b/x-pack/plugins/infra/public/alerting/log_threshold/log_threshold_rule_type.tsx @@ -6,9 +6,9 @@ */ import { i18n } from '@kbn/i18n'; +import { UrlService } from '@kbn/share-plugin/common/url_service'; +import { getLogsLocatorsFromUrlService } from '@kbn/logs-shared-plugin/common'; import { ObservabilityRuleTypeModel } from '@kbn/observability-plugin/public'; -import type { LocatorPublic } from '@kbn/share-plugin/public'; -import type { LogsLocatorParams } from '@kbn/logs-shared-plugin/common'; import { LOG_DOCUMENT_COUNT_RULE_TYPE_ID, PartialRuleParams, @@ -44,7 +44,7 @@ const logThresholdDefaultRecoveryMessage = i18n.translate( export function createLogThresholdRuleType( core: InfraClientCoreSetup, - logsLocator: LocatorPublic + urlService: UrlService ): ObservabilityRuleTypeModel { const ruleParamsExpression = createLazyComponentWithKibanaContext( core, @@ -56,6 +56,8 @@ export function createLogThresholdRuleType( () => import('./components/alert_details_app_section') ); + const { logsLocator } = getLogsLocatorsFromUrlService(urlService); + return { id: LOG_DOCUMENT_COUNT_RULE_TYPE_ID, description: i18n.translate('xpack.infra.logs.alertFlyout.alertDescription', { diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/logs/logs.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/logs/logs.tsx index 1999c6604f553..cec2bb6f5e3e5 100644 --- a/x-pack/plugins/infra/public/components/asset_details/tabs/logs/logs.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/logs/logs.tsx @@ -12,7 +12,11 @@ import { i18n } from '@kbn/i18n'; import { EuiFieldSearch, EuiFlexGroup, EuiFlexItem, EuiButtonEmpty } from '@elastic/eui'; import { RedirectAppLinks } from '@kbn/shared-ux-link-redirect-app'; import { LogStream } from '@kbn/logs-shared-plugin/public'; -import { DEFAULT_LOG_VIEW, LogViewReference } from '@kbn/logs-shared-plugin/common'; +import { + DEFAULT_LOG_VIEW, + getLogsLocatorsFromUrlService, + LogViewReference, +} from '@kbn/logs-shared-plugin/common'; import { findInventoryFields } from '@kbn/metrics-data-access-plugin/common'; import { useKibanaContextForPlugin } from '../../../../hooks/use_kibana'; import { InfraLoadingPanel } from '../../../loading'; @@ -34,7 +38,7 @@ export const Logs = () => { const { loading: logViewLoading, reference: logViewReference } = logs ?? {}; const { services } = useKibanaContextForPlugin(); - const { locators } = services; + const { nodeLogsLocator } = getLogsLocatorsFromUrlService(services.share.url); const [textQuery, setTextQuery] = useState(urlState?.logsSearch ?? ''); const [textQueryDebounced, setTextQueryDebounced] = useState(urlState?.logsSearch ?? ''); @@ -77,21 +81,14 @@ export const Logs = () => { ); const logsUrl = useMemo(() => { - return locators.nodeLogsLocator.getRedirectUrl({ - nodeType: asset.type, + return nodeLogsLocator.getRedirectUrl({ + nodeField: findInventoryFields(asset.type).id, nodeId: asset.name, time: state.startTimestamp, filter: textQueryDebounced, logView, }); - }, [ - locators.nodeLogsLocator, - asset.name, - asset.type, - state.startTimestamp, - textQueryDebounced, - logView, - ]); + }, [nodeLogsLocator, asset.name, asset.type, state.startTimestamp, textQueryDebounced, logView]); return ( diff --git a/x-pack/plugins/infra/public/pages/link_to/redirect_to_logs.tsx b/x-pack/plugins/infra/public/pages/link_to/redirect_to_logs.tsx index 663df4c0f4d1a..16f13171f7106 100644 --- a/x-pack/plugins/infra/public/pages/link_to/redirect_to_logs.tsx +++ b/x-pack/plugins/infra/public/pages/link_to/redirect_to_logs.tsx @@ -7,7 +7,7 @@ import { useEffect } from 'react'; import { useLocation, useParams } from 'react-router-dom'; -import { DEFAULT_LOG_VIEW } from '@kbn/logs-shared-plugin/common'; +import { DEFAULT_LOG_VIEW, getLogsLocatorsFromUrlService } from '@kbn/logs-shared-plugin/common'; import { getFilterFromLocation, getTimeFromLocation } from './query_params'; import { useKibanaContextForPlugin } from '../../hooks/use_kibana'; @@ -16,14 +16,15 @@ export const RedirectToLogs = () => { const location = useLocation(); const { - services: { locators }, + services: { share }, } = useKibanaContextForPlugin(); + const { logsLocator } = getLogsLocatorsFromUrlService(share.url); const filter = getFilterFromLocation(location); const time = getTimeFromLocation(location); useEffect(() => { - locators.logsLocator.navigate( + logsLocator.navigate( { time, filter, @@ -31,7 +32,7 @@ export const RedirectToLogs = () => { }, { replace: true } ); - }, [filter, locators.logsLocator, logViewId, time]); + }, [filter, logsLocator, logViewId, time]); return null; }; diff --git a/x-pack/plugins/infra/public/pages/link_to/redirect_to_node_logs.tsx b/x-pack/plugins/infra/public/pages/link_to/redirect_to_node_logs.tsx index 0eade78931ed0..0be958882cedb 100644 --- a/x-pack/plugins/infra/public/pages/link_to/redirect_to_node_logs.tsx +++ b/x-pack/plugins/infra/public/pages/link_to/redirect_to_node_logs.tsx @@ -7,8 +7,8 @@ import { useEffect } from 'react'; import { RouteComponentProps } from 'react-router-dom'; -import { DEFAULT_LOG_VIEW } from '@kbn/logs-shared-plugin/common'; -import { InventoryItemType } from '@kbn/metrics-data-access-plugin/common'; +import { DEFAULT_LOG_VIEW, getLogsLocatorsFromUrlService } from '@kbn/logs-shared-plugin/common'; +import { findInventoryFields, InventoryItemType } from '@kbn/metrics-data-access-plugin/common'; import { useKibanaContextForPlugin } from '../../hooks/use_kibana'; import { getFilterFromLocation, getTimeFromLocation } from './query_params'; @@ -26,24 +26,25 @@ export const RedirectToNodeLogs = ({ location, }: RedirectToNodeLogsType) => { const { - services: { locators }, + services: { share }, } = useKibanaContextForPlugin(); + const { nodeLogsLocator } = getLogsLocatorsFromUrlService(share.url); const filter = getFilterFromLocation(location); const time = getTimeFromLocation(location); useEffect(() => { - locators.nodeLogsLocator.navigate( + nodeLogsLocator.navigate( { + nodeField: findInventoryFields(nodeType).id, nodeId, - nodeType, time, filter, logView: { type: 'log-view-reference', logViewId }, }, { replace: true } ); - }, [filter, locators.nodeLogsLocator, logViewId, nodeId, nodeType, time]); + }, [filter, nodeLogsLocator, logViewId, nodeId, nodeType, time]); return null; }; diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/components/tabs/logs/logs_link_to_stream.tsx b/x-pack/plugins/infra/public/pages/metrics/hosts/components/tabs/logs/logs_link_to_stream.tsx index cd2537418e46c..d7fbd4dbf1be9 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/components/tabs/logs/logs_link_to_stream.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/components/tabs/logs/logs_link_to_stream.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { RedirectAppLinks } from '@kbn/shared-ux-link-redirect-app'; import { EuiButtonEmpty } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; -import { LogViewReference } from '@kbn/logs-shared-plugin/common'; +import { getLogsLocatorsFromUrlService, LogViewReference } from '@kbn/logs-shared-plugin/common'; import { useKibanaContextForPlugin } from '../../../../../../hooks/use_kibana'; interface LogsLinkToStreamProps { @@ -20,12 +20,13 @@ interface LogsLinkToStreamProps { export const LogsLinkToStream = ({ startTime, endTime, query, logView }: LogsLinkToStreamProps) => { const { services } = useKibanaContextForPlugin(); - const { locators } = services; + const { share } = services; + const { logsLocator } = getLogsLocatorsFromUrlService(share.url); return ( = withTheme const inventoryModel = findInventoryModel(nodeType); const nodeDetailFrom = currentTime - inventoryModel.metrics.defaultTimeRangeInSeconds * 1000; const { services } = useKibanaContextForPlugin(); - const { application, share, locators } = services; + const { application, share } = services; + const { nodeLogsLocator } = getLogsLocatorsFromUrlService(share.url); const uiCapabilities = application?.capabilities; // Due to the changing nature of the fields between APM and this UI, // We need to have some exceptions until 7.0 & ECS is finalized. Reference @@ -109,8 +111,8 @@ export const NodeContextMenu: React.FC = withTheme defaultMessage: '{inventoryName} logs', values: { inventoryName: inventoryModel.singularDisplayName }, }), - href: locators.nodeLogsLocator.getRedirectUrl({ - nodeType, + href: nodeLogsLocator.getRedirectUrl({ + nodeField: findInventoryFields(nodeType).id, nodeId: node.id, time: currentTime, }), diff --git a/x-pack/plugins/infra/public/plugin.ts b/x-pack/plugins/infra/public/plugin.ts index 7d717cf9057e4..f89d99a43a57b 100644 --- a/x-pack/plugins/infra/public/plugin.ts +++ b/x-pack/plugins/infra/public/plugin.ts @@ -27,8 +27,8 @@ import { LOG_STREAM_EMBEDDABLE } from './components/log_stream/log_stream_embedd import { LogStreamEmbeddableFactoryDefinition } from './components/log_stream/log_stream_embeddable_factory'; import { type InfraLocators, - LogsLocatorDefinition, - NodeLogsLocatorDefinition, + InfraLogsLocatorDefinition, + InfraNodeLogsLocatorDefinition, } from '../common/locators'; import { createMetricsFetchData, createMetricsHasData } from './metrics_overview_fetchers'; import { registerFeatures } from './register_feature'; @@ -179,13 +179,15 @@ export class Plugin implements InfraClientPluginClass { ); // Register Locators - const logsLocator = pluginsSetup.share.url.locators.create(new LogsLocatorDefinition({ core })); - const nodeLogsLocator = pluginsSetup.share.url.locators.create( - new NodeLogsLocatorDefinition({ core }) - ); + const logsLocator = this.config.featureFlags.logsUIEnabled + ? pluginsSetup.share.url.locators.create(new InfraLogsLocatorDefinition({ core })) + : undefined; + const nodeLogsLocator = this.config.featureFlags.logsUIEnabled + ? pluginsSetup.share.url.locators.create(new InfraNodeLogsLocatorDefinition({ core })) + : undefined; pluginsSetup.observability.observabilityRuleTypeRegistry.register( - createLogThresholdRuleType(core, logsLocator) + createLogThresholdRuleType(core, pluginsSetup.share.url) ); if (this.config.featureFlags.logsUIEnabled) { diff --git a/x-pack/plugins/logs_shared/common/index.ts b/x-pack/plugins/logs_shared/common/index.ts index 99fd7c1166863..f6b1e9ea27e43 100644 --- a/x-pack/plugins/logs_shared/common/index.ts +++ b/x-pack/plugins/logs_shared/common/index.ts @@ -60,5 +60,13 @@ export { } from './http_api'; // Locators -export { LOGS_LOCATOR_ID, NODE_LOGS_LOCATOR_ID } from './locators'; -export type { LogsLocatorParams, NodeLogsLocatorParams } from './locators'; +export { + LOGS_LOCATOR_ID, + TRACE_LOGS_LOCATOR_ID, + NODE_LOGS_LOCATOR_ID, + INFRA_LOGS_LOCATOR_ID, + INFRA_NODE_LOGS_LOCATOR_ID, + getLogsLocatorsFromUrlService, +} from './locators'; +export type { LogsLocatorParams, NodeLogsLocatorParams, TraceLogsLocatorParams } from './locators'; +export { createNodeLogsQuery } from './locators/helpers'; diff --git a/x-pack/plugins/logs_shared/common/locators/get_logs_locators.ts b/x-pack/plugins/logs_shared/common/locators/get_logs_locators.ts new file mode 100644 index 0000000000000..5c403c2bcb5b0 --- /dev/null +++ b/x-pack/plugins/logs_shared/common/locators/get_logs_locators.ts @@ -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 { UrlService } from '@kbn/share-plugin/common/url_service'; + +import { LogsLocatorParams, NodeLogsLocatorParams, TraceLogsLocatorParams } from './types'; +import { LOGS_LOCATOR_ID } from './logs_locator'; +import { NODE_LOGS_LOCATOR_ID } from './node_logs_locator'; +import { TRACE_LOGS_LOCATOR_ID } from './trace_logs_locator'; + +export const getLogsLocatorsFromUrlService = (urlService: UrlService) => { + const logsLocator = urlService.locators.get(LOGS_LOCATOR_ID)!; + const nodeLogsLocator = urlService.locators.get(NODE_LOGS_LOCATOR_ID)!; + const traceLogsLocator = urlService.locators.get(TRACE_LOGS_LOCATOR_ID)!; + + return { + logsLocator, + traceLogsLocator, + nodeLogsLocator, + }; +}; diff --git a/x-pack/plugins/logs_shared/common/locators/helpers.ts b/x-pack/plugins/logs_shared/common/locators/helpers.ts new file mode 100644 index 0000000000000..ae25c8abb3c18 --- /dev/null +++ b/x-pack/plugins/logs_shared/common/locators/helpers.ts @@ -0,0 +1,43 @@ +/* + * 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 moment, { DurationInputObject } from 'moment'; +import { LogsLocatorParams, NodeLogsLocatorParams, TraceLogsLocatorParams } from './types'; + +export const getLogsQuery = (params: LogsLocatorParams) => { + const { filter } = params; + + return filter ? { language: 'kuery', query: filter } : undefined; +}; + +export const createNodeLogsQuery = (params: NodeLogsLocatorParams) => { + const { nodeField, nodeId, filter } = params; + + const nodeFilter = `${nodeField}: ${nodeId}`; + return filter ? `(${nodeFilter}) and (${filter})` : nodeFilter; +}; + +export const getNodeQuery = (params: NodeLogsLocatorParams) => { + return { language: 'kuery', query: createNodeLogsQuery(params) }; +}; + +export const getTraceQuery = (params: TraceLogsLocatorParams) => { + const { traceId, filter } = params; + + const traceFilter = `trace.id:"${traceId}" OR (not trace.id:* AND "${traceId}")`; + const query = filter ? `(${traceFilter}) and (${filter})` : traceFilter; + + return { language: 'kuery', query }; +}; + +const defaultTimeRangeFromPositionOffset: DurationInputObject = { hours: 1 }; + +export const getTimeRangeStartFromTime = (time: number): string => + moment(time).subtract(defaultTimeRangeFromPositionOffset).toISOString(); + +export const getTimeRangeEndFromTime = (time: number): string => + moment(time).add(defaultTimeRangeFromPositionOffset).toISOString(); diff --git a/x-pack/plugins/logs_shared/common/locators/index.ts b/x-pack/plugins/logs_shared/common/locators/index.ts index d680977f29f89..2cbe5cc2d6ba3 100644 --- a/x-pack/plugins/logs_shared/common/locators/index.ts +++ b/x-pack/plugins/logs_shared/common/locators/index.ts @@ -6,4 +6,14 @@ */ export * from './logs_locator'; +export * from './trace_logs_locator'; export * from './node_logs_locator'; +export * from './infra'; +export * from './get_logs_locators'; + +export type { + LogsSharedLocators, + LogsLocatorParams, + NodeLogsLocatorParams, + TraceLogsLocatorParams, +} from './types'; diff --git a/x-pack/plugins/logs_shared/common/locators/infra.ts b/x-pack/plugins/logs_shared/common/locators/infra.ts new file mode 100644 index 0000000000000..c9351c375d03f --- /dev/null +++ b/x-pack/plugins/logs_shared/common/locators/infra.ts @@ -0,0 +1,10 @@ +/* + * 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. + */ + +export const INFRA_LOGS_LOCATOR_ID = 'INFRA_LOGS_LOCATOR'; + +export const INFRA_NODE_LOGS_LOCATOR_ID = 'INFRA_NODE_LOGS_LOCATOR'; diff --git a/x-pack/plugins/logs_shared/common/locators/logs_locator.ts b/x-pack/plugins/logs_shared/common/locators/logs_locator.ts index bfd53276ab3e9..2ebb343e10bbc 100644 --- a/x-pack/plugins/logs_shared/common/locators/logs_locator.ts +++ b/x-pack/plugins/logs_shared/common/locators/logs_locator.ts @@ -5,19 +5,40 @@ * 2.0. */ -import { SerializableRecord } from '@kbn/utility-types'; -import type { TimeRange } from './time_range'; -import type { LogViewReference } from '../log_views/types'; +import { ALL_DATASETS_LOCATOR_ID, AllDatasetsLocatorParams } from '@kbn/deeplinks-observability'; +import { LocatorDefinition } from '@kbn/share-plugin/common'; +import { LocatorClient } from '@kbn/share-plugin/common/url_service'; + +import { INFRA_LOGS_LOCATOR_ID } from './infra'; +import { LogsLocatorParams } from './types'; +import { getLogsQuery, getTimeRangeEndFromTime, getTimeRangeStartFromTime } from './helpers'; export const LOGS_LOCATOR_ID = 'LOGS_LOCATOR'; -export interface LogsLocatorParams extends SerializableRecord { - /** Defines log position */ - time?: number; - /** - * Optionally set the time range in the time picker. - */ - timeRange?: TimeRange; - filter?: string; - logView?: LogViewReference; +export class LogsLocatorDefinition implements LocatorDefinition { + public readonly id = LOGS_LOCATOR_ID; + + constructor(private readonly locators: LocatorClient) {} + + public readonly getLocation = async (params: LogsLocatorParams) => { + const infraLogsLocator = this.locators.get(INFRA_LOGS_LOCATOR_ID); + if (infraLogsLocator) { + return infraLogsLocator.getLocation(params); + } + + const allDatasetsLocator = + this.locators.get(ALL_DATASETS_LOCATOR_ID)!; + const { time } = params; + return allDatasetsLocator.getLocation({ + query: getLogsQuery(params), + ...(time + ? { + timeRange: { + from: getTimeRangeStartFromTime(time), + to: getTimeRangeEndFromTime(time), + }, + } + : {}), + }); + }; } diff --git a/x-pack/plugins/logs_shared/common/locators/node_logs_locator.ts b/x-pack/plugins/logs_shared/common/locators/node_logs_locator.ts index 188c4d1e5a966..e5288630334b8 100644 --- a/x-pack/plugins/logs_shared/common/locators/node_logs_locator.ts +++ b/x-pack/plugins/logs_shared/common/locators/node_logs_locator.ts @@ -5,12 +5,45 @@ * 2.0. */ -import type { InventoryItemType } from './types'; -import type { LogsLocatorParams } from './logs_locator'; +import { + AllDatasetsLocatorParams, + ALL_DATASETS_LOCATOR_ID, +} from '@kbn/deeplinks-observability/locators'; +import { LocatorClient, LocatorDefinition } from '@kbn/share-plugin/common/url_service'; + +import { NodeLogsLocatorParams } from './types'; +import { INFRA_NODE_LOGS_LOCATOR_ID } from './infra'; +import { getNodeQuery, getTimeRangeStartFromTime, getTimeRangeEndFromTime } from './helpers'; export const NODE_LOGS_LOCATOR_ID = 'NODE_LOGS_LOCATOR'; -export interface NodeLogsLocatorParams extends LogsLocatorParams { - nodeId: string; - nodeType: InventoryItemType; +export class NodeLogsLocatorDefinition implements LocatorDefinition { + public readonly id = NODE_LOGS_LOCATOR_ID; + + constructor(private readonly locators: LocatorClient) {} + + public readonly getLocation = async (params: NodeLogsLocatorParams) => { + const infraNodeLogsLocator = this.locators.get( + INFRA_NODE_LOGS_LOCATOR_ID + ); + + if (infraNodeLogsLocator) { + return infraNodeLogsLocator.getLocation(params); + } + + const allDatasetsLocator = + this.locators.get(ALL_DATASETS_LOCATOR_ID)!; + const { time } = params; + return allDatasetsLocator.getLocation({ + query: getNodeQuery(params), + ...(time + ? { + timeRange: { + from: getTimeRangeStartFromTime(time), + to: getTimeRangeEndFromTime(time), + }, + } + : {}), + }); + }; } diff --git a/x-pack/plugins/logs_shared/common/locators/trace_logs_locator.ts b/x-pack/plugins/logs_shared/common/locators/trace_logs_locator.ts new file mode 100644 index 0000000000000..a62155aaaf4d1 --- /dev/null +++ b/x-pack/plugins/logs_shared/common/locators/trace_logs_locator.ts @@ -0,0 +1,47 @@ +/* + * 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 { ALL_DATASETS_LOCATOR_ID, AllDatasetsLocatorParams } from '@kbn/deeplinks-observability'; +import { LocatorDefinition } from '@kbn/share-plugin/common'; +import { LocatorClient } from '@kbn/share-plugin/common/url_service'; +import { INFRA_LOGS_LOCATOR_ID } from './infra'; +import { LogsLocatorParams, TraceLogsLocatorParams } from './types'; + +import { getTraceQuery, getTimeRangeEndFromTime, getTimeRangeStartFromTime } from './helpers'; + +export const TRACE_LOGS_LOCATOR_ID = 'TRACE_LOGS_LOCATOR'; + +export class TraceLogsLocatorDefinition implements LocatorDefinition { + public readonly id = TRACE_LOGS_LOCATOR_ID; + + constructor(private readonly locators: LocatorClient) {} + + public readonly getLocation = async (params: TraceLogsLocatorParams) => { + const infraLogsLocator = this.locators.get(INFRA_LOGS_LOCATOR_ID); + if (infraLogsLocator) { + return infraLogsLocator.getLocation({ + ...params, + filter: getTraceQuery(params).query, + }); + } + + const { time } = params; + const allDatasetsLocator = + this.locators.get(ALL_DATASETS_LOCATOR_ID)!; + return allDatasetsLocator.getLocation({ + query: getTraceQuery(params), + ...(time + ? { + timeRange: { + from: getTimeRangeStartFromTime(time), + to: getTimeRangeEndFromTime(time), + }, + } + : {}), + }); + }; +} diff --git a/x-pack/plugins/logs_shared/common/locators/types.ts b/x-pack/plugins/logs_shared/common/locators/types.ts index af6ec963098a0..07c50590b3efb 100644 --- a/x-pack/plugins/logs_shared/common/locators/types.ts +++ b/x-pack/plugins/logs_shared/common/locators/types.ts @@ -5,16 +5,33 @@ * 2.0. */ -import * as rt from 'io-ts'; +import { SerializableRecord } from '@kbn/utility-types'; +import { LocatorPublic } from '@kbn/share-plugin/common'; +import { LogViewReference } from '../log_views/types'; +import { TimeRange } from './time_range'; -export const ItemTypeRT = rt.keyof({ - host: null, - pod: null, - container: null, - awsEC2: null, - awsS3: null, - awsSQS: null, - awsRDS: null, -}); +export interface LogsLocatorParams extends SerializableRecord { + /** Defines log position */ + time?: number; + /** + * Optionally set the time range in the time picker. + */ + timeRange?: TimeRange; + filter?: string; + logView?: LogViewReference; +} -export type InventoryItemType = rt.TypeOf; +export interface TraceLogsLocatorParams extends LogsLocatorParams { + traceId: string; +} + +export interface NodeLogsLocatorParams extends LogsLocatorParams { + nodeField: string; + nodeId: string; +} + +export interface LogsSharedLocators { + logsLocator: LocatorPublic; + nodeLogsLocator: LocatorPublic; + traceLogsLocator: LocatorPublic; +} diff --git a/x-pack/plugins/logs_shared/kibana.jsonc b/x-pack/plugins/logs_shared/kibana.jsonc index b78503b140a71..fc8dcf0e64d96 100644 --- a/x-pack/plugins/logs_shared/kibana.jsonc +++ b/x-pack/plugins/logs_shared/kibana.jsonc @@ -13,7 +13,8 @@ "dataViews", "usageCollection", "observabilityShared", - "observabilityAIAssistant" + "observabilityAIAssistant", + "share" ], "requiredBundles": ["kibanaUtils", "kibanaReact"], "extraPublicDirs": ["common"] diff --git a/x-pack/plugins/logs_shared/public/plugin.ts b/x-pack/plugins/logs_shared/public/plugin.ts index 092e95570db7f..1d6063c34eed3 100644 --- a/x-pack/plugins/logs_shared/public/plugin.ts +++ b/x-pack/plugins/logs_shared/public/plugin.ts @@ -6,9 +6,19 @@ */ import { CoreStart } from '@kbn/core/public'; +import { + LogsLocatorDefinition, + NodeLogsLocatorDefinition, + TraceLogsLocatorDefinition, +} from '../common/locators'; import { createLogAIAssistant } from './components/log_ai_assistant'; import { LogViewsService } from './services/log_views'; -import { LogsSharedClientPluginClass, LogsSharedClientStartDeps } from './types'; +import { + LogsSharedClientCoreSetup, + LogsSharedClientPluginClass, + LogsSharedClientSetupDeps, + LogsSharedClientStartDeps, +} from './types'; export class LogsSharedPlugin implements LogsSharedClientPluginClass { private logViews: LogViewsService; @@ -17,10 +27,27 @@ export class LogsSharedPlugin implements LogsSharedClientPluginClass { this.logViews = new LogViewsService(); } - public setup() { + public setup(_: LogsSharedClientCoreSetup, pluginsSetup: LogsSharedClientSetupDeps) { const logViews = this.logViews.setup(); - return { logViews }; + const logsLocator = pluginsSetup.share.url.locators.create( + new LogsLocatorDefinition(pluginsSetup.share.url.locators) + ); + const nodeLogsLocator = pluginsSetup.share.url.locators.create( + new NodeLogsLocatorDefinition(pluginsSetup.share.url.locators) + ); + + const traceLogsLocator = pluginsSetup.share.url.locators.create( + new TraceLogsLocatorDefinition(pluginsSetup.share.url.locators) + ); + + const locators = { + logsLocator, + nodeLogsLocator, + traceLogsLocator, + }; + + return { logViews, locators }; } public start(core: CoreStart, plugins: LogsSharedClientStartDeps) { diff --git a/x-pack/plugins/logs_shared/public/types.ts b/x-pack/plugins/logs_shared/public/types.ts index 2a2e9c1cf742d..da5d2ec49e622 100644 --- a/x-pack/plugins/logs_shared/public/types.ts +++ b/x-pack/plugins/logs_shared/public/types.ts @@ -5,18 +5,14 @@ * 2.0. */ -/* - * 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 { CoreSetup, CoreStart, Plugin as PluginClass } from '@kbn/core/public'; import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; import { ObservabilityAIAssistantPluginStart } from '@kbn/observability-ai-assistant-plugin/public'; +import { SharePluginSetup } from '@kbn/share-plugin/public'; import { UiActionsStart } from '@kbn/ui-actions-plugin/public'; + +import { LogsSharedLocators } from '../common/locators'; import type { LogAIAssistantProps } from './components/log_ai_assistant/log_ai_assistant'; // import type { OsqueryPluginStart } from '../../osquery/public'; import { LogViewsServiceSetup, LogViewsServiceStart } from './services/log_views'; @@ -24,6 +20,7 @@ import { LogViewsServiceSetup, LogViewsServiceStart } from './services/log_views // Our own setup and start contract values export interface LogsSharedClientSetupExports { logViews: LogViewsServiceSetup; + locators: LogsSharedLocators; } export interface LogsSharedClientStartExports { @@ -31,8 +28,9 @@ export interface LogsSharedClientStartExports { LogAIAssistant: (props: Omit) => JSX.Element; } -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface LogsSharedClientSetupDeps {} +export interface LogsSharedClientSetupDeps { + share: SharePluginSetup; +} export interface LogsSharedClientStartDeps { data: DataPublicPluginStart; diff --git a/x-pack/plugins/logs_shared/tsconfig.json b/x-pack/plugins/logs_shared/tsconfig.json index b7c17b46c9a62..8d06a68a70873 100644 --- a/x-pack/plugins/logs_shared/tsconfig.json +++ b/x-pack/plugins/logs_shared/tsconfig.json @@ -26,6 +26,8 @@ "@kbn/datemath", "@kbn/core-http-browser", "@kbn/ui-actions-plugin", - "@kbn/observability-ai-assistant-plugin" + "@kbn/observability-ai-assistant-plugin", + "@kbn/deeplinks-observability", + "@kbn/share-plugin" ] }