Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Logs UI] Alerting #62806

Merged
merged 35 commits into from
Apr 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
ea12307
[Logs UI Alerting] Bootstrap with skeleton of alert typedef and front…
Zacqary Apr 3, 2020
99d3110
Merge remote-tracking branch 'upstream/master' into logs-alerting
Kerry350 Apr 7, 2020
8a68de3
Amend schema and add alert dropdown menu
Kerry350 Apr 7, 2020
a2b4fae
Register public side of AlertType
Kerry350 Apr 7, 2020
4af8470
Document count portion of expression editor
Kerry350 Apr 8, 2020
295c223
Start of criteria
Kerry350 Apr 8, 2020
d7cafd4
Merge remote-tracking branch 'upstream/master' into logs-alerting
Kerry350 Apr 9, 2020
2bd61dc
(Most of) criteria selection
Kerry350 Apr 9, 2020
e906ff6
Add "for the last" functionality
Kerry350 Apr 9, 2020
c18a7e1
Add ability to add more criteria
Kerry350 Apr 9, 2020
34c629b
Merge remote-tracking branch 'upstream/master' into logs-alerting
Kerry350 Apr 15, 2020
7f6e9f7
Add ability to remove criterion
Kerry350 Apr 15, 2020
cc14109
Add bulk of UI validation logic
Kerry350 Apr 15, 2020
8f0050b
Merge remote-tracking branch 'upstream/master' into logs-alerting
Kerry350 Apr 16, 2020
1a37346
Ensure compatibility between field and comparator / value
Kerry350 Apr 16, 2020
ba482ec
Change getSourceConfiguration dependencies so we can use it outside o…
Kerry350 Apr 16, 2020
12e2270
Pull index pattern into executor through sources library
Kerry350 Apr 16, 2020
603ccb8
Executor and ActionVariable logic
Kerry350 Apr 17, 2020
3cd7453
Merge remote-tracking branch 'upstream/master' into logs-alerting
Kerry350 Apr 20, 2020
023edda
Move types to /common
Kerry350 Apr 20, 2020
b44a04b
Full typing for executor function
Kerry350 Apr 20, 2020
be0cdb7
Client side typing
Kerry350 Apr 20, 2020
74dcaba
Amend source config tests
Kerry350 Apr 21, 2020
6a158d8
Merge remote-tracking branch 'upstream/master' into logs-alerting
Kerry350 Apr 21, 2020
b923d0a
Ensure i18n
Kerry350 Apr 21, 2020
b91688c
Tweak / polish styling
Kerry350 Apr 21, 2020
3063455
Merge remote-tracking branch 'upstream/master' into logs-alerting
Kerry350 Apr 22, 2020
f717a51
Merge remote-tracking branch 'upstream/master' into logs-alerting
Kerry350 Apr 23, 2020
7942328
Add hrefOnly option to useLinkProps
Kerry350 Apr 23, 2020
4a3380b
Merge branch 'master' into logs-alerting
elasticmachine Apr 23, 2020
adc5deb
Merge remote-tracking branch 'upstream/master' into logs-alerting
Kerry350 Apr 27, 2020
b3ee986
Differentiate string / number wording
Kerry350 Apr 27, 2020
aeaac32
Re-throw Error
Kerry350 Apr 27, 2020
e3f201c
Differentiate singular vs plural for document count
Kerry350 Apr 27, 2020
92de5b8
Fix duplicate i18n IDs
Kerry350 Apr 27, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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