mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[Monitoring/React] Logstash cluster status bars in react (#19433)
* [Monitoring/React] Logstash cluster status bars in react * not have a prop named children * simplify conditional metric * fix functional tests
This commit is contained in:
parent
c8d53bcf76
commit
6760a64c3d
14 changed files with 176 additions and 76 deletions
|
@ -22,7 +22,7 @@ export function ClusterStatus({ stats }) {
|
|||
status
|
||||
} = stats;
|
||||
|
||||
const children = [
|
||||
const metrics = [
|
||||
{
|
||||
label: 'Nodes',
|
||||
value: nodesCount,
|
||||
|
@ -68,7 +68,7 @@ export function ClusterStatus({ stats }) {
|
|||
|
||||
return (
|
||||
<SummaryStatus
|
||||
children={children}
|
||||
metrics={metrics}
|
||||
status={status}
|
||||
IconComponent={IconComponent}
|
||||
data-test-subj="elasticsearchClusterStatus"
|
||||
|
|
|
@ -18,7 +18,7 @@ export function IndexDetailStatus({ stats }) {
|
|||
status
|
||||
} = stats;
|
||||
|
||||
const children = [
|
||||
const metrics = [
|
||||
{
|
||||
label: 'Total',
|
||||
value: formatMetric(dataSize.total, '0.0 b'),
|
||||
|
@ -54,7 +54,7 @@ export function IndexDetailStatus({ stats }) {
|
|||
|
||||
return (
|
||||
<SummaryStatus
|
||||
children={children}
|
||||
metrics={metrics}
|
||||
status={status}
|
||||
IconComponent={IconComponent}
|
||||
data-test-subj="elasticsearchIndexDetailStatus"
|
||||
|
|
|
@ -23,7 +23,7 @@ export function NodeDetailStatus({ stats }) {
|
|||
isOnline,
|
||||
} = stats;
|
||||
|
||||
const children = [
|
||||
const metrics = [
|
||||
{
|
||||
value: transportAddress,
|
||||
dataTestSubj: 'transportAddress'
|
||||
|
@ -73,7 +73,7 @@ export function NodeDetailStatus({ stats }) {
|
|||
|
||||
return (
|
||||
<SummaryStatus
|
||||
children={children}
|
||||
metrics={metrics}
|
||||
status={status}
|
||||
isOnline={isOnline}
|
||||
IconComponent={IconComponent}
|
||||
|
|
|
@ -20,7 +20,7 @@ export function ClusterStatus({ stats }) {
|
|||
status,
|
||||
} = stats;
|
||||
|
||||
const children = [
|
||||
const metrics = [
|
||||
{
|
||||
label: 'Instances',
|
||||
value: instances,
|
||||
|
@ -56,7 +56,7 @@ export function ClusterStatus({ stats }) {
|
|||
|
||||
return (
|
||||
<SummaryStatus
|
||||
children={children}
|
||||
metrics={metrics}
|
||||
status={status}
|
||||
IconComponent={IconComponent}
|
||||
data-test-subj="kibanaClusterStatus"
|
||||
|
|
|
@ -18,7 +18,7 @@ export function DetailStatus({ stats }) {
|
|||
status
|
||||
} = stats;
|
||||
|
||||
const children = [
|
||||
const metrics = [
|
||||
{
|
||||
value: transportAddress,
|
||||
dataTestSubj: 'transportAddress'
|
||||
|
@ -48,7 +48,7 @@ export function DetailStatus({ stats }) {
|
|||
|
||||
return (
|
||||
<SummaryStatus
|
||||
children={children}
|
||||
metrics={metrics}
|
||||
status={status}
|
||||
IconComponent={IconComponent}
|
||||
data-test-subj="kibanaDetailStatus"
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { SummaryStatus } from '../../summary_status';
|
||||
import { formatMetric } from '../../../lib/format_number';
|
||||
|
||||
export function ClusterStatus({ stats }) {
|
||||
const {
|
||||
node_count: nodeCount,
|
||||
avg_memory_used: avgMemoryUsed,
|
||||
avg_memory: avgMemory,
|
||||
events_in_total: eventsInTotal,
|
||||
events_out_total: eventsOutTotal
|
||||
} = stats;
|
||||
|
||||
const metrics = [
|
||||
{
|
||||
label: 'Nodes',
|
||||
value: nodeCount,
|
||||
dataTestSubj: 'node_count'
|
||||
},
|
||||
{
|
||||
label: 'Memory',
|
||||
value: formatMetric(avgMemoryUsed, 'byte') + ' / ' + formatMetric(avgMemory, 'byte'),
|
||||
dataTestSubj: 'memory_used'
|
||||
},
|
||||
{
|
||||
label: 'Events Received',
|
||||
value: formatMetric(eventsInTotal, '0.[0]a'),
|
||||
dataTestSubj: 'events_in_total'
|
||||
},
|
||||
{
|
||||
label: 'Events Emitted',
|
||||
value: formatMetric(eventsOutTotal, '0.[0]a'),
|
||||
dataTestSubj: 'events_out_total'
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<SummaryStatus
|
||||
metrics={metrics}
|
||||
data-test-subj="logstashClusterStatus"
|
||||
/>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { SummaryStatus } from '../../summary_status';
|
||||
import { formatMetric } from '../../../lib/format_number';
|
||||
|
||||
export function DetailStatus({ stats }) {
|
||||
const {
|
||||
http_address: httpAddress,
|
||||
events,
|
||||
reloads,
|
||||
pipeline,
|
||||
queue_type: queueType,
|
||||
version,
|
||||
uptime
|
||||
} = stats;
|
||||
|
||||
const firstMetrics = [
|
||||
{
|
||||
value: httpAddress,
|
||||
dataTestSubj: 'httpAddress'
|
||||
},
|
||||
{
|
||||
label: 'Events Received',
|
||||
value: formatMetric(events.in, '0.[0]a'),
|
||||
dataTestSubj: 'eventsIn'
|
||||
},
|
||||
{
|
||||
label: 'Events Emitted',
|
||||
value: formatMetric(events.out, '0.[0]a'),
|
||||
dataTestSubj: 'eventsOut'
|
||||
},
|
||||
{
|
||||
label: 'Config Reloads',
|
||||
value: reloads.successes,
|
||||
dataTestSubj: 'numReloads'
|
||||
},
|
||||
{
|
||||
label: 'Pipeline Workers',
|
||||
value: pipeline.workers,
|
||||
dataTestSubj: 'pipelineWorkers'
|
||||
},
|
||||
{
|
||||
label: 'Batch Size',
|
||||
value: pipeline.batch_size,
|
||||
dataTestSubj: 'pipelineBatchSize'
|
||||
}
|
||||
];
|
||||
|
||||
const lastMetrics = [
|
||||
{
|
||||
label: 'Version',
|
||||
value: version,
|
||||
dataTestSubj: 'version'
|
||||
},
|
||||
{
|
||||
label: 'Uptime',
|
||||
value: formatMetric(uptime, 'time_since'),
|
||||
dataTestSubj: 'uptime'
|
||||
}
|
||||
];
|
||||
|
||||
// make queueType conditional
|
||||
const metrics = [...firstMetrics];
|
||||
if (queueType) {
|
||||
metrics.push({
|
||||
label: 'Queue Type',
|
||||
value: queueType,
|
||||
dataTestSubj: 'queueType'
|
||||
});
|
||||
}
|
||||
metrics.push(...lastMetrics);
|
||||
|
||||
return (
|
||||
<SummaryStatus
|
||||
metrics={metrics}
|
||||
data-test-subj="logstashDetailStatus"
|
||||
/>
|
||||
);
|
||||
}
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
import React, { Fragment } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { isEmpty, capitalize } from 'lodash';
|
||||
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
|
||||
import { StatusIcon } from '../';
|
||||
|
@ -42,12 +43,12 @@ const StatusIndicator = ({ status, isOnline, IconComponent }) => {
|
|||
);
|
||||
};
|
||||
|
||||
export function SummaryStatus({ children, status, isOnline, IconComponent = DefaultIconComponent, ...props }) {
|
||||
export function SummaryStatus({ metrics, status, isOnline, IconComponent = DefaultIconComponent, ...props }) {
|
||||
return (
|
||||
<div className="monitoring-summary-status" role="status">
|
||||
<div className="monitoring-summary-status__content" {...props}>
|
||||
<EuiFlexGroup gutterSize="xs" alignItems="center">
|
||||
{children.map(wrapChild)}
|
||||
{metrics.map(wrapChild)}
|
||||
|
||||
<EuiFlexItem
|
||||
grow={true}
|
||||
|
@ -60,3 +61,7 @@ export function SummaryStatus({ children, status, isOnline, IconComponent = Defa
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
SummaryStatus.propTypes = {
|
||||
metrics: PropTypes.array.isRequired
|
||||
};
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
<div class="monitoring-summary-status" role="status">
|
||||
<div
|
||||
class="monitoring-summary-status__content"
|
||||
data-test-subj="logstashSummaryStatus"
|
||||
>
|
||||
<div>Nodes:
|
||||
<strong data-test-subj="node_count">{{ status.node_count }}</strong>
|
||||
</div>
|
||||
<div>Memory:
|
||||
<strong data-test-subj="memory_used">{{ status.avg_memory_used|formatNumber:'byte' }} / {{ status.avg_memory|formatNumber:'byte' }}</strong>
|
||||
</div>
|
||||
<div>Events Received:
|
||||
<strong data-test-subj="events_in_total">{{ status.events_in_total|formatNumber:'0.[0]a' }}</strong>
|
||||
</div>
|
||||
<div>Events Emitted:
|
||||
<strong data-test-subj="events_out_total">{{ status.events_out_total|formatNumber:'0.[0]a' }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -4,16 +4,22 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { render } from 'react-dom';
|
||||
import { uiModules } from 'ui/modules';
|
||||
import template from './index.html';
|
||||
import { ClusterStatus } from 'plugins/monitoring/components/logstash/cluster_status';
|
||||
|
||||
const uiModule = uiModules.get('monitoring/directives', []);
|
||||
uiModule.directive('monitoringClusterStatusLogstash', () => {
|
||||
return {
|
||||
restrict: 'E',
|
||||
template,
|
||||
scope: {
|
||||
status: '='
|
||||
},
|
||||
link(scope, $el) {
|
||||
scope.$watch('status', status => {
|
||||
render(<ClusterStatus stats={status} />, $el[0]);
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
<div class="monitoring-summary-status" role="status">
|
||||
<div class="monitoring-summary-status__content">
|
||||
<div>
|
||||
<strong data-test-subj="httpAddress">{{ logstash.http_address }}</strong>
|
||||
</div>
|
||||
<div>Events Received:
|
||||
<strong data-test-subj="eventsIn">{{ logstash.events.in|formatNumber:'0.[0]a' }}</strong>
|
||||
</div>
|
||||
<div>Events Emitted:
|
||||
<strong data-test-subj="eventsOut">{{ logstash.events.out|formatNumber:'0.[0]a' }}</strong>
|
||||
</div>
|
||||
<div>Config Reloads:
|
||||
<strong data-test-subj="numReloads">{{ logstash.reloads.successes }}</strong>
|
||||
</div>
|
||||
<div>Pipeline Workers:
|
||||
<strong data-test-subj="pipelineWorkers">{{ logstash.pipeline.workers }}</strong>
|
||||
</div>
|
||||
<div>Batch Size:
|
||||
<strong data-test-subj="pipelineBatchSize">{{ logstash.pipeline.batch_size }}</strong>
|
||||
</div>
|
||||
<div ng-show="logstash.queue_type">Queue Type:
|
||||
<strong data-test-subj="queueType">{{ logstash.queue_type }}</strong>
|
||||
</div>
|
||||
<div>Logstash:
|
||||
<strong data-test-subj="version">{{ logstash.version }}</strong>
|
||||
</div>
|
||||
<div>Uptime:
|
||||
<strong data-test-subj="uptime">{{ logstash.uptime|formatNumber:'time_since' }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -4,16 +4,22 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import template from './index.html';
|
||||
import React from 'react';
|
||||
import { render } from 'react-dom';
|
||||
import { uiModules } from 'ui/modules';
|
||||
import { DetailStatus } from 'plugins/monitoring/components/logstash/detail_status';
|
||||
|
||||
const uiModule = uiModules.get('monitoring/directives', []);
|
||||
uiModule.directive('monitoringLogstashNodeSummary', () => {
|
||||
return {
|
||||
restrict: 'E',
|
||||
template: template,
|
||||
scope: {
|
||||
logstash: '='
|
||||
},
|
||||
link(scope, $el) {
|
||||
scope.$watch('logstash', logstash => {
|
||||
render(<DetailStatus stats={logstash} />, $el[0]);
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
|
|
|
@ -30,16 +30,16 @@ export default function ({ getService, getPageObjects }) {
|
|||
await tearDown();
|
||||
});
|
||||
|
||||
it('Logstash Cluster Summary Status shows correct info', async () => {
|
||||
it('should have Logstash Cluster Summary Status showing correct info', async () => {
|
||||
expect(await lsClusterSummaryStatus.getContent()).to.eql({
|
||||
nodeCount: '2',
|
||||
memoryUsed: '528.4 MB / 1.9 GB',
|
||||
eventsInTotal: '117.9k',
|
||||
eventsOutTotal: '111.9k'
|
||||
nodeCount: 'Nodes: 2',
|
||||
memoryUsed: 'Memory: 528.4 MB / 1.9 GB',
|
||||
eventsInTotal: 'Events Received: 117.9k',
|
||||
eventsOutTotal: 'Events Emitted: 111.9k'
|
||||
});
|
||||
});
|
||||
|
||||
it('Pipelines table shows correct rows with default sorting', async () => {
|
||||
it('should have Pipelines table showing correct rows with default sorting', async () => {
|
||||
const rows = await pipelinesList.getRows();
|
||||
expect(rows.length).to.be(4);
|
||||
|
||||
|
@ -60,7 +60,7 @@ export default function ({ getService, getPageObjects }) {
|
|||
});
|
||||
});
|
||||
|
||||
it('Pipelines Table shows correct rows after sorting by Events Emitted Rate Asc', async () => {
|
||||
it('should have Pipelines Table showing correct rows after sorting by Events Emitted Rate Asc', async () => {
|
||||
await pipelinesList.clickEventsEmittedRateCol();
|
||||
|
||||
const rows = await pipelinesList.getRows();
|
||||
|
@ -83,14 +83,14 @@ export default function ({ getService, getPageObjects }) {
|
|||
});
|
||||
});
|
||||
|
||||
it('filters for specific pipelines', async () => {
|
||||
it('should filter for specific pipelines', async () => {
|
||||
await pipelinesList.setFilter('la');
|
||||
const rows = await pipelinesList.getRows();
|
||||
expect(rows.length).to.be(2);
|
||||
await pipelinesList.clearFilter();
|
||||
});
|
||||
|
||||
it('filters for non-existent pipeline', async () => {
|
||||
it('should filter for non-existent pipeline', async () => {
|
||||
await pipelinesList.setFilter('foobar');
|
||||
await pipelinesList.assertNoData();
|
||||
await pipelinesList.clearFilter();
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
export function MonitoringLogstashSummaryStatusProvider({ getService }) {
|
||||
const testSubjects = getService('testSubjects');
|
||||
|
||||
const SUBJ_SUMMARY = 'logstashSummaryStatus';
|
||||
const SUBJ_SUMMARY = 'logstashClusterStatus';
|
||||
const SUBJ_SUMMARY_NODE_COUNT = `${SUBJ_SUMMARY} node_count`;
|
||||
const SUBJ_SUMMARY_MEMORY_USED = `${SUBJ_SUMMARY} memory_used`;
|
||||
const SUBJ_SUMMARY_EVENTS_IN_TOTAL = `${SUBJ_SUMMARY} events_in_total`;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue