mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
Added OTel information to service metadata icons (#154458)
## Summary Added OpenTelemetry information to metadata icons on OTel services: <img width="709" alt="image" src="https://user-images.githubusercontent.com/866830/230113359-307c25dd-9846-4079-bb26-7d145472181a.png">
This commit is contained in:
parent
03464e79c2
commit
5f24c14d58
8 changed files with 156 additions and 24 deletions
|
@ -5,7 +5,10 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { AgentName } from '../typings/es_schemas/ui/fields/agent';
|
||||
import {
|
||||
AgentName,
|
||||
OpenTelemetryAgentName,
|
||||
} from '../typings/es_schemas/ui/fields/agent';
|
||||
import { ServerlessType } from './serverless';
|
||||
|
||||
/*
|
||||
|
@ -47,8 +50,11 @@ export const AGENT_NAMES: AgentName[] = [
|
|||
...OPEN_TELEMETRY_AGENT_NAMES,
|
||||
];
|
||||
|
||||
export const isOpenTelemetryAgentName = (agentName: AgentName) =>
|
||||
OPEN_TELEMETRY_AGENT_NAMES.includes(agentName);
|
||||
export function isOpenTelemetryAgentName(
|
||||
agentName: string
|
||||
): agentName is OpenTelemetryAgentName {
|
||||
return OPEN_TELEMETRY_AGENT_NAMES.includes(agentName as AgentName);
|
||||
}
|
||||
|
||||
export const JAVA_AGENT_NAMES: AgentName[] = ['java', 'opentelemetry/java'];
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ import darkIosIcon from './icons/ios_dark.svg';
|
|||
import javaIcon from './icons/java.svg';
|
||||
import nodeJsIcon from './icons/nodejs.svg';
|
||||
import ocamlIcon from './icons/ocaml.svg';
|
||||
import openTelemetryIcon from './icons/opentelemetry.svg';
|
||||
import openTelemetryIcon from './icons/otel_default.svg';
|
||||
import phpIcon from './icons/php.svg';
|
||||
import pythonIcon from './icons/python.svg';
|
||||
import rubyIcon from './icons/ruby.svg';
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
<svg width="128" height="128" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<svg viewBox="4 4 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M16.75 6.165a1.5 1.5 0 00-1.5 0l-7.392 4.268a1.5 1.5 0 00-.75 1.3v8.535a1.5 1.5 0 00.75 1.299l7.392 4.268a1.5 1.5 0 001.5 0l7.392-4.268a1.5 1.5 0 00.75-1.299v-8.536a1.5 1.5 0 00-.75-1.299L16.75 6.165zm.75-1.299l7.392 4.268a3 3 0 011.5 2.598v8.536a3 3 0 01-1.5 2.598L17.5 27.134a3 3 0 01-3 0l-7.392-4.268a3 3 0 01-1.5-2.598v-8.536a3 3 0 011.5-2.598L14.5 4.866a3 3 0 013 0z" fill="#98A2B3"/>
|
||||
</svg>
|
||||
<svg x="32" y="32" width="64" height="64" xmlns="http://www.w3.org/2000/svg" role="img" viewBox="0 0 1024.40 1024.40">
|
||||
<style>svg {enable-background:new 0 0 1000 1000}</style>
|
||||
<path fill="#f5a800" d="M528.7 545.9c-42 42-42 110.1 0 152.1s110.1 42 152.1 0 42-110.1 0-152.1-110.1-42-152.1 0zm113.7 113.8c-20.8 20.8-54.5 20.8-75.3 0-20.8-20.8-20.8-54.5 0-75.3 20.8-20.8 54.5-20.8 75.3 0 20.8 20.7 20.8 54.5 0 75.3zm36.6-643l-65.9 65.9c-12.9 12.9-12.9 34.1 0 47l257.3 257.3c12.9 12.9 34.1 12.9 47 0l65.9-65.9c12.9-12.9 12.9-34.1 0-47L725.9 16.7c-12.9-12.9-34-12.9-46.9 0zM217.3 858.8c11.7-11.7 11.7-30.8 0-42.5l-33.5-33.5c-11.7-11.7-30.8-11.7-42.5 0L72.1 852l-.1.1-19-19c-10.5-10.5-27.6-10.5-38 0-10.5 10.5-10.5 27.6 0 38l114 114c10.5 10.5 27.6 10.5 38 0s10.5-27.6 0-38l-19-19 .1-.1 69.2-69.2z"/>
|
||||
<path fill="#425cc7" d="M565.9 205.9L419.5 352.3c-13 13-13 34.4 0 47.4l90.4 90.4c63.9-46 153.5-40.3 211 17.2l73.2-73.2c13-13 13-34.4 0-47.4L613.3 205.9c-13-13.1-34.4-13.1-47.4 0zm-94 322.3l-53.4-53.4c-12.5-12.5-33-12.5-45.5 0L184.7 663.2c-12.5 12.5-12.5 33 0 45.5l106.7 106.7c12.5 12.5 33 12.5 45.5 0L458 694.1c-25.6-52.9-21-116.8 13.9-165.9z"/>
|
||||
</svg>
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
|
@ -16,9 +16,12 @@ import { getServerlessIcon } from '../agent_icon/get_serverless_icon';
|
|||
import { CloudDetails } from './cloud_details';
|
||||
import { ServerlessDetails } from './serverless_details';
|
||||
import { ContainerDetails } from './container_details';
|
||||
import { OTelDetails } from './otel_details';
|
||||
import { IconPopover } from './icon_popover';
|
||||
import { ServiceDetails } from './service_details';
|
||||
import { ServerlessType } from '../../../../common/serverless';
|
||||
import { isOpenTelemetryAgentName } from '../../../../common/agent_name';
|
||||
import openTelemetryIcon from '../agent_icon/icons/opentelemetry.svg';
|
||||
|
||||
interface Props {
|
||||
serviceName: string;
|
||||
|
@ -70,7 +73,13 @@ export function getContainerIcon(container?: ContainerType) {
|
|||
}
|
||||
}
|
||||
|
||||
type Icons = 'service' | 'container' | 'serverless' | 'cloud' | 'alerts';
|
||||
type Icons =
|
||||
| 'service'
|
||||
| 'opentelemetry'
|
||||
| 'container'
|
||||
| 'serverless'
|
||||
| 'cloud'
|
||||
| 'alerts';
|
||||
|
||||
export interface PopoverItem {
|
||||
key: Icons;
|
||||
|
@ -142,6 +151,23 @@ export function ServiceIcons({ start, end, serviceName }: Props) {
|
|||
}),
|
||||
component: <ServiceDetails service={details?.service} />,
|
||||
},
|
||||
{
|
||||
key: 'opentelemetry',
|
||||
icon: {
|
||||
type: openTelemetryIcon,
|
||||
},
|
||||
isVisible:
|
||||
!!icons?.agentName && isOpenTelemetryAgentName(icons.agentName),
|
||||
title: i18n.translate('xpack.apm.serviceIcons.opentelemetry', {
|
||||
defaultMessage: 'OpenTelemetry',
|
||||
}),
|
||||
component: (
|
||||
<OTelDetails
|
||||
opentelemetry={details?.opentelemetry}
|
||||
agentName={icons?.agentName}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'container',
|
||||
icon: {
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* 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 { EuiDescriptionList, EuiDescriptionListProps } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React from 'react';
|
||||
import { APIReturnType } from '../../../services/rest/create_call_apm_api';
|
||||
|
||||
type ServiceDetailsReturnType =
|
||||
APIReturnType<'GET /internal/apm/services/{serviceName}/metadata/details'>;
|
||||
|
||||
interface Props {
|
||||
opentelemetry: ServiceDetailsReturnType['opentelemetry'];
|
||||
agentName?: string;
|
||||
}
|
||||
|
||||
export function OTelDetails({ opentelemetry }: Props) {
|
||||
if (!opentelemetry) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const listItems: EuiDescriptionListProps['listItems'] = [];
|
||||
listItems.push({
|
||||
title: i18n.translate(
|
||||
'xpack.apm.serviceIcons.otelDetails.opentelemetry.language',
|
||||
{
|
||||
defaultMessage: 'Language',
|
||||
}
|
||||
),
|
||||
description: (
|
||||
<>{!!opentelemetry.language ? opentelemetry.language : 'unknown'}</>
|
||||
),
|
||||
});
|
||||
|
||||
if (!!opentelemetry.sdkVersion) {
|
||||
listItems.push({
|
||||
title: i18n.translate(
|
||||
'xpack.apm.serviceIcons.otelDetails.opentelemetry.sdkVersion',
|
||||
{
|
||||
defaultMessage: 'OTel SDK version',
|
||||
}
|
||||
),
|
||||
description: <>{opentelemetry.sdkVersion}</>,
|
||||
});
|
||||
}
|
||||
|
||||
if (!!opentelemetry.autoVersion) {
|
||||
listItems.push({
|
||||
title: i18n.translate(
|
||||
'xpack.apm.serviceIcons.otelDetails.opentelemetry.autoVersion',
|
||||
{
|
||||
defaultMessage: 'Auto instrumentation agent version',
|
||||
}
|
||||
),
|
||||
description: <>{opentelemetry.autoVersion}</>,
|
||||
});
|
||||
}
|
||||
|
||||
return <EuiDescriptionList textStyle="reverse" listItems={listItems} />;
|
||||
}
|
|
@ -24,17 +24,18 @@ import {
|
|||
SERVICE_VERSION,
|
||||
FAAS_ID,
|
||||
FAAS_TRIGGER_TYPE,
|
||||
LABEL_TELEMETRY_AUTO_VERSION,
|
||||
} from '../../../common/es_fields/apm';
|
||||
|
||||
import { ContainerType } from '../../../common/service_metadata';
|
||||
import { TransactionRaw } from '../../../typings/es_schemas/raw/transaction_raw';
|
||||
import { getProcessorEventForTransactions } from '../../lib/helpers/transactions';
|
||||
import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client';
|
||||
import { should } from './get_service_metadata_icons';
|
||||
import { isOpenTelemetryAgentName } from '../../../common/agent_name';
|
||||
|
||||
type ServiceMetadataDetailsRaw = Pick<
|
||||
TransactionRaw,
|
||||
'service' | 'agent' | 'host' | 'container' | 'kubernetes' | 'cloud'
|
||||
'service' | 'agent' | 'host' | 'container' | 'kubernetes' | 'cloud' | 'labels'
|
||||
>;
|
||||
|
||||
export interface ServiceMetadataDetails {
|
||||
|
@ -50,6 +51,11 @@ export interface ServiceMetadataDetails {
|
|||
version: string;
|
||||
};
|
||||
};
|
||||
opentelemetry?: {
|
||||
language?: string;
|
||||
sdkVersion?: string;
|
||||
autoVersion?: string;
|
||||
};
|
||||
container?: {
|
||||
ids?: string[];
|
||||
image?: string;
|
||||
|
@ -81,13 +87,11 @@ export interface ServiceMetadataDetails {
|
|||
export async function getServiceMetadataDetails({
|
||||
serviceName,
|
||||
apmEventClient,
|
||||
searchAggregatedTransactions,
|
||||
start,
|
||||
end,
|
||||
}: {
|
||||
serviceName: string;
|
||||
apmEventClient: APMEventClient;
|
||||
searchAggregatedTransactions: boolean;
|
||||
start: number;
|
||||
end: number;
|
||||
}): Promise<ServiceMetadataDetails> {
|
||||
|
@ -99,16 +103,27 @@ export async function getServiceMetadataDetails({
|
|||
const params = {
|
||||
apm: {
|
||||
events: [
|
||||
getProcessorEventForTransactions(searchAggregatedTransactions),
|
||||
ProcessorEvent.transaction,
|
||||
ProcessorEvent.error,
|
||||
ProcessorEvent.metric,
|
||||
],
|
||||
},
|
||||
sort: [{ '@timestamp': { order: 'desc' as const } }],
|
||||
sort: [
|
||||
{ _score: { order: 'desc' as const } },
|
||||
{ '@timestamp': { order: 'desc' as const } },
|
||||
],
|
||||
body: {
|
||||
track_total_hits: 1,
|
||||
size: 1,
|
||||
_source: [SERVICE, AGENT, HOST, CONTAINER, KUBERNETES, CLOUD],
|
||||
_source: [
|
||||
SERVICE,
|
||||
AGENT,
|
||||
HOST,
|
||||
CONTAINER,
|
||||
KUBERNETES,
|
||||
CLOUD,
|
||||
LABEL_TELEMETRY_AUTO_VERSION,
|
||||
],
|
||||
query: { bool: { filter, should } },
|
||||
aggs: {
|
||||
serviceVersions: {
|
||||
|
@ -178,8 +193,8 @@ export async function getServiceMetadataDetails({
|
|||
};
|
||||
}
|
||||
|
||||
const { service, agent, host, kubernetes, container, cloud } = response.hits
|
||||
.hits[0]._source as ServiceMetadataDetailsRaw;
|
||||
const { service, agent, host, kubernetes, container, cloud, labels } =
|
||||
response.hits.hits[0]._source as ServiceMetadataDetailsRaw;
|
||||
|
||||
const serviceMetadataDetails = {
|
||||
versions: response.aggregations?.serviceVersions.buckets.map(
|
||||
|
@ -190,6 +205,17 @@ export async function getServiceMetadataDetails({
|
|||
agent,
|
||||
};
|
||||
|
||||
const otelDetails =
|
||||
!!agent?.name && isOpenTelemetryAgentName(agent.name)
|
||||
? {
|
||||
language: agent.name.startsWith('opentelemetry')
|
||||
? agent.name.replace(/^opentelemetry\//, '')
|
||||
: undefined,
|
||||
sdkVersion: agent?.version,
|
||||
autoVersion: labels?.telemetry_auto_version as string,
|
||||
}
|
||||
: undefined;
|
||||
|
||||
const totalNumberInstances =
|
||||
response.aggregations?.totalNumberInstances.value;
|
||||
|
||||
|
@ -238,6 +264,7 @@ export async function getServiceMetadataDetails({
|
|||
|
||||
return {
|
||||
service: serviceMetadataDetails,
|
||||
opentelemetry: otelDetails,
|
||||
container: containerDetails,
|
||||
serverless: serverlessDetails,
|
||||
cloud: cloudDetails,
|
||||
|
|
|
@ -16,6 +16,9 @@ import {
|
|||
SERVICE_NAME,
|
||||
KUBERNETES_POD_NAME,
|
||||
HOST_OS_PLATFORM,
|
||||
LABEL_TELEMETRY_AUTO_VERSION,
|
||||
AGENT_VERSION,
|
||||
SERVICE_FRAMEWORK_NAME,
|
||||
} from '../../../common/es_fields/apm';
|
||||
import { ContainerType } from '../../../common/service_metadata';
|
||||
import { TransactionRaw } from '../../../typings/es_schemas/raw/transaction_raw';
|
||||
|
@ -44,6 +47,9 @@ export const should = [
|
|||
{ exists: { field: CLOUD_PROVIDER } },
|
||||
{ exists: { field: HOST_OS_PLATFORM } },
|
||||
{ exists: { field: AGENT_NAME } },
|
||||
{ exists: { field: AGENT_VERSION } },
|
||||
{ exists: { field: SERVICE_FRAMEWORK_NAME } },
|
||||
{ exists: { field: LABEL_TELEMETRY_AUTO_VERSION } },
|
||||
];
|
||||
|
||||
export async function getServiceMetadataIcons({
|
||||
|
|
|
@ -240,22 +240,13 @@ const serviceMetadataDetailsRoute = createApmServerRoute({
|
|||
handler: async (resources): Promise<ServiceMetadataDetails> => {
|
||||
const apmEventClient = await getApmEventClient(resources);
|
||||
const infraMetricsClient = createInfraMetricsClient(resources);
|
||||
const { params, config } = resources;
|
||||
const { params } = resources;
|
||||
const { serviceName } = params.path;
|
||||
const { start, end } = params.query;
|
||||
|
||||
const searchAggregatedTransactions = await getSearchTransactionsEvents({
|
||||
apmEventClient,
|
||||
config,
|
||||
start,
|
||||
end,
|
||||
kuery: '',
|
||||
});
|
||||
|
||||
const serviceMetadataDetails = await getServiceMetadataDetails({
|
||||
serviceName,
|
||||
apmEventClient,
|
||||
searchAggregatedTransactions,
|
||||
start,
|
||||
end,
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue