mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[APM] Fix overlapping transaction names (#76083)
...in the table and the header. Did this by adding `word-break: break-all` to them. Also: * Rename List to TransactionList * Add stories for TransactionList and ApmHeader * Add missing type information to transactions based on sample transaction Fixes #73960.
This commit is contained in:
parent
6d4e772cec
commit
4d4eae4413
12 changed files with 206 additions and 21 deletions
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import React from 'react';
|
||||
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
|
||||
import { TransactionGroup } from '../../../../../server/lib/transaction_groups/fetcher';
|
||||
import { TransactionList } from './';
|
||||
|
||||
storiesOf('app/TransactionOverview/TransactionList', module).add(
|
||||
'Single Row',
|
||||
() => {
|
||||
const items: TransactionGroup[] = [
|
||||
{
|
||||
name:
|
||||
'GET /api/v1/regions/azure-eastus2/clusters/elasticsearch/xc18de071deb4262be54baebf5f6a1ce/proxy/_snapshot/found-snapshots/_all',
|
||||
sample: {
|
||||
container: {
|
||||
id:
|
||||
'xa802046074071c9c828e8db3b7ef92ea0484d9fe783b9c518f65a7b45dfdd2c',
|
||||
},
|
||||
agent: {
|
||||
name: 'java',
|
||||
ephemeral_id: 'x787d6b7-3241-4b55-ba49-0c96bc9857d1',
|
||||
version: '1.17.0',
|
||||
},
|
||||
process: {
|
||||
pid: 28,
|
||||
title: '/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java',
|
||||
},
|
||||
processor: {
|
||||
name: 'transaction',
|
||||
event: 'transaction',
|
||||
},
|
||||
labels: {
|
||||
path:
|
||||
'/api/v1/regions/azure-eastus2/clusters/elasticsearch/xc18de071deb4262be54baebf5f6a1ce/proxy/_snapshot/found-snapshots/_all',
|
||||
status_code: '200',
|
||||
request_method: 'GET',
|
||||
request_id: 'x273dc2477e021979125e0ec67e8d778',
|
||||
},
|
||||
observer: {
|
||||
hostname: 'x840922c967b',
|
||||
name: 'instance-000000000x',
|
||||
id: 'xb384baf-c16a-415a-928a-a10635a04b81',
|
||||
ephemeral_id: 'x9227f0e-848d-423e-a65a-5fdee321f4a9',
|
||||
type: 'apm-server',
|
||||
version: '7.8.1',
|
||||
version_major: 7,
|
||||
},
|
||||
trace: {
|
||||
id: 'x998d7e5db84aa8341b358a264a78984',
|
||||
},
|
||||
'@timestamp': '2020-08-26T14:40:31.472Z',
|
||||
ecs: {
|
||||
version: '1.5.0',
|
||||
},
|
||||
service: {
|
||||
node: {
|
||||
name:
|
||||
'xa802046074071c9c828e8db3b7ef92ea0484d9fe783b9c518f65a7b45dfdd2c',
|
||||
},
|
||||
environment: 'qa',
|
||||
framework: {
|
||||
name: 'API',
|
||||
},
|
||||
name: 'adminconsole',
|
||||
runtime: {
|
||||
name: 'Java',
|
||||
version: '1.8.0_265',
|
||||
},
|
||||
language: {
|
||||
name: 'Java',
|
||||
version: '1.8.0_265',
|
||||
},
|
||||
version: 'ms-44.1-BC_1',
|
||||
},
|
||||
host: {
|
||||
hostname: 'xa8020460740',
|
||||
os: {
|
||||
platform: 'Linux',
|
||||
},
|
||||
ip: '3.83.239.24',
|
||||
name: 'xa8020460740',
|
||||
architecture: 'amd64',
|
||||
},
|
||||
transaction: {
|
||||
duration: {
|
||||
us: 8260617,
|
||||
},
|
||||
result: 'HTTP 2xx',
|
||||
name:
|
||||
'GET /api/v1/regions/azure-eastus2/clusters/elasticsearch/xc18de071deb4262be54baebf5f6a1ce/proxy/_snapshot/found-snapshots/_all',
|
||||
span_count: {
|
||||
dropped: 0,
|
||||
started: 8,
|
||||
},
|
||||
id: 'xaa3cae6fd4f7023',
|
||||
type: 'request',
|
||||
sampled: true,
|
||||
},
|
||||
timestamp: {
|
||||
us: 1598452831472001,
|
||||
},
|
||||
},
|
||||
p95: 11974156,
|
||||
averageResponseTime: 8087434.558974359,
|
||||
transactionsPerMinute: 0.40625,
|
||||
impact: 100,
|
||||
impactRelative: 100,
|
||||
},
|
||||
];
|
||||
|
||||
return <TransactionList isLoading={false} items={items} />;
|
||||
}
|
||||
);
|
|
@ -19,9 +19,16 @@ import { LoadingStatePrompt } from '../../../shared/LoadingStatePrompt';
|
|||
import { EmptyMessage } from '../../../shared/EmptyMessage';
|
||||
import { TransactionDetailLink } from '../../../shared/Links/apm/TransactionDetailLink';
|
||||
|
||||
// Truncate both the link and the child span (the tooltip anchor.) The link so
|
||||
// it doesn't overflow, and the anchor so we get the ellipsis.
|
||||
const TransactionNameLink = styled(TransactionDetailLink)`
|
||||
${truncate('100%')};
|
||||
font-family: ${fontFamilyCode};
|
||||
white-space: nowrap;
|
||||
${truncate('100%')};
|
||||
|
||||
> span {
|
||||
${truncate('100%')};
|
||||
}
|
||||
`;
|
||||
|
||||
interface Props {
|
||||
|
@ -41,20 +48,20 @@ export function TransactionList({ items, isLoading }: Props) {
|
|||
sortable: true,
|
||||
render: (_, { sample }: TransactionGroup) => {
|
||||
return (
|
||||
<EuiToolTip
|
||||
id="transaction-name-link-tooltip"
|
||||
content={sample.transaction.name || NOT_AVAILABLE_LABEL}
|
||||
<TransactionNameLink
|
||||
serviceName={sample.service.name}
|
||||
transactionId={sample.transaction.id}
|
||||
traceId={sample.trace.id}
|
||||
transactionName={sample.transaction.name}
|
||||
transactionType={sample.transaction.type}
|
||||
>
|
||||
<TransactionNameLink
|
||||
serviceName={sample.service.name}
|
||||
transactionId={sample.transaction.id}
|
||||
traceId={sample.trace.id}
|
||||
transactionName={sample.transaction.name}
|
||||
transactionType={sample.transaction.type}
|
||||
<EuiToolTip
|
||||
id="transaction-name-link-tooltip"
|
||||
content={sample.transaction.name || NOT_AVAILABLE_LABEL}
|
||||
>
|
||||
{sample.transaction.name || NOT_AVAILABLE_LABEL}
|
||||
</TransactionNameLink>
|
||||
</EuiToolTip>
|
||||
<>{sample.transaction.name || NOT_AVAILABLE_LABEL}</>
|
||||
</EuiToolTip>
|
||||
</TransactionNameLink>
|
||||
);
|
||||
},
|
||||
},
|
|
@ -33,7 +33,7 @@ import { ElasticDocsLink } from '../../shared/Links/ElasticDocsLink';
|
|||
import { fromQuery, toQuery } from '../../shared/Links/url_helpers';
|
||||
import { LocalUIFilters } from '../../shared/LocalUIFilters';
|
||||
import { TransactionTypeFilter } from '../../shared/LocalUIFilters/TransactionTypeFilter';
|
||||
import { TransactionList } from './List';
|
||||
import { TransactionList } from './TransactionList';
|
||||
import { useRedirect } from './useRedirect';
|
||||
|
||||
function getRedirectLocation({
|
||||
|
@ -62,6 +62,7 @@ function getRedirectLocation({
|
|||
export function TransactionOverview() {
|
||||
const location = useLocation();
|
||||
const { urlParams } = useUrlParams();
|
||||
|
||||
const { serviceName, transactionType } = urlParams;
|
||||
|
||||
// TODO: fetching of transaction types should perhaps be lifted since it is needed in several places. Context?
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { EuiTitle } from '@elastic/eui';
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import React from 'react';
|
||||
import { MockApmPluginContextWrapper } from '../../../context/ApmPluginContext/MockApmPluginContext';
|
||||
import { ApmHeader } from './';
|
||||
|
||||
storiesOf('shared/ApmHeader', module)
|
||||
.addDecorator((storyFn) => {
|
||||
return (
|
||||
<MockApmPluginContextWrapper>{storyFn()}</MockApmPluginContextWrapper>
|
||||
);
|
||||
})
|
||||
.add('Example', () => {
|
||||
return (
|
||||
<ApmHeader>
|
||||
<EuiTitle size="l">
|
||||
<h1>
|
||||
GET
|
||||
/api/v1/regions/azure-eastus2/clusters/elasticsearch/xc18de071deb4262be54baebf5f6a1ce/proxy/_snapshot/found-snapshots/_all
|
||||
</h1>
|
||||
</EuiTitle>
|
||||
</ApmHeader>
|
||||
);
|
||||
});
|
|
@ -6,15 +6,25 @@
|
|||
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui';
|
||||
import React, { ReactNode } from 'react';
|
||||
import { KueryBar } from '../KueryBar';
|
||||
import styled from 'styled-components';
|
||||
import { DatePicker } from '../DatePicker';
|
||||
import { EnvironmentFilter } from '../EnvironmentFilter';
|
||||
import { KueryBar } from '../KueryBar';
|
||||
|
||||
// Header titles with long, unbroken words, like you would see for a long URL in
|
||||
// a transaction name, with the default `work-break`, don't break, and that ends
|
||||
// up pushing the date picker off of the screen. Setting `break-all` here lets
|
||||
// it wrap even if it has a long, unbroken work. The wrapped result is not great
|
||||
// looking, since it wraps, but it doesn't push any controls off of the screen.
|
||||
const ChildrenContainerFlexItem = styled(EuiFlexItem)`
|
||||
word-break: break-all;
|
||||
`;
|
||||
|
||||
export function ApmHeader({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<>
|
||||
<EuiFlexGroup alignItems="center" gutterSize="s">
|
||||
<EuiFlexItem>{children}</EuiFlexItem>
|
||||
<ChildrenContainerFlexItem>{children}</ChildrenContainerFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<DatePicker />
|
||||
</EuiFlexItem>
|
||||
|
|
|
@ -185,10 +185,12 @@ export async function transactionGroupsFetcher(
|
|||
}
|
||||
|
||||
export interface TransactionGroup {
|
||||
key: Record<string, any> | string;
|
||||
name?: string;
|
||||
key?: Record<string, any> | string;
|
||||
averageResponseTime: number | null | undefined;
|
||||
transactionsPerMinute: number;
|
||||
p95: number | null | undefined;
|
||||
impact: number;
|
||||
impactRelative?: number;
|
||||
sample: Transaction;
|
||||
}
|
||||
|
|
|
@ -5,5 +5,11 @@
|
|||
*/
|
||||
|
||||
export interface Host {
|
||||
architecture?: string;
|
||||
hostname?: string;
|
||||
name?: string;
|
||||
ip?: string;
|
||||
os?: {
|
||||
platform?: string;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -5,7 +5,11 @@
|
|||
*/
|
||||
|
||||
export interface Observer {
|
||||
ephemeral_id?: string;
|
||||
hostname?: string;
|
||||
id?: string;
|
||||
name?: string;
|
||||
type?: string;
|
||||
version: string;
|
||||
version_major: number;
|
||||
}
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
*/
|
||||
|
||||
export interface Process {
|
||||
args: string[];
|
||||
args?: string[];
|
||||
pid: number;
|
||||
ppid: number;
|
||||
title: string;
|
||||
ppid?: number;
|
||||
title?: string;
|
||||
}
|
||||
|
|
|
@ -9,7 +9,10 @@ export interface Service {
|
|||
environment?: string;
|
||||
framework?: {
|
||||
name: string;
|
||||
version: string;
|
||||
version?: string;
|
||||
};
|
||||
node?: {
|
||||
name?: string;
|
||||
};
|
||||
runtime?: {
|
||||
name: string;
|
||||
|
@ -19,4 +22,5 @@ export interface Service {
|
|||
name: string;
|
||||
version?: string;
|
||||
};
|
||||
version?: string;
|
||||
}
|
||||
|
|
|
@ -54,6 +54,7 @@ export interface TransactionRaw extends APMBaseDoc {
|
|||
|
||||
// Shared by errors and transactions
|
||||
container?: Container;
|
||||
ecs?: { version?: string };
|
||||
host?: Host;
|
||||
http?: Http;
|
||||
kubernetes?: Kubernetes;
|
||||
|
|
|
@ -19,6 +19,7 @@ export type AgentName =
|
|||
| 'ruby';
|
||||
|
||||
export interface Agent {
|
||||
ephemeral_id?: string;
|
||||
name: AgentName;
|
||||
version: string;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue