-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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
[APM] Threshold alerts #59566
[APM] Threshold alerts #59566
Changes from all commits
573570c
6107771
daea3ae
33acee5
b326c42
5ff8d75
ecf61d6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -86,24 +86,34 @@ export const apm: LegacyPluginInitializer = kibana => { | |
navLinkId: 'apm', | ||
app: ['apm', 'kibana'], | ||
catalogue: ['apm'], | ||
// see x-pack/plugins/features/common/feature_kibana_privileges.ts | ||
privileges: { | ||
all: { | ||
api: ['apm', 'apm_write'], | ||
api: ['apm', 'apm_write', 'actions-read', 'alerting-read'], | ||
catalogue: ['apm'], | ||
savedObject: { | ||
all: [], | ||
all: ['action', 'action_task_params'], | ||
read: [] | ||
}, | ||
ui: ['show', 'save'] | ||
ui: [ | ||
'show', | ||
'save', | ||
'alerting:show', | ||
'actions:show', | ||
'alerting:save', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it possible to grant users granular access, like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Possible for us? Or for admins? |
||
'actions:save', | ||
'alerting:delete', | ||
'actions:delete' | ||
] | ||
}, | ||
read: { | ||
api: ['apm'], | ||
api: ['apm', 'actions-read', 'alerting-read'], | ||
catalogue: ['apm'], | ||
savedObject: { | ||
all: [], | ||
all: ['action', 'action_task_params'], | ||
read: [] | ||
}, | ||
ui: ['show'] | ||
ui: ['show', 'alerting:show', 'actions:show'] | ||
} | ||
} | ||
}); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
/* | ||
* 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 { AlertType } from '../../../../../../../../../plugins/apm/common/alert_types'; | ||
import { AlertAdd } from '../../../../../../../../../plugins/triggers_actions_ui/public'; | ||
|
||
type AlertAddProps = React.ComponentProps<typeof AlertAdd>; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is such an underrated ts helper |
||
|
||
interface Props { | ||
addFlyoutVisible: AlertAddProps['addFlyoutVisible']; | ||
setAddFlyoutVisibility: AlertAddProps['setAddFlyoutVisibility']; | ||
alertType: AlertType | null; | ||
} | ||
|
||
export function AlertingFlyout(props: Props) { | ||
const { addFlyoutVisible, setAddFlyoutVisibility, alertType } = props; | ||
|
||
return alertType ? ( | ||
<AlertAdd | ||
addFlyoutVisible={addFlyoutVisible} | ||
setAddFlyoutVisibility={setAddFlyoutVisibility} | ||
consumer="apm" | ||
alertTypeId={alertType} | ||
canChangeTrigger={false} | ||
/> | ||
) : null; | ||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,146 @@ | ||||||
/* | ||||||
* 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 { | ||||||
EuiButtonEmpty, | ||||||
EuiContextMenu, | ||||||
EuiPopover, | ||||||
EuiContextMenuPanelDescriptor | ||||||
} from '@elastic/eui'; | ||||||
import { i18n } from '@kbn/i18n'; | ||||||
import React, { useState } from 'react'; | ||||||
import { AlertType } from '../../../../../../../../plugins/apm/common/alert_types'; | ||||||
import { AlertingFlyout } from './AlertingFlyout'; | ||||||
import { useApmPluginContext } from '../../../../hooks/useApmPluginContext'; | ||||||
|
||||||
const alertLabel = i18n.translate( | ||||||
'xpack.apm.serviceDetails.alertsMenu.alerts', | ||||||
{ | ||||||
defaultMessage: 'Alerts' | ||||||
} | ||||||
); | ||||||
|
||||||
const createThresholdAlertLabel = i18n.translate( | ||||||
'xpack.apm.serviceDetails.alertsMenu.createThresholdAlert', | ||||||
{ | ||||||
defaultMessage: 'Create threshold alert' | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
} | ||||||
); | ||||||
|
||||||
const CREATE_THRESHOLD_ALERT_PANEL_ID = 'create_threshold'; | ||||||
|
||||||
interface Props { | ||||||
canReadAlerts: boolean; | ||||||
canSaveAlerts: boolean; | ||||||
} | ||||||
|
||||||
export function AlertIntegrations(props: Props) { | ||||||
const { canSaveAlerts, canReadAlerts } = props; | ||||||
|
||||||
const plugin = useApmPluginContext(); | ||||||
|
||||||
const [popoverOpen, setPopoverOpen] = useState(false); | ||||||
|
||||||
const [alertType, setAlertType] = useState<AlertType | null>(null); | ||||||
|
||||||
const button = ( | ||||||
<EuiButtonEmpty | ||||||
iconType="arrowDown" | ||||||
iconSide="right" | ||||||
onClick={() => setPopoverOpen(true)} | ||||||
> | ||||||
{i18n.translate('xpack.apm.serviceDetails.alertsMenu.alerts', { | ||||||
defaultMessage: 'Alerts' | ||||||
})} | ||||||
</EuiButtonEmpty> | ||||||
); | ||||||
|
||||||
const panels: EuiContextMenuPanelDescriptor[] = [ | ||||||
{ | ||||||
id: 0, | ||||||
title: alertLabel, | ||||||
items: [ | ||||||
...(canSaveAlerts | ||||||
? [ | ||||||
{ | ||||||
name: createThresholdAlertLabel, | ||||||
panel: CREATE_THRESHOLD_ALERT_PANEL_ID, | ||||||
icon: 'bell' | ||||||
} | ||||||
] | ||||||
: []), | ||||||
...(canReadAlerts | ||||||
? [ | ||||||
{ | ||||||
name: i18n.translate( | ||||||
'xpack.apm.serviceDetails.alertsMenu.viewActiveAlerts', | ||||||
{ | ||||||
defaultMessage: 'View active alerts' | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
} | ||||||
), | ||||||
href: plugin.core.http.basePath.prepend( | ||||||
'/app/kibana#/management/kibana/triggersActions/alerts' | ||||||
), | ||||||
icon: 'tableOfContents' | ||||||
} | ||||||
] | ||||||
: []) | ||||||
] | ||||||
}, | ||||||
{ | ||||||
id: CREATE_THRESHOLD_ALERT_PANEL_ID, | ||||||
title: createThresholdAlertLabel, | ||||||
items: [ | ||||||
{ | ||||||
name: i18n.translate( | ||||||
'xpack.apm.serviceDetails.alertsMenu.transactionDuration', | ||||||
{ | ||||||
defaultMessage: 'Transaction duration' | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
} | ||||||
), | ||||||
onClick: () => { | ||||||
setAlertType(AlertType.TransactionDuration); | ||||||
} | ||||||
}, | ||||||
{ | ||||||
name: i18n.translate( | ||||||
'xpack.apm.serviceDetails.alertsMenu.errorRate', | ||||||
{ | ||||||
defaultMessage: 'Error rate' | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
} | ||||||
), | ||||||
onClick: () => { | ||||||
setAlertType(AlertType.ErrorRate); | ||||||
} | ||||||
} | ||||||
] | ||||||
} | ||||||
]; | ||||||
|
||||||
return ( | ||||||
<> | ||||||
<EuiPopover | ||||||
id="integrations-menu" | ||||||
button={button} | ||||||
isOpen={popoverOpen} | ||||||
closePopover={() => setPopoverOpen(false)} | ||||||
panelPaddingSize="none" | ||||||
anchorPosition="downRight" | ||||||
> | ||||||
<EuiContextMenu initialPanelId={0} panels={panels} /> | ||||||
</EuiPopover> | ||||||
<AlertingFlyout | ||||||
alertType={alertType} | ||||||
addFlyoutVisible={!!alertType} | ||||||
setAddFlyoutVisibility={visible => { | ||||||
if (!visible) { | ||||||
setAlertType(null); | ||||||
} | ||||||
}} | ||||||
/> | ||||||
</> | ||||||
); | ||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
apm_write
uses snake_case. Should we stay consistent?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Btw. Should
apm
be renamed toapm_read
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah..
actions-read
is what's defined in the Action app endpoints...My mind is a little hazy on this mapping concept. Are we mapping tags to privileges here? How does it work?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understood it last time I looked into it, but that was last year. It seems this mapping concept is not immediately intuitive so adding some comments (albeit a bit verbose) might be a good idea.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would just linking to
x-pack/plugins/features/common/feature_kibana_privileges.ts
where it's explained be OK? Rather than copying documentation between files?