Skip to content

Commit

Permalink
[RAM] Add error logs in rule details page (#128925) (#129278)
Browse files Browse the repository at this point in the history
* add error log on details page + snooze

* refresh table in details page

* fix type

* add + fix jest test

* add test for error log

* remove console

* update functional test + delete flaky jest test + fix i18n

* review I

* remove skip

* review II

* remove disable panel

* clean up design

* fix check

* fix types

* Design tweaks to header, status dropdown, mobile

* remove dead code

* jest test

* fix actions layout

* review III

Co-authored-by: Ryan Keairns <[email protected]>
(cherry picked from commit d6b8e4b)
  • Loading branch information
XavierM authored Apr 3, 2022
1 parent 8374636 commit 2aa076a
Show file tree
Hide file tree
Showing 18 changed files with 1,048 additions and 637 deletions.
14 changes: 14 additions & 0 deletions x-pack/plugins/alerting/common/execution_log_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,21 @@ export interface IExecutionLog {
timed_out: boolean;
}

export interface IExecutionErrors {
id: string;
timestamp: string;
type: string;
message: string;
}

export interface IExecutionErrorsResult {
totalErrors: number;
errors: IExecutionErrors[];
}

export interface IExecutionLogResult {
total: number;
data: IExecutionLog[];
}

export type IExecutionLogWithErrorsResult = IExecutionLogResult & IExecutionErrorsResult;
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,14 @@

import { get } from 'lodash';
import { QueryEventsBySavedObjectResult, IValidatedEvent } from '../../../event_log/server';
import { IExecutionErrors, IExecutionErrorsResult } from '../../common';

const EXECUTION_UUID_FIELD = 'kibana.alert.rule.execution.uuid';
const TIMESTAMP_FIELD = '@timestamp';
const PROVIDER_FIELD = 'event.provider';
const MESSAGE_FIELD = 'message';
const ERROR_MESSAGE_FIELD = 'error.message';

export interface IExecutionErrors {
id: string;
timestamp: string;
type: string;
message: string;
}

export interface IExecutionErrorsResult {
totalErrors: number;
errors: IExecutionErrors[];
}

export const EMPTY_EXECUTION_ERRORS_RESULT = {
totalErrors: 0,
errors: [],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { licenseStateMock } from '../lib/license_state.mock';
import { mockHandlerArguments } from './_mock_handler_arguments';
import { SavedObjectsErrorHelpers } from 'src/core/server';
import { rulesClientMock } from '../rules_client.mock';
import { IExecutionLogWithErrorsResult } from '../rules_client';
import { IExecutionLogWithErrorsResult } from '../../common';

const rulesClient = rulesClientMock.create();
jest.mock('../lib/license_api_access.ts', () => ({
Expand Down
8 changes: 2 additions & 6 deletions x-pack/plugins/alerting/server/rules_client/rules_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,10 @@ import {
formatExecutionLogResult,
getExecutionLogAggregation,
} from '../lib/get_execution_log_aggregation';
import { IExecutionLogResult } from '../../common';
import { IExecutionLogWithErrorsResult } from '../../common';
import { validateSnoozeDate } from '../lib/validate_snooze_date';
import { RuleMutedError } from '../lib/errors/rule_muted';
import {
formatExecutionErrorsResult,
IExecutionErrorsResult,
} from '../lib/format_execution_log_errors';
import { formatExecutionErrorsResult } from '../lib/format_execution_log_errors';

export interface RegistryAlertTypeWithAuth extends RegistryRuleType {
authorizedConsumers: string[];
Expand Down Expand Up @@ -263,7 +260,6 @@ export interface GetExecutionLogByIdParams {
sort: estypes.Sort;
}

export type IExecutionLogWithErrorsResult = IExecutionLogResult & IExecutionErrorsResult;
interface ScheduleRuleOptions {
id: string;
consumer: string;
Expand Down
7 changes: 0 additions & 7 deletions x-pack/plugins/translations/translations/ja-JP.json
Original file line number Diff line number Diff line change
Expand Up @@ -27777,13 +27777,6 @@
"xpack.triggersActionsUI.sections.ruleDetails.actionWithBrokenConnectorWarningBannerEditText": "ルールを編集",
"xpack.triggersActionsUI.sections.ruleDetails.actionWithBrokenConnectorWarningBannerTitle": "このルールに関連付けられたコネクターの1つで問題が発生しています。",
"xpack.triggersActionsUI.sections.ruleDetails.ruleDetailsTitle": "{ruleName}",
"xpack.triggersActionsUI.sections.ruleDetails.alertInstances.disabledRule": "このルールは無効になっていて再表示できません。",
"xpack.triggersActionsUI.sections.ruleDetails.alertInstances.disabledRuleTitle": "無効なルール",
"xpack.triggersActionsUI.sections.ruleDetails.collapsedItemActons.enableLoadingTitle": "有効にする",
"xpack.triggersActionsUI.sections.ruleDetails.collapsedItemActons.enableTitle": "有効にする",
"xpack.triggersActionsUI.sections.ruleDetails.collapsedItemActons.muteLoadingTitle": "ミュート",
"xpack.triggersActionsUI.sections.ruleDetails.collapsedItemActons.muteTitle": "ミュート",
"xpack.triggersActionsUI.sections.ruleDetails.dismissButtonTitle": "閉じる",
"xpack.triggersActionsUI.sections.ruleDetails.editRuleButtonLabel": "編集",
"xpack.triggersActionsUI.sections.ruleDetails.manageLicensePlanBannerLinkTitle": "ライセンスの管理",
"xpack.triggersActionsUI.sections.ruleDetails.redirectObjectNoun": "ルール",
Expand Down
7 changes: 0 additions & 7 deletions x-pack/plugins/translations/translations/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -27806,13 +27806,6 @@
"xpack.triggersActionsUI.sections.ruleDetails.actionWithBrokenConnectorWarningBannerEditText": "编辑规则",
"xpack.triggersActionsUI.sections.ruleDetails.actionWithBrokenConnectorWarningBannerTitle": "与此规则关联的连接器之一出现问题。",
"xpack.triggersActionsUI.sections.ruleDetails.ruleDetailsTitle": "{ruleName}",
"xpack.triggersActionsUI.sections.ruleDetails.alertInstances.disabledRule": "此规则已禁用,无法显示。",
"xpack.triggersActionsUI.sections.ruleDetails.alertInstances.disabledRuleTitle": "已禁用规则",
"xpack.triggersActionsUI.sections.ruleDetails.collapsedItemActons.enableLoadingTitle": "启用",
"xpack.triggersActionsUI.sections.ruleDetails.collapsedItemActons.enableTitle": "启用",
"xpack.triggersActionsUI.sections.ruleDetails.collapsedItemActons.muteLoadingTitle": "静音",
"xpack.triggersActionsUI.sections.ruleDetails.collapsedItemActons.muteTitle": "静音",
"xpack.triggersActionsUI.sections.ruleDetails.dismissButtonTitle": "关闭",
"xpack.triggersActionsUI.sections.ruleDetails.editRuleButtonLabel": "编辑",
"xpack.triggersActionsUI.sections.ruleDetails.manageLicensePlanBannerLinkTitle": "管理许可证",
"xpack.triggersActionsUI.sections.ruleDetails.redirectObjectNoun": "规则",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ import type { SortOrder } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'
import { INTERNAL_BASE_ALERTING_API_PATH } from '../../constants';

import {
IExecutionLogResult,
IExecutionLog,
ExecutionLogSortFields,
IExecutionLogWithErrorsResult,
} from '../../../../../alerting/common';
import { AsApiContract, RewriteRequestCase } from '../../../../../actions/common';

Expand All @@ -36,9 +36,12 @@ const getRenamedLog = (data: IExecutionLog) => {
};
};

const rewriteBodyRes: RewriteRequestCase<IExecutionLogResult> = ({ data, total }: any) => ({
const rewriteBodyRes: RewriteRequestCase<IExecutionLogWithErrorsResult> = ({
data,
...rest
}: any) => ({
data: data.map((log: IExecutionLog) => getRenamedLog(log)),
total,
...rest,
});

const getFilter = (filter: string[] | undefined) => {
Expand Down Expand Up @@ -77,7 +80,7 @@ export const loadExecutionLogAggregations = async ({
}: LoadExecutionLogAggregationsProps & { http: HttpSetup }) => {
const sortField: any[] = sort;

const result = await http.get<AsApiContract<IExecutionLogResult>>(
const result = await http.get<AsApiContract<IExecutionLogWithErrorsResult>>(
`${INTERNAL_BASE_ALERTING_API_PATH}/rule/${id}/_execution_log`,
{
query: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,10 @@ import {
resolveRule,
loadExecutionLogAggregations,
LoadExecutionLogAggregationsProps,
snoozeRule,
unsnoozeRule,
} from '../../../lib/rule_api';
import { IExecutionLogResult } from '../../../../../../alerting/common';
import { IExecutionLogWithErrorsResult } from '../../../../../../alerting/common';
import { useKibana } from '../../../../common/lib/kibana';

export interface ComponentOpts {
Expand Down Expand Up @@ -64,9 +66,11 @@ export interface ComponentOpts {
loadRuleTypes: () => Promise<RuleType[]>;
loadExecutionLogAggregations: (
props: LoadExecutionLogAggregationsProps
) => Promise<IExecutionLogResult>;
) => Promise<IExecutionLogWithErrorsResult>;
getHealth: () => Promise<AlertingFrameworkHealth>;
resolveRule: (id: Rule['id']) => Promise<ResolvedRule>;
snoozeRule: (rule: Rule, snoozeEndTime: string | -1) => Promise<void>;
unsnoozeRule: (rule: Rule) => Promise<void>;
}

export type PropsWithOptionalApiHandlers<T> = Omit<T, keyof ComponentOpts> & Partial<ComponentOpts>;
Expand Down Expand Up @@ -145,6 +149,12 @@ export function withBulkRuleOperations<T>(
}
resolveRule={async (ruleId: Rule['id']) => resolveRule({ http, ruleId })}
getHealth={async () => alertingFrameworkHealth({ http })}
snoozeRule={async (rule: Rule, snoozeEndTime: string | -1) => {
return await snoozeRule({ http, id: rule.id, snoozeEndTime });
}}
unsnoozeRule={async (rule: Rule) => {
return await unsnoozeRule({ http, id: rule.id });
}}
/>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,16 @@ import {
EuiSpacer,
EuiFlexGroup,
EuiFlexItem,
EuiHorizontalRule,
EuiPanel,
EuiStat,
EuiIconTip,
EuiTabbedContent,
EuiText,
} from '@elastic/eui';
// @ts-ignore
import { RIGHT_ALIGNMENT, CENTER_ALIGNMENT } from '@elastic/eui/lib/services';
import { FormattedMessage } from '@kbn/i18n-react';
import moment from 'moment';
import {
ActionGroup,
AlertExecutionStatusErrorReasons,
Expand Down Expand Up @@ -47,6 +49,7 @@ import { getIsExperimentalFeatureEnabled } from '../../../../common/get_experime
import { suspendedComponentWithProps } from '../../../lib/suspended_component_with_props';

const RuleEventLogListWithApi = lazy(() => import('./rule_event_log_list'));
const RuleErrorLogWithApi = lazy(() => import('./rule_error_log'));

const RuleAlertList = lazy(() => import('./rule_alert_list'));

Expand All @@ -56,6 +59,7 @@ type RuleProps = {
readOnly: boolean;
ruleSummary: RuleSummary;
requestRefresh: () => Promise<void>;
refreshToken?: number;
numberOfExecutions: number;
onChangeDuration: (length: number) => void;
durationEpoch?: number;
Expand All @@ -64,6 +68,7 @@ type RuleProps = {

const EVENT_LOG_LIST_TAB = 'rule_event_log_list';
const ALERT_LIST_TAB = 'rule_alert_list';
const EVENT_ERROR_LOG_TAB = 'rule_error_log_list';

export function RuleComponent({
rule,
Expand All @@ -73,6 +78,7 @@ export function RuleComponent({
muteAlertInstance,
unmuteAlertInstance,
requestRefresh,
refreshToken,
numberOfExecutions,
onChangeDuration,
durationEpoch = Date.now(),
Expand Down Expand Up @@ -116,10 +122,13 @@ export function RuleComponent({
{
id: EVENT_LOG_LIST_TAB,
name: i18n.translate('xpack.triggersActionsUI.sections.ruleDetails.rule.eventLogTabText', {
defaultMessage: 'Execution History',
defaultMessage: 'Execution history',
}),
'data-test-subj': 'eventLogListTab',
content: suspendedComponentWithProps(RuleEventLogListWithApi, 'xl')({ rule }),
content: suspendedComponentWithProps(
RuleEventLogListWithApi,
'xl'
)({ requestRefresh, rule, refreshToken }),
},
{
id: ALERT_LIST_TAB,
Expand All @@ -129,6 +138,17 @@ export function RuleComponent({
'data-test-subj': 'ruleAlertListTab',
content: renderRuleAlertList(),
},
{
id: EVENT_ERROR_LOG_TAB,
name: i18n.translate('xpack.triggersActionsUI.sections.ruleDetails.rule.errorLogTabText', {
defaultMessage: 'Error log',
}),
'data-test-subj': 'errorLogTab',
content: suspendedComponentWithProps(
RuleErrorLogWithApi,
'xl'
)({ requestRefresh, rule, refreshToken }),
},
];

const renderTabs = () => {
Expand All @@ -141,29 +161,51 @@ export function RuleComponent({

return (
<>
<EuiHorizontalRule />
<EuiFlexGroup>
<EuiFlexItem grow={1}>
<EuiPanel color="subdued" hasBorder={false}>
<EuiStat
data-test-subj={`ruleStatus-${rule.executionStatus.status}`}
titleSize="xs"
title={
<EuiHealth
<EuiFlexGroup
gutterSize="none"
direction="column"
justifyContent="spaceBetween"
responsive={false}
style={{ height: '100%' }}
>
<EuiFlexItem>
<EuiStat
data-test-subj={`ruleStatus-${rule.executionStatus.status}`}
textSize="inherit"
color={healthColor}
>
{statusMessage}
</EuiHealth>
}
description={i18n.translate(
'xpack.triggersActionsUI.sections.ruleDetails.rulesList.ruleLastExecutionDescription',
{
defaultMessage: `Last response`,
}
)}
/>
titleSize="xs"
title={
<EuiHealth
data-test-subj={`ruleStatus-${rule.executionStatus.status}`}
textSize="inherit"
color={healthColor}
>
{statusMessage}
</EuiHealth>
}
description={i18n.translate(
'xpack.triggersActionsUI.sections.ruleDetails.rulesList.ruleLastExecutionDescription',
{
defaultMessage: `Last response`,
}
)}
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<p>
<EuiText size="xs">
<FormattedMessage
id="xpack.triggersActionsUI.sections.ruleDetails.ruleLastExecutionUpdatedAt"
defaultMessage="Updated"
/>
</EuiText>
<EuiText color="subdued" size="xs">
{moment(rule.executionStatus.lastExecutionDate).fromNow()}
</EuiText>
</p>
</EuiFlexItem>
</EuiFlexGroup>
</EuiPanel>
</EuiFlexItem>
<EuiFlexItem grow={1}>
Expand Down Expand Up @@ -217,6 +259,7 @@ export function RuleComponent({
/>
</EuiFlexItem>
</EuiFlexGroup>

<EuiSpacer size="xl" />
<input
type="hidden"
Expand Down
Loading

0 comments on commit 2aa076a

Please sign in to comment.