[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:
Tim Sullivan 2018-05-29 14:36:32 -07:00 committed by GitHub
parent c8d53bcf76
commit 6760a64c3d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 176 additions and 76 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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();

View file

@ -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`;