mirror of
https://github.com/elastic/kibana.git
synced 2025-06-27 18:51:07 -04:00
[APM] Fix Agent Explorer page (#225071)
## Summary closes https://github.com/elastic/observability-error-backlog/issues/154 ### Before https://github.com/user-attachments/assets/288fb639-351a-4738-811e-44ed03649f5b ### After https://github.com/user-attachments/assets/5df0a45a-7d35-467d-963c-2a80b28ff120
This commit is contained in:
parent
c28fd76508
commit
bc5a533202
4 changed files with 149 additions and 18 deletions
|
@ -30,7 +30,7 @@ export function service(
|
|||
): Service;
|
||||
|
||||
export function service(
|
||||
options: { name: string; environment: string } & (
|
||||
options: { name: string; environment: string; agentVersion?: string } & (
|
||||
| { agentName: string }
|
||||
| { agentName: OpenTelemetryAgentName }
|
||||
)
|
||||
|
@ -38,16 +38,28 @@ export function service(
|
|||
|
||||
export function service(
|
||||
...args:
|
||||
| [{ name: string; environment: string; agentName: string | OpenTelemetryAgentName }]
|
||||
| [
|
||||
{
|
||||
name: string;
|
||||
environment: string;
|
||||
agentName: string | OpenTelemetryAgentName;
|
||||
agentVersion?: string;
|
||||
}
|
||||
]
|
||||
| [string, string, string]
|
||||
) {
|
||||
const [serviceName, environment, agentName] =
|
||||
args.length === 1 ? [args[0].name, args[0].environment, args[0].agentName] : args;
|
||||
const [serviceName, environment, agentName, agentVersion] =
|
||||
args.length === 1
|
||||
? [args[0].name, args[0].environment, args[0].agentName, args[0].agentVersion]
|
||||
: args;
|
||||
|
||||
return new Service({
|
||||
'service.name': serviceName,
|
||||
'service.environment': environment,
|
||||
'agent.name': agentName,
|
||||
...(agentVersion && {
|
||||
'agent.version': agentVersion,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* 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 { apm, timerange } from '@kbn/apm-synthtrace-client';
|
||||
import url from 'url';
|
||||
import { synthtrace } from '../../../synthtrace';
|
||||
|
||||
const agentExplorerHref = url.format({
|
||||
query: {
|
||||
kuery: '',
|
||||
agentLanguage: '',
|
||||
serviceName: '',
|
||||
comparisonEnabled: 'true',
|
||||
environment: 'ENVIRONMENT_ALL',
|
||||
},
|
||||
pathname: '/app/apm/settings/agent-explorer',
|
||||
});
|
||||
|
||||
function generateData({
|
||||
from,
|
||||
to,
|
||||
serviceName,
|
||||
agentName,
|
||||
}: {
|
||||
from: number;
|
||||
to: number;
|
||||
serviceName: string;
|
||||
agentName: string;
|
||||
}) {
|
||||
const range = timerange(from, to);
|
||||
|
||||
const service = apm
|
||||
.service({
|
||||
agentVersion: '1.0.0',
|
||||
name: serviceName,
|
||||
environment: 'production',
|
||||
agentName,
|
||||
})
|
||||
.instance('instance-1')
|
||||
.podId('pod-1');
|
||||
|
||||
return range
|
||||
.interval('1m')
|
||||
.rate(1)
|
||||
.generator((timestamp, index) => [
|
||||
service
|
||||
.transaction({ transactionName: 'GET /apple 🍎 ' })
|
||||
.timestamp(timestamp)
|
||||
.duration(1000)
|
||||
.success(),
|
||||
]);
|
||||
}
|
||||
|
||||
describe('Agent explorer', () => {
|
||||
before(() => {
|
||||
const start = Date.now() - 1000 * 60 * 150;
|
||||
const end = Date.now() + 1000 * 60 * 5;
|
||||
|
||||
synthtrace.index([
|
||||
...generateData({
|
||||
from: start,
|
||||
to: end,
|
||||
serviceName: 'opbeans-node',
|
||||
agentName: 'nodejs',
|
||||
}),
|
||||
]);
|
||||
});
|
||||
|
||||
after(() => {
|
||||
synthtrace.clean();
|
||||
});
|
||||
|
||||
describe('when logged in as viewer user', () => {
|
||||
beforeEach(() => {
|
||||
cy.loginAsViewerUser();
|
||||
cy.visitKibana(agentExplorerHref);
|
||||
});
|
||||
|
||||
it('shows the agent list', () => {
|
||||
cy.contains('opbeans-node');
|
||||
cy.contains('nodejs');
|
||||
});
|
||||
|
||||
it('opens agent details and clicks the instance', () => {
|
||||
cy.getByTestSubj('apmAgentExplorerListToggle').click();
|
||||
cy.contains('Agent Instances');
|
||||
cy.contains('production');
|
||||
cy.contains('instance-1').click();
|
||||
cy.location().should((loc) => {
|
||||
expect(loc.pathname).to.eq('/app/apm/services/opbeans-node/metrics');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -181,26 +181,30 @@ interface Props {
|
|||
serviceName: string;
|
||||
agentName: AgentName;
|
||||
agentDocsPageUrl?: string;
|
||||
environment: string;
|
||||
items: AgentExplorerInstance[];
|
||||
isLoading: boolean;
|
||||
start: string;
|
||||
end: string;
|
||||
}
|
||||
|
||||
export function AgentInstancesDetails({
|
||||
serviceName,
|
||||
agentName,
|
||||
start,
|
||||
end,
|
||||
agentDocsPageUrl,
|
||||
items,
|
||||
isLoading,
|
||||
}: Props) {
|
||||
const {
|
||||
query,
|
||||
query: { environment, rangeFrom, rangeTo, serviceGroup },
|
||||
} = useAnyOfApmParams('/services/{serviceName}/overview', '/services/{serviceName}/metrics');
|
||||
query: { environment },
|
||||
} = useAnyOfApmParams('/settings/agent-explorer');
|
||||
const { core } = useApmPluginContext();
|
||||
|
||||
const defaultComparisonEnabled = getComparisonEnabled({
|
||||
core,
|
||||
urlComparisonEnabled: query.comparisonEnabled,
|
||||
});
|
||||
|
||||
return (
|
||||
|
@ -212,10 +216,10 @@ export function AgentInstancesDetails({
|
|||
agentName,
|
||||
query: {
|
||||
...query,
|
||||
serviceGroup: '',
|
||||
environment: environment ?? ENVIRONMENT_NOT_DEFINED.value,
|
||||
rangeFrom,
|
||||
rangeTo,
|
||||
serviceGroup,
|
||||
rangeFrom: start,
|
||||
rangeTo: end,
|
||||
comparisonEnabled: defaultComparisonEnabled,
|
||||
},
|
||||
agentDocsPageUrl,
|
||||
|
|
|
@ -26,13 +26,19 @@ import type { AgentExplorerItem } from '../agent_list';
|
|||
import { AgentContextualInformation } from './agent_contextual_information';
|
||||
import { AgentInstancesDetails } from './agent_instances_details';
|
||||
|
||||
function useAgentInstancesFetcher({ serviceName }: { serviceName: string }) {
|
||||
const {
|
||||
query: { environment, kuery },
|
||||
} = useApmParams('/settings/agent-explorer');
|
||||
|
||||
const { start, end } = useTimeRange({ rangeFrom: 'now-24h', rangeTo: 'now' });
|
||||
|
||||
function useAgentInstancesFetcher({
|
||||
serviceName,
|
||||
environment,
|
||||
kuery,
|
||||
start,
|
||||
end,
|
||||
}: {
|
||||
serviceName: string;
|
||||
environment: string;
|
||||
kuery: string;
|
||||
start: string;
|
||||
end: string;
|
||||
}) {
|
||||
return useProgressiveFetcher(
|
||||
(callApmApi) => {
|
||||
return callApmApi('GET /internal/apm/services/{serviceName}/agent_instances', {
|
||||
|
@ -66,9 +72,18 @@ export function AgentInstances({
|
|||
latestVersionsFailed,
|
||||
onClose,
|
||||
}: Props) {
|
||||
const { query } = useApmParams('/settings/agent-explorer');
|
||||
const {
|
||||
query,
|
||||
query: { environment, kuery },
|
||||
} = useApmParams('/settings/agent-explorer');
|
||||
|
||||
const { start, end } = useTimeRange({ rangeFrom: 'now-24h', rangeTo: 'now' });
|
||||
|
||||
const instances = useAgentInstancesFetcher({
|
||||
environment,
|
||||
kuery,
|
||||
start,
|
||||
end,
|
||||
serviceName: agent.serviceName,
|
||||
});
|
||||
|
||||
|
@ -105,7 +120,10 @@ export function AgentInstances({
|
|||
<EuiSpacer size="m" />
|
||||
<AgentInstancesDetails
|
||||
serviceName={agent.serviceName}
|
||||
environment={environment}
|
||||
agentName={agent.agentName}
|
||||
start={start}
|
||||
end={end}
|
||||
agentDocsPageUrl={agent.agentDocsPageUrl}
|
||||
isLoading={isLoading}
|
||||
items={instances.data?.items ?? []}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue