[Stack Monitoring] New FTR for "view logs" link (#208351)

## Summary

Closes https://github.com/elastic/kibana/issues/202675

A [recent bug](https://github.com/elastic/kibana/issues/199902) broke
the Stack Monitoring UI only if/when logs were present. Functional test
coverage was lacking to detect such a situation.

This PR adds some functional test coverage to make sure that the "View
logs" link in Stack Monitoring works whenever logs are available,
wherever logs can be visible, i.e. in the cluster overview page, the
node details page and the index details page.

### Checklist

- [X] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Valentin Crettaz 2025-03-12 23:35:28 +01:00 committed by GitHub
parent 6a3becf296
commit c218f4239a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 13481 additions and 50 deletions

View file

@ -13,6 +13,7 @@ exports[`Logs should render a link to filter by cluster uuid 1`] = `
values={
Object {
"link": <EuiLink
data-test-subj="monitoringLogsLink"
href="http://localhost:5601/app/discover"
>
Discover
@ -37,6 +38,7 @@ exports[`Logs should render a link to filter by cluster uuid and index uuid 1`]
values={
Object {
"link": <EuiLink
data-test-subj="monitoringLogsLink"
href="http://localhost:5601/app/discover"
>
Discover
@ -61,6 +63,7 @@ exports[`Logs should render a link to filter by cluster uuid and node uuid 1`] =
values={
Object {
"link": <EuiLink
data-test-subj="monitoringLogsLink"
href="http://localhost:5601/app/discover"
>
Discover
@ -73,7 +76,9 @@ exports[`Logs should render a link to filter by cluster uuid and node uuid 1`] =
`;
exports[`Logs should render a reason if the logs are disabled 1`] = `
<div>
<div
data-test-subj="monitoringLogs"
>
<EuiTitle>
<h1>
Recent Log Entries
@ -131,7 +136,9 @@ Array [
`;
exports[`Logs should render normally 1`] = `
<div>
<div
data-test-subj="monitoringLogs"
>
<EuiTitle>
<h1>
Recent Log Entries
@ -291,6 +298,7 @@ exports[`Logs should render normally 1`] = `
values={
Object {
"link": <EuiLink
data-test-subj="monitoringLogsLink"
href="http://localhost:5601/app/discover"
>
Discover

View file

@ -239,7 +239,7 @@ export class LogsContent extends PureComponent<LogsContentProps> {
defaultMessage="Visit {link} to dive deeper."
values={{
link: (
<EuiLink href={discoverLink}>
<EuiLink href={discoverLink} data-test-subj="monitoringLogsLink">
{i18n.translate('xpack.monitoring.logs.listing.calloutLinkText', {
defaultMessage: 'Discover',
})}
@ -288,7 +288,7 @@ export class LogsContent extends PureComponent<LogsContentProps> {
}
return (
<div>
<div data-test-subj="monitoringLogs">
<EuiTitle>
<h1>
{i18n.translate('xpack.monitoring.logs.listing.pageTitle', {

View file

@ -345,9 +345,9 @@
"enabled": false,
"logs": [],
"reason": {
"indexPatternExists": false,
"indexPatternExists": true,
"indexPatternInTimeRangeExists": false,
"typeExistsAtAnyTime": false,
"typeExistsAtAnyTime": true,
"typeExists": false,
"usingStructuredLogs": false,
"clusterExists": false,

View file

@ -1009,9 +1009,9 @@
"enabled": false,
"logs": [],
"reason": {
"indexPatternExists": false,
"indexPatternExists": true,
"indexPatternInTimeRangeExists": false,
"typeExistsAtAnyTime": false,
"typeExistsAtAnyTime": true,
"typeExists": false,
"usingStructuredLogs": false,
"clusterExists": false,

View file

@ -15,19 +15,19 @@
]
},
"logs": {
"enabled": false,
"enabled": true,
"limit": 10,
"reason": {
"clusterExists": false,
"indexPatternExists": false,
"indexPatternInTimeRangeExists": false,
"typeExistsAtAnyTime": false,
"usingStructuredLogs": false,
"nodeExists": null,
"indexExists": null,
"typeExists": false
},
"logs": []
"logs": [
{
"component": "o.e.c.m.MetaDataMappingService",
"index": "phone-home",
"level": "INFO",
"message": "update_mapping [_doc]",
"node": "whatever-01",
"timestamp": 1507235724641,
"type": "server"
}
]
},
"metrics": {
"cluster_index_latency": [

View file

@ -28,7 +28,12 @@ export const getLifecycleMethods = (getService, getPageObjects) => {
async setup(archive, { from, to, useSuperUser = false, useCreate = false }) {
_archive = archive;
if (!useSuperUser) {
await security.testUser.setRoles(['monitoring_user', 'kibana_admin', 'test_monitoring']);
await security.testUser.setRoles([
'monitoring_user',
'kibana_admin',
'test_monitoring',
'test_filebeat_reader',
]);
}
const kibanaServer = getService('kibanaServer');

View file

@ -28,7 +28,7 @@ export default function ({ getService, getPageObjects }) {
'x-pack/test/functional/es_archives/monitoring/singlecluster_three_nodes_shard_relocation',
{
from: 'Oct 5, 2017 @ 20:31:48.354',
to: 'Oct 5, 2017 @ 20:35:12.176',
to: 'Oct 5, 2017 @ 20:35:30.176',
}
);
@ -81,6 +81,12 @@ export default function ({ getService, getPageObjects }) {
health: 'Health: yellow',
});
});
it('should show the link to view more index logs', async () => {
await indicesList.clickRowByName('phone-home');
expect(await indexDetail.viewLogsLinkIsShowing()).to.be(true);
});
});
});
}

View file

@ -28,7 +28,7 @@ export default function ({ getService, getPageObjects }) {
'x-pack/test/functional/es_archives/monitoring/singlecluster_three_nodes_shard_relocation_mb',
{
from: 'Oct 5, 2017 @ 20:31:48.354',
to: 'Oct 5, 2017 @ 20:35:12.176',
to: 'Oct 5, 2017 @ 20:35:30.176',
useCreate: true,
}
);
@ -82,6 +82,12 @@ export default function ({ getService, getPageObjects }) {
health: 'Health: yellow',
});
});
it('should show the link to view more index logs', async () => {
await indicesList.clickRowByName('phone-home');
expect(await indexDetail.viewLogsLinkIsShowing()).to.be(true);
});
});
});
}

