mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[Stack Monitoring] Migrate logs-related components to TypeScript (#203536)
## Summary A recent [bug](https://github.com/elastic/kibana/issues/199902) that affected some of the pages in Stack Monitoring was caused by changes related to the locators of the logs-related apps. The issue wasn't caught by type checks as the affected area in the monitoring plugin was written in JavaScript. The goal of this PR is to migrate the logs-related components to TypeScript. ### Testing The stateful environment deployed by this PR includes logs and metrics for stack monitoring. Please make sure to select a larger time range (e.g. last 14 days).
This commit is contained in:
parent
e061b4c352
commit
46a1535f03
8 changed files with 71 additions and 29 deletions
|
@ -14,6 +14,7 @@ export interface ExternalConfig {
|
|||
renderReactApp: boolean;
|
||||
staleStatusThresholdSeconds: number;
|
||||
isCcsEnabled: boolean;
|
||||
logsIndices: string;
|
||||
}
|
||||
|
||||
export const ExternalConfigContext = createContext({} as ExternalConfig);
|
||||
|
|
|
@ -29,7 +29,7 @@ const sharePlugin = {
|
|||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
} as unknown as ReturnType<typeof sharePluginMock.createStartContract>;
|
||||
|
||||
const logs = {
|
||||
enabled: true,
|
|
@ -8,16 +8,42 @@
|
|||
import React, { PureComponent, useContext } from 'react';
|
||||
import { RedirectAppLinks } from '@kbn/shared-ux-link-redirect-app';
|
||||
import { upperFirst } from 'lodash';
|
||||
import { Legacy } from '../../legacy_shims';
|
||||
import { EuiBasicTable, EuiTitle, EuiSpacer, EuiText, EuiCallOut, EuiLink } from '@elastic/eui';
|
||||
import { formatDateTimeLocal } from '../../../common/formatting';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { Reason } from './reason';
|
||||
import { useKibana } from '@kbn/kibana-react-plugin/public';
|
||||
import { SharePluginStart } from '@kbn/share-plugin/public';
|
||||
import { Reason, type IReason } from './reason';
|
||||
import { formatDateTimeLocal } from '../../../common/formatting';
|
||||
import { Legacy } from '../../legacy_shims';
|
||||
import { ExternalConfigContext } from '../../application/contexts/external_config_context';
|
||||
import { MonitoringStartServices } from '../../types';
|
||||
|
||||
const getFormattedDateTimeLocal = (timestamp) => {
|
||||
interface LogsProps {
|
||||
logs: {
|
||||
logs?: Array<{
|
||||
timestamp: string;
|
||||
component: string;
|
||||
level: string;
|
||||
type: string;
|
||||
node: string;
|
||||
message: string;
|
||||
}>;
|
||||
enabled: boolean;
|
||||
limit: number;
|
||||
reason?: IReason;
|
||||
};
|
||||
nodeId?: string;
|
||||
indexUuid?: string;
|
||||
clusterUuid?: string;
|
||||
}
|
||||
|
||||
interface LogsContentProps extends LogsProps {
|
||||
sharePlugin: SharePluginStart;
|
||||
logsIndices: string;
|
||||
}
|
||||
|
||||
const getFormattedDateTimeLocal = (timestamp: number | Date) => {
|
||||
const timezone = Legacy.shims.uiSettings?.get('dateFormat:tz');
|
||||
return formatDateTimeLocal(timestamp, timezone);
|
||||
};
|
||||
|
@ -51,7 +77,7 @@ const columns = [
|
|||
field: 'timestamp',
|
||||
name: columnTimestampTitle,
|
||||
width: '12%',
|
||||
render: (timestamp) => getFormattedDateTimeLocal(timestamp),
|
||||
render: (timestamp: number | Date) => getFormattedDateTimeLocal(timestamp),
|
||||
},
|
||||
{
|
||||
field: 'level',
|
||||
|
@ -62,7 +88,7 @@ const columns = [
|
|||
field: 'type',
|
||||
name: columnTypeTitle,
|
||||
width: '10%',
|
||||
render: (type) => upperFirst(type),
|
||||
render: (type: string) => upperFirst(type),
|
||||
},
|
||||
{
|
||||
field: 'message',
|
||||
|
@ -81,7 +107,7 @@ const clusterColumns = [
|
|||
field: 'timestamp',
|
||||
name: columnTimestampTitle,
|
||||
width: '12%',
|
||||
render: (timestamp) => getFormattedDateTimeLocal(timestamp),
|
||||
render: (timestamp: number | Date) => getFormattedDateTimeLocal(timestamp),
|
||||
},
|
||||
{
|
||||
field: 'level',
|
||||
|
@ -92,7 +118,7 @@ const clusterColumns = [
|
|||
field: 'type',
|
||||
name: columnTypeTitle,
|
||||
width: '10%',
|
||||
render: (type) => upperFirst(type),
|
||||
render: (type: string) => upperFirst(type),
|
||||
},
|
||||
{
|
||||
field: 'message',
|
||||
|
@ -111,7 +137,13 @@ const clusterColumns = [
|
|||
},
|
||||
];
|
||||
|
||||
function getDiscoverLink(clusterUuid, nodeId, indexUuid, sharePlugin, logsIndices) {
|
||||
function getDiscoverLink(
|
||||
clusterUuid?: string,
|
||||
nodeId?: string,
|
||||
indexUuid?: string,
|
||||
sharePlugin?: SharePluginStart,
|
||||
logsIndices?: string
|
||||
) {
|
||||
const params = [];
|
||||
if (clusterUuid) {
|
||||
params.push(`elasticsearch.cluster.uuid:${clusterUuid}`);
|
||||
|
@ -124,13 +156,9 @@ function getDiscoverLink(clusterUuid, nodeId, indexUuid, sharePlugin, logsIndice
|
|||
}
|
||||
|
||||
const filter = params.join(' and ');
|
||||
const discoverLocator = sharePlugin.url.locators.get('DISCOVER_APP_LOCATOR');
|
||||
const discoverLocator = sharePlugin?.url.locators.get('DISCOVER_APP_LOCATOR');
|
||||
|
||||
if (!discoverLocator) {
|
||||
return;
|
||||
}
|
||||
|
||||
const base = discoverLocator.getRedirectUrl({
|
||||
const base = discoverLocator?.getRedirectUrl({
|
||||
dataViewSpec: {
|
||||
id: logsIndices,
|
||||
title: logsIndices,
|
||||
|
@ -144,14 +172,15 @@ function getDiscoverLink(clusterUuid, nodeId, indexUuid, sharePlugin, logsIndice
|
|||
return base;
|
||||
}
|
||||
|
||||
export const Logs = (props) => {
|
||||
export const Logs = (props: LogsProps) => {
|
||||
const {
|
||||
services: { share },
|
||||
} = useKibana();
|
||||
} = useKibana<MonitoringStartServices>();
|
||||
const externalConfig = useContext(ExternalConfigContext);
|
||||
return <LogsContent sharePlugin={share} logsIndices={externalConfig.logsIndices} {...props} />;
|
||||
};
|
||||
export class LogsContent extends PureComponent {
|
||||
|
||||
export class LogsContent extends PureComponent<LogsContentProps> {
|
||||
renderLogs() {
|
||||
const {
|
||||
logs: { enabled, logs },
|
|
@ -12,7 +12,19 @@ import { FormattedMessage } from '@kbn/i18n-react';
|
|||
import { Legacy } from '../../legacy_shims';
|
||||
import { Monospace } from '../metricbeat_migration/instruction_steps/components/monospace/monospace';
|
||||
|
||||
export const Reason = ({ reason }) => {
|
||||
export interface IReason {
|
||||
indexPatternExists?: boolean;
|
||||
indexPatternInTimeRangeExists?: boolean;
|
||||
typeExists?: boolean;
|
||||
typeExistsAtAnyTime?: boolean;
|
||||
usingStructuredLogs?: boolean;
|
||||
clusterExists?: boolean;
|
||||
nodeExists?: boolean | null;
|
||||
indexExists?: boolean;
|
||||
correctIndexName?: boolean;
|
||||
}
|
||||
|
||||
export const Reason = ({ reason }: { reason?: IReason }) => {
|
||||
const filebeatUrl = Legacy.shims.docLinks.links.filebeat.installation;
|
||||
const elasticsearchUrl = Legacy.shims.docLinks.links.filebeat.elasticsearchModule;
|
||||
const troubleshootUrl = Legacy.shims.docLinks.links.monitoring.troubleshootKibana;
|
||||
|
@ -36,7 +48,7 @@ export const Reason = ({ reason }) => {
|
|||
/>
|
||||
);
|
||||
|
||||
if (false === reason.indexPatternExists) {
|
||||
if (false === reason?.indexPatternExists) {
|
||||
title = i18n.translate('xpack.monitoring.logs.reason.noIndexPatternTitle', {
|
||||
defaultMessage: 'No log data found',
|
||||
});
|
||||
|
@ -56,8 +68,8 @@ export const Reason = ({ reason }) => {
|
|||
/>
|
||||
);
|
||||
} else if (
|
||||
false === reason.indexPatternInTimeRangeExists ||
|
||||
(false === reason.typeExists && reason.typeExistsAtAnyTime)
|
||||
false === reason?.indexPatternInTimeRangeExists ||
|
||||
(false === reason?.typeExists && reason.typeExistsAtAnyTime)
|
||||
) {
|
||||
title = i18n.translate('xpack.monitoring.logs.reason.noIndexPatternInTimePeriodTitle', {
|
||||
defaultMessage: 'No logs for the selected time',
|
||||
|
@ -68,7 +80,7 @@ export const Reason = ({ reason }) => {
|
|||
defaultMessage="Use the time filter to adjust your timeframe."
|
||||
/>
|
||||
);
|
||||
} else if (false === reason.typeExists) {
|
||||
} else if (false === reason?.typeExists) {
|
||||
title = i18n.translate('xpack.monitoring.logs.reason.noTypeTitle', {
|
||||
defaultMessage: 'No logs for Elasticsearch',
|
||||
});
|
||||
|
@ -87,7 +99,7 @@ export const Reason = ({ reason }) => {
|
|||
}}
|
||||
/>
|
||||
);
|
||||
} else if (false === reason.usingStructuredLogs) {
|
||||
} else if (false === reason?.usingStructuredLogs) {
|
||||
title = i18n.translate('xpack.monitoring.logs.reason.notUsingStructuredLogsTitle', {
|
||||
defaultMessage: 'No structured logs found',
|
||||
});
|
||||
|
@ -107,7 +119,7 @@ export const Reason = ({ reason }) => {
|
|||
}}
|
||||
/>
|
||||
);
|
||||
} else if (false === reason.clusterExists) {
|
||||
} else if (false === reason?.clusterExists) {
|
||||
title = i18n.translate('xpack.monitoring.logs.reason.noClusterTitle', {
|
||||
defaultMessage: 'No logs for this cluster',
|
||||
});
|
||||
|
@ -126,7 +138,7 @@ export const Reason = ({ reason }) => {
|
|||
}}
|
||||
/>
|
||||
);
|
||||
} else if (false === reason.nodeExists) {
|
||||
} else if (false === reason?.nodeExists) {
|
||||
title = i18n.translate('xpack.monitoring.logs.reason.noNodeTitle', {
|
||||
defaultMessage: 'No logs for this Elasticsearch node',
|
||||
});
|
||||
|
@ -145,7 +157,7 @@ export const Reason = ({ reason }) => {
|
|||
}}
|
||||
/>
|
||||
);
|
||||
} else if (false === reason.indexExists) {
|
||||
} else if (false === reason?.indexExists) {
|
||||
title = i18n.translate('xpack.monitoring.logs.reason.noIndexTitle', {
|
||||
defaultMessage: 'No logs for this index',
|
||||
});
|
||||
|
@ -164,7 +176,7 @@ export const Reason = ({ reason }) => {
|
|||
}}
|
||||
/>
|
||||
);
|
||||
} else if (false === reason.correctIndexName) {
|
||||
} else if (false === reason?.correctIndexName) {
|
||||
title = i18n.translate('xpack.monitoring.logs.reason.correctIndexNameTitle', {
|
||||
defaultMessage: 'Corrupted filebeat index',
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue