Skip to content

Commit

Permalink
[Logs UI] Alerting (elastic#62806)
Browse files Browse the repository at this point in the history
First iteration of logs alerting
  • Loading branch information
Kerry350 committed Apr 27, 2020
1 parent 72e85cc commit 8610d36
Show file tree
Hide file tree
Showing 30 changed files with 1,405 additions and 44 deletions.
95 changes: 95 additions & 0 deletions x-pack/plugins/infra/common/alerting/logs/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { i18n } from '@kbn/i18n';

export const LOG_DOCUMENT_COUNT_ALERT_TYPE_ID = 'logs.alert.document.count';

export enum Comparator {
GT = 'more than',
GT_OR_EQ = 'more than or equals',
LT = 'less than',
LT_OR_EQ = 'less than or equals',
EQ = 'equals',
NOT_EQ = 'does not equal',
MATCH = 'matches',
NOT_MATCH = 'does not match',
MATCH_PHRASE = 'matches phrase',
NOT_MATCH_PHRASE = 'does not match phrase',
}

// Maps our comparators to i18n strings, some comparators have more specific wording
// depending on the field type the comparator is being used with.
export const ComparatorToi18nMap = {
[Comparator.GT]: i18n.translate('xpack.infra.logs.alerting.comparator.gt', {
defaultMessage: 'more than',
}),
[Comparator.GT_OR_EQ]: i18n.translate('xpack.infra.logs.alerting.comparator.gtOrEq', {
defaultMessage: 'more than or equals',
}),
[Comparator.LT]: i18n.translate('xpack.infra.logs.alerting.comparator.lt', {
defaultMessage: 'less than',
}),
[Comparator.LT_OR_EQ]: i18n.translate('xpack.infra.logs.alerting.comparator.ltOrEq', {
defaultMessage: 'less than or equals',
}),
[Comparator.EQ]: i18n.translate('xpack.infra.logs.alerting.comparator.eq', {
defaultMessage: 'is',
}),
[Comparator.NOT_EQ]: i18n.translate('xpack.infra.logs.alerting.comparator.notEq', {
defaultMessage: 'is not',
}),
[`${Comparator.EQ}:number`]: i18n.translate('xpack.infra.logs.alerting.comparator.eqNumber', {
defaultMessage: 'equals',
}),
[`${Comparator.NOT_EQ}:number`]: i18n.translate(
'xpack.infra.logs.alerting.comparator.notEqNumber',
{
defaultMessage: 'does not equal',
}
),
[Comparator.MATCH]: i18n.translate('xpack.infra.logs.alerting.comparator.match', {
defaultMessage: 'matches',
}),
[Comparator.NOT_MATCH]: i18n.translate('xpack.infra.logs.alerting.comparator.notMatch', {
defaultMessage: 'does not match',
}),
[Comparator.MATCH_PHRASE]: i18n.translate('xpack.infra.logs.alerting.comparator.matchPhrase', {
defaultMessage: 'matches phrase',
}),
[Comparator.NOT_MATCH_PHRASE]: i18n.translate(
'xpack.infra.logs.alerting.comparator.notMatchPhrase',
{
defaultMessage: 'does not match phrase',
}
),
};

export enum AlertStates {
OK,
ALERT,
NO_DATA,
ERROR,
}

export interface DocumentCount {
comparator: Comparator;
value: number;
}

export interface Criterion {
field: string;
comparator: Comparator;
value: string | number;
}

export interface LogDocumentCountAlertParams {
count: DocumentCount;
criteria: Criterion[];
timeUnit: 's' | 'm' | 'h' | 'd';
timeSize: number;
}

export type TimeUnit = 's' | 'm' | 'h' | 'd';
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import React, { useState, useCallback, useMemo } from 'react';
import { EuiPopover, EuiButtonEmpty, EuiContextMenuItem, EuiContextMenuPanel } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { AlertFlyout } from './alert_flyout';
import { useLinkProps } from '../../../hooks/use_link_props';

export const AlertDropdown = () => {
const [popoverOpen, setPopoverOpen] = useState(false);
const [flyoutVisible, setFlyoutVisible] = useState(false);
const manageAlertsLinkProps = useLinkProps(
{
app: 'kibana',
hash: 'management/kibana/triggersActions/alerts',
},
{
hrefOnly: true,
}
);

const closePopover = useCallback(() => {
setPopoverOpen(false);
}, [setPopoverOpen]);

const openPopover = useCallback(() => {
setPopoverOpen(true);
}, [setPopoverOpen]);

const menuItems = useMemo(() => {
return [
<EuiContextMenuItem icon="bell" key="createLink" onClick={() => setFlyoutVisible(true)}>
<FormattedMessage
id="xpack.infra.alerting.logs.createAlertButton"
defaultMessage="Create alert"
/>
</EuiContextMenuItem>,
<EuiContextMenuItem icon="tableOfContents" key="manageLink" {...manageAlertsLinkProps}>
<FormattedMessage
id="xpack.infra.alerting.logs.manageAlerts"
defaultMessage="Manage alerts"
/>
</EuiContextMenuItem>,
];
}, [manageAlertsLinkProps]);

return (
<>
<EuiPopover
button={
<EuiButtonEmpty iconSide={'right'} iconType={'arrowDown'} onClick={openPopover}>
<FormattedMessage id="xpack.infra.alerting.logs.alertsButton" defaultMessage="Alerts" />
</EuiButtonEmpty>
}
isOpen={popoverOpen}
closePopover={closePopover}
>
<EuiContextMenuPanel items={menuItems} />
</EuiPopover>
<AlertFlyout setVisible={setFlyoutVisible} visible={flyoutVisible} />
</>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import React, { useContext } from 'react';
import { AlertsContextProvider, AlertAdd } from '../../../../../triggers_actions_ui/public';
import { TriggerActionsContext } from '../../../utils/triggers_actions_context';
import { useKibana } from '../../../../../../../src/plugins/kibana_react/public';
import { LOG_DOCUMENT_COUNT_ALERT_TYPE_ID } from '../../../../common/alerting/logs/types';

interface Props {
visible?: boolean;
setVisible: React.Dispatch<React.SetStateAction<boolean>>;
}

export const AlertFlyout = (props: Props) => {
const { triggersActionsUI } = useContext(TriggerActionsContext);
const { services } = useKibana();

return (
<>
{triggersActionsUI && (
<AlertsContextProvider
value={{
metadata: {},
toastNotifications: services.notifications?.toasts,
http: services.http,
docLinks: services.docLinks,
actionTypeRegistry: triggersActionsUI.actionTypeRegistry,
alertTypeRegistry: triggersActionsUI.alertTypeRegistry,
}}
>
<AlertAdd
addFlyoutVisible={props.visible!}
setAddFlyoutVisibility={props.setVisible}
alertTypeId={LOG_DOCUMENT_COUNT_ALERT_TYPE_ID}
canChangeTrigger={false}
consumer={'logs'}
/>
</AlertsContextProvider>
)}
</>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import React from 'react';
import { EuiFlexItem, EuiFlexGroup } from '@elastic/eui';
import { IFieldType } from 'src/plugins/data/public';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { IErrorObject } from '../../../../../../triggers_actions_ui/public/types';
import { Criterion } from './criterion';
import {
LogDocumentCountAlertParams,
Criterion as CriterionType,
} from '../../../../../common/alerting/logs/types';

interface Props {
fields: IFieldType[];
criteria?: LogDocumentCountAlertParams['criteria'];
updateCriterion: (idx: number, params: Partial<CriterionType>) => void;
removeCriterion: (idx: number) => void;
errors: IErrorObject;
}

export const Criteria: React.FC<Props> = ({
fields,
criteria,
updateCriterion,
removeCriterion,
errors,
}) => {
if (!criteria) return null;
return (
<EuiFlexGroup gutterSize="s">
<EuiFlexItem grow>
{criteria.map((criterion, idx) => {
return (
<Criterion
key={idx}
idx={idx}
fields={fields}
criterion={criterion}
updateCriterion={updateCriterion}
removeCriterion={removeCriterion}
canDelete={criteria.length > 1}
errors={errors[idx.toString()] as IErrorObject}
/>
);
})}
</EuiFlexItem>
</EuiFlexGroup>
);
};
Loading

0 comments on commit 8610d36

Please sign in to comment.