From a9c510f9f0b0beeca5c1333744af502605d6d752 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Tue, 17 Dec 2024 11:48:35 +0100 Subject: [PATCH] [Logs UX] Classify logs-data-access and logs-shared as platform plugins (#201263) This classifies `@kbn/logs-data-access-plugin`, `@kbn/logs-shared-plugin` and `@kbn/observability-logs-overview` as "platform/shared". --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Elastic Machine (cherry picked from commit d5e0d3a2f6cd7b9158950c7151d2aaba674214ca) # Conflicts: # .eslintrc.js --- .eslintrc.js | 3 - packages/kbn-xstate-utils/kibana.jsonc | 4 +- .../deeplinks/observability/locators/apm.ts | 18 +++ .../deeplinks/observability/locators/index.ts | 1 + .../observability/logs_overview/kibana.jsonc | 4 +- .../infra/public/plugin.ts | 5 - .../logs_data_access/kibana.jsonc | 8 +- .../logs_shared/kibana.jsonc | 18 ++- .../components/log_stream/log_stream.tsx | 4 +- .../log_entry_actions_menu.test.tsx | 31 +++-- .../log_entry_actions_menu.tsx | 108 +++++++++--------- .../log_entry_flyout/log_entry_flyout.tsx | 20 ++-- .../logging/log_text_stream/index.ts | 7 +- .../logging/log_text_stream/log_entry_row.tsx | 25 +--- .../logs_shared/public/hooks/use_kibana.tsx | 5 +- .../public/utils/use_kibana_query_settings.ts | 31 +++++ .../public/utils/use_ui_tracker.ts | 44 +++++++ .../logs_shared/tsconfig.json | 7 +- ...transaction_details_by_trace_id_locator.ts | 21 ++-- .../common/trigger_ids.ts | 1 - .../observability_shared/tsconfig.json | 1 + 21 files changed, 233 insertions(+), 133 deletions(-) create mode 100644 src/platform/packages/shared/deeplinks/observability/locators/apm.ts create mode 100644 x-pack/plugins/observability_solution/logs_shared/public/utils/use_kibana_query_settings.ts create mode 100644 x-pack/plugins/observability_solution/logs_shared/public/utils/use_ui_tracker.ts diff --git a/.eslintrc.js b/.eslintrc.js index b52b33cc3de86..4222c8ab867fe 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1998,9 +1998,6 @@ module.exports = { }, { files: [ - // logsShared depends on o11y/private plugins, but platform plugins depend on it - 'x-pack/plugins/observability_solution/logs_shared/**', - // this plugin depends on visTypeTimeseries plugin (for TSVB viz) which is platform/private ATM 'x-pack/plugins/observability_solution/infra/**', diff --git a/packages/kbn-xstate-utils/kibana.jsonc b/packages/kbn-xstate-utils/kibana.jsonc index 3b1bcf6bf8d76..5638550a862df 100644 --- a/packages/kbn-xstate-utils/kibana.jsonc +++ b/packages/kbn-xstate-utils/kibana.jsonc @@ -4,6 +4,6 @@ "owner": [ "@elastic/obs-ux-logs-team" ], - "group": "observability", - "visibility": "private" + "group": "platform", + "visibility": "shared" } diff --git a/src/platform/packages/shared/deeplinks/observability/locators/apm.ts b/src/platform/packages/shared/deeplinks/observability/locators/apm.ts new file mode 100644 index 0000000000000..64e446e883f1f --- /dev/null +++ b/src/platform/packages/shared/deeplinks/observability/locators/apm.ts @@ -0,0 +1,18 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { SerializableRecord } from '@kbn/utility-types'; + +export const TRANSACTION_DETAILS_BY_TRACE_ID_LOCATOR = 'TRANSACTION_DETAILS_BY_TRACE_ID_LOCATOR'; + +export interface TransactionDetailsByTraceIdLocatorParams extends SerializableRecord { + rangeFrom?: string; + rangeTo?: string; + traceId: string; +} diff --git a/src/platform/packages/shared/deeplinks/observability/locators/index.ts b/src/platform/packages/shared/deeplinks/observability/locators/index.ts index 5d45f66194b6d..3317df2268df3 100644 --- a/src/platform/packages/shared/deeplinks/observability/locators/index.ts +++ b/src/platform/packages/shared/deeplinks/observability/locators/index.ts @@ -7,6 +7,7 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ +export * from './apm'; export * from './dataset_quality'; export * from './dataset_quality_details'; export * from './logs_explorer'; diff --git a/x-pack/packages/observability/logs_overview/kibana.jsonc b/x-pack/packages/observability/logs_overview/kibana.jsonc index 34d8ac98a5253..1709e01f926ed 100644 --- a/x-pack/packages/observability/logs_overview/kibana.jsonc +++ b/x-pack/packages/observability/logs_overview/kibana.jsonc @@ -4,6 +4,6 @@ "owner": [ "@elastic/obs-ux-logs-team" ], - "group": "observability", - "visibility": "private" + "group": "platform", + "visibility": "shared" } diff --git a/x-pack/plugins/observability_solution/infra/public/plugin.ts b/x-pack/plugins/observability_solution/infra/public/plugin.ts index 023c6be375ec1..eb350f81a111b 100644 --- a/x-pack/plugins/observability_solution/infra/public/plugin.ts +++ b/x-pack/plugins/observability_solution/infra/public/plugin.ts @@ -21,7 +21,6 @@ import { enableInfrastructureHostsView } from '@kbn/observability-plugin/public' import { METRICS_EXPLORER_LOCATOR_ID, MetricsExplorerLocatorParams, - ObservabilityTriggerId, } from '@kbn/observability-shared-plugin/common'; import { BehaviorSubject, @@ -103,10 +102,6 @@ export class Plugin implements InfraClientPluginClass { registerFeatures(pluginsSetup.home); } - pluginsSetup.uiActions.registerTrigger({ - id: ObservabilityTriggerId.LogEntryContextMenu, - }); - const assetDetailsLocator = pluginsSetup.share.url.locators.get(ASSET_DETAILS_LOCATOR_ID); const inventoryLocator = diff --git a/x-pack/plugins/observability_solution/logs_data_access/kibana.jsonc b/x-pack/plugins/observability_solution/logs_data_access/kibana.jsonc index 02fcff85404a0..f3eccc1c0c154 100644 --- a/x-pack/plugins/observability_solution/logs_data_access/kibana.jsonc +++ b/x-pack/plugins/observability_solution/logs_data_access/kibana.jsonc @@ -1,13 +1,17 @@ { "type": "plugin", "id": "@kbn/logs-data-access-plugin", - "owner": ["@elastic/obs-ux-logs-team"], + "owner": [ + "@elastic/obs-ux-logs-team" + ], + "group": "platform", + "visibility": "shared", "plugin": { "id": "logsDataAccess", "server": true, "browser": true, "requiredPlugins": [ - "data", + "data", "dataViews" ], "optionalPlugins": [], diff --git a/x-pack/plugins/observability_solution/logs_shared/kibana.jsonc b/x-pack/plugins/observability_solution/logs_shared/kibana.jsonc index e6ee1a22edc05..46aa8f451260d 100644 --- a/x-pack/plugins/observability_solution/logs_shared/kibana.jsonc +++ b/x-pack/plugins/observability_solution/logs_shared/kibana.jsonc @@ -2,12 +2,17 @@ "type": "plugin", "id": "@kbn/logs-shared-plugin", "owner": "@elastic/obs-ux-logs-team", + "group": "platform", + "visibility": "shared", "description": "Exposes the shared components and APIs to access and visualize logs.", "plugin": { "id": "logsShared", "server": true, "browser": true, - "configPath": ["xpack", "logs_shared"], + "configPath": [ + "xpack", + "logs_shared" + ], "requiredPlugins": [ "charts", "data", @@ -15,16 +20,21 @@ "dataViews", "discoverShared", "logsDataAccess", - "observabilityShared", "share", "spaces", + "uiActions", "usageCollection", "embeddable", ], "optionalPlugins": [ "observabilityAIAssistant", ], - "requiredBundles": ["kibanaUtils", "kibanaReact"], - "extraPublicDirs": ["common"] + "requiredBundles": [ + "kibanaUtils", + "kibanaReact" + ], + "extraPublicDirs": [ + "common" + ] } } diff --git a/x-pack/plugins/observability_solution/logs_shared/public/components/log_stream/log_stream.tsx b/x-pack/plugins/observability_solution/logs_shared/public/components/log_stream/log_stream.tsx index f82e9436fe5cd..8d33fe4b5d343 100644 --- a/x-pack/plugins/observability_solution/logs_shared/public/components/log_stream/log_stream.tsx +++ b/x-pack/plugins/observability_solution/logs_shared/public/components/log_stream/log_stream.tsx @@ -10,19 +10,19 @@ import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; import { buildEsQuery, Filter, Query } from '@kbn/es-query'; import { euiStyled } from '@kbn/kibana-react-plugin/common'; import { useKibana } from '@kbn/kibana-react-plugin/public'; +import type { LogsDataAccessPluginStart } from '@kbn/logs-data-access-plugin/public'; import type { SharePluginStart } from '@kbn/share-plugin/public'; import { JsonValue } from '@kbn/utility-types'; import { noop } from 'lodash'; import React, { useCallback, useEffect, useMemo } from 'react'; import usePrevious from 'react-use/lib/usePrevious'; -import type { LogsDataAccessPluginStart } from '@kbn/logs-data-access-plugin/public'; -import { useKibanaQuerySettings } from '@kbn/observability-shared-plugin/public'; import { LogEntryCursor } from '../../../common/log_entry'; import { defaultLogViewsStaticConfig, LogViewReference } from '../../../common/log_views'; import { BuiltEsQuery, useLogStream } from '../../containers/logs/log_stream'; import { useLogView } from '../../hooks/use_log_view'; import { LogViewsClient } from '../../services/log_views'; import { LogColumnRenderConfiguration } from '../../utils/log_column_render_configuration'; +import { useKibanaQuerySettings } from '../../utils/use_kibana_query_settings'; import { useLogEntryFlyout } from '../logging/log_entry_flyout'; import { ScrollableLogTextStreamView, VisibleInterval } from '../logging/log_text_stream'; import { LogStreamErrorBoundary } from './log_stream_error_boundary'; diff --git a/x-pack/plugins/observability_solution/logs_shared/public/components/logging/log_entry_flyout/log_entry_actions_menu.test.tsx b/x-pack/plugins/observability_solution/logs_shared/public/components/logging/log_entry_flyout/log_entry_actions_menu.test.tsx index ad989f8460016..05906b2794c9f 100644 --- a/x-pack/plugins/observability_solution/logs_shared/public/components/logging/log_entry_flyout/log_entry_actions_menu.test.tsx +++ b/x-pack/plugins/observability_solution/logs_shared/public/components/logging/log_entry_flyout/log_entry_actions_menu.test.tsx @@ -7,6 +7,8 @@ import { coreMock } from '@kbn/core/public/mocks'; import { + TRANSACTION_DETAILS_BY_TRACE_ID_LOCATOR, + TransactionDetailsByTraceIdLocatorParams, uptimeOverviewLocatorID, UptimeOverviewLocatorInfraParams, UptimeOverviewLocatorParams, @@ -26,10 +28,10 @@ coreStartMock.application.getUrlForApp.mockImplementation((app, options) => { }); const emptyUrlService = new MockUrlService(); -const urlServiceWithUptimeLocator = new MockUrlService(); +const urlServiceWithMockLocators = new MockUrlService(); // we can't use the actual locator here because its import would create a // forbidden ts project reference cycle -urlServiceWithUptimeLocator.locators.create< +urlServiceWithMockLocators.locators.create< UptimeOverviewLocatorInfraParams | UptimeOverviewLocatorParams >({ id: uptimeOverviewLocatorID, @@ -37,6 +39,12 @@ urlServiceWithUptimeLocator.locators.create< return { app: 'uptime', path: '/overview', state: {} }; }, }); +urlServiceWithMockLocators.locators.create({ + id: TRANSACTION_DETAILS_BY_TRACE_ID_LOCATOR, + getLocation: async (params) => { + return { app: 'apm', path: '/trace-id', state: {} }; + }, +}); const ProviderWrapper: FC> = ({ children, @@ -90,7 +98,7 @@ describe('LogEntryActionsMenu component', () => { describe('uptime link with legacy uptime enabled', () => { it('renders as enabled when a host ip is present in the log entry', () => { const elementWrapper = mount( - + { it('renders as enabled when a container id is present in the log entry', () => { const elementWrapper = mount( - + { it('renders as enabled when a pod uid is present in the log entry', () => { const elementWrapper = mount( - + { it('renders as disabled when no supported field is present in the log entry', () => { const elementWrapper = mount( - + { describe('apm link', () => { it('renders with a trace id filter when present in log entry', () => { const elementWrapper = mount( - + { it('renders with a trace id filter and timestamp when present in log entry', () => { const timestamp = '2019-06-27T17:44:08.693Z'; const elementWrapper = mount( - + { it('renders as disabled when no supported field is present in log entry', () => { const elementWrapper = mount( - + { elementWrapper.update(); expect( - elementWrapper.find(`button${testSubject('~apmLogEntryActionsMenuItem')}`).prop('disabled') + elementWrapper + .find(`${testSubject('~apmLogEntryActionsMenuItem')}`) + .first() + .prop('disabled') ).toEqual(true); }); }); diff --git a/x-pack/plugins/observability_solution/logs_shared/public/components/logging/log_entry_flyout/log_entry_actions_menu.tsx b/x-pack/plugins/observability_solution/logs_shared/public/components/logging/log_entry_flyout/log_entry_actions_menu.tsx index 4f16d34a489ac..404f6c37bffaa 100644 --- a/x-pack/plugins/observability_solution/logs_shared/public/components/logging/log_entry_flyout/log_entry_actions_menu.tsx +++ b/x-pack/plugins/observability_solution/logs_shared/public/components/logging/log_entry_flyout/log_entry_actions_menu.tsx @@ -7,13 +7,14 @@ import { EuiButton, EuiContextMenuItem, EuiContextMenuPanel, EuiPopover } from '@elastic/eui'; import { + TRANSACTION_DETAILS_BY_TRACE_ID_LOCATOR, uptimeOverviewLocatorID, + type TransactionDetailsByTraceIdLocatorParams, type UptimeOverviewLocatorInfraParams, } from '@kbn/deeplinks-observability'; import { FormattedMessage } from '@kbn/i18n-react'; -import { LinkDescriptor, useLinkProps } from '@kbn/observability-shared-plugin/public'; import { getRouterLinkProps } from '@kbn/router-utils'; -import { ILocatorClient } from '@kbn/share-plugin/common/url_service'; +import { BrowserUrlService } from '@kbn/share-plugin/public'; import React, { useMemo } from 'react'; import { LogEntry } from '../../../../common/search_strategies/log_entries/log_entry'; import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; @@ -33,14 +34,11 @@ export const LogEntryActionsMenu = ({ logEntry }: LogEntryActionsMenuProps) => { } = useKibanaContextForPlugin(); const { hide, isVisible, toggle } = useVisibilityState(false); - const apmLinkDescriptor = useMemo(() => getAPMLink(logEntry), [logEntry]); - - const uptimeLinkProps = getUptimeLink({ locators })(logEntry); - - const apmLinkProps = useLinkProps({ - app: 'apm', - ...(apmLinkDescriptor ? apmLinkDescriptor : {}), - }); + const apmLinkProps = useMemo(() => getAPMLink({ locators })(logEntry), [locators, logEntry]); + const uptimeLinkProps = useMemo( + () => getUptimeLink({ locators })(logEntry), + [locators, logEntry] + ); const menuItems = useMemo( () => [ @@ -58,7 +56,7 @@ export const LogEntryActionsMenu = ({ logEntry }: LogEntryActionsMenuProps) => { , { /> , ], - [apmLinkDescriptor, apmLinkProps, uptimeLinkProps] + [apmLinkProps, uptimeLinkProps] ); const hasMenuItems = useMemo(() => menuItems.length > 0, [menuItems]); @@ -101,8 +99,8 @@ export const LogEntryActionsMenu = ({ logEntry }: LogEntryActionsMenuProps) => { }; const getUptimeLink = - ({ locators }: { locators: ILocatorClient }) => - (logEntry: LogEntry): ContextRouterLinkProps | undefined => { + ({ locators }: { locators: BrowserUrlService['locators'] }) => + (logEntry: LogEntry) => { const uptimeLocator = locators.get(uptimeOverviewLocatorID); if (!uptimeLocator) { @@ -135,47 +133,49 @@ const getUptimeLink = }) as ContextRouterLinkProps; }; -const getAPMLink = (logEntry: LogEntry): LinkDescriptor | undefined => { - const traceId = logEntry.fields.find( - ({ field, value }) => typeof value[0] === 'string' && field === 'trace.id' - )?.value?.[0]; - - if (typeof traceId !== 'string') { - return undefined; - } - - const timestampField = logEntry.fields.find(({ field }) => field === '@timestamp'); - const timestamp = timestampField ? timestampField.value[0] : null; - const { rangeFrom, rangeTo } = - typeof timestamp === 'number' - ? (() => { - const from = new Date(timestamp); - const to = new Date(timestamp); - - from.setMinutes(from.getMinutes() - 10); - to.setMinutes(to.getMinutes() + 10); - - return { rangeFrom: from.toISOString(), rangeTo: to.toISOString() }; - })() - : { rangeFrom: 'now-1y', rangeTo: 'now' }; - - return { - app: 'apm', - pathname: getApmTraceUrl({ traceId, rangeFrom, rangeTo }), - }; -}; +const getAPMLink = + ({ locators }: { locators: BrowserUrlService['locators'] }) => + (logEntry: LogEntry) => { + const traceId = logEntry.fields.find( + ({ field, value }) => typeof value[0] === 'string' && field === 'trace.id' + )?.value?.[0]; -function getApmTraceUrl({ - traceId, - rangeFrom, - rangeTo, -}: { - traceId: string; - rangeFrom: string; - rangeTo: string; -}) { - return `/link-to/trace/${traceId}?` + new URLSearchParams({ rangeFrom, rangeTo }).toString(); -} + if (typeof traceId !== 'string') { + return undefined; + } + + const apmLocator = locators.get( + TRANSACTION_DETAILS_BY_TRACE_ID_LOCATOR + ); + + if (!apmLocator) { + return undefined; + } + + const timestampField = logEntry.fields.find(({ field }) => field === '@timestamp'); + const timestamp = timestampField ? timestampField.value[0] : null; + const { rangeFrom, rangeTo } = + typeof timestamp === 'number' || typeof timestamp === 'string' + ? (() => { + const from = new Date(timestamp); + const to = new Date(timestamp); + + from.setMinutes(from.getMinutes() - 10); + to.setMinutes(to.getMinutes() + 10); + + return { rangeFrom: from.toISOString(), rangeTo: to.toISOString() }; + })() + : { rangeFrom: 'now-1y', rangeTo: 'now' }; + + const apmLocatorParams = { traceId, rangeFrom, rangeTo }; + + // Coercing the return value to ContextRouterLinkProps because + // EuiContextMenuItem defines a too broad type for onClick + return getRouterLinkProps({ + href: apmLocator.getRedirectUrl(apmLocatorParams), + onClick: () => apmLocator.navigate(apmLocatorParams), + }) as ContextRouterLinkProps; + }; export interface ContextRouterLinkProps { href: string | undefined; diff --git a/x-pack/plugins/observability_solution/logs_shared/public/components/logging/log_entry_flyout/log_entry_flyout.tsx b/x-pack/plugins/observability_solution/logs_shared/public/components/logging/log_entry_flyout/log_entry_flyout.tsx index 952ee959e4a72..a66cb1790525a 100644 --- a/x-pack/plugins/observability_solution/logs_shared/public/components/logging/log_entry_flyout/log_entry_flyout.tsx +++ b/x-pack/plugins/observability_solution/logs_shared/public/components/logging/log_entry_flyout/log_entry_flyout.tsx @@ -28,7 +28,6 @@ import { useLogEntry } from '../../../containers/logs/log_entry'; import { CenteredEuiFlyoutBody } from '../../centered_flyout_body'; import { DataSearchErrorCallout } from '../../data_search_error_callout'; import { DataSearchProgress } from '../../data_search_progress'; -import LogAIAssistant from '../../log_ai_assistant/log_ai_assistant'; import { LogEntryActionsMenu } from './log_entry_actions_menu'; import { LogEntryFieldsTable } from './log_entry_fields_table'; @@ -42,7 +41,7 @@ export interface LogEntryFlyoutProps { export const useLogEntryFlyout = (logViewReference: LogViewReference) => { const flyoutRef = useRef(); const { - services: { http, data, share, uiSettings, application, observabilityAIAssistant }, + services: { http, data, share, uiSettings, application, logsShared }, overlays: { openFlyout }, } = useKibanaContextForPlugin(); @@ -58,7 +57,7 @@ export const useLogEntryFlyout = (logViewReference: LogViewReference) => { share, uiSettings, application, - observabilityAIAssistant, + logsShared, }); flyoutRef.current = openFlyout( @@ -72,12 +71,12 @@ export const useLogEntryFlyout = (logViewReference: LogViewReference) => { ); }, [ + logsShared, application, closeLogEntryFlyout, data, http, logViewReference, - observabilityAIAssistant, openFlyout, share, uiSettings, @@ -115,7 +114,11 @@ export const LogEntryFlyout = ({ logEntryId, }); - const { observabilityAIAssistant } = useKibanaContextForPlugin().services; + const { + services: { + logsShared: { LogAIAssistant }, + }, + } = useKibanaContextForPlugin(); useEffect(() => { if (logViewReference && logEntryId) { @@ -183,12 +186,9 @@ export const LogEntryFlyout = ({ } > - {observabilityAIAssistant && ( + {LogAIAssistant && ( - + )} diff --git a/x-pack/plugins/observability_solution/logs_shared/public/components/logging/log_text_stream/index.ts b/x-pack/plugins/observability_solution/logs_shared/public/components/logging/log_text_stream/index.ts index 6468ea3d94d22..be32a2be6dc58 100644 --- a/x-pack/plugins/observability_solution/logs_shared/public/components/logging/log_text_stream/index.ts +++ b/x-pack/plugins/observability_solution/logs_shared/public/components/logging/log_text_stream/index.ts @@ -5,12 +5,11 @@ * 2.0. */ -export type { LogEntryStreamItem } from './item'; -export type { LogEntryColumnWidths } from './log_entry_column'; - export { LogColumnHeader } from './column_headers'; export { LogColumnHeadersWrapper } from './column_headers_wrapper'; -export { iconColumnId, LogEntryColumn, useColumnWidths } from './log_entry_column'; +export type { LogEntryStreamItem } from './item'; +export { LogEntryColumn, iconColumnId, useColumnWidths } from './log_entry_column'; +export type { LogEntryColumnWidths } from './log_entry_column'; export { LogEntryContextMenu } from './log_entry_context_menu'; export { LogEntryFieldColumn } from './log_entry_field_column'; export { LogEntryMessageColumn } from './log_entry_message_column'; diff --git a/x-pack/plugins/observability_solution/logs_shared/public/components/logging/log_text_stream/log_entry_row.tsx b/x-pack/plugins/observability_solution/logs_shared/public/components/logging/log_text_stream/log_entry_row.tsx index b73da833032f4..411b5d0731380 100644 --- a/x-pack/plugins/observability_solution/logs_shared/public/components/logging/log_text_stream/log_entry_row.tsx +++ b/x-pack/plugins/observability_solution/logs_shared/public/components/logging/log_text_stream/log_entry_row.tsx @@ -6,25 +6,19 @@ */ import { i18n } from '@kbn/i18n'; -import { ObservabilityTriggerId } from '@kbn/observability-shared-plugin/common'; -import { - useUiTracker, - getContextMenuItemsFromActions, -} from '@kbn/observability-shared-plugin/public'; import { isEmpty } from 'lodash'; import React, { memo, useCallback, useMemo, useState } from 'react'; -import useAsync from 'react-use/lib/useAsync'; import { LogColumn, LogEntry } from '../../../../common/log_entry'; import { TextScale } from '../../../../common/log_text_scale'; -import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; import { + LogColumnRenderConfiguration, isFieldColumnRenderConfiguration, isMessageColumnRenderConfiguration, isTimestampColumnRenderConfiguration, - LogColumnRenderConfiguration, } from '../../../utils/log_column_render_configuration'; import { isTimestampColumn } from '../../../utils/log_entry'; -import { iconColumnId, LogEntryColumn, LogEntryColumnWidths } from './log_entry_column'; +import { useUiTracker } from '../../../utils/use_ui_tracker'; +import { LogEntryColumn, LogEntryColumnWidths, iconColumnId } from './log_entry_column'; import { LogEntryContextMenu } from './log_entry_context_menu'; import { LogEntryFieldColumn } from './log_entry_field_column'; import { LogEntryMessageColumn } from './log_entry_message_column'; @@ -74,7 +68,7 @@ export const LogEntryRow = memo( scale, wrap, }: LogEntryRowProps) => { - const trackMetric = useUiTracker({ app: 'infra_logs' }); + const trackMetric = useUiTracker(); const [isHovered, setIsHovered] = useState(false); const [isMenuOpen, setIsMenuOpen] = useState(false); @@ -99,16 +93,6 @@ export const LogEntryRow = memo( const hasActionViewLogInContext = hasContext && openViewLogInContext !== undefined; const hasActionsMenu = hasActionFlyoutWithItem || hasActionViewLogInContext; - const uiActions = useKibanaContextForPlugin().services.uiActions; - - const externalContextMenuItems = useAsync(() => { - return getContextMenuItemsFromActions({ - uiActions, - triggerId: ObservabilityTriggerId.LogEntryContextMenu, - context: logEntry, - }); - }, [uiActions, logEntry]); - const menuItems = useMemo(() => { const items = []; if (hasActionFlyoutWithItem) { @@ -251,7 +235,6 @@ export const LogEntryRow = memo( onOpen={openMenu} onClose={closeMenu} items={menuItems} - externalItems={externalContextMenuItems.value} /> ) : null} diff --git a/x-pack/plugins/observability_solution/logs_shared/public/hooks/use_kibana.tsx b/x-pack/plugins/observability_solution/logs_shared/public/hooks/use_kibana.tsx index 09032b4b644a2..af55accdd66b5 100644 --- a/x-pack/plugins/observability_solution/logs_shared/public/hooks/use_kibana.tsx +++ b/x-pack/plugins/observability_solution/logs_shared/public/hooks/use_kibana.tsx @@ -20,8 +20,7 @@ import { } from '../types'; export type PluginKibanaContextValue = CoreStart & - LogsSharedClientStartDeps & - LogsSharedClientStartExports; + LogsSharedClientStartDeps & { logsShared: LogsSharedClientStartExports }; export const createKibanaContextForPlugin = ( core: CoreStart, @@ -31,7 +30,7 @@ export const createKibanaContextForPlugin = ( createKibanaReactContext({ ...core, ...plugins, - ...pluginStart, + logsShared: pluginStart, }); export const useKibanaContextForPlugin = diff --git a/x-pack/plugins/observability_solution/logs_shared/public/utils/use_kibana_query_settings.ts b/x-pack/plugins/observability_solution/logs_shared/public/utils/use_kibana_query_settings.ts new file mode 100644 index 0000000000000..521cd0142303b --- /dev/null +++ b/x-pack/plugins/observability_solution/logs_shared/public/utils/use_kibana_query_settings.ts @@ -0,0 +1,31 @@ +/* + * 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 { EsQueryConfig } from '@kbn/es-query'; +import { SerializableRecord } from '@kbn/utility-types'; +import { useMemo } from 'react'; +import { UI_SETTINGS } from '@kbn/data-plugin/public'; +import { useUiSetting$ } from '@kbn/kibana-react-plugin/public'; + +export const useKibanaQuerySettings = (): EsQueryConfig => { + const [allowLeadingWildcards] = useUiSetting$(UI_SETTINGS.QUERY_ALLOW_LEADING_WILDCARDS); + const [queryStringOptions] = useUiSetting$(UI_SETTINGS.QUERY_STRING_OPTIONS); + const [dateFormatTZ] = useUiSetting$(UI_SETTINGS.DATEFORMAT_TZ); + const [ignoreFilterIfFieldNotInIndex] = useUiSetting$( + UI_SETTINGS.COURIER_IGNORE_FILTER_IF_FIELD_NOT_IN_INDEX + ); + + return useMemo( + () => ({ + allowLeadingWildcards, + queryStringOptions, + dateFormatTZ, + ignoreFilterIfFieldNotInIndex, + }), + [allowLeadingWildcards, dateFormatTZ, ignoreFilterIfFieldNotInIndex, queryStringOptions] + ); +}; diff --git a/x-pack/plugins/observability_solution/logs_shared/public/utils/use_ui_tracker.ts b/x-pack/plugins/observability_solution/logs_shared/public/utils/use_ui_tracker.ts new file mode 100644 index 0000000000000..bc7e3696b993e --- /dev/null +++ b/x-pack/plugins/observability_solution/logs_shared/public/utils/use_ui_tracker.ts @@ -0,0 +1,44 @@ +/* + * 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 { useMemo } from 'react'; +import { METRIC_TYPE, UiCounterMetricType } from '@kbn/analytics'; +import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public'; +import { useKibana } from '@kbn/kibana-react-plugin/public'; + +/** + * Note: The usage_collection plugin will take care of sending this data to the telemetry server. + * You can find the metrics that are collected by these hooks in Stack Telemetry. + * Search the index `kibana-ui-counter`. You can filter for `eventName` and/or `appName`. + */ + +interface TrackOptions { + metricType?: UiCounterMetricType; + delay?: number; // in ms +} + +interface ServiceDeps { + usageCollection: UsageCollectionSetup; // TODO: This should really be start. Looking into it. +} + +export type TrackMetricOptions = TrackOptions & { metric: string }; +export type UiTracker = ReturnType; +export type TrackEvent = (options: TrackMetricOptions) => void; + +export { METRIC_TYPE }; + +export function useUiTracker(): TrackEvent { + const reportUiCounter = useKibana().services?.usageCollection?.reportUiCounter; + const trackEvent = useMemo(() => { + return ({ metric, metricType = METRIC_TYPE.COUNT }: TrackMetricOptions) => { + if (reportUiCounter) { + reportUiCounter('infra_logs', metricType, metric); + } + }; + }, [reportUiCounter]); + return trackEvent; +} diff --git a/x-pack/plugins/observability_solution/logs_shared/tsconfig.json b/x-pack/plugins/observability_solution/logs_shared/tsconfig.json index 221d6db6d6466..d21e4a2c6a24b 100644 --- a/x-pack/plugins/observability_solution/logs_shared/tsconfig.json +++ b/x-pack/plugins/observability_solution/logs_shared/tsconfig.json @@ -10,7 +10,9 @@ "server/**/*", "types/**/*" ], - "exclude": ["target/**/*"], + "exclude": [ + "target/**/*" + ], "kbn_references": [ "@kbn/core", "@kbn/i18n", @@ -28,7 +30,6 @@ "@kbn/logging-mocks", "@kbn/kibana-react-plugin", "@kbn/test-subj-selector", - "@kbn/observability-shared-plugin", "@kbn/datemath", "@kbn/core-http-browser", "@kbn/ui-actions-plugin", @@ -52,5 +53,7 @@ "@kbn/embeddable-plugin", "@kbn/saved-search-plugin", "@kbn/spaces-plugin", + "@kbn/analytics", + "@kbn/usage-collection-plugin", ] } diff --git a/x-pack/plugins/observability_solution/observability_shared/common/locators/apm/transaction_details_by_trace_id_locator.ts b/x-pack/plugins/observability_solution/observability_shared/common/locators/apm/transaction_details_by_trace_id_locator.ts index 2e461bc4f9d55..94fa1176c3ee0 100644 --- a/x-pack/plugins/observability_solution/observability_shared/common/locators/apm/transaction_details_by_trace_id_locator.ts +++ b/x-pack/plugins/observability_solution/observability_shared/common/locators/apm/transaction_details_by_trace_id_locator.ts @@ -4,14 +4,14 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import qs from 'query-string'; import type { LocatorDefinition, LocatorPublic } from '@kbn/share-plugin/public'; -import type { SerializableRecord } from '@kbn/utility-types'; +import { + TRANSACTION_DETAILS_BY_TRACE_ID_LOCATOR, + type TransactionDetailsByTraceIdLocatorParams, +} from '@kbn/deeplinks-observability'; -export const TRANSACTION_DETAILS_BY_TRACE_ID_LOCATOR = 'TRANSACTION_DETAILS_BY_TRACE_ID_LOCATOR'; - -export interface TransactionDetailsByTraceIdLocatorParams extends SerializableRecord { - traceId: string; -} +export { TRANSACTION_DETAILS_BY_TRACE_ID_LOCATOR, type TransactionDetailsByTraceIdLocatorParams }; export type TransactionDetailsByTraceIdLocator = LocatorPublic; @@ -21,10 +21,15 @@ export class TransactionDetailsByTraceIdLocatorDefinition { public readonly id = TRANSACTION_DETAILS_BY_TRACE_ID_LOCATOR; - public readonly getLocation = async ({ traceId }: TransactionDetailsByTraceIdLocatorParams) => { + public readonly getLocation = async ({ + rangeFrom, + rangeTo, + traceId, + }: TransactionDetailsByTraceIdLocatorParams) => { + const params = { rangeFrom, rangeTo }; return { app: 'apm', - path: `/link-to/trace/${encodeURIComponent(traceId)}`, + path: `/link-to/trace/${encodeURIComponent(traceId)}?${qs.stringify(params)}`, state: {}, }; }; diff --git a/x-pack/plugins/observability_solution/observability_shared/common/trigger_ids.ts b/x-pack/plugins/observability_solution/observability_shared/common/trigger_ids.ts index 404aaab8781b1..8a75472e0546b 100644 --- a/x-pack/plugins/observability_solution/observability_shared/common/trigger_ids.ts +++ b/x-pack/plugins/observability_solution/observability_shared/common/trigger_ids.ts @@ -6,7 +6,6 @@ */ export enum ObservabilityTriggerId { - LogEntryContextMenu = 'logEntryContextMenu', ApmTransactionContextMenu = 'apmTransactionContextMenu', ApmErrorContextMenu = 'apmErrorContextMenu', } diff --git a/x-pack/plugins/observability_solution/observability_shared/tsconfig.json b/x-pack/plugins/observability_solution/observability_shared/tsconfig.json index f7b8a7ff6c573..15ae8d34c7f55 100644 --- a/x-pack/plugins/observability_solution/observability_shared/tsconfig.json +++ b/x-pack/plugins/observability_solution/observability_shared/tsconfig.json @@ -46,6 +46,7 @@ "@kbn/es-query", "@kbn/serverless", "@kbn/data-views-plugin", + "@kbn/deeplinks-observability", ], "exclude": ["target/**/*", ".storybook/**/*.js"] }