[APM] Add “Analyze Data” button (#103485)
Co-authored-by: Shahzad <shahzad31comp@gmail.com>
This commit is contained in:
parent
21858a570d
commit
4aca0b7b61
|
@ -16,6 +16,9 @@ exports[`APM telemetry helpers getApmTelemetry generates a JSON object with the
|
||||||
"dotnet": {
|
"dotnet": {
|
||||||
"type": "long"
|
"type": "long"
|
||||||
},
|
},
|
||||||
|
"iOS/swift": {
|
||||||
|
"type": "long"
|
||||||
|
},
|
||||||
"go": {
|
"go": {
|
||||||
"type": "long"
|
"type": "long"
|
||||||
},
|
},
|
||||||
|
@ -70,6 +73,9 @@ exports[`APM telemetry helpers getApmTelemetry generates a JSON object with the
|
||||||
"opentelemetry/ruby": {
|
"opentelemetry/ruby": {
|
||||||
"type": "long"
|
"type": "long"
|
||||||
},
|
},
|
||||||
|
"opentelemetry/swift": {
|
||||||
|
"type": "long"
|
||||||
|
},
|
||||||
"opentelemetry/webjs": {
|
"opentelemetry/webjs": {
|
||||||
"type": "long"
|
"type": "long"
|
||||||
}
|
}
|
||||||
|
@ -131,6 +137,60 @@ exports[`APM telemetry helpers getApmTelemetry generates a JSON object with the
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"iOS/swift": {
|
||||||
|
"properties": {
|
||||||
|
"agent": {
|
||||||
|
"properties": {
|
||||||
|
"version": {
|
||||||
|
"type": "keyword"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"service": {
|
||||||
|
"properties": {
|
||||||
|
"framework": {
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "keyword"
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"type": "keyword"
|
||||||
|
},
|
||||||
|
"composite": {
|
||||||
|
"type": "keyword"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"language": {
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "keyword"
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"type": "keyword"
|
||||||
|
},
|
||||||
|
"composite": {
|
||||||
|
"type": "keyword"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "keyword"
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"type": "keyword"
|
||||||
|
},
|
||||||
|
"composite": {
|
||||||
|
"type": "keyword"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"go": {
|
"go": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"agent": {
|
"agent": {
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
* 2.0.
|
* 2.0.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { isJavaAgentName, isRumAgentName } from './agent_name';
|
import { isJavaAgentName, isRumAgentName, isIosAgentName } from './agent_name';
|
||||||
|
|
||||||
describe('agent name helpers', () => {
|
describe('agent name helpers', () => {
|
||||||
describe('isJavaAgentName', () => {
|
describe('isJavaAgentName', () => {
|
||||||
|
@ -22,7 +22,7 @@ describe('agent name helpers', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when the agent name is not java', () => {
|
describe('when the agent name is not java', () => {
|
||||||
it('returns true', () => {
|
it('returns false', () => {
|
||||||
expect(isJavaAgentName('not java')).toEqual(false);
|
expect(isJavaAgentName('not java')).toEqual(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -47,9 +47,35 @@ describe('agent name helpers', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when the agent name something else', () => {
|
describe('when the agent name is something else', () => {
|
||||||
|
it('returns false', () => {
|
||||||
|
expect(isRumAgentName('not rum')).toEqual(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('isIosAgentName', () => {
|
||||||
|
describe('when the agent name is js-base', () => {
|
||||||
it('returns true', () => {
|
it('returns true', () => {
|
||||||
expect(isRumAgentName('java')).toEqual(false);
|
expect(isIosAgentName('iOS/swift')).toEqual(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when the agent name is rum-js', () => {
|
||||||
|
it('returns true', () => {
|
||||||
|
expect(isIosAgentName('ios/swift')).toEqual(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when the agent name is opentelemetry/swift', () => {
|
||||||
|
it('returns true', () => {
|
||||||
|
expect(isIosAgentName('opentelemetry/swift')).toEqual(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when the agent name is something else', () => {
|
||||||
|
it('returns false', () => {
|
||||||
|
expect(isIosAgentName('not ios')).toEqual(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -26,12 +26,14 @@ export const OPEN_TELEMETRY_AGENT_NAMES: AgentName[] = [
|
||||||
'opentelemetry/php',
|
'opentelemetry/php',
|
||||||
'opentelemetry/python',
|
'opentelemetry/python',
|
||||||
'opentelemetry/ruby',
|
'opentelemetry/ruby',
|
||||||
|
'opentelemetry/swift',
|
||||||
'opentelemetry/webjs',
|
'opentelemetry/webjs',
|
||||||
];
|
];
|
||||||
|
|
||||||
export const AGENT_NAMES: AgentName[] = [
|
export const AGENT_NAMES: AgentName[] = [
|
||||||
'dotnet',
|
'dotnet',
|
||||||
'go',
|
'go',
|
||||||
|
'iOS/swift',
|
||||||
'java',
|
'java',
|
||||||
'js-base',
|
'js-base',
|
||||||
'nodejs',
|
'nodejs',
|
||||||
|
@ -62,7 +64,9 @@ export function isRumAgentName(
|
||||||
return RUM_AGENT_NAMES.includes(agentName! as AgentName);
|
return RUM_AGENT_NAMES.includes(agentName! as AgentName);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function normalizeAgentName(agentName: string | undefined) {
|
export function normalizeAgentName<T extends string | undefined>(
|
||||||
|
agentName: T
|
||||||
|
): T | string {
|
||||||
if (isRumAgentName(agentName)) {
|
if (isRumAgentName(agentName)) {
|
||||||
return 'rum-js';
|
return 'rum-js';
|
||||||
}
|
}
|
||||||
|
@ -71,5 +75,14 @@ export function normalizeAgentName(agentName: string | undefined) {
|
||||||
return 'java';
|
return 'java';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isIosAgentName(agentName)) {
|
||||||
|
return 'ios';
|
||||||
|
}
|
||||||
|
|
||||||
return agentName;
|
return agentName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isIosAgentName(agentName?: string) {
|
||||||
|
const lowercased = agentName && agentName.toLowerCase();
|
||||||
|
return lowercased === 'ios/swift' || lowercased === 'opentelemetry/swift';
|
||||||
|
}
|
||||||
|
|
|
@ -131,6 +131,7 @@ export function Correlations() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<EuiButton
|
<EuiButton
|
||||||
|
fill
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setIsFlyoutVisible(true);
|
setIsFlyoutVisible(true);
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
import { EuiFlexGroup, EuiFlexItem, EuiPanel } from '@elastic/eui';
|
import { EuiFlexGroup, EuiFlexItem, EuiPanel } from '@elastic/eui';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useTrackPageview } from '../../../../../observability/public';
|
import { useTrackPageview } from '../../../../../observability/public';
|
||||||
import { isRumAgentName } from '../../../../common/agent_name';
|
import { isRumAgentName, isIosAgentName } from '../../../../common/agent_name';
|
||||||
import { AnnotationsContextProvider } from '../../../context/annotations/annotations_context';
|
import { AnnotationsContextProvider } from '../../../context/annotations/annotations_context';
|
||||||
import { useApmServiceContext } from '../../../context/apm_service/use_apm_service_context';
|
import { useApmServiceContext } from '../../../context/apm_service/use_apm_service_context';
|
||||||
import { ChartPointerEventContextProvider } from '../../../context/chart_pointer_event/chart_pointer_event_context';
|
import { ChartPointerEventContextProvider } from '../../../context/chart_pointer_event/chart_pointer_event_context';
|
||||||
|
@ -43,6 +43,7 @@ export function ServiceOverview({ serviceName }: ServiceOverviewProps) {
|
||||||
const { isMedium } = useBreakPoints();
|
const { isMedium } = useBreakPoints();
|
||||||
const rowDirection = isMedium ? 'column' : 'row';
|
const rowDirection = isMedium ? 'column' : 'row';
|
||||||
const isRumAgent = isRumAgentName(agentName);
|
const isRumAgent = isRumAgentName(agentName);
|
||||||
|
const isIosAgent = isIosAgentName(agentName);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AnnotationsContextProvider>
|
<AnnotationsContextProvider>
|
||||||
|
@ -110,7 +111,7 @@ export function ServiceOverview({ serviceName }: ServiceOverviewProps) {
|
||||||
)}
|
)}
|
||||||
</EuiFlexGroup>
|
</EuiFlexGroup>
|
||||||
</EuiFlexItem>
|
</EuiFlexItem>
|
||||||
{!isRumAgent && (
|
{!isRumAgent && !isIosAgent && (
|
||||||
<EuiFlexItem>
|
<EuiFlexItem>
|
||||||
<EuiFlexGroup
|
<EuiFlexGroup
|
||||||
direction="column"
|
direction="column"
|
||||||
|
|
|
@ -13,11 +13,18 @@ import {
|
||||||
EuiPageHeaderProps,
|
EuiPageHeaderProps,
|
||||||
EuiTitle,
|
EuiTitle,
|
||||||
EuiBetaBadge,
|
EuiBetaBadge,
|
||||||
|
EuiToolTip,
|
||||||
|
EuiButtonEmpty,
|
||||||
} from '@elastic/eui';
|
} from '@elastic/eui';
|
||||||
import { ApmMainTemplate } from './apm_main_template';
|
import { ApmMainTemplate } from './apm_main_template';
|
||||||
|
import { useKibana } from '../../../../../../../src/plugins/kibana_react/public';
|
||||||
import { ApmServiceContextProvider } from '../../../context/apm_service/apm_service_context';
|
import { ApmServiceContextProvider } from '../../../context/apm_service/apm_service_context';
|
||||||
import { enableServiceOverview } from '../../../../common/ui_settings_keys';
|
import { enableServiceOverview } from '../../../../common/ui_settings_keys';
|
||||||
import { isJavaAgentName, isRumAgentName } from '../../../../common/agent_name';
|
import {
|
||||||
|
isJavaAgentName,
|
||||||
|
isRumAgentName,
|
||||||
|
isIosAgentName,
|
||||||
|
} from '../../../../common/agent_name';
|
||||||
import { ServiceIcons } from '../../shared/service_icons';
|
import { ServiceIcons } from '../../shared/service_icons';
|
||||||
import { useApmPluginContext } from '../../../context/apm_plugin/use_apm_plugin_context';
|
import { useApmPluginContext } from '../../../context/apm_plugin/use_apm_plugin_context';
|
||||||
import { useApmServiceContext } from '../../../context/apm_service/use_apm_service_context';
|
import { useApmServiceContext } from '../../../context/apm_service/use_apm_service_context';
|
||||||
|
@ -29,8 +36,17 @@ import { useServiceOverviewHref } from '../../shared/Links/apm/service_overview_
|
||||||
import { useServiceProfilingHref } from '../../shared/Links/apm/service_profiling_link';
|
import { useServiceProfilingHref } from '../../shared/Links/apm/service_profiling_link';
|
||||||
import { useTransactionsOverviewHref } from '../../shared/Links/apm/transaction_overview_link';
|
import { useTransactionsOverviewHref } from '../../shared/Links/apm/transaction_overview_link';
|
||||||
import { useUrlParams } from '../../../context/url_params_context/use_url_params';
|
import { useUrlParams } from '../../../context/url_params_context/use_url_params';
|
||||||
|
import { ENVIRONMENT_NOT_DEFINED } from '../../../../common/environment_filter_values';
|
||||||
|
import {
|
||||||
|
SERVICE_NAME,
|
||||||
|
SERVICE_ENVIRONMENT,
|
||||||
|
} from '../../../../common/elasticsearch_fieldnames';
|
||||||
import { Correlations } from '../../app/correlations';
|
import { Correlations } from '../../app/correlations';
|
||||||
import { SearchBar } from '../../shared/search_bar';
|
import { SearchBar } from '../../shared/search_bar';
|
||||||
|
import {
|
||||||
|
createExploratoryViewUrl,
|
||||||
|
SeriesUrl,
|
||||||
|
} from '../../../../../observability/public';
|
||||||
|
|
||||||
type Tab = NonNullable<EuiPageHeaderProps['tabs']>[0] & {
|
type Tab = NonNullable<EuiPageHeaderProps['tabs']>[0] & {
|
||||||
key:
|
key:
|
||||||
|
@ -54,12 +70,12 @@ interface Props {
|
||||||
export function ApmServiceTemplate(props: Props) {
|
export function ApmServiceTemplate(props: Props) {
|
||||||
return (
|
return (
|
||||||
<ApmServiceContextProvider>
|
<ApmServiceContextProvider>
|
||||||
<Template {...props} />
|
<TemplateWithContext {...props} />
|
||||||
</ApmServiceContextProvider>
|
</ApmServiceContextProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function Template({
|
function TemplateWithContext({
|
||||||
children,
|
children,
|
||||||
serviceName,
|
serviceName,
|
||||||
selectedTab,
|
selectedTab,
|
||||||
|
@ -86,6 +102,10 @@ function Template({
|
||||||
</EuiFlexGroup>
|
</EuiFlexGroup>
|
||||||
</EuiFlexItem>
|
</EuiFlexItem>
|
||||||
|
|
||||||
|
<EuiFlexItem grow={false}>
|
||||||
|
<AnalyzeDataButton serviceName={serviceName} />
|
||||||
|
</EuiFlexItem>
|
||||||
|
|
||||||
<EuiFlexItem grow={false}>
|
<EuiFlexItem grow={false}>
|
||||||
<Correlations />
|
<Correlations />
|
||||||
</EuiFlexItem>
|
</EuiFlexItem>
|
||||||
|
@ -100,6 +120,53 @@ function Template({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function AnalyzeDataButton({ serviceName }: { serviceName: string }) {
|
||||||
|
const { agentName } = useApmServiceContext();
|
||||||
|
const { services } = useKibana();
|
||||||
|
const { urlParams } = useUrlParams();
|
||||||
|
const { rangeTo, rangeFrom, environment } = urlParams;
|
||||||
|
const basepath = services.http?.basePath.get();
|
||||||
|
|
||||||
|
if (isRumAgentName(agentName) || isIosAgentName(agentName)) {
|
||||||
|
const href = createExploratoryViewUrl(
|
||||||
|
{
|
||||||
|
'apm-series': {
|
||||||
|
dataType: isRumAgentName(agentName) ? 'ux' : 'mobile',
|
||||||
|
time: { from: rangeFrom, to: rangeTo },
|
||||||
|
reportType: 'kpi-over-time',
|
||||||
|
reportDefinitions: {
|
||||||
|
[SERVICE_NAME]: [serviceName],
|
||||||
|
...(!!environment && ENVIRONMENT_NOT_DEFINED.value !== environment
|
||||||
|
? { [SERVICE_ENVIRONMENT]: [environment] }
|
||||||
|
: {}),
|
||||||
|
},
|
||||||
|
operationType: 'average',
|
||||||
|
isNew: true,
|
||||||
|
} as SeriesUrl,
|
||||||
|
},
|
||||||
|
basepath
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<EuiToolTip
|
||||||
|
position="top"
|
||||||
|
content={i18n.translate('xpack.apm.analyzeDataButton.tooltip', {
|
||||||
|
defaultMessage:
|
||||||
|
'EXPERIMENTAL - Analyze Data allows you to select and filter result data in any dimension, and look for the cause or impact of performance problems',
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<EuiButtonEmpty href={href} iconType="visBarVerticalStacked">
|
||||||
|
{i18n.translate('xpack.apm.analyzeDataButton.label', {
|
||||||
|
defaultMessage: 'Analyze data',
|
||||||
|
})}
|
||||||
|
</EuiButtonEmpty>
|
||||||
|
</EuiToolTip>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
function useTabs({
|
function useTabs({
|
||||||
serviceName,
|
serviceName,
|
||||||
selectedTab,
|
selectedTab,
|
||||||
|
@ -153,7 +220,10 @@ function useTabs({
|
||||||
defaultMessage: 'Metrics',
|
defaultMessage: 'Metrics',
|
||||||
}),
|
}),
|
||||||
hidden:
|
hidden:
|
||||||
!agentName || isRumAgentName(agentName) || isJavaAgentName(agentName),
|
!agentName ||
|
||||||
|
isRumAgentName(agentName) ||
|
||||||
|
isJavaAgentName(agentName) ||
|
||||||
|
isIosAgentName(agentName),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'service-map',
|
key: 'service-map',
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
isIosAgentName,
|
||||||
isRumAgentName,
|
isRumAgentName,
|
||||||
isJavaAgentName,
|
isJavaAgentName,
|
||||||
OPEN_TELEMETRY_AGENT_NAMES,
|
OPEN_TELEMETRY_AGENT_NAMES,
|
||||||
|
@ -70,6 +71,10 @@ export function getAgentIconKey(agentName: string) {
|
||||||
return 'java';
|
return 'java';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isIosAgentName(lowercasedAgentName)) {
|
||||||
|
return 'ios';
|
||||||
|
}
|
||||||
|
|
||||||
// Remove "opentelemetry/" prefix
|
// Remove "opentelemetry/" prefix
|
||||||
const agentNameWithoutPrefix = lowercasedAgentName.replace(
|
const agentNameWithoutPrefix = lowercasedAgentName.replace(
|
||||||
/^opentelemetry\//,
|
/^opentelemetry\//,
|
||||||
|
|
|
@ -74,6 +74,7 @@ const apmPerAgentSchema: Pick<
|
||||||
// In the meanwhile, we'll have to maintain these lists up to date (TS will remind us to update)
|
// In the meanwhile, we'll have to maintain these lists up to date (TS will remind us to update)
|
||||||
services_per_agent: {
|
services_per_agent: {
|
||||||
dotnet: long,
|
dotnet: long,
|
||||||
|
'iOS/swift': long,
|
||||||
go: long,
|
go: long,
|
||||||
java: long,
|
java: long,
|
||||||
'js-base': long,
|
'js-base': long,
|
||||||
|
@ -92,10 +93,12 @@ const apmPerAgentSchema: Pick<
|
||||||
'opentelemetry/php': long,
|
'opentelemetry/php': long,
|
||||||
'opentelemetry/python': long,
|
'opentelemetry/python': long,
|
||||||
'opentelemetry/ruby': long,
|
'opentelemetry/ruby': long,
|
||||||
|
'opentelemetry/swift': long,
|
||||||
'opentelemetry/webjs': long,
|
'opentelemetry/webjs': long,
|
||||||
},
|
},
|
||||||
agents: {
|
agents: {
|
||||||
dotnet: agentSchema,
|
dotnet: agentSchema,
|
||||||
|
'iOS/swift': agentSchema,
|
||||||
go: agentSchema,
|
go: agentSchema,
|
||||||
java: agentSchema,
|
java: agentSchema,
|
||||||
'js-base': agentSchema,
|
'js-base': agentSchema,
|
||||||
|
|
|
@ -9,6 +9,7 @@ export type ElasticAgentName =
|
||||||
| 'go'
|
| 'go'
|
||||||
| 'java'
|
| 'java'
|
||||||
| 'js-base'
|
| 'js-base'
|
||||||
|
| 'iOS/swift'
|
||||||
| 'rum-js'
|
| 'rum-js'
|
||||||
| 'nodejs'
|
| 'nodejs'
|
||||||
| 'python'
|
| 'python'
|
||||||
|
@ -27,6 +28,7 @@ export type OpenTelemetryAgentName =
|
||||||
| 'opentelemetry/php'
|
| 'opentelemetry/php'
|
||||||
| 'opentelemetry/python'
|
| 'opentelemetry/python'
|
||||||
| 'opentelemetry/ruby'
|
| 'opentelemetry/ruby'
|
||||||
|
| 'opentelemetry/swift'
|
||||||
| 'opentelemetry/webjs';
|
| 'opentelemetry/webjs';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -319,6 +319,9 @@
|
||||||
"dotnet": {
|
"dotnet": {
|
||||||
"type": "long"
|
"type": "long"
|
||||||
},
|
},
|
||||||
|
"iOS/swift": {
|
||||||
|
"type": "long"
|
||||||
|
},
|
||||||
"go": {
|
"go": {
|
||||||
"type": "long"
|
"type": "long"
|
||||||
},
|
},
|
||||||
|
@ -373,6 +376,9 @@
|
||||||
"opentelemetry/ruby": {
|
"opentelemetry/ruby": {
|
||||||
"type": "long"
|
"type": "long"
|
||||||
},
|
},
|
||||||
|
"opentelemetry/swift": {
|
||||||
|
"type": "long"
|
||||||
|
},
|
||||||
"opentelemetry/webjs": {
|
"opentelemetry/webjs": {
|
||||||
"type": "long"
|
"type": "long"
|
||||||
}
|
}
|
||||||
|
@ -464,6 +470,90 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"iOS/swift": {
|
||||||
|
"properties": {
|
||||||
|
"agent": {
|
||||||
|
"properties": {
|
||||||
|
"version": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "keyword"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"service": {
|
||||||
|
"properties": {
|
||||||
|
"framework": {
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "keyword"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "keyword"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"composite": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "keyword"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"language": {
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "keyword"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "keyword"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"composite": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "keyword"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "keyword"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "keyword"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"composite": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "keyword"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"go": {
|
"go": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"agent": {
|
"agent": {
|
||||||
|
|
Loading…
Reference in a new issue