Katerina 2025-06-25 16:29:48 +03:00 committed by GitHub
parent c28fd76508
commit bc5a533202
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 149 additions and 18 deletions

View file

@ -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,
}),
});
}

View file

@ -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');
});
});
});
});

View file

@ -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,

View file

@ -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 ?? []}