mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[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 <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
c4cf9fe8a5
commit
d5e0d3a2f6
21 changed files with 228 additions and 128 deletions
|
@ -1997,9 +1997,6 @@ module.exports = {
|
|||
},
|
||||
{
|
||||
files: [
|
||||
// logsShared depends on o11y/private plugins, but platform plugins depend on it
|
||||
'x-pack/plugins/observability_solution/logs_shared/**',
|
||||
|
||||
// TODO @kibana/operations
|
||||
'scripts/create_observability_rules.js', // is importing "@kbn/observability-alerting-test-data" (observability/private)
|
||||
'src/cli_setup/**', // is importing "@kbn/interactive-setup-plugin" (platform/private)
|
||||
|
|
|
@ -4,6 +4,6 @@
|
|||
"owner": [
|
||||
"@elastic/obs-ux-logs-team"
|
||||
],
|
||||
"group": "observability",
|
||||
"visibility": "private"
|
||||
"group": "platform",
|
||||
"visibility": "shared"
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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';
|
||||
|
|
|
@ -4,6 +4,6 @@
|
|||
"owner": [
|
||||
"@elastic/obs-ux-logs-team"
|
||||
],
|
||||
"group": "observability",
|
||||
"visibility": "private"
|
||||
"group": "platform",
|
||||
"visibility": "shared"
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ import { i18n } from '@kbn/i18n';
|
|||
import {
|
||||
METRICS_EXPLORER_LOCATOR_ID,
|
||||
MetricsExplorerLocatorParams,
|
||||
ObservabilityTriggerId,
|
||||
} from '@kbn/observability-shared-plugin/common';
|
||||
import {
|
||||
BehaviorSubject,
|
||||
|
@ -101,10 +100,6 @@ export class Plugin implements InfraClientPluginClass {
|
|||
registerFeatures(pluginsSetup.home);
|
||||
}
|
||||
|
||||
pluginsSetup.uiActions.registerTrigger({
|
||||
id: ObservabilityTriggerId.LogEntryContextMenu,
|
||||
});
|
||||
|
||||
const assetDetailsLocator =
|
||||
pluginsSetup.share.url.locators.get<AssetDetailsLocatorParams>(ASSET_DETAILS_LOCATOR_ID);
|
||||
const inventoryLocator =
|
||||
|
|
|
@ -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": [],
|
||||
|
|
|
@ -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"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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<TransactionDetailsByTraceIdLocatorParams>({
|
||||
id: TRANSACTION_DETAILS_BY_TRACE_ID_LOCATOR,
|
||||
getLocation: async (params) => {
|
||||
return { app: 'apm', path: '/trace-id', state: {} };
|
||||
},
|
||||
});
|
||||
|
||||
const ProviderWrapper: FC<React.PropsWithChildren<{ urlService?: UrlService }>> = ({
|
||||
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(
|
||||
<ProviderWrapper urlService={urlServiceWithUptimeLocator}>
|
||||
<ProviderWrapper urlService={urlServiceWithMockLocators}>
|
||||
<LogEntryActionsMenu
|
||||
logEntry={{
|
||||
fields: [{ field: 'host.ip', value: ['HOST_IP'] }],
|
||||
|
@ -120,7 +128,7 @@ describe('LogEntryActionsMenu component', () => {
|
|||
|
||||
it('renders as enabled when a container id is present in the log entry', () => {
|
||||
const elementWrapper = mount(
|
||||
<ProviderWrapper urlService={urlServiceWithUptimeLocator}>
|
||||
<ProviderWrapper urlService={urlServiceWithMockLocators}>
|
||||
<LogEntryActionsMenu
|
||||
logEntry={{
|
||||
fields: [{ field: 'container.id', value: ['CONTAINER_ID'] }],
|
||||
|
@ -150,7 +158,7 @@ describe('LogEntryActionsMenu component', () => {
|
|||
|
||||
it('renders as enabled when a pod uid is present in the log entry', () => {
|
||||
const elementWrapper = mount(
|
||||
<ProviderWrapper urlService={urlServiceWithUptimeLocator}>
|
||||
<ProviderWrapper urlService={urlServiceWithMockLocators}>
|
||||
<LogEntryActionsMenu
|
||||
logEntry={{
|
||||
fields: [{ field: 'kubernetes.pod.uid', value: ['POD_UID'] }],
|
||||
|
@ -180,7 +188,7 @@ describe('LogEntryActionsMenu component', () => {
|
|||
|
||||
it('renders as disabled when no supported field is present in the log entry', () => {
|
||||
const elementWrapper = mount(
|
||||
<ProviderWrapper urlService={urlServiceWithUptimeLocator}>
|
||||
<ProviderWrapper urlService={urlServiceWithMockLocators}>
|
||||
<LogEntryActionsMenu
|
||||
logEntry={{
|
||||
fields: [],
|
||||
|
@ -215,7 +223,7 @@ describe('LogEntryActionsMenu component', () => {
|
|||
describe('apm link', () => {
|
||||
it('renders with a trace id filter when present in log entry', () => {
|
||||
const elementWrapper = mount(
|
||||
<ProviderWrapper>
|
||||
<ProviderWrapper urlService={urlServiceWithMockLocators}>
|
||||
<LogEntryActionsMenu
|
||||
logEntry={{
|
||||
fields: [{ field: 'trace.id', value: ['1234567'] }],
|
||||
|
@ -246,7 +254,7 @@ describe('LogEntryActionsMenu component', () => {
|
|||
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(
|
||||
<ProviderWrapper>
|
||||
<ProviderWrapper urlService={urlServiceWithMockLocators}>
|
||||
<LogEntryActionsMenu
|
||||
logEntry={{
|
||||
fields: [
|
||||
|
@ -279,7 +287,7 @@ describe('LogEntryActionsMenu component', () => {
|
|||
|
||||
it('renders as disabled when no supported field is present in log entry', () => {
|
||||
const elementWrapper = mount(
|
||||
<ProviderWrapper>
|
||||
<ProviderWrapper urlService={urlServiceWithMockLocators}>
|
||||
<LogEntryActionsMenu
|
||||
logEntry={{
|
||||
fields: [],
|
||||
|
@ -303,7 +311,10 @@ describe('LogEntryActionsMenu component', () => {
|
|||
elementWrapper.update();
|
||||
|
||||
expect(
|
||||
elementWrapper.find(`button${testSubject('~apmLogEntryActionsMenuItem')}`).prop('disabled')
|
||||
elementWrapper
|
||||
.find(`${testSubject('~apmLogEntryActionsMenuItem')}`)
|
||||
.first()
|
||||
.prop('disabled')
|
||||
).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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) => {
|
|||
</EuiContextMenuItem>,
|
||||
<EuiContextMenuItem
|
||||
data-test-subj="logEntryActionsMenuItem apmLogEntryActionsMenuItem"
|
||||
disabled={!apmLinkDescriptor}
|
||||
disabled={!apmLinkProps}
|
||||
icon="apmApp"
|
||||
key="apmLink"
|
||||
{...apmLinkProps}
|
||||
|
@ -69,7 +67,7 @@ export const LogEntryActionsMenu = ({ logEntry }: LogEntryActionsMenuProps) => {
|
|||
/>
|
||||
</EuiContextMenuItem>,
|
||||
],
|
||||
[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<UptimeOverviewLocatorInfraParams>(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];
|
||||
const getAPMLink =
|
||||
({ locators }: { locators: BrowserUrlService['locators'] }) =>
|
||||
(logEntry: LogEntry) => {
|
||||
const traceId = logEntry.fields.find(
|
||||
({ field, value }) => typeof value[0] === 'string' && field === 'trace.id'
|
||||
)?.value?.[0];
|
||||
|
||||
if (typeof traceId !== 'string') {
|
||||
return undefined;
|
||||
}
|
||||
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);
|
||||
const apmLocator = locators.get<TransactionDetailsByTraceIdLocatorParams>(
|
||||
TRANSACTION_DETAILS_BY_TRACE_ID_LOCATOR
|
||||
);
|
||||
|
||||
from.setMinutes(from.getMinutes() - 10);
|
||||
to.setMinutes(to.getMinutes() + 10);
|
||||
if (!apmLocator) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return { rangeFrom: from.toISOString(), rangeTo: to.toISOString() };
|
||||
})()
|
||||
: { rangeFrom: 'now-1y', rangeTo: 'now' };
|
||||
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);
|
||||
|
||||
return {
|
||||
app: 'apm',
|
||||
pathname: getApmTraceUrl({ traceId, rangeFrom, rangeTo }),
|
||||
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;
|
||||
};
|
||||
};
|
||||
|
||||
function getApmTraceUrl({
|
||||
traceId,
|
||||
rangeFrom,
|
||||
rangeTo,
|
||||
}: {
|
||||
traceId: string;
|
||||
rangeFrom: string;
|
||||
rangeTo: string;
|
||||
}) {
|
||||
return `/link-to/trace/${traceId}?` + new URLSearchParams({ rangeFrom, rangeTo }).toString();
|
||||
}
|
||||
|
||||
export interface ContextRouterLinkProps {
|
||||
href: string | undefined;
|
||||
|
|
|
@ -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<OverlayRef>();
|
||||
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 = ({
|
|||
}
|
||||
>
|
||||
<EuiFlexGroup direction="column" gutterSize="m">
|
||||
{observabilityAIAssistant && (
|
||||
{LogAIAssistant && (
|
||||
<EuiFlexItem grow={false}>
|
||||
<LogAIAssistant
|
||||
observabilityAIAssistant={observabilityAIAssistant}
|
||||
doc={logEntry}
|
||||
/>
|
||||
<LogAIAssistant doc={logEntry} />
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
<EuiFlexItem grow={false}>
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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}
|
||||
</LogEntryColumn>
|
||||
|
|
|
@ -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<PluginKibanaContextValue>({
|
||||
...core,
|
||||
...plugins,
|
||||
...pluginStart,
|
||||
logsShared: pluginStart,
|
||||
});
|
||||
|
||||
export const useKibanaContextForPlugin =
|
||||
|
|
|
@ -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$<boolean>(UI_SETTINGS.QUERY_ALLOW_LEADING_WILDCARDS);
|
||||
const [queryStringOptions] = useUiSetting$<SerializableRecord>(UI_SETTINGS.QUERY_STRING_OPTIONS);
|
||||
const [dateFormatTZ] = useUiSetting$<string>(UI_SETTINGS.DATEFORMAT_TZ);
|
||||
const [ignoreFilterIfFieldNotInIndex] = useUiSetting$<boolean>(
|
||||
UI_SETTINGS.COURIER_IGNORE_FILTER_IF_FIELD_NOT_IN_INDEX
|
||||
);
|
||||
|
||||
return useMemo(
|
||||
() => ({
|
||||
allowLeadingWildcards,
|
||||
queryStringOptions,
|
||||
dateFormatTZ,
|
||||
ignoreFilterIfFieldNotInIndex,
|
||||
}),
|
||||
[allowLeadingWildcards, dateFormatTZ, ignoreFilterIfFieldNotInIndex, queryStringOptions]
|
||||
);
|
||||
};
|
|
@ -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<typeof useUiTracker>;
|
||||
export type TrackEvent = (options: TrackMetricOptions) => void;
|
||||
|
||||
export { METRIC_TYPE };
|
||||
|
||||
export function useUiTracker<Services extends ServiceDeps>(): TrackEvent {
|
||||
const reportUiCounter = useKibana<Services>().services?.usageCollection?.reportUiCounter;
|
||||
const trackEvent = useMemo(() => {
|
||||
return ({ metric, metricType = METRIC_TYPE.COUNT }: TrackMetricOptions) => {
|
||||
if (reportUiCounter) {
|
||||
reportUiCounter('infra_logs', metricType, metric);
|
||||
}
|
||||
};
|
||||
}, [reportUiCounter]);
|
||||
return trackEvent;
|
||||
}
|
|
@ -11,7 +11,9 @@
|
|||
"types/**/*",
|
||||
"emotion.d.ts"
|
||||
],
|
||||
"exclude": ["target/**/*"],
|
||||
"exclude": [
|
||||
"target/**/*"
|
||||
],
|
||||
"kbn_references": [
|
||||
"@kbn/core",
|
||||
"@kbn/i18n",
|
||||
|
@ -29,7 +31,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",
|
||||
|
@ -53,5 +54,7 @@
|
|||
"@kbn/embeddable-plugin",
|
||||
"@kbn/saved-search-plugin",
|
||||
"@kbn/spaces-plugin",
|
||||
"@kbn/analytics",
|
||||
"@kbn/usage-collection-plugin",
|
||||
]
|
||||
}
|
||||
|
|
|
@ -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<TransactionDetailsByTraceIdLocatorParams>;
|
||||
|
@ -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: {},
|
||||
};
|
||||
};
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
*/
|
||||
|
||||
export enum ObservabilityTriggerId {
|
||||
LogEntryContextMenu = 'logEntryContextMenu',
|
||||
ApmTransactionContextMenu = 'apmTransactionContextMenu',
|
||||
ApmErrorContextMenu = 'apmErrorContextMenu',
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
"@kbn/es-query",
|
||||
"@kbn/serverless",
|
||||
"@kbn/data-views-plugin",
|
||||
"@kbn/deeplinks-observability",
|
||||
],
|
||||
"exclude": ["target/**/*", ".storybook/**/*.js"]
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue