Skip to content

Commit

Permalink
[APM][ECO] Service name and trace id links on Logs Explorer and Disco…
Browse files Browse the repository at this point in the history
…ver (elastic#192349)

closes elastic#192164

This PR adds links to the **logs explorer** and **discover**
service.name fields and trace.id field.

- service.name link points to `/link-to/entity/{serviceName}`.
- trace.id link points to `/link-to/trace/{traceId}`.

### Logs explorer


https://github.com/user-attachments/assets/4b2ec665-8968-4b19-822d-f06ba7d1978a

#### When EEM setting is disabled:

<img width="1763" alt="Screenshot 2024-09-09 at 15 00 28"
src="https://github.com/user-attachments/assets/a8b4ca60-b835-43d1-a0fc-cdb5ae25452f">

---

### Discover


https://github.com/user-attachments/assets/563e91c2-0e54-4ef3-9f98-d5c83573e513

#### When EEM setting is disabled:
<img width="1869" alt="Screenshot 2024-09-09 at 15 00 51"
src="https://github.com/user-attachments/assets/30257e85-5b2d-42d7-a3a7-a34b1591e50b">

### EEM callout
<img width="1504" alt="Screenshot 2024-09-10 at 16 44 39"
src="https://github.com/user-attachments/assets/7cb67172-671a-4fed-b5bb-72a3295b905f">

---

### Remove links when APM is not enabled
<img width="1422" alt="Screenshot 2024-09-11 at 10 13 25"
src="https://github.com/user-attachments/assets/022406a1-e9c1-4763-9d8b-625551cdabd9">
<img width="1568" alt="Screenshot 2024-09-11 at 10 13 40"
src="https://github.com/user-attachments/assets/aa65acc3-4a8f-4f0d-9544-95bd0adec3cf">

---------

Co-authored-by: Kate Patticha <[email protected]>
Co-authored-by: kibanamachine <[email protected]>
  • Loading branch information
3 people authored Sep 18, 2024
1 parent 6a3adf7 commit 6221afa
Show file tree
Hide file tree
Showing 31 changed files with 958 additions and 311 deletions.
2 changes: 1 addition & 1 deletion packages/kbn-optimizer/limits.yml
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ pageLoadAssetSize:
observabilityAiAssistantManagement: 19279
observabilityLogsExplorer: 46650
observabilityOnboarding: 19573
observabilityShared: 72039
observabilityShared: 80000
osquery: 107090
painlessLab: 179748
presentationPanel: 55463
Expand Down
201 changes: 0 additions & 201 deletions packages/kbn-typed-react-router-config/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,204 +191,3 @@ type MapRoutes<TRouteMap extends RouteMap, TParents extends RouteWithPath[] = []
> extends Record<string, Route[]>
? FromRouteMap<TRouteMap, TParents>
: never;

// const element = null as any;

// const routes = {
// '/link-to/transaction/{transactionId}': {
// element,
// },
// '/link-to/trace/{traceId}': {
// element,
// },
// '/': {
// element,
// children: {
// '/settings': {
// element,
// children: {
// '/settings/agent-configuration': {
// element,
// },
// '/settings/agent-configuration/create': {
// element,
// params: t.partial({
// query: t.partial({
// pageStep: t.string,
// }),
// }),
// },
// '/settings/agent-configuration/edit': {
// element,
// params: t.partial({
// query: t.partial({
// pageStep: t.string,
// }),
// }),
// },
// '/settings/apm-indices': {
// element,
// },
// '/settings/custom-links': {
// element,
// },
// '/settings/schema': {
// element,
// },
// '/settings/anomaly-detection': {
// element,
// },
// '/settings/agent-keys': {
// element,
// },
// '/settings': {
// element,
// },
// },
// },
// '/services/:serviceName': {
// element,
// params: t.intersection([
// t.type({
// path: t.type({
// serviceName: t.string,
// }),
// }),
// t.partial({
// query: t.partial({
// environment: t.string,
// rangeFrom: t.string,
// rangeTo: t.string,
// comparisonEnabled: t.string,
// comparisonType: t.string,
// latencyAggregationType: t.string,
// transactionType: t.string,
// kuery: t.string,
// }),
// }),
// ]),
// children: {
// '/services/:serviceName/overview': {
// element,
// },
// '/services/:serviceName/transactions': {
// element,
// },
// '/services/:serviceName/transactions/view': {
// element,
// },
// '/services/:serviceName/dependencies': {
// element,
// },
// '/services/:serviceName/errors': {
// element,
// children: {
// '/services/:serviceName/errors/:groupId': {
// element,
// params: t.type({
// path: t.type({
// groupId: t.string,
// }),
// }),
// },
// '/services/:serviceName/errors': {
// element,
// params: t.partial({
// query: t.partial({
// sortDirection: t.string,
// sortField: t.string,
// pageSize: t.string,
// page: t.string,
// }),
// }),
// },
// },
// },
// '/services/:serviceName/metrics': {
// element,
// },
// '/services/:serviceName/nodes': {
// element,
// children: {
// '/services/{serviceName}/nodes/{serviceNodeName}/metrics': {
// element,
// },
// '/services/:serviceName/nodes': {
// element,
// },
// },
// },
// '/services/:serviceName/service-map': {
// element,
// },
// '/services/:serviceName/logs': {
// element,
// },
// '/services/:serviceName/profiling': {
// element,
// },
// '/services/:serviceName': {
// element,
// },
// },
// },
// '/': {
// element,
// params: t.partial({
// query: t.partial({
// rangeFrom: t.string,
// rangeTo: t.string,
// }),
// }),
// children: {
// '/services': {
// element,
// },
// '/traces': {
// element,
// },
// '/service-map': {
// element,
// },
// '/backends': {
// element,
// children: {
// '/backends/{backendName}/overview': {
// element,
// },
// '/backends/overview': {
// element,
// },
// '/backends': {
// element,
// },
// },
// },
// '/': {
// element,
// },
// },
// },
// },
// },
// };

// type Routes = typeof routes;

// type Mapped = MapRoutes<Routes>;
// type Paths = PathsOf<Routes>;

// type Bar = Match<Routes, '/*'>;
// type Foo = OutputOf<Routes, '/*'>;
// type Baz = OutputOf<Routes, '/services/:serviceName/errors'>;

// const { path }: Foo = {} as any;

// function _useApmParams<TPath extends PathsOf<Routes>>(p: TPath): OutputOf<Routes, TPath> {
// return {} as any;
// }

// const {
// path: { serviceName },
// query: { comparisonType },
// } = _useApmParams('/services/:serviceName/nodes/*');
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,11 @@ const DataTablePopoverCellValue = dynamic(
() => import('@kbn/unified-data-table/src/components/data_table_cell_value')
);

interface ChipWithPopoverProps {
type ChipWithPopoverChildrenType = (props: {
content: string;
}) => React.ReactNode | React.ReactNode;

export interface ChipWithPopoverProps {
/**
* ECS mapping for the key
*/
Expand All @@ -42,6 +46,7 @@ interface ChipWithPopoverProps {
dataTestSubj?: string;
leftSideIcon?: React.ReactNode;
rightSideIcon?: EuiBadgeProps['iconType'];
children?: ChipWithPopoverChildrenType;
}

export function ChipWithPopover({
Expand All @@ -50,6 +55,7 @@ export function ChipWithPopover({
dataTestSubj = `dataTablePopoverChip_${property}`,
leftSideIcon,
rightSideIcon,
children,
}: ChipWithPopoverProps) {
return (
<ChipPopover
Expand All @@ -71,7 +77,9 @@ export function ChipWithPopover({
</EuiFlexGroup>
</EuiBadge>
)}
/>
>
{children}
</ChipPopover>
);
}

Expand All @@ -89,9 +97,10 @@ interface ChipPopoverProps {
handleChipClickAriaLabel: string;
chipCss: SerializedStyles;
}) => ReactElement;
children?: ChipWithPopoverChildrenType;
}

export function ChipPopover({ property, text, renderChip }: ChipPopoverProps) {
export function ChipPopover({ property, text, renderChip, children }: ChipPopoverProps) {
const xsFontSize = useEuiFontSize('xs').fontSize;
const [isPopoverOpen, setIsPopoverOpen] = useState(false);

Expand Down Expand Up @@ -131,7 +140,8 @@ export function ChipPopover({ property, text, renderChip }: ChipPopoverProps) {
<div style={{ maxWidth: '200px' }}>
<EuiText size="s">
<DataTablePopoverCellValue>
<span style={{ fontWeight: 700 }}>{property}</span> {text}
<span style={{ fontWeight: 700 }}>{property}</span>{' '}
{typeof children === 'function' ? children({ content: text }) : text}
</DataTablePopoverCellValue>
</EuiText>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* 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 React from 'react';
import { getRouterLinkProps } from '@kbn/router-utils';
import { EuiLink } from '@elastic/eui';
import { OBSERVABILITY_ENTITY_CENTRIC_EXPERIENCE } from '@kbn/management-settings-ids';
import { type ChipWithPopoverProps, ChipWithPopover } from './popover_chip';
import { useDiscoverServices } from '../../../hooks/use_discover_services';

const SERVICE_ENTITY_LOCATOR = 'SERVICE_ENTITY_LOCATOR';

export function ServiceNameChipWithPopover(props: ChipWithPopoverProps) {
const { share, core } = useDiscoverServices();
const canViewApm = core.application.capabilities.apm?.show || false;
const isEntityCentricExperienceSettingEnabled = canViewApm
? core.uiSettings.get(OBSERVABILITY_ENTITY_CENTRIC_EXPERIENCE)
: false;
const urlService = share?.url;

const apmLinkToServiceEntityLocator = urlService?.locators.get<{ serviceName: string }>(
SERVICE_ENTITY_LOCATOR
);
const href = apmLinkToServiceEntityLocator?.getRedirectUrl({
serviceName: props.text,
});

const routeLinkProps = href
? getRouterLinkProps({
href,
onClick: () => apmLinkToServiceEntityLocator?.navigate({ serviceName: props.text }),
})
: undefined;

return (
<ChipWithPopover {...props}>
{canViewApm && isEntityCentricExperienceSettingEnabled && routeLinkProps
? ({ content }) => <EuiLink {...routeLinkProps}>{content}</EuiLink>
: undefined}
</ChipWithPopover>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { LogDocument } from '@kbn/discover-utils/src';
import * as constants from '../../../../../common/data_types/logs/constants';
import { getUnformattedResourceFields } from './utils/resource';
import { ChipWithPopover } from '../../../data_types/logs/popover_chip';
import { ServiceNameChipWithPopover } from '../../../data_types/logs/service_name_chip_with_popover';

const AgentIcon = dynamic(() => import('@kbn/custom-icons/src/components/agent_icon'));

Expand All @@ -23,7 +24,7 @@ export const Resource = ({ row }: DataGridCellValueElementProps) => {
return (
<div>
{(resourceDoc[constants.SERVICE_NAME_FIELD] as string) && (
<ChipWithPopover
<ServiceNameChipWithPopover
property={constants.SERVICE_NAME_FIELD}
text={resourceDoc[constants.SERVICE_NAME_FIELD] as string}
rightSideIcon="arrowDown"
Expand Down
2 changes: 2 additions & 0 deletions src/plugins/discover/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@
"@kbn/observability-ai-assistant-plugin",
"@kbn/fields-metadata-plugin",
"@kbn/security-solution-common",
"@kbn/router-utils",
"@kbn/management-settings-ids",
"@kbn/logs-data-access-plugin"
],
"exclude": [
Expand Down
Loading

0 comments on commit 6221afa

Please sign in to comment.