From 8b443f4e3ba982f99d7d0d6368bb05395fea0aeb Mon Sep 17 00:00:00 2001 From: Ilya Nuevo Date: Sun, 7 Apr 2024 17:01:41 +0300 Subject: [PATCH] DEV-23041 - log to logzio on any error (#17) * DEV-23041 - log to logzio on any error DEV-26768 - Use new label resolving api for m3 * DEV-28224 disable exemplars Disable sending frontend metrics Email validation Adding types icons Handle email endpoint Disable endpoints editing in grafana (ALERTS) Add emails input --> Disable AM Selector DEV-33551 * Fix compile errors --- .../src/components/PromExploreExtraField.tsx | 33 +++-- packages/grafana-prometheus/src/datasource.ts | 69 ++++----- public/app/core/copy/appNotification.ts | 13 ++ .../echo/backends/PerformanceBackend.ts | 9 +- public/app/features/alerting/AlertTabCtrl.ts | 77 +++++++++- .../alerting/NotificationsListPage.tsx | 132 +++++++++++------- .../features/alerting/partials/alert_tab.html | 22 ++- .../unified/components/AlertManagerPicker.tsx | 1 + .../components/rule-editor/FolderAndGroup.tsx | 2 +- .../components/rule-viewer/tabs/History.tsx | 6 +- .../rules/RuleDetailsActionButtons.tsx | 4 +- .../components/rules/RuleListGroupView.tsx | 9 +- .../features/dashboard/utils/getPanelMenu.ts | 25 ++-- .../app/features/panel/panellinks/link_srv.ts | 20 ++- public/app/features/profile/state/actions.ts | 20 +-- .../plugins/datasource/elasticsearch/types.ts | 2 + .../components/PromExploreExtraField.tsx | 34 +++-- .../prometheus/metric_find_query.ts | 19 +++ public/app/plugins/panel/news/plugin.json | 5 +- public/app/routes/routes.tsx | 2 +- 20 files changed, 343 insertions(+), 161 deletions(-) diff --git a/packages/grafana-prometheus/src/components/PromExploreExtraField.tsx b/packages/grafana-prometheus/src/components/PromExploreExtraField.tsx index c9ad0a79e36b8..a614b1c017e2f 100644 --- a/packages/grafana-prometheus/src/components/PromExploreExtraField.tsx +++ b/packages/grafana-prometheus/src/components/PromExploreExtraField.tsx @@ -1,14 +1,16 @@ import { css, cx } from '@emotion/css'; -import { isEqual } from 'lodash'; -import React, { memo, useCallback } from 'react'; -import { usePrevious } from 'react-use'; +// LOGZIO GRAFANA CHANGE :: DEV-28224 disable exemplars +// import { isEqual } from 'lodash'; +import React, { memo } from 'react'; +// import { usePrevious } from 'react-use'; +// LOGZIO GRAFANA CHANGE :: end import { InlineFormLabel, RadioButtonGroup } from '@grafana/ui'; import { PrometheusDatasource } from '../datasource'; import { PromQuery } from '../types'; -import { PromExemplarField } from './PromExemplarField'; +// import { PromExemplarField } from './PromExemplarField'// LOGZIO GRAFANA CHANGE :: DEV-28224 disable exemplars export interface PromExploreExtraFieldProps { query: PromQuery; @@ -19,16 +21,17 @@ export interface PromExploreExtraFieldProps { export const PromExploreExtraField = memo(({ query, datasource, onChange, onRunQuery }: PromExploreExtraFieldProps) => { const rangeOptions = getQueryTypeOptions(true); - const prevQuery = usePrevious(query); - - const onExemplarChange = useCallback( - (exemplar: boolean) => { - if (!isEqual(query, prevQuery) || exemplar !== query.exemplar) { - onChange({ ...query, exemplar }); - } - }, - [prevQuery, query, onChange] - ); +// LOGZIO GRAFANA CHANGE :: DEV-28224 disable exemplars +//const prevQuery = usePrevious(query); + +//const onExemplarChange = useCallback( +// (exemplar: boolean) => { +// if (!isEqual(query, prevQuery) || exemplar !== query.exemplar) { +// onChange({ ...query, exemplar }); +// } +// }, +// [prevQuery, query, onChange] +//); function onChangeQueryStep(interval: string) { onChange({ ...query, interval }); @@ -102,7 +105,7 @@ export const PromExploreExtraField = memo(({ query, datasource, onChange, onRunQ /> - + {/* // LOGZ.IO GRAFANA CHANGE :: Disable exemplars*/} ); }); diff --git a/packages/grafana-prometheus/src/datasource.ts b/packages/grafana-prometheus/src/datasource.ts index 956b4a268be27..f26453908103e 100644 --- a/packages/grafana-prometheus/src/datasource.ts +++ b/packages/grafana-prometheus/src/datasource.ts @@ -124,7 +124,7 @@ export class PrometheusDatasource this.defaultEditor = instanceSettings.jsonData.defaultEditor; this.disableRecordingRules = instanceSettings.jsonData.disableRecordingRules ?? false; this.variables = new PrometheusVariableSupport(this, this.templateSrv); - this.exemplarsAvailable = true; + this.exemplarsAvailable = false; // LOGZ.IO GRAFANA CHANGE :: Disable exemplars this.cacheLevel = instanceSettings.jsonData.cacheLevel ?? PrometheusCacheLevel.Low; this.cache = new QueryCache({ @@ -339,18 +339,19 @@ export class PrometheusDatasource } shouldRunExemplarQuery(target: PromQuery, request: DataQueryRequest): boolean { - if (target.exemplar) { - // We check all already processed targets and only create exemplar target for not used metric names - const metricName = this.languageProvider.histogramMetrics.find((m) => target.expr.includes(m)); - // Remove targets that weren't processed yet (in targets array they are after current target) - const currentTargetIdx = request.targets.findIndex((t) => t.refId === target.refId); - const targets = request.targets.slice(0, currentTargetIdx).filter((t) => !t.hide); - - if (!metricName || (metricName && !targets.some((t) => t.expr.includes(metricName)))) { - return true; - } - return false; - } + // LOGZ.IO GRAFANA CHANGE :: Disable exemplars + // if (target.exemplar) { + // // We check all already processed targets and only create exemplar target for not used metric names + // const metricName = this.languageProvider.histogramMetrics.find((m) => target.expr.includes(m)); + // // Remove targets that weren't processed yet (in targets array they are after current target) + // const currentTargetIdx = request.targets.findIndex((t) => t.refId === target.refId); + // const targets = request.targets.slice(0, currentTargetIdx).filter((t) => !t.hide); + + // if (!metricName || (metricName && !targets.some((t) => t.expr.includes(metricName)))) { + // return true; + // } + // return false; + // } return false; } @@ -758,27 +759,29 @@ export class PrometheusDatasource } } + // LOGZ.IO GRAFANA CHANGE :: Disable exemplars async areExemplarsAvailable() { - try { - const res = await this.metadataRequest( - '/api/v1/query_exemplars', - { - query: 'test', - start: dateTime().subtract(30, 'minutes').valueOf().toString(), - end: dateTime().valueOf().toString(), - }, - { - // Avoid alerting the user if this test fails - showErrorAlert: false, - } - ); - if (res.data.status === 'success') { - return true; - } - return false; - } catch (err) { - return false; - } + return false; + // try { + // const res = await this.metadataRequest( + // '/api/v1/query_exemplars', + // { + // query: 'test', + // start: dateTime().subtract(30, 'minutes').valueOf().toString(), + // end: dateTime().valueOf().toString(), + // }, + // { + // // Avoid alerting the user if this test fails + // showErrorAlert: false, + // } + // ); + // if (res.data.status === 'success') { + // return true; + // } + // return false; + // } catch (err) { + // return false; + // } } modifyQuery(query: PromQuery, action: QueryFixAction): PromQuery { diff --git a/public/app/core/copy/appNotification.ts b/public/app/core/copy/appNotification.ts index 485cdc6d4c6d5..f7012324d7d14 100644 --- a/public/app/core/copy/appNotification.ts +++ b/public/app/core/copy/appNotification.ts @@ -1,6 +1,7 @@ import { useMemo } from 'react'; import { v4 as uuidv4 } from 'uuid'; +import { logzioServices } from '@grafana/data'; // LOGZ.IO GRAFANA CHANGE :: DEV-23041 - log to logzio on any error import { getMessageFromError } from 'app/core/utils/errors'; import { AppNotification, AppNotificationSeverity, useDispatch } from 'app/types'; @@ -42,6 +43,18 @@ export const createErrorNotification = ( traceId?: string, component?: React.ReactElement ): AppNotification => { + // LOGZ.IO GRAFANA CHANGE :: DEV-23041 - log to logzio on any error + const logzLogger = logzioServices.LoggerService; + logzLogger.logError({ + origin: logzLogger.Origin.GRAFANA, + message: getMessageFromError(text), + error: null, + uxType: logzLogger.UxType.TOAST, + extra: { + title, + }, + }); + return { ...defaultErrorNotification, text: getMessageFromError(text), diff --git a/public/app/core/services/echo/backends/PerformanceBackend.ts b/public/app/core/services/echo/backends/PerformanceBackend.ts index 29ff37882bcc2..92530381af0ce 100644 --- a/public/app/core/services/echo/backends/PerformanceBackend.ts +++ b/public/app/core/services/echo/backends/PerformanceBackend.ts @@ -1,6 +1,6 @@ import { EchoBackend, EchoEvent, EchoEventType } from '@grafana/runtime'; -import { backendSrv } from '../../backend_srv'; +// import { backendSrv } from '../../backend_srv'; // LOGZ.IO GRAFANA CHANGE :: Disable sending frontend metrics export interface PerformanceEventPayload { name: string; @@ -32,9 +32,10 @@ export class PerformanceBackend implements EchoBackend { - return this.uiSegmentSrv.newSegment(item.name); + // LOGZ.IO GRAFANA CHANGE :: (ALERTS) Alert {type.name} + return this.uiSegmentSrv.newSegment(`${item.type}.${item.name}`); }) ); } notificationAdded() { + // LOGZ.IO GRAFANA CHANGE :: (ALERTS) Get name from 'type.name' + const endpointName = this.addNotificationSegment.value.substr(this.addNotificationSegment.value.indexOf('.') + 1); + const model: any = find(this.notifications, { - name: this.addNotificationSegment.value, + name: endpointName, }); + // LOGZ.IO GRAFANA CHANGE :: end + if (!model) { return; } @@ -169,6 +190,55 @@ export class AlertTabCtrl { this.addNotificationSegment.fake = true; } + // LOGZ.IO GRAFANA CHANGE :: (ALERTS) Handle email endpoint + emailInputChanged(e: any) { + if (e.keyCode === 13) { + this.addEmail(); + return; + } + + this.isEmailValid = !this.emailInEdit || (window as any).logzio.services.logzPatterns.email.test(this.emailInEdit); + } + + addEmail() { + if (!this.emailInEdit || !this.isEmailValid) { + this.isEmailValid = false; + + return; + } + + const address = this.emailInEdit; + this.emailInEdit = ''; + + this.alert.emailNotifications.push({ + address, + }); + + this.alertEmailNotifications.push({ + name: address, + iconClass: this.getNotificationIcon('email'), + isDefault: false, + }); + } + + initEmails() { + this.alert.emailNotifications = this.alert.emailNotifications || []; + + this.alert.emailNotifications.forEach((email: any) => { + this.alertEmailNotifications.push({ + name: email.address, + iconClass: this.getNotificationIcon('email'), + isDefault: false, + }); + }); + } + + removeEmailNotification(an: any) { + remove(this.alertEmailNotifications, (n: any) => n.name === an.name); + remove(this.alert.emailNotifications, (n: any) => n.address === an.name); + } + // LOGZ.IO GRAFANA CHANGE :: (ALERTS) Handle email endpoint : End + removeNotification(an: any) { // remove notifiers referred to by id and uid to support notifiers added // before and after we added support for uid @@ -263,6 +333,9 @@ export class AlertTabCtrl { } } + // LOGZ.IO GRAFANA CHANGE :: (ALERTS) Init emails + this.initEmails(); + this.panelCtrl.editingThresholds = true; this.panelCtrl.render(); } diff --git a/public/app/features/alerting/NotificationsListPage.tsx b/public/app/features/alerting/NotificationsListPage.tsx index 89e4bea26377b..e52646a309f48 100644 --- a/public/app/features/alerting/NotificationsListPage.tsx +++ b/public/app/features/alerting/NotificationsListPage.tsx @@ -2,14 +2,17 @@ import React, { useState, FC, useEffect } from 'react'; import { useAsyncFn } from 'react-use'; import { getBackendSrv } from '@grafana/runtime'; -import { HorizontalGroup, Button, LinkButton } from '@grafana/ui'; +// LOGZ.IO GRAFANA CHANGE :: (ALERTS) Disable endpoints editing in grafana +import { LinkButton } from '@grafana/ui'; import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA'; import { Page } from 'app/core/components/Page/Page'; -import { appEvents } from 'app/core/core'; +// LOGZ.IO GRAFANA CHANGE :: (ALERTS) Disable endpoints editing in grafana +//import { appEvents } from 'app/core/core'; import { useNavModel } from 'app/core/hooks/useNavModel'; import { AlertNotification } from 'app/types/alerting'; -import { ShowConfirmModalEvent } from '../../types/events'; +// LOGZ.IO GRAFANA CHANGE :: (ALERTS) Disable endpoints editing in grafana +//import { ShowConfirmModalEvent } from '../../types/events'; const NotificationsListPage: FC = () => { const navModel = useNavModel('channels'); @@ -27,40 +30,51 @@ const NotificationsListPage: FC = () => { }); }, [fetchNotifications]); - const deleteNotification = (id: number) => { - appEvents.publish( - new ShowConfirmModalEvent({ - title: 'Delete', - text: 'Do you want to delete this notification channel?', - text2: `Deleting this notification channel will not delete from alerts any references to it`, - icon: 'trash-alt', - confirmText: 'Delete', - yesText: 'Delete', - onConfirm: async () => { - deleteNotificationConfirmed(id); - }, - }) - ); - }; +// LOGZ.IO GRAFANA CHANGE :: (ALERTS) Disable endpoints editing in grafana +//const deleteNotification = (id: number) => { +// appEvents.publish( +// new ShowConfirmModalEvent({ +// title: 'Delete', +// text: 'Do you want to delete this notification channel?', +// text2: `Deleting this notification channel will not delete from alerts any references to it`, +// icon: 'trash-alt', +// confirmText: 'Delete', +// yesText: 'Delete', +// onConfirm: async () => { +// deleteNotificationConfirmed(id); +// }, +// }) +// ); +//}; - const deleteNotificationConfirmed = async (id: number) => { - await getBackendSrv().delete(`/api/alert-notifications/${id}`); - const notifications = await fetchNotifications(); - setNotifications(notifications); - }; +//const deleteNotificationConfirmed = async (id: number) => { +// await getBackendSrv().delete(`/api/alert-notifications/${id}`); +// const notifications = await fetchNotifications(); +// setNotifications(notifications); +//}; return ( {state.error &&

{state.error.message}

} + {/*LOGZ.IO GRAFANA CHANGE :: (ALERTS) Open logz's alert endpoints page and show when empty*/} +
+
+ + New channel + +
+ {/*LOGZ.IO GRAFANA CHANGE :: END*/} {!!notifications.length && ( <> -
-
- - New channel - -
+ {/*LOGZ.IO GRAFANA CHANGE :: (ALERTS) Open logz's alert endpoints page and show when empty*/} + {/*
*/} + {/*
*/} + {/* */} + {/* New channel*/} + {/* */} + {/*
*/} + {/*LOGZ.IO GRAFANA CHANGE :: END*/} @@ -74,37 +88,47 @@ const NotificationsListPage: FC = () => { {notifications.map((notification) => ( - - - - + + + + ))}
- {notification.name} - - {notification.type} - - - {notification.isDefault && ( - - )} -
+ {/*LOGZ.IO GRAFANA CHANGE :: (ALERTS) Disable endpoints editing in grafana*/} + {/*{notification.name}*/} + {notification.name} + {/*LOGZ.IO GRAFANA CHANGE :: END*/} + + {/*LOGZ.IO GRAFANA CHANGE :: (ALERTS) Disable endpoints editing in grafana*/} + {/*{notification.type}*/} + {notification.type} + {/*LOGZ.IO GRAFANA CHANGE :: END*/} + + {/*LOGZ.IO GRAFANA CHANGE :: (ALERTS) Disable endpoints editing in grafana*/} + {/**/} + {/* {notification.isDefault && (*/} + {/* */} + {/* )}*/} + {/* {*/} + {/* deleteNotification(notification.id);*/} + {/* }}*/} + {/* />*/} + {/**/} + {/*LOGZ.IO GRAFANA CHANGE :: END*/} +
)} - {!(notifications.length || state.loading) && ( + {/* LOGZ.IO GRAFANA CHANGE :: (ALERTS) Creating new endpoint only from Logz alerts endpoints*/} + {/*{!(notifications.length || state.loading) && (*/} + {false && ( Rule
Evaluate every + + disabled + /> +
@@ -187,6 +190,23 @@

Notifications

>
+ +
+
+ +  {{nc.name}}  + + +
+
+ +
+ Add email +
+
Message