[Infra UI] Add kubernetes charts to the host detail view (#166383)

closes https://github.com/elastic/kibana/issues/162944
## Summary

This PR adds the Kubernetes Overview section to the Host Detail view.

**Old view**
<img width="778" alt="image"
src="2c6c3341-7aa3-48e4-a5d5-e9580b2e2c13">

**New view**
<img width="778" alt="image"
src="357ef56d-b783-41ed-8d7f-e9a3369d13b0">

There was some reog in the formulas folder too, separating nginx and
kubernetes from hosts formulas.

### How to test

- Start a local Kibana pointing to a oblt cluster
- Navigate to `Infrastructure` > `Hosts`
- Click on a `gke` host to navigate to the detail view
This commit is contained in:
Carlos Crespo 2023-09-20 08:51:15 +02:00 committed by GitHub
parent 1de39176f6
commit f94b4c2755
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
42 changed files with 624 additions and 280 deletions

View file

@ -5,81 +5,5 @@
* 2.0.
*/
import {
cpuUsage,
cpuUsageIowait,
cpuUsageIrq,
cpuUsageNice,
cpuUsageSoftirq,
cpuUsageSteal,
cpuUsageUser,
cpuUsageSystem,
diskIORead,
diskIOWrite,
diskReadThroughput,
diskWriteThroughput,
diskSpaceAvailability,
diskSpaceAvailable,
diskUsage,
logRate,
normalizedLoad1m,
load1m,
load5m,
load15m,
memoryUsage,
memoryFree,
memoryUsed,
memoryFreeExcludingCache,
memoryCache,
nginxActiveConnections,
nginxRequestRate,
nginxRequestsPerConnection,
nginxSuccessStatusCodes,
nginxRedirectStatusCodes,
nginxClientErrorStatusCodes,
nginxServerErrorStatusCodes,
rx,
tx,
hostCount,
} from './lens/formulas/host';
export const hostLensFormulas = {
cpuUsage,
cpuUsageIowait,
cpuUsageIrq,
cpuUsageNice,
cpuUsageSoftirq,
cpuUsageSteal,
cpuUsageUser,
cpuUsageSystem,
diskIORead,
diskIOWrite,
diskReadThroughput,
diskWriteThroughput,
diskSpaceAvailability,
diskSpaceAvailable,
diskUsage,
hostCount,
logRate,
normalizedLoad1m,
load1m,
load5m,
load15m,
memoryUsage,
memoryFree,
memoryUsed,
memoryFreeExcludingCache,
memoryCache,
nginxActiveConnections,
nginxRequestRate,
nginxRequestsPerConnection,
nginxSuccessStatusCodes,
nginxRedirectStatusCodes,
nginxClientErrorStatusCodes,
nginxServerErrorStatusCodes,
rx,
tx,
};
export const HOST_METRICS_DOC_HREF = 'https://ela.st/docs-infra-host-metrics';
export const HOST_METRICS_DOTTED_LINES_DOC_HREF = 'https://ela.st/docs-infra-why-dotted';

View file

@ -5,11 +5,5 @@
* 2.0.
*/
export type {
HostsLensFormulas,
HostsLensMetricChartFormulas,
HostsLensLineChartFormulas,
} from './types';
export * from './lens/dashboards';
export { hostLensFormulas } from './constants';
export * from './lens/formulas';

View file

@ -7,7 +7,7 @@
import { i18n } from '@kbn/i18n';
import type { TypedLensByValueInput } from '@kbn/lens-plugin/public';
import { hostLensFormulas } from '../../../../constants';
import { hostLensFormulas } from '../../../formulas';
import type { MetricChartLayerParams } from '../../../../types';
import { METRICS_TOOLTIP } from '../../translations';

View file

@ -0,0 +1,94 @@
/*
* 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 { i18n } from '@kbn/i18n';
import { kubernetesLensFormulas } from '../../../formulas';
import { XY_OVERRIDES } from '../../constants';
import type { XYConfig } from '../metric_charts/types';
export const kubernetesCharts: XYConfig[] = [
{
id: 'nodeCpuCapacity',
title: i18n.translate('xpack.infra.assetDetails.metricsCharts.kubernetes.nodeCpuCapacity', {
defaultMessage: 'Node CPU Capacity',
}),
layers: [
{
data: [kubernetesLensFormulas.nodeCpuCapacity, kubernetesLensFormulas.nodeCpuUsed],
type: 'visualization',
options: {
seriesType: 'area',
},
},
],
dataViewOrigin: 'metrics',
overrides: {
settings: XY_OVERRIDES.settings,
},
},
{
id: 'nodeMemoryCapacity',
title: i18n.translate('xpack.infra.assetDetails.metricsCharts.nginx.nodeMemoryCapacity', {
defaultMessage: 'Node Memory Capacity',
}),
layers: [
{
data: [kubernetesLensFormulas.nodeMemoryCapacity, kubernetesLensFormulas.nodeMemoryUsed],
type: 'visualization',
options: {
seriesType: 'area',
},
},
],
dataViewOrigin: 'metrics',
overrides: {
settings: XY_OVERRIDES.settings,
},
},
{
id: 'nodeDiskCapacity',
title: i18n.translate('xpack.infra.assetDetails.metricsCharts.nginx.nodeDiskCapacity', {
defaultMessage: 'Node Disk Capacity',
}),
layers: [
{
data: [kubernetesLensFormulas.nodeDiskCapacity, kubernetesLensFormulas.nodeDiskUsed],
type: 'visualization',
options: {
seriesType: 'area',
},
},
],
dataViewOrigin: 'metrics',
overrides: {
settings: XY_OVERRIDES.settings,
},
},
{
id: 'nodePodCapacity',
title: i18n.translate('xpack.infra.assetDetails.metricsCharts.nginx.nodePodCapacity', {
defaultMessage: 'Node Pod Capacity',
}),
layers: [
{
data: [kubernetesLensFormulas.nodePodCapacity, kubernetesLensFormulas.nodePodUsed],
type: 'visualization',
options: {
seriesType: 'area',
},
},
],
dataViewOrigin: 'metrics',
overrides: {
settings: XY_OVERRIDES.settings,
},
},
];

View file

@ -4,18 +4,81 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import {
nginxActiveConnections,
nginxRequestRate,
nginxRequestsPerConnection,
nginxResponseStatusCodes,
} from '../metric_charts/nginx';
import { i18n } from '@kbn/i18n';
import { nginxLensFormulas } from '../../../formulas';
import { XY_OVERRIDES } from '../../constants';
import type { XYConfig } from '../metric_charts/types';
export const nginxStubstatusCharts: XYConfig[] = [
nginxActiveConnections,
nginxRequestRate,
nginxRequestsPerConnection,
{
id: 'requestRate',
title: i18n.translate('xpack.infra.assetDetails.metricsCharts.nginx.requestRate', {
defaultMessage: 'Request Rate',
}),
layers: [
{
data: [nginxLensFormulas.requestRate],
type: 'visualization',
},
],
dataViewOrigin: 'metrics',
},
{
id: 'activeConnections',
title: i18n.translate('xpack.infra.assetDetails.metricsCharts.nginx.activeConnections', {
defaultMessage: 'Active Connections',
}),
layers: [
{
data: [nginxLensFormulas.activeConnections],
type: 'visualization',
},
],
dataViewOrigin: 'metrics',
},
{
id: 'requestsPerConnection',
title: i18n.translate('xpack.infra.assetDetails.metricsCharts.nginx.requestsPerConnection', {
defaultMessage: 'Requests Per Connection',
}),
layers: [
{
data: [nginxLensFormulas.requestsPerConnection],
type: 'visualization',
},
],
dataViewOrigin: 'metrics',
},
];
export const nginxAccessCharts: XYConfig[] = [nginxResponseStatusCodes];
export const nginxAccessCharts: XYConfig[] = [
{
id: 'responseStatusCodes',
title: i18n.translate('xpack.infra.assetDetails.metricsCharts.nginx.responseStatusCodes', {
defaultMessage: 'Response Status Codes',
}),
layers: [
{
data: [
nginxLensFormulas.successStatusCodes,
nginxLensFormulas.redirectStatusCodes,
nginxLensFormulas.clientErrorStatusCodes,
nginxLensFormulas.serverErrorStatusCodes,
],
options: {
seriesType: 'area',
},
type: 'visualization',
},
],
overrides: {
settings: XY_OVERRIDES.settings,
},
dataViewOrigin: 'metrics',
},
];

View file

@ -8,9 +8,20 @@
import { hostMetricFlyoutCharts, hostMetricChartsFullPage } from './host/host_metric_charts';
import { hostKPICharts, KPIChartProps } from './host/host_kpi_charts';
import { nginxAccessCharts, nginxStubstatusCharts } from './host/nginx_charts';
import { kubernetesCharts } from './host/kubernetes_charts';
export { type KPIChartProps };
export const assetDetailsDashboards = {
host: { hostMetricFlyoutCharts, hostMetricChartsFullPage, hostKPICharts },
nginx: { nginxStubstatusCharts, nginxAccessCharts },
host: { hostMetricFlyoutCharts, hostMetricChartsFullPage, hostKPICharts, keyField: 'host.name' },
nginx: {
nginxStubstatusCharts,
nginxAccessCharts,
keyField: 'host.name',
dependsOn: ['nginx.stubstatus', 'nginx.access'],
},
kubernetes: {
kubernetesCharts,
keyField: 'kubernetes.node.name',
dependsOn: ['kubernetes.node'],
},
};

View file

@ -6,7 +6,7 @@
*/
import { i18n } from '@kbn/i18n';
import { hostLensFormulas } from '../../../../constants';
import { hostLensFormulas } from '../../../formulas';
import { REFERENCE_LINE, XY_OVERRIDES } from '../../constants';
import type { XYConfig } from './types';

View file

@ -6,7 +6,7 @@
*/
import { i18n } from '@kbn/i18n';
import { hostLensFormulas } from '../../../../constants';
import { hostLensFormulas } from '../../../formulas';
import { XY_OVERRIDES } from '../../constants';
import type { XYConfig } from './types';

View file

@ -6,7 +6,7 @@
*/
import { i18n } from '@kbn/i18n';
import { hostLensFormulas } from '../../../../constants';
import { hostLensFormulas } from '../../../formulas';
import type { XYConfig } from './types';
export const logRate: XYConfig = {

View file

@ -6,7 +6,7 @@
*/
import { i18n } from '@kbn/i18n';
import { hostLensFormulas } from '../../../../constants';
import { hostLensFormulas } from '../../../formulas';
import { XY_OVERRIDES } from '../../constants';
import type { XYConfig } from './types';

View file

@ -6,7 +6,7 @@
*/
import { i18n } from '@kbn/i18n';
import { hostLensFormulas } from '../../../../constants';
import { hostLensFormulas } from '../../../formulas';
import { XY_OVERRIDES } from '../../constants';
import type { XYConfig } from './types';

View file

@ -1,82 +0,0 @@
/*
* 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 { i18n } from '@kbn/i18n';
import { hostLensFormulas } from '../../../../constants';
import { XY_OVERRIDES } from '../../constants';
import type { XYConfig } from './types';
export const nginxRequestRate: XYConfig = {
id: 'RequestRate',
title: i18n.translate('xpack.infra.assetDetails.metricsCharts.nginx.requestRate', {
defaultMessage: 'Request Rate',
}),
layers: [
{
data: [hostLensFormulas.nginxRequestRate],
type: 'visualization',
},
],
dataViewOrigin: 'metrics',
};
export const nginxActiveConnections: XYConfig = {
id: 'ActiveConnections',
title: i18n.translate('xpack.infra.assetDetails.metricsCharts.nginx.activeConnections', {
defaultMessage: 'Active Connections',
}),
layers: [
{
data: [hostLensFormulas.nginxActiveConnections],
type: 'visualization',
},
],
dataViewOrigin: 'metrics',
};
export const nginxRequestsPerConnection: XYConfig = {
id: 'RequestsPerConnection',
title: i18n.translate('xpack.infra.assetDetails.metricsCharts.nginx.requestsPerConnection', {
defaultMessage: 'Requests Per Connection',
}),
layers: [
{
data: [hostLensFormulas.nginxRequestsPerConnection],
type: 'visualization',
},
],
dataViewOrigin: 'metrics',
};
export const nginxResponseStatusCodes: XYConfig = {
id: 'ResponseStatusCodes',
title: i18n.translate('xpack.infra.assetDetails.metricsCharts.nginx.responseStatusCodes', {
defaultMessage: 'Response Status Codes',
}),
layers: [
{
data: [
hostLensFormulas.nginxSuccessStatusCodes,
hostLensFormulas.nginxRedirectStatusCodes,
hostLensFormulas.nginxClientErrorStatusCodes,
hostLensFormulas.nginxServerErrorStatusCodes,
],
options: {
seriesType: 'area',
},
type: 'visualization',
},
],
overrides: {
settings: XY_OVERRIDES.settings,
},
dataViewOrigin: 'metrics',
};

View file

@ -8,7 +8,7 @@
import { i18n } from '@kbn/i18n';
import type { XYLayerOptions } from '@kbn/lens-embeddable-utils';
import type { TypedLensByValueInput } from '@kbn/lens-plugin/public';
import { hostLensFormulas } from '../../../constants';
import { hostLensFormulas } from '../../formulas';
import type { XYChartLayerParams } from '../../../types';
import { REFERENCE_LINE, XY_OVERRIDES } from '../constants';

View file

@ -5,38 +5,62 @@
* 2.0.
*/
export { cpuUsage } from './cpu_usage';
export { cpuUsageIowait } from './cpu_usage_iowait';
export { cpuUsageIrq } from './cpu_usage_irq';
export { cpuUsageNice } from './cpu_usage_nice';
export { cpuUsageSoftirq } from './cpu_usage_softirq';
export { cpuUsageSteal } from './cpu_usage_steal';
export { cpuUsageUser } from './cpu_usage_user';
export { cpuUsageSystem } from './cpu_usage_system';
export { diskIORead } from './disk_read_iops';
export { diskIOWrite } from './disk_write_iops';
export { diskReadThroughput } from './disk_read_throughput';
export { diskWriteThroughput } from './disk_write_throughput';
export { diskSpaceAvailability } from './disk_space_availability';
export { diskSpaceAvailable } from './disk_space_available';
export { diskUsage } from './disk_usage';
export { hostCount } from './host_count';
export { logRate } from './log_rate';
export { normalizedLoad1m } from './normalized_load_1m';
export { load1m } from './load_1m';
export { load5m } from './load_5m';
export { load15m } from './load_15m';
export { memoryUsage } from './memory_usage';
export { memoryFree } from './memory_free';
export { memoryUsed } from './memory_used';
export { memoryFreeExcludingCache } from './memory_free_excluding_cache';
export { memoryCache } from './memory_cache';
export { nginxRequestRate } from './nginx_request_rate';
export { nginxActiveConnections } from './nginx_active_connections';
export { nginxRequestsPerConnection } from './nginx_requests_per_connection';
export { nginxSuccessStatusCodes } from './nginx_success_status_codes';
export { nginxRedirectStatusCodes } from './nginx_redirect_status_codes';
export { nginxClientErrorStatusCodes } from './nginx_client_error_status_codes';
export { nginxServerErrorStatusCodes } from './nginx_server_error_status_codes';
export { rx } from './rx';
export { tx } from './tx';
import { cpuUsage } from './cpu_usage';
import { cpuUsageIowait } from './cpu_usage_iowait';
import { cpuUsageIrq } from './cpu_usage_irq';
import { cpuUsageNice } from './cpu_usage_nice';
import { cpuUsageSoftirq } from './cpu_usage_softirq';
import { cpuUsageSteal } from './cpu_usage_steal';
import { cpuUsageUser } from './cpu_usage_user';
import { cpuUsageSystem } from './cpu_usage_system';
import { diskIORead } from './disk_read_iops';
import { diskIOWrite } from './disk_write_iops';
import { diskReadThroughput } from './disk_read_throughput';
import { diskWriteThroughput } from './disk_write_throughput';
import { diskSpaceAvailability } from './disk_space_availability';
import { diskSpaceAvailable } from './disk_space_available';
import { diskUsage } from './disk_usage';
import { hostCount } from './host_count';
import { logRate } from './log_rate';
import { normalizedLoad1m } from './normalized_load_1m';
import { load1m } from './load_1m';
import { load5m } from './load_5m';
import { load15m } from './load_15m';
import { memoryUsage } from './memory_usage';
import { memoryFree } from './memory_free';
import { memoryUsed } from './memory_used';
import { memoryFreeExcludingCache } from './memory_free_excluding_cache';
import { memoryCache } from './memory_cache';
import { rx } from './rx';
import { tx } from './tx';
export const hostLensFormulas = {
cpuUsage,
cpuUsageIowait,
cpuUsageIrq,
cpuUsageNice,
cpuUsageSoftirq,
cpuUsageSteal,
cpuUsageUser,
cpuUsageSystem,
diskIORead,
diskIOWrite,
diskReadThroughput,
diskWriteThroughput,
diskSpaceAvailability,
diskSpaceAvailable,
diskUsage,
hostCount,
logRate,
normalizedLoad1m,
load1m,
load5m,
load15m,
memoryUsage,
memoryFree,
memoryUsed,
memoryFreeExcludingCache,
memoryCache,
rx,
tx,
};

View file

@ -0,0 +1,10 @@
/*
* 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.
*/
export { hostLensFormulas } from './host';
export { nginxLensFormulas } from './nginx';
export { kubernetesLensFormulas } from './kubernetes';

View file

@ -0,0 +1,26 @@
/*
* 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 { nodeCpuCapacity } from './node_cpu_capacity';
import { nodeCpuUsed } from './node_cpu_used';
import { nodeDiskCapacity } from './node_disk_capacity';
import { nodeDiskUsed } from './node_disk_used';
import { nodeMemoryCapacity } from './node_memory_capacity';
import { nodeMemoryUsed } from './node_memory_used';
import { nodePodCapacity } from './node_pod_capacity';
import { nodePodUsed } from './node_pod_used';
export const kubernetesLensFormulas = {
nodeCpuCapacity,
nodeCpuUsed,
nodeDiskCapacity,
nodeDiskUsed,
nodeMemoryCapacity,
nodeMemoryUsed,
nodePodCapacity,
nodePodUsed,
};

View file

@ -0,0 +1,23 @@
/*
* 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 { i18n } from '@kbn/i18n';
import { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
export const nodeCpuCapacity: FormulaValueConfig = {
label: i18n.translate('xpack.infra.assetDetails.formulas.kubernetes.capacity', {
defaultMessage: 'Capacity',
}),
value: 'max(kubernetes.node.cpu.allocatable.cores) * 1000000000',
format: {
id: 'number',
params: {
decimals: 1,
compact: true,
},
},
};

View file

@ -0,0 +1,23 @@
/*
* 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 { i18n } from '@kbn/i18n';
import { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
export const nodeCpuUsed: FormulaValueConfig = {
label: i18n.translate('xpack.infra.assetDetails.formulas.kubernetes.used', {
defaultMessage: 'Used',
}),
value: 'average(kubernetes.node.cpu.usage.nanocores)',
format: {
id: 'number',
params: {
decimals: 1,
compact: true,
},
},
};

View file

@ -0,0 +1,22 @@
/*
* 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 { i18n } from '@kbn/i18n';
import { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
export const nodeDiskCapacity: FormulaValueConfig = {
label: i18n.translate('xpack.infra.assetDetails.formulas.kubernetes.capacity', {
defaultMessage: 'Capacity',
}),
value: 'max(kubernetes.node.fs.capacity.bytes)',
format: {
id: 'bytes',
params: {
decimals: 1,
},
},
};

View file

@ -0,0 +1,22 @@
/*
* 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 { i18n } from '@kbn/i18n';
import { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
export const nodeDiskUsed: FormulaValueConfig = {
label: i18n.translate('xpack.infra.assetDetails.formulas.kubernetes.used', {
defaultMessage: 'Used',
}),
value: 'average(kubernetes.node.fs.used.bytes)',
format: {
id: 'bytes',
params: {
decimals: 1,
},
},
};

View file

@ -0,0 +1,22 @@
/*
* 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 { i18n } from '@kbn/i18n';
import { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
export const nodeMemoryCapacity: FormulaValueConfig = {
label: i18n.translate('xpack.infra.assetDetails.formulas.kubernetes.capacity', {
defaultMessage: 'Capacity',
}),
value: 'max(kubernetes.node.memory.allocatable.bytes)',
format: {
id: 'bytes',
params: {
decimals: 1,
},
},
};

View file

@ -0,0 +1,22 @@
/*
* 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 { i18n } from '@kbn/i18n';
import { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
export const nodeMemoryUsed: FormulaValueConfig = {
label: i18n.translate('xpack.infra.assetDetails.formulas.kubernetes.used', {
defaultMessage: 'Used',
}),
value: 'average(kubernetes.node.memory.usage.bytes)',
format: {
id: 'bytes',
params: {
decimals: 1,
},
},
};

View file

@ -0,0 +1,23 @@
/*
* 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 { i18n } from '@kbn/i18n';
import { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
export const nodePodCapacity: FormulaValueConfig = {
label: i18n.translate('xpack.infra.assetDetails.formulas.kubernetes.capacity', {
defaultMessage: 'Capacity',
}),
value:
"last_value(kubernetes.node.pod.allocatable.total, kql='kubernetes.node.pod.allocatable.total: *')",
format: {
id: 'number',
params: {
decimals: 0,
},
},
};

View file

@ -0,0 +1,22 @@
/*
* 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 { i18n } from '@kbn/i18n';
import { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
export const nodePodUsed: FormulaValueConfig = {
label: i18n.translate('xpack.infra.assetDetails.formulas.kubernetes.used', {
defaultMessage: 'Used',
}),
value: 'unique_count(kubernetes.pod.uid)',
format: {
id: 'number',
params: {
decimals: 0,
},
},
};

View file

@ -8,7 +8,7 @@
import { i18n } from '@kbn/i18n';
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
export const nginxActiveConnections: FormulaValueConfig = {
export const activeConnections: FormulaValueConfig = {
label: i18n.translate('xpack.infra.assetDetails.formulas.nginx.activeConnections', {
defaultMessage: 'Active Connections',
}),

View file

@ -8,7 +8,7 @@
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
import { defaultPalette, Color } from '../../../../../../common/color_palette';
export const nginxClientErrorStatusCodes: FormulaValueConfig = {
export const clientErrorStatusCodes: FormulaValueConfig = {
label: '400-499',
value: `count(kql='http.response.status_code >= 400 and http.response.status_code <= 499')`,
format: {

View file

@ -0,0 +1,24 @@
/*
* 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 { requestRate } from './request_rate';
import { activeConnections } from './active_connections';
import { requestsPerConnection } from './requests_per_connection';
import { successStatusCodes } from './success_status_codes';
import { redirectStatusCodes } from './redirect_status_codes';
import { clientErrorStatusCodes } from './client_error_status_codes';
import { serverErrorStatusCodes } from './server_error_status_codes';
export const nginxLensFormulas = {
activeConnections,
requestRate,
requestsPerConnection,
successStatusCodes,
redirectStatusCodes,
clientErrorStatusCodes,
serverErrorStatusCodes,
};

View file

@ -8,7 +8,7 @@
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
import { defaultPalette, Color } from '../../../../../../common/color_palette';
export const nginxRedirectStatusCodes: FormulaValueConfig = {
export const redirectStatusCodes: FormulaValueConfig = {
label: '300-399',
value: `count(kql='http.response.status_code >= 300 and http.response.status_code <= 399')`,
format: {

View file

@ -8,7 +8,7 @@
import { i18n } from '@kbn/i18n';
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
export const nginxRequestRate: FormulaValueConfig = {
export const requestRate: FormulaValueConfig = {
label: i18n.translate('xpack.infra.assetDetails.formulas.nginx.requestRate', {
defaultMessage: 'Request Rate',
}),

View file

@ -8,7 +8,7 @@
import { i18n } from '@kbn/i18n';
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
export const nginxRequestsPerConnection: FormulaValueConfig = {
export const requestsPerConnection: FormulaValueConfig = {
label: i18n.translate('xpack.infra.assetDetails.formulas.nginx.requestsPerConnection', {
defaultMessage: 'Requests Per Connection',
}),

View file

@ -8,7 +8,7 @@
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
import { defaultPalette, Color } from '../../../../../../common/color_palette';
export const nginxServerErrorStatusCodes: FormulaValueConfig = {
export const serverErrorStatusCodes: FormulaValueConfig = {
label: '500-599',
value: `count(kql='http.response.status_code >= 500 and http.response.status_code <= 599')`,
format: {

View file

@ -8,7 +8,7 @@
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
import { defaultPalette, Color } from '../../../../../../common/color_palette';
export const nginxSuccessStatusCodes: FormulaValueConfig = {
export const successStatusCodes: FormulaValueConfig = {
label: '200-299',
value: `count(kql='http.response.status_code >= 200 and http.response.status_code <= 299')`,
format: {

View file

@ -10,11 +10,6 @@ import type {
XYLayerConfig,
XYReferenceLinesLayerConfig,
} from '@kbn/lens-embeddable-utils';
import { hostLensFormulas } from './constants';
export type HostsLensFormulas = keyof typeof hostLensFormulas;
export type HostsLensMetricChartFormulas = Exclude<HostsLensFormulas, 'diskIORead' | 'diskIOWrite'>;
export type HostsLensLineChartFormulas = Exclude<HostsLensFormulas, 'hostCount'>;
export type XYChartLayerParams =
| (XYLayerConfig & { type: 'visualization' })

View file

@ -72,6 +72,14 @@ export const NginxMetricsSectionTitle = () => (
/>
);
export const KubernetesMetricsSectionTitle = () => (
<SectionTitle
title={i18n.translate('xpack.infra.assetDetails.overview.kubernetesMetricsSectionTitle', {
defaultMessage: 'Kubernetes Overview',
})}
/>
);
export const MetadataSectionTitle = () => (
<SectionTitle
title={i18n.translate('xpack.infra.assetDetails.overview.metadataSectionTitle', {

View file

@ -19,6 +19,7 @@ export interface ChartProps extends XYConfig {
visualOptions?: XYVisualOptions;
metricsDataView?: DataView;
logsDataView?: DataView;
filterFieldName: string;
dateRange: TimeRange;
assetName: string;
['data-test-subj']: string;
@ -30,6 +31,7 @@ export const Chart = ({
layers,
metricsDataView,
logsDataView,
filterFieldName,
visualOptions,
dataViewOrigin,
overrides,
@ -46,12 +48,12 @@ export const Chart = ({
const filters = useMemo(() => {
return [
buildCombinedHostsFilter({
field: 'host.name',
field: filterFieldName,
values: [assetName],
dataView,
}),
];
}, [assetName, dataView]);
}, [assetName, dataView, filterFieldName]);
const handleBrushEnd = useCallback(
({ range, preventDefault }: BrushEndArgs) => {

View file

@ -17,6 +17,7 @@ interface Props {
dateRange: TimeRange;
metricsDataView?: DataView;
logsDataView?: DataView;
filterFieldName: string;
charts: Array<XYConfig & { dependsOn?: string[] }>;
['data-test-subj']: string;
}
@ -26,6 +27,7 @@ export const MetricsGrid = ({
metricsDataView,
logsDataView,
dateRange,
filterFieldName,
charts,
...props
}: Props) => {
@ -49,6 +51,7 @@ export const MetricsGrid = ({
{...chartProp}
assetName={assetName}
dateRange={dateRange}
filterFieldName={filterFieldName}
logsDataView={logsDataView}
metricsDataView={metricsDataView}
data-test-subj={props['data-test-subj']}

View file

@ -6,12 +6,16 @@
*/
import React, { useMemo } from 'react';
import { EuiSpacer, EuiFlexItem } from '@elastic/eui';
import { EuiFlexItem } from '@elastic/eui';
import type { DataView } from '@kbn/data-views-plugin/public';
import type { TimeRange } from '@kbn/es-query';
import { EuiFlexGroup } from '@elastic/eui';
import { assetDetailsDashboards } from '../../../../../common/visualizations';
import { MetricsSectionTitle, NginxMetricsSectionTitle } from '../../../components/section_titles';
import {
MetricsSectionTitle,
NginxMetricsSectionTitle,
KubernetesMetricsSectionTitle,
} from '../../../components/section_titles';
import { useMetadataStateProviderContext } from '../../../hooks/use_metadata_state';
import { MetricsGrid } from './metrics_grid';
@ -22,26 +26,38 @@ interface Props {
logsDataView?: DataView;
}
const { host, nginx } = assetDetailsDashboards;
const { host, nginx, kubernetes } = assetDetailsDashboards;
export const MetricsSection = ({ assetName, metricsDataView, logsDataView, dateRange }: Props) => {
return (
<>
<EuiFlexGroup direction="column" gutterSize="s">
<Section title={MetricsSectionTitle}>
<MetricsGrid
assetName={assetName}
dateRange={dateRange}
charts={host.hostMetricChartsFullPage}
filterFieldName={host.keyField}
metricsDataView={metricsDataView}
logsDataView={logsDataView}
data-test-subj="infraAssetDetailsMetricsChart"
/>
</Section>
<EuiSpacer size="s" />
<Section dependsOn={['nginx.stubstatus', 'nginx.access']} title={NginxMetricsSectionTitle}>
<Section dependsOn={kubernetes.dependsOn} title={KubernetesMetricsSectionTitle}>
<MetricsGrid
assetName={assetName}
dateRange={dateRange}
filterFieldName={kubernetes.keyField}
charts={kubernetes.kubernetesCharts}
metricsDataView={metricsDataView}
logsDataView={logsDataView}
data-test-subj="infraAssetDetailsKubernetesMetricsChart"
/>
</Section>
<Section dependsOn={nginx.dependsOn} title={NginxMetricsSectionTitle}>
<MetricsGrid
assetName={assetName}
dateRange={dateRange}
filterFieldName={nginx.keyField}
charts={[
...nginx.nginxStubstatusCharts.map((chart) => ({
...chart,
@ -57,7 +73,7 @@ export const MetricsSection = ({ assetName, metricsDataView, logsDataView, dateR
data-test-subj="infraAssetDetailsNginxMetricsChart"
/>
</Section>
</>
</EuiFlexGroup>
);
};
@ -71,6 +87,7 @@ export const MetricsSectionCompact = ({
<MetricsGrid
assetName={assetName}
dateRange={dateRange}
filterFieldName={host.keyField}
charts={host.hostMetricFlyoutCharts}
metricsDataView={metricsDataView}
logsDataView={logsDataView}

View file

@ -41,6 +41,7 @@ export interface FormulaPublicApi {
id: string;
params?: {
decimals: number;
compact?: boolean;
};
};
},

View file

@ -26,6 +26,8 @@ export const DATES = {
max: '2018-10-17T19:58:03.952Z',
processesDataStartDate: '2023-03-28T18:20:00.000Z',
processesDataEndDate: '2023-03-28T18:21:00.000Z',
kubernetesSectionStartDate: '2023-09-19T07:20:00.000Z',
kubernetesSectionEndDate: '2023-09-19T07:21:00.000Z',
},
stream: {
startWithData: '2018-10-17T19:42:22.000Z',

View file

@ -14,6 +14,12 @@ const START_HOST_ALERTS_DATE = moment.utc(DATES.metricsAndLogs.hosts.min);
const END_HOST_ALERTS_DATE = moment.utc(DATES.metricsAndLogs.hosts.max);
const START_HOST_PROCESSES_DATE = moment.utc(DATES.metricsAndLogs.hosts.processesDataStartDate);
const END_HOST_PROCESSES_DATE = moment.utc(DATES.metricsAndLogs.hosts.processesDataEndDate);
const START_HOST_KUBERNETES_SECTION_DATE = moment.utc(
DATES.metricsAndLogs.hosts.kubernetesSectionStartDate
);
const END_HOST_KUBERNETES_SECTION_DATE = moment.utc(
DATES.metricsAndLogs.hosts.kubernetesSectionEndDate
);
export default ({ getPageObjects, getService }: FtrProviderContext) => {
const observability = getService('observability');
@ -339,57 +345,93 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
expect(processValue).to.eql('N/A');
});
});
});
});
describe('#With Asset Details using nginx host', () => {
before(async () => {
await Promise.all([
esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_and_logs'),
kibanaServer.savedObjects.cleanStandardList(),
]);
await browser.setWindowSize(1600, 1200);
describe('#With Nginx section', () => {
before(async () => {
await navigateToNodeDetails('demo-stack-nginx-01', 'demo-stack-nginx-01');
await pageObjects.header.waitUntilLoadingHasFinished();
});
await navigateToNodeDetails('demo-stack-nginx-01', 'demo-stack-nginx-01');
await pageObjects.header.waitUntilLoadingHasFinished();
});
describe('Overview Tab', () => {
before(async () => {
await pageObjects.assetDetails.clickOverviewTab();
after(async () => {
await esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_and_logs');
});
await pageObjects.timePicker.setAbsoluteRange(
START_HOST_ALERTS_DATE.format(DATE_PICKER_FORMAT),
END_HOST_ALERTS_DATE.format(DATE_PICKER_FORMAT)
);
});
describe('Overview Tab Nginx', () => {
before(async () => {
await pageObjects.assetDetails.clickOverviewTab();
[
{ metric: 'cpuUsage', value: '0.8%' },
{ metric: 'normalizedLoad1m', value: '1.4%' },
{ metric: 'memoryUsage', value: '18.0%' },
{ metric: 'diskSpaceUsage', value: '17.5%' },
].forEach(({ metric, value }) => {
it(`${metric} tile should show ${value}`, async () => {
await retry.tryForTime(3 * 1000, async () => {
const tileValue = await pageObjects.assetDetails.getAssetDetailsKPITileValue(
metric
);
expect(tileValue).to.eql(value);
});
});
});
await pageObjects.timePicker.setAbsoluteRange(
START_HOST_ALERTS_DATE.format(DATE_PICKER_FORMAT),
END_HOST_ALERTS_DATE.format(DATE_PICKER_FORMAT)
);
});
it('should render 12 charts in the Metrics section', async () => {
const hosts = await pageObjects.assetDetails.getAssetDetailsMetricsCharts();
expect(hosts.length).to.equal(12);
});
[
{ metric: 'cpuUsage', value: '0.8%' },
{ metric: 'normalizedLoad1m', value: '1.4%' },
{ metric: 'memoryUsage', value: '18.0%' },
{ metric: 'diskSpaceUsage', value: '17.5%' },
].forEach(({ metric, value }) => {
it(`${metric} tile should show ${value}`, async () => {
await retry.tryForTime(3 * 1000, async () => {
const tileValue = await pageObjects.assetDetails.getAssetDetailsKPITileValue(metric);
expect(tileValue).to.eql(value);
it('should render 3 charts in the Nginx Metrics section', async () => {
const hosts = await pageObjects.assetDetails.getAssetDetailsNginxMetricsCharts();
expect(hosts.length).to.equal(3);
});
});
});
it('should render 12 charts in the Metrics section', async () => {
const hosts = await pageObjects.assetDetails.getAssetDetailsMetricsCharts();
expect(hosts.length).to.equal(12);
});
describe('#With Kubernetes section', () => {
before(async () => {
await navigateToNodeDetails('demo-stack-kubernetes-01', 'demo-stack-kubernetes-01');
await pageObjects.header.waitUntilLoadingHasFinished();
});
it('should render 3 charts in the Nginx Metrics section', async () => {
const hosts = await pageObjects.assetDetails.getAssetDetailsNginxMetricsCharts();
expect(hosts.length).to.equal(3);
describe('Overview Tab', () => {
before(async () => {
await pageObjects.assetDetails.clickOverviewTab();
await pageObjects.timePicker.setAbsoluteRange(
START_HOST_KUBERNETES_SECTION_DATE.format(DATE_PICKER_FORMAT),
END_HOST_KUBERNETES_SECTION_DATE.format(DATE_PICKER_FORMAT)
);
});
[
{ metric: 'cpuUsage', value: '99.6%' },
{ metric: 'normalizedLoad1m', value: '1,300.3%' },
{ metric: 'memoryUsage', value: '42.2%' },
{ metric: 'diskSpaceUsage', value: '36.0%' },
].forEach(({ metric, value }) => {
it(`${metric} tile should show ${value}`, async () => {
await retry.tryForTime(3 * 1000, async () => {
const tileValue = await pageObjects.assetDetails.getAssetDetailsKPITileValue(
metric
);
expect(tileValue).to.eql(value);
});
});
});
it('should render 12 charts in the Metrics section', async () => {
const hosts = await pageObjects.assetDetails.getAssetDetailsMetricsCharts();
expect(hosts.length).to.equal(12);
});
it('should render 4 charts in the Kubernetes Metrics section', async () => {
const hosts = await pageObjects.assetDetails.getAssetDetailsKubernetesMetricsCharts();
expect(hosts.length).to.equal(4);
});
});
});
});
});

View file

@ -47,6 +47,13 @@ export function AssetDetailsProvider({ getService }: FtrProviderContext) {
);
},
async getAssetDetailsKubernetesMetricsCharts() {
const container = await testSubjects.find('infraAssetDetailsKubernetesMetricsChartGrid');
return container.findAllByCssSelector(
'[data-test-subj*="infraAssetDetailsKubernetesMetricsChart"]'
);
},
async clickOverviewLinkToAlerts() {
return testSubjects.click('infraAssetDetailsAlertsShowAllButton');
},