View file

@ -23,7 +23,7 @@ export default function ({ getService, getPageObjects }) {
'x-pack/test/functional/es_archives/monitoring/singlecluster_three_nodes_shard_relocation',
{
from: 'Oct 5, 2017 @ 20:31:48.354',
to: 'Oct 5, 2017 @ 20:35:12.176',
to: 'Oct 5, 2017 @ 20:35:30.176',
}
);
@ -47,7 +47,7 @@ export default function ({ getService, getPageObjects }) {
expect(await nodeDetail.getSummary()).to.eql({
transportAddress: 'Transport Address\n127.0.0.1:9300',
jvmHeap: 'JVM Heap\n29%',
jvmHeap: 'JVM Heap\n41%',
freeDiskSpace: 'Free Disk Space\n173.9 GB (37.42%)',
documentCount: 'Documents\n24.8k',
dataSize: 'Data\n50.4 MB',
@ -58,21 +58,27 @@ export default function ({ getService, getPageObjects }) {
});
});
it('should show node summary of data node with 4 indices and 4 shards', async () => {
it('should show node summary of data node with 5 indices and 5 shards', async () => {
await nodesList.clickRowByResolver('bwQWH-7IQY-mFPpfoaoFXQ');
expect(await nodeDetail.getSummary()).to.eql({
transportAddress: 'Transport Address\n127.0.0.1:9302',
jvmHeap: 'JVM Heap\n17%',
jvmHeap: 'JVM Heap\n28%',
freeDiskSpace: 'Free Disk Space\n173.9 GB (37.42%)',
documentCount: 'Documents\n240',
documentCount: 'Documents\n247',
dataSize: 'Data\n1.4 MB',
indicesCount: 'Indices\n4',
shardsCount: 'Shards\n4',
indicesCount: 'Indices\n5',
shardsCount: 'Shards\n5',
nodeType: 'Type\nNode',
status: 'Status: Online',
});
});
it('should show the link to view more node logs', async () => {
await nodesList.clickRowByResolver('jUT5KdxfRbORSCWkb5zjmA');
expect(await nodeDetail.viewLogsLinkIsShowing()).to.be(true);
});
});
describe('Offline Node', () => {

View file

@ -23,7 +23,7 @@ export default function ({ getService, getPageObjects }) {
'x-pack/test/functional/es_archives/monitoring/singlecluster_three_nodes_shard_relocation_mb',
{
from: 'Oct 5, 2017 @ 20:31:48.354',
to: 'Oct 5, 2017 @ 20:35:12.176',
to: 'Oct 5, 2017 @ 20:35:30.176',
useCreate: true,
}
);
@ -48,7 +48,7 @@ export default function ({ getService, getPageObjects }) {
expect(await nodeDetail.getSummary()).to.eql({
transportAddress: 'Transport Address\n127.0.0.1:9300',
jvmHeap: 'JVM Heap\n29%',
jvmHeap: 'JVM Heap\n41%',
freeDiskSpace: 'Free Disk Space\n173.9 GB (37.42%)',
documentCount: 'Documents\n24.8k',
dataSize: 'Data\n50.4 MB',
@ -59,21 +59,27 @@ export default function ({ getService, getPageObjects }) {
});
});
it('should show node summary of data node with 4 indices and 4 shards', async () => {
it('should show node summary of data node with 5 indices and 5 shards', async () => {
await nodesList.clickRowByResolver('bwQWH-7IQY-mFPpfoaoFXQ');
expect(await nodeDetail.getSummary()).to.eql({
transportAddress: 'Transport Address\n127.0.0.1:9302',
jvmHeap: 'JVM Heap\n17%',
jvmHeap: 'JVM Heap\n28%',
freeDiskSpace: 'Free Disk Space\n173.9 GB (37.42%)',
documentCount: 'Documents\n240',
documentCount: 'Documents\n247',
dataSize: 'Data\n1.4 MB',
indicesCount: 'Indices\n4',
shardsCount: 'Shards\n4',
indicesCount: 'Indices\n5',
shardsCount: 'Shards\n5',
nodeType: 'Type\nNode',
status: 'Status: Online',
});
});
it('should show the link to view more node logs', async () => {
await nodesList.clickRowByResolver('jUT5KdxfRbORSCWkb5zjmA');
expect(await nodeDetail.viewLogsLinkIsShowing()).to.be(true);
});
});
describe('Offline Node', () => {

View file

@ -21,7 +21,7 @@ export default function ({ getService, getPageObjects }) {
'x-pack/test/functional/es_archives/monitoring/singlecluster_three_nodes_shard_relocation',
{
from: 'Oct 5, 2017 @ 20:31:48.354',
to: 'Oct 5, 2017 @ 20:35:12.176',
to: 'Oct 5, 2017 @ 20:35:30.176',
}
);
@ -39,14 +39,18 @@ export default function ({ getService, getPageObjects }) {
it('should have an Elasticsearch Cluster Summary Status with correct info', async () => {
expect(await esClusterSummaryStatus.getContent()).to.eql({
nodesCount: 'Nodes\n3',
indicesCount: 'Indices\n20',
memory: 'JVM Heap\n575.3 MB / 2.0 GB',
totalShards: 'Total shards\n80',
indicesCount: 'Indices\n21',
memory: 'JVM Heap\n629.3 MB / 2.0 GB',
totalShards: 'Total shards\n82',
unassignedShards: 'Unassigned shards\n5',
documentCount: 'Documents\n25,927',
dataSize: 'Data\n101.6 MB',
documentCount: 'Documents\n26,062',
dataSize: 'Data\n101.9 MB',
health: 'Health: yellow',
});
});
it('should show the link to view more cluster logs', async () => {
expect(await esClusterSummaryStatus.viewLogsLinkIsShowing()).to.be(true);
});
});
}

View file

@ -21,7 +21,7 @@ export default function ({ getService, getPageObjects }) {
'x-pack/test/functional/es_archives/monitoring/singlecluster_three_nodes_shard_relocation_mb',
{
from: 'Oct 5, 2017 @ 20:31:48.354',
to: 'Oct 5, 2017 @ 20:35:12.176',
to: 'Oct 5, 2017 @ 20:35:30.176',
useCreate: true,
}
);
@ -40,14 +40,18 @@ export default function ({ getService, getPageObjects }) {
it('should have an Elasticsearch Cluster Summary Status with correct info', async () => {
expect(await esClusterSummaryStatus.getContent()).to.eql({
nodesCount: 'Nodes\n3',
indicesCount: 'Indices\n20',
memory: 'JVM Heap\n575.3 MB / 2.0 GB',
totalShards: 'Total shards\n80',
indicesCount: 'Indices\n21',
memory: 'JVM Heap\n629.3 MB / 2.0 GB',
totalShards: 'Total shards\n82',
unassignedShards: 'Unassigned shards\n5',
documentCount: 'Documents\n25,927',
dataSize: 'Data\n101.6 MB',
documentCount: 'Documents\n26,062',
dataSize: 'Data\n101.9 MB',
health: 'Health: yellow',
});
});
it('should show the link to view more cluster logs', async () => {
expect(await esClusterSummaryStatus.viewLogsLinkIsShowing()).to.be(true);
});
});
}

View file

@ -241,6 +241,20 @@ export default async function ({ readConfigFile }) {
},
kibana: [],
},
test_filebeat_reader: {
elasticsearch: {
cluster: [],
indices: [
{
names: ['filebeat*'],
privileges: ['read', 'view_index_metadata'],
field_security: { grant: ['*'], except: [] },
},
],
run_as: [],
},
kibana: [],
},
global_canvas_all: {
kibana: [

View file

@ -16,6 +16,9 @@ export function MonitoringElasticsearchIndexDetailProvider({ getService }) {
const SUBJ_SUMMARY_UNASSIGNED_SHARDS = `${SUBJ_SUMMARY} > unassignedShards`;
const SUBJ_SUMMARY_HEALTH = `${SUBJ_SUMMARY} > statusIcon`;
const SUBJ_SUMMARY_LOGS = 'monitoringLogs';
const SUBJ_SUMMARY_LOGS_LINK = `${SUBJ_SUMMARY_LOGS} > monitoringLogsLink`;
return new (class ElasticsearchIndexDetail {
async getSummary() {
return {
@ -27,5 +30,9 @@ export function MonitoringElasticsearchIndexDetailProvider({ getService }) {
health: await testSubjects.getAttribute(SUBJ_SUMMARY_HEALTH, 'alt'),
};
}
viewLogsLinkIsShowing() {
return testSubjects.exists(SUBJ_SUMMARY_LOGS_LINK);
}
})();
}

View file

@ -19,6 +19,9 @@ export function MonitoringElasticsearchNodeDetailProvider({ getService }) {
const SUBJ_SUMMARY_NODE_TYPE = `${SUBJ_SUMMARY} > nodeType`;
const SUBJ_SUMMARY_STATUS = `${SUBJ_SUMMARY} > statusIcon`;
const SUBJ_SUMMARY_LOGS = 'monitoringLogs';
const SUBJ_SUMMARY_LOGS_LINK = `${SUBJ_SUMMARY_LOGS} > monitoringLogsLink`;
return new (class ElasticsearchNodeDetail {
async clickAdvanced() {
return testSubjects.click('esItemDetailAdvancedLink');
@ -37,5 +40,9 @@ export function MonitoringElasticsearchNodeDetailProvider({ getService }) {
status: await testSubjects.getAttribute(SUBJ_SUMMARY_STATUS, 'alt'),
};
}
viewLogsLinkIsShowing() {
return testSubjects.exists(SUBJ_SUMMARY_LOGS_LINK);
}
})();
}

View file

@ -18,6 +18,9 @@ export function MonitoringElasticsearchSummaryStatusProvider({ getService }) {
const SUBJ_SUMMARY_DATA_SIZE = `${SUBJ_SUMMARY} > dataSize`;
const SUBJ_SUMMARY_HEALTH = `${SUBJ_SUMMARY} > statusIcon`;
const SUBJ_SUMMARY_LOGS = 'monitoringLogs';
const SUBJ_SUMMARY_LOGS_LINK = `${SUBJ_SUMMARY_LOGS} > monitoringLogsLink`;
return new (class ElasticsearchSummaryStatus {
async getContent() {
return {
@ -31,5 +34,9 @@ export function MonitoringElasticsearchSummaryStatusProvider({ getService }) {
health: await testSubjects.getAttribute(SUBJ_SUMMARY_HEALTH, 'alt'),
};
}
viewLogsLinkIsShowing() {
return testSubjects.exists(SUBJ_SUMMARY_LOGS_LINK);
}
})();
}