mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
# Backport This will backport the following commits from `main` to `8.x`: - [[Synthetics] Fix overview status empty state !! (#193898)](https://github.com/elastic/kibana/pull/193898) <!--- Backport version: 9.4.3 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Shahzad","email":"shahzad31comp@gmail.com"},"sourceCommit":{"committedDate":"2024-09-25T06:10:56Z","message":"[Synthetics] Fix overview status empty state !! (#193898)\n\n## Summary\r\n\r\nFix overview status empty state !!\r\n\r\nFixes https://github.com/elastic/kibana/issues/193603\r\n\r\n---------\r\n\r\nCo-authored-by: Dominique Belcher <dominique.clarke@elastic.co>","sha":"7f6982789b66a5b014b4efd06e83e5282b97e0e3","branchLabelMapping":{"^v9.0.0$":"main","^v8.16.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","backport:prev-minor","ci:project-deploy-observability","Team:obs-ux-management"],"title":"[Synthetics] Fix overview status empty state !!","number":193898,"url":"https://github.com/elastic/kibana/pull/193898","mergeCommit":{"message":"[Synthetics] Fix overview status empty state !! (#193898)\n\n## Summary\r\n\r\nFix overview status empty state !!\r\n\r\nFixes https://github.com/elastic/kibana/issues/193603\r\n\r\n---------\r\n\r\nCo-authored-by: Dominique Belcher <dominique.clarke@elastic.co>","sha":"7f6982789b66a5b014b4efd06e83e5282b97e0e3"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/193898","number":193898,"mergeCommit":{"message":"[Synthetics] Fix overview status empty state !! (#193898)\n\n## Summary\r\n\r\nFix overview status empty state !!\r\n\r\nFixes https://github.com/elastic/kibana/issues/193603\r\n\r\n---------\r\n\r\nCo-authored-by: Dominique Belcher <dominique.clarke@elastic.co>","sha":"7f6982789b66a5b014b4efd06e83e5282b97e0e3"}}]}] BACKPORT--> Co-authored-by: Shahzad <shahzad31comp@gmail.com>
This commit is contained in:
parent
1524b53bb6
commit
93fcb9bc54
12 changed files with 121 additions and 84 deletions
|
@ -78,9 +78,9 @@ export const PublicLocationsCodec = t.array(PublicLocationCodec);
|
|||
export const MonitorServiceLocationCodec = t.intersection([
|
||||
t.interface({
|
||||
id: t.string,
|
||||
label: t.string,
|
||||
}),
|
||||
t.partial({
|
||||
label: t.string,
|
||||
geo: LocationGeoCodec,
|
||||
url: t.string,
|
||||
isServiceManaged: t.boolean,
|
||||
|
|
|
@ -63,6 +63,7 @@ export const OverviewStatusCodec = t.interface({
|
|||
upConfigs: t.record(t.string, OverviewStatusMetaDataCodec),
|
||||
downConfigs: t.record(t.string, OverviewStatusMetaDataCodec),
|
||||
pendingConfigs: t.record(t.string, OverviewStatusMetaDataCodec),
|
||||
disabledConfigs: t.record(t.string, OverviewStatusMetaDataCodec),
|
||||
enabledMonitorQueryIds: t.array(t.string),
|
||||
disabledMonitorQueryIds: t.array(t.string),
|
||||
allIds: t.array(t.string),
|
||||
|
|
|
@ -27,6 +27,7 @@ describe('defaults', () => {
|
|||
{
|
||||
id: 'us_central',
|
||||
isServiceManaged: true,
|
||||
label: 'US Central',
|
||||
},
|
||||
],
|
||||
name: 'Browser monitor',
|
||||
|
@ -89,6 +90,7 @@ describe('defaults', () => {
|
|||
{
|
||||
id: 'us_central',
|
||||
isServiceManaged: true,
|
||||
label: 'US Central',
|
||||
},
|
||||
],
|
||||
name: 'Browser monitor',
|
||||
|
|
|
@ -14,6 +14,7 @@ import {
|
|||
SyntheticsMonitor,
|
||||
BrowserFields,
|
||||
HTTPFields,
|
||||
ScheduleUnit,
|
||||
} from '../types';
|
||||
|
||||
export const getDefaultFormFields = (
|
||||
|
@ -61,15 +62,15 @@ export const formatDefaultFormValues = (monitor?: SyntheticsMonitor) => {
|
|||
|
||||
let formMonitorType = monitor[ConfigKey.FORM_MONITOR_TYPE];
|
||||
const monitorType = monitor[ConfigKey.MONITOR_TYPE];
|
||||
let schedule = monitor[ConfigKey.SCHEDULE];
|
||||
if (schedule?.unit === 's') {
|
||||
schedule = { number: `${schedule.number}s`, unit: 's' as ScheduleUnit };
|
||||
}
|
||||
const monitorWithFormMonitorType = {
|
||||
...monitor,
|
||||
[ConfigKey.SCHEDULE]: schedule,
|
||||
};
|
||||
|
||||
const schedule = monitor[ConfigKey.SCHEDULE];
|
||||
if (schedule?.unit === 's') {
|
||||
schedule.number = `${schedule.number}s`;
|
||||
}
|
||||
|
||||
const params = monitorWithFormMonitorType[ConfigKey.PARAMS];
|
||||
if (typeof params !== 'string' && params) {
|
||||
try {
|
||||
|
|
|
@ -53,6 +53,7 @@ export const overviewStatusReducer = createReducer(initialState, (builder) => {
|
|||
...action.payload.upConfigs,
|
||||
...action.payload.downConfigs,
|
||||
...action.payload.pendingConfigs,
|
||||
...action.payload.disabledConfigs,
|
||||
});
|
||||
state.disabledConfigs = state.allConfigs.filter((monitor) => !monitor.isEnabled);
|
||||
state.loaded = true;
|
||||
|
|
|
@ -438,7 +438,7 @@ function getMonitorDetailsMockSlice() {
|
|||
tags: [],
|
||||
timeout: null,
|
||||
name: 'One pixel monitor',
|
||||
locations: [{ isServiceManaged: true, id: 'us_central' }],
|
||||
locations: [{ isServiceManaged: true, id: 'us_central', label: 'US Central' }],
|
||||
namespace: 'default',
|
||||
origin: SourceType.UI,
|
||||
max_attempts: 2,
|
||||
|
|
|
@ -153,6 +153,23 @@ export async function queryMonitorStatus({
|
|||
const downConfigs: Record<string, OverviewStatusMetaData> = {};
|
||||
const monitorsWithoutData = new Map(Object.entries(cloneDeep(monitorLocationsMap)));
|
||||
const pendingConfigs: Record<string, OverviewStatusMetaData> = {};
|
||||
const disabledConfigs: Record<string, OverviewStatusMetaData> = {};
|
||||
|
||||
monitors
|
||||
.filter((monitor) => !monitor.attributes[ConfigKey.ENABLED])
|
||||
.forEach((monitor) => {
|
||||
const monitorQueryId = monitor.attributes[ConfigKey.MONITOR_QUERY_ID];
|
||||
monitor.attributes[ConfigKey.LOCATIONS]?.forEach((location) => {
|
||||
disabledConfigs[`${monitorQueryIdToConfigIdMap[monitorQueryId]}-${location.id}`] = {
|
||||
configId: `${monitorQueryIdToConfigIdMap[monitorQueryId]}`,
|
||||
monitorQueryId,
|
||||
status: 'disabled',
|
||||
locationId: location.id,
|
||||
locationLabel: location.label,
|
||||
...getMonitorMeta(monitor),
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
const queries: MsearchMultisearchBody[] = times(pageCount).map((i) => {
|
||||
const idsToQuery = (monitorQueryIds as string[]).slice(i * idSize, i * idSize + idSize);
|
||||
|
@ -164,78 +181,73 @@ export async function queryMonitorStatus({
|
|||
}).body;
|
||||
});
|
||||
|
||||
const { responses } = await esClient.msearch<StatusQueryParams, OverviewPing>(
|
||||
queries,
|
||||
'getCurrentStatusOverview'
|
||||
);
|
||||
if (queries.length) {
|
||||
const { responses } = await esClient.msearch<StatusQueryParams, OverviewPing>(
|
||||
queries,
|
||||
'getCurrentStatusOverview'
|
||||
);
|
||||
|
||||
responses.forEach((result) => {
|
||||
result.aggregations?.id.buckets.forEach(({ location, key: queryId }) => {
|
||||
const locationSummaries = location.buckets.map(({ status, key: locationName }) => {
|
||||
const ping = status.hits.hits[0]._source;
|
||||
return { location: locationName, ping };
|
||||
});
|
||||
responses.forEach((result) => {
|
||||
result.aggregations?.id.buckets.forEach(({ location, key: queryId }) => {
|
||||
const locationSummaries = location.buckets.map(({ status, key: locationName }) => {
|
||||
const ping = status.hits.hits[0]._source;
|
||||
return { location: locationName, ping };
|
||||
});
|
||||
|
||||
const monitor = monitors.find((m) => m.attributes[ConfigKey.MONITOR_QUERY_ID] === queryId)!;
|
||||
const monitor = monitors.find((m) => m.attributes[ConfigKey.MONITOR_QUERY_ID] === queryId)!;
|
||||
|
||||
// discard any locations that are not in the monitorLocationsMap for the given monitor as well as those which are
|
||||
// in monitorLocationsMap but not in listOfLocations
|
||||
const monLocations = monitorLocationsMap?.[queryId];
|
||||
const monQueriedLocations = intersection(monLocations, monitorLocationIds);
|
||||
monQueriedLocations?.forEach((monLocation) => {
|
||||
const locationSummary = locationSummaries.find(
|
||||
(summary) => summary.location === monLocation
|
||||
);
|
||||
|
||||
if (locationSummary) {
|
||||
const { ping } = locationSummary;
|
||||
const downCount = ping.summary?.down ?? 0;
|
||||
const upCount = ping.summary?.up ?? 0;
|
||||
const configId = ping.config_id;
|
||||
const monitorQueryId = ping.monitor.id;
|
||||
|
||||
const meta = {
|
||||
ping,
|
||||
configId,
|
||||
monitorQueryId,
|
||||
locationId: monLocation,
|
||||
timestamp: ping['@timestamp'],
|
||||
locationLabel: ping.observer.geo!.name!,
|
||||
name: monitor.attributes[ConfigKey.NAME],
|
||||
schedule: monitor.attributes[ConfigKey.SCHEDULE].number,
|
||||
tags: monitor.attributes[ConfigKey.TAGS],
|
||||
isEnabled: monitor.attributes[ConfigKey.ENABLED],
|
||||
type: monitor.attributes[ConfigKey.MONITOR_TYPE],
|
||||
projectId: monitor.attributes[ConfigKey.PROJECT_ID],
|
||||
isStatusAlertEnabled: isStatusEnabled(monitor.attributes[ConfigKey.ALERT_CONFIG]),
|
||||
updated_at: monitor.updated_at,
|
||||
};
|
||||
|
||||
if (downCount > 0) {
|
||||
down += 1;
|
||||
downConfigs[`${configId}-${monLocation}`] = {
|
||||
...meta,
|
||||
status: 'down',
|
||||
};
|
||||
} else if (upCount > 0) {
|
||||
up += 1;
|
||||
upConfigs[`${configId}-${monLocation}`] = {
|
||||
...meta,
|
||||
status: 'up',
|
||||
};
|
||||
}
|
||||
const monitorsMissingData = monitorsWithoutData.get(monitorQueryId) || [];
|
||||
monitorsWithoutData.set(
|
||||
monitorQueryId,
|
||||
monitorsMissingData?.filter((loc) => loc !== monLocation)
|
||||
// discard any locations that are not in the monitorLocationsMap for the given monitor as well as those which are
|
||||
// in monitorLocationsMap but not in listOfLocations
|
||||
const monLocations = monitorLocationsMap?.[queryId];
|
||||
const monQueriedLocations = intersection(monLocations, monitorLocationIds);
|
||||
monQueriedLocations?.forEach((monLocation) => {
|
||||
const locationSummary = locationSummaries.find(
|
||||
(summary) => summary.location === monLocation
|
||||
);
|
||||
if (!monitorsWithoutData.get(monitorQueryId)?.length) {
|
||||
monitorsWithoutData.delete(monitorQueryId);
|
||||
|
||||
if (locationSummary) {
|
||||
const { ping } = locationSummary;
|
||||
const downCount = ping.summary?.down ?? 0;
|
||||
const upCount = ping.summary?.up ?? 0;
|
||||
const configId = ping.config_id;
|
||||
const monitorQueryId = ping.monitor.id;
|
||||
|
||||
const meta = {
|
||||
ping,
|
||||
configId,
|
||||
monitorQueryId,
|
||||
locationId: monLocation,
|
||||
timestamp: ping['@timestamp'],
|
||||
locationLabel: ping.observer.geo!.name!,
|
||||
...getMonitorMeta(monitor),
|
||||
};
|
||||
|
||||
if (downCount > 0) {
|
||||
down += 1;
|
||||
downConfigs[`${configId}-${monLocation}`] = {
|
||||
...meta,
|
||||
status: 'down',
|
||||
};
|
||||
} else if (upCount > 0) {
|
||||
up += 1;
|
||||
upConfigs[`${configId}-${monLocation}`] = {
|
||||
...meta,
|
||||
status: 'up',
|
||||
};
|
||||
}
|
||||
const monitorsMissingData = monitorsWithoutData.get(monitorQueryId) || [];
|
||||
monitorsWithoutData.set(
|
||||
monitorQueryId,
|
||||
monitorsMissingData?.filter((loc) => loc !== monLocation)
|
||||
);
|
||||
if (!monitorsWithoutData.get(monitorQueryId)?.length) {
|
||||
monitorsWithoutData.delete(monitorQueryId);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// identify the remaining monitors without data, to determine pending monitors
|
||||
for (const [queryId, locs] of monitorsWithoutData) {
|
||||
|
@ -269,5 +281,19 @@ export async function queryMonitorStatus({
|
|||
downConfigs,
|
||||
pendingConfigs,
|
||||
enabledMonitorQueryIds: monitorQueryIds,
|
||||
disabledConfigs,
|
||||
};
|
||||
}
|
||||
|
||||
const getMonitorMeta = (monitor: SavedObjectsFindResult<EncryptedSyntheticsMonitorAttributes>) => {
|
||||
return {
|
||||
name: monitor.attributes[ConfigKey.NAME],
|
||||
schedule: monitor.attributes[ConfigKey.SCHEDULE].number,
|
||||
tags: monitor.attributes[ConfigKey.TAGS],
|
||||
isEnabled: monitor.attributes[ConfigKey.ENABLED],
|
||||
type: monitor.attributes[ConfigKey.MONITOR_TYPE],
|
||||
projectId: monitor.attributes[ConfigKey.PROJECT_ID],
|
||||
isStatusAlertEnabled: isStatusEnabled(monitor.attributes[ConfigKey.ALERT_CONFIG]),
|
||||
updated_at: monitor.updated_at,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -262,6 +262,7 @@ describe('current status route', () => {
|
|||
})
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"disabledConfigs": Object {},
|
||||
"down": 1,
|
||||
"downConfigs": Object {
|
||||
"id2-Europe - Germany": Object {
|
||||
|
@ -527,6 +528,7 @@ describe('current status route', () => {
|
|||
})
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"disabledConfigs": Object {},
|
||||
"down": 1,
|
||||
"downConfigs": Object {
|
||||
"id2-Europe - Germany": Object {
|
||||
|
@ -820,6 +822,7 @@ describe('current status route', () => {
|
|||
})
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"disabledConfigs": Object {},
|
||||
"down": 1,
|
||||
"downConfigs": Object {
|
||||
"id2-Europe - Germany": Object {
|
||||
|
|
|
@ -67,6 +67,7 @@ export async function getStatus(context: RouteContext, params: OverviewStatusQue
|
|||
ConfigKey.NAME,
|
||||
ConfigKey.TAGS,
|
||||
ConfigKey.PROJECT_ID,
|
||||
ConfigKey.ALERT_CONFIG,
|
||||
],
|
||||
});
|
||||
|
||||
|
@ -94,15 +95,16 @@ export async function getStatus(context: RouteContext, params: OverviewStatusQue
|
|||
to: 'now',
|
||||
};
|
||||
|
||||
const { up, down, pending, upConfigs, downConfigs, pendingConfigs } = await queryMonitorStatus({
|
||||
range,
|
||||
monitors: allMonitors,
|
||||
monitorLocationsMap,
|
||||
monitorQueryIdToConfigIdMap,
|
||||
esClient: syntheticsEsClient,
|
||||
monitorLocationIds: listOfLocationAfterFilter,
|
||||
monitorQueryIds: enabledMonitorQueryIds,
|
||||
});
|
||||
const { up, down, pending, upConfigs, downConfigs, pendingConfigs, disabledConfigs } =
|
||||
await queryMonitorStatus({
|
||||
range,
|
||||
monitors: allMonitors,
|
||||
monitorLocationsMap,
|
||||
monitorQueryIdToConfigIdMap,
|
||||
esClient: syntheticsEsClient,
|
||||
monitorLocationIds: listOfLocationAfterFilter,
|
||||
monitorQueryIds: enabledMonitorQueryIds,
|
||||
});
|
||||
|
||||
return {
|
||||
allIds,
|
||||
|
@ -118,6 +120,7 @@ export async function getStatus(context: RouteContext, params: OverviewStatusQue
|
|||
upConfigs,
|
||||
downConfigs,
|
||||
pendingConfigs,
|
||||
disabledConfigs,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ const monitor850UI = {
|
|||
tags: [],
|
||||
timeout: '16',
|
||||
name: 'Dominique Clarke',
|
||||
locations: [{ id: 'us_central', isServiceManaged: true }],
|
||||
locations: [{ id: 'us_central', isServiceManaged: true }] as any,
|
||||
namespace: 'default',
|
||||
origin: 'ui',
|
||||
journey_id: '',
|
||||
|
|
|
@ -27,7 +27,7 @@ export const httpUI = {
|
|||
tags: [],
|
||||
timeout: '16',
|
||||
name: 'Test monitor',
|
||||
locations: [{ id: 'us_central', isServiceManaged: true }],
|
||||
locations: [{ id: 'us_central', isServiceManaged: true }] as any,
|
||||
namespace: 'default',
|
||||
origin: 'ui',
|
||||
journey_id: '',
|
||||
|
|
|
@ -288,7 +288,7 @@ const dummyBrowserConfig: Partial<MonitorFields> & {
|
|||
tags: [],
|
||||
timeout: null,
|
||||
name: 'Browser monitor',
|
||||
locations: [{ isServiceManaged: false, id: '1' }],
|
||||
locations: [{ isServiceManaged: false, id: '1', label: 'Fleet managed' }],
|
||||
namespace: 'default',
|
||||
origin: SourceType.UI,
|
||||
journey_id: '',
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue