mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[Status UI] Use the new output format of API GET /api/status
(#107937)
This commit is contained in:
parent
6d2c1da2ba
commit
def97bd734
8 changed files with 149 additions and 106 deletions
|
@ -8,7 +8,7 @@ pageLoadAssetSize:
|
|||
charts: 95000
|
||||
cloud: 21076
|
||||
console: 46091
|
||||
core: 434325
|
||||
core: 435325
|
||||
crossClusterReplication: 65408
|
||||
dashboard: 374194
|
||||
dashboardEnhanced: 65646
|
||||
|
|
|
@ -27,7 +27,7 @@ exports[`StatusTable renders when statuses is provided 1`] = `
|
|||
Object {
|
||||
"id": "plugin:1",
|
||||
"state": Object {
|
||||
"id": "green",
|
||||
"id": "available",
|
||||
"message": "Ready",
|
||||
"title": "green",
|
||||
"uiColor": "secondary",
|
||||
|
|
|
@ -12,7 +12,7 @@ import { ServerStatus } from './server_status';
|
|||
import { FormattedStatus } from '../lib';
|
||||
|
||||
const getStatus = (parts: Partial<FormattedStatus['state']> = {}): FormattedStatus['state'] => ({
|
||||
id: 'green',
|
||||
id: 'available',
|
||||
title: 'Green',
|
||||
uiColor: 'secondary',
|
||||
message: '',
|
||||
|
@ -29,7 +29,7 @@ describe('ServerStatus', () => {
|
|||
|
||||
it('renders correctly for red state', () => {
|
||||
const status = getStatus({
|
||||
id: 'red',
|
||||
id: 'unavailable',
|
||||
title: 'Red',
|
||||
});
|
||||
const component = mount(<ServerStatus serverState={status} name="My Computer" />);
|
||||
|
|
|
@ -11,7 +11,7 @@ import { shallow } from 'enzyme';
|
|||
import { StatusTable } from './status_table';
|
||||
|
||||
const state = {
|
||||
id: 'green',
|
||||
id: 'available' as const,
|
||||
uiColor: 'secondary',
|
||||
message: 'Ready',
|
||||
title: 'green',
|
||||
|
|
|
@ -17,36 +17,37 @@ const mockedResponse: StatusResponse = {
|
|||
version: {
|
||||
number: '8.0.0',
|
||||
build_hash: '9007199254740991',
|
||||
build_number: '12',
|
||||
build_snapshot: 'XXXXXXXX',
|
||||
build_number: 12,
|
||||
build_snapshot: false,
|
||||
},
|
||||
status: {
|
||||
overall: {
|
||||
id: 'overall',
|
||||
state: 'yellow',
|
||||
title: 'Yellow',
|
||||
message: 'yellow',
|
||||
uiColor: 'secondary',
|
||||
level: 'degraded',
|
||||
summary: 'yellow',
|
||||
},
|
||||
statuses: [
|
||||
{
|
||||
id: 'plugin:1',
|
||||
state: 'green',
|
||||
title: 'Green',
|
||||
message: 'Ready',
|
||||
uiColor: 'secondary',
|
||||
core: {
|
||||
elasticsearch: {
|
||||
level: 'available',
|
||||
summary: 'Elasticsearch is available',
|
||||
},
|
||||
{
|
||||
id: 'plugin:2',
|
||||
state: 'yellow',
|
||||
title: 'Yellow',
|
||||
message: 'Something is weird',
|
||||
uiColor: 'warning',
|
||||
savedObjects: {
|
||||
level: 'available',
|
||||
summary: 'SavedObjects service has completed migrations and is available',
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: {
|
||||
'1': {
|
||||
level: 'available',
|
||||
summary: 'Ready',
|
||||
},
|
||||
'2': {
|
||||
level: 'degraded',
|
||||
summary: 'Something is weird',
|
||||
},
|
||||
},
|
||||
},
|
||||
metrics: {
|
||||
collected_at: new Date('2020-01-01 01:00:00'),
|
||||
last_updated: '2020-01-01 01:00:00',
|
||||
collection_interval_in_millis: 1000,
|
||||
os: {
|
||||
platform: 'darwin' as const,
|
||||
|
@ -80,6 +81,7 @@ const mockedResponse: StatusResponse = {
|
|||
disconnects: 1,
|
||||
total: 400,
|
||||
statusCodes: {},
|
||||
status_codes: {},
|
||||
},
|
||||
concurrent_connections: 1,
|
||||
},
|
||||
|
@ -148,13 +150,36 @@ describe('response processing', () => {
|
|||
test('includes the plugin statuses', async () => {
|
||||
const data = await loadStatus({ http, notifications });
|
||||
expect(data.statuses).toEqual([
|
||||
{
|
||||
id: 'core:elasticsearch',
|
||||
state: {
|
||||
id: 'available',
|
||||
title: 'Green',
|
||||
message: 'Elasticsearch is available',
|
||||
uiColor: 'secondary',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'core:savedObjects',
|
||||
state: {
|
||||
id: 'available',
|
||||
title: 'Green',
|
||||
message: 'SavedObjects service has completed migrations and is available',
|
||||
uiColor: 'secondary',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'plugin:1',
|
||||
state: { id: 'green', title: 'Green', message: 'Ready', uiColor: 'secondary' },
|
||||
state: { id: 'available', title: 'Green', message: 'Ready', uiColor: 'secondary' },
|
||||
},
|
||||
{
|
||||
id: 'plugin:2',
|
||||
state: { id: 'yellow', title: 'Yellow', message: 'Something is weird', uiColor: 'warning' },
|
||||
state: {
|
||||
id: 'degraded',
|
||||
title: 'Yellow',
|
||||
message: 'Something is weird',
|
||||
uiColor: 'warning',
|
||||
},
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
@ -162,10 +187,10 @@ describe('response processing', () => {
|
|||
test('includes the serverState', async () => {
|
||||
const data = await loadStatus({ http, notifications });
|
||||
expect(data.serverState).toEqual({
|
||||
id: 'yellow',
|
||||
id: 'degraded',
|
||||
title: 'Yellow',
|
||||
message: 'yellow',
|
||||
uiColor: 'secondary',
|
||||
uiColor: 'warning',
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import type { UnwrapPromise } from '@kbn/utility-types';
|
||||
import type { ServerStatus, StatusResponse } from '../../../../types/status';
|
||||
import type { StatusResponse, ServiceStatus, ServiceStatusLevel } from '../../../../types/status';
|
||||
import type { HttpSetup } from '../../../http';
|
||||
import type { NotificationsSetup } from '../../../notifications';
|
||||
import type { DataType } from '../lib';
|
||||
|
@ -22,13 +22,18 @@ export interface Metric {
|
|||
export interface FormattedStatus {
|
||||
id: string;
|
||||
state: {
|
||||
id: string;
|
||||
id: ServiceStatusLevel;
|
||||
title: string;
|
||||
message: string;
|
||||
uiColor: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface StatusUIAttributes {
|
||||
title: string;
|
||||
uiColor: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object of any keys that should be included for metrics.
|
||||
*/
|
||||
|
@ -86,18 +91,47 @@ function formatMetrics({ metrics }: StatusResponse): Metric[] {
|
|||
/**
|
||||
* Reformat the backend data to make the frontend views simpler.
|
||||
*/
|
||||
function formatStatus(status: ServerStatus): FormattedStatus {
|
||||
function formatStatus(id: string, status: ServiceStatus): FormattedStatus {
|
||||
const { title, uiColor } = STATUS_LEVEL_UI_ATTRS[status.level];
|
||||
|
||||
return {
|
||||
id: status.id,
|
||||
id,
|
||||
state: {
|
||||
id: status.state,
|
||||
title: status.title,
|
||||
message: status.message,
|
||||
uiColor: status.uiColor,
|
||||
id: status.level,
|
||||
message: status.summary,
|
||||
title,
|
||||
uiColor,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const STATUS_LEVEL_UI_ATTRS: Record<ServiceStatusLevel, StatusUIAttributes> = {
|
||||
critical: {
|
||||
title: i18n.translate('core.status.redTitle', {
|
||||
defaultMessage: 'Red',
|
||||
}),
|
||||
uiColor: 'danger',
|
||||
},
|
||||
unavailable: {
|
||||
title: i18n.translate('core.status.redTitle', {
|
||||
defaultMessage: 'Red',
|
||||
}),
|
||||
uiColor: 'danger',
|
||||
},
|
||||
degraded: {
|
||||
title: i18n.translate('core.status.yellowTitle', {
|
||||
defaultMessage: 'Yellow',
|
||||
}),
|
||||
uiColor: 'warning',
|
||||
},
|
||||
available: {
|
||||
title: i18n.translate('core.status.greenTitle', {
|
||||
defaultMessage: 'Green',
|
||||
}),
|
||||
uiColor: 'secondary',
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the status from the server API and format it for display.
|
||||
*/
|
||||
|
@ -111,7 +145,7 @@ export async function loadStatus({
|
|||
let response: StatusResponse;
|
||||
|
||||
try {
|
||||
response = await http.get('/api/status');
|
||||
response = await http.get('/api/status', { query: { v8format: true } });
|
||||
} catch (e) {
|
||||
// API returns a 503 response if not all services are available.
|
||||
// In this case, we want to treat this as a successful API call, so that we can
|
||||
|
@ -144,8 +178,15 @@ export async function loadStatus({
|
|||
return {
|
||||
name: response.name,
|
||||
version: response.version,
|
||||
statuses: response.status.statuses.map(formatStatus),
|
||||
serverState: formatStatus(response.status.overall).state,
|
||||
statuses: [
|
||||
...Object.entries(response.status.core).map(([serviceName, status]) =>
|
||||
formatStatus(`core:${serviceName}`, status)
|
||||
),
|
||||
...Object.entries(response.status.plugins).map(([pluginName, status]) =>
|
||||
formatStatus(`plugin:${pluginName}`, status)
|
||||
),
|
||||
],
|
||||
serverState: formatStatus('overall', response.status.overall).state,
|
||||
metrics: formatMetrics(response),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import { ServiceStatus, CoreStatus, ServiceStatusLevels } from '../types';
|
|||
import { PluginName } from '../../plugins';
|
||||
import { calculateLegacyStatus, LegacyStatusInfo } from '../legacy_status';
|
||||
import { PackageInfo } from '../../config';
|
||||
import { StatusResponse } from '../../../types/status';
|
||||
|
||||
const SNAPSHOT_POSTFIX = /-SNAPSHOT$/;
|
||||
|
||||
|
@ -41,55 +42,9 @@ interface StatusInfo {
|
|||
plugins: Record<string, ServiceStatus>;
|
||||
}
|
||||
|
||||
interface StatusHttpBody {
|
||||
name: string;
|
||||
uuid: string;
|
||||
version: {
|
||||
number: string;
|
||||
build_hash: string;
|
||||
build_number: number;
|
||||
build_snapshot: boolean;
|
||||
};
|
||||
// The moment we remove support for the LegacyStatusInfo, we can use the StatusResponse straight away.
|
||||
interface StatusHttpBody extends Omit<StatusResponse, 'status'> {
|
||||
status: StatusInfo | LegacyStatusInfo;
|
||||
metrics: {
|
||||
/** ISO-8601 date string w/o timezone */
|
||||
last_updated: string;
|
||||
collection_interval_in_millis: number;
|
||||
process: {
|
||||
memory: {
|
||||
heap: {
|
||||
total_in_bytes: number;
|
||||
used_in_bytes: number;
|
||||
size_limit: number;
|
||||
};
|
||||
resident_set_size_in_bytes: number;
|
||||
};
|
||||
event_loop_delay: number;
|
||||
pid: number;
|
||||
uptime_in_millis: number;
|
||||
};
|
||||
os: {
|
||||
load: Record<string, number>;
|
||||
memory: {
|
||||
total_in_bytes: number;
|
||||
used_in_bytes: number;
|
||||
free_in_bytes: number;
|
||||
};
|
||||
uptime_in_millis: number;
|
||||
platform: string;
|
||||
platformRelease: string;
|
||||
};
|
||||
response_times: {
|
||||
max_in_millis: number;
|
||||
};
|
||||
requests: {
|
||||
total: number;
|
||||
disconnects: number;
|
||||
statusCodes: Record<number, number>;
|
||||
status_codes: Record<number, number>;
|
||||
};
|
||||
concurrent_connections: number;
|
||||
};
|
||||
}
|
||||
|
||||
export const registerStatusRoute = ({ router, config, metrics, status }: Deps) => {
|
||||
|
|
|
@ -6,36 +6,58 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { OpsMetrics } from '../server/metrics';
|
||||
import type {
|
||||
CoreStatus as CoreStatusFromServer,
|
||||
ServiceStatus as ServiceStatusFromServer,
|
||||
ServiceStatusLevel as ServiceStatusLevelFromServer,
|
||||
OpsMetrics,
|
||||
} from '../server';
|
||||
|
||||
export interface ServerStatus {
|
||||
id: string;
|
||||
title: string;
|
||||
state: string;
|
||||
message: string;
|
||||
uiColor: string;
|
||||
icon?: string;
|
||||
since?: string;
|
||||
/**
|
||||
* We need this type to convert the object `ServiceStatusLevel` to a union of the possible strings.
|
||||
* This is because of the "stringification" that occurs when serving HTTP requests.
|
||||
*/
|
||||
export type ServiceStatusLevel = ReturnType<ServiceStatusLevelFromServer['toString']>;
|
||||
|
||||
export interface ServiceStatus extends Omit<ServiceStatusFromServer, 'level'> {
|
||||
level: ServiceStatusLevel;
|
||||
}
|
||||
|
||||
export type ServerMetrics = OpsMetrics & {
|
||||
/**
|
||||
* Copy all the services listed in CoreStatus with their specific ServiceStatus declarations
|
||||
* but overwriting the `level` to its stringified version.
|
||||
*/
|
||||
export type CoreStatus = {
|
||||
[ServiceName in keyof CoreStatusFromServer]: Omit<CoreStatusFromServer[ServiceName], 'level'> & {
|
||||
level: ServiceStatusLevel;
|
||||
};
|
||||
};
|
||||
|
||||
export type ServerMetrics = Omit<OpsMetrics, 'collected_at'> & {
|
||||
last_updated: string;
|
||||
collection_interval_in_millis: number;
|
||||
requests: {
|
||||
status_codes: Record<number, number>;
|
||||
};
|
||||
};
|
||||
|
||||
export interface ServerVersion {
|
||||
number: string;
|
||||
build_hash: string;
|
||||
build_number: string;
|
||||
build_snapshot: string;
|
||||
build_number: number;
|
||||
build_snapshot: boolean;
|
||||
}
|
||||
|
||||
export interface StatusInfo {
|
||||
overall: ServiceStatus;
|
||||
core: CoreStatus;
|
||||
plugins: Record<string, ServiceStatus>;
|
||||
}
|
||||
|
||||
export interface StatusResponse {
|
||||
name: string;
|
||||
uuid: string;
|
||||
version: ServerVersion;
|
||||
status: {
|
||||
overall: ServerStatus;
|
||||
statuses: ServerStatus[];
|
||||
};
|
||||
status: StatusInfo;
|
||||
metrics: ServerMetrics;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue