link to the explore view from the metric name in the detail view
This commit is contained in:
@@ -72,6 +72,7 @@ export interface UnifiedAlertingConfig {
|
|||||||
alertStateHistoryBackend?: string;
|
alertStateHistoryBackend?: string;
|
||||||
// will be undefined if implementation is not "multiple"
|
// will be undefined if implementation is not "multiple"
|
||||||
alertStateHistoryPrimary?: string;
|
alertStateHistoryPrimary?: string;
|
||||||
|
grafanaRecordingRulesUrl?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Supported OAuth services
|
/** Supported OAuth services
|
||||||
|
|||||||
@@ -152,6 +152,7 @@ export class GrafanaBootConfig implements GrafanaConfig {
|
|||||||
minInterval: '',
|
minInterval: '',
|
||||||
alertStateHistoryBackend: undefined,
|
alertStateHistoryBackend: undefined,
|
||||||
alertStateHistoryPrimary: undefined,
|
alertStateHistoryPrimary: undefined,
|
||||||
|
grafanaRecordingRulesUrl: undefined,
|
||||||
};
|
};
|
||||||
applicationInsightsConnectionString?: string;
|
applicationInsightsConnectionString?: string;
|
||||||
applicationInsightsEndpointUrl?: string;
|
applicationInsightsEndpointUrl?: string;
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ type FrontendSettingsUnifiedAlertingDTO struct {
|
|||||||
MinInterval string `json:"minInterval"`
|
MinInterval string `json:"minInterval"`
|
||||||
AlertStateHistoryBackend string `json:"alertStateHistoryBackend,omitempty"`
|
AlertStateHistoryBackend string `json:"alertStateHistoryBackend,omitempty"`
|
||||||
AlertStateHistoryPrimary string `json:"alertStateHistoryPrimary,omitempty"`
|
AlertStateHistoryPrimary string `json:"alertStateHistoryPrimary,omitempty"`
|
||||||
|
GrafanaRecordingRulesUrl string `json:"grafanaRecordingRulesUrl,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enterprise-only
|
// Enterprise-only
|
||||||
|
|||||||
@@ -329,6 +329,9 @@ func (hs *HTTPServer) getFrontendSettings(c *contextmodel.ReqContext) (*dtos.Fro
|
|||||||
if hs.Cfg.UnifiedAlerting.Enabled != nil {
|
if hs.Cfg.UnifiedAlerting.Enabled != nil {
|
||||||
frontendSettings.UnifiedAlertingEnabled = *hs.Cfg.UnifiedAlerting.Enabled
|
frontendSettings.UnifiedAlertingEnabled = *hs.Cfg.UnifiedAlerting.Enabled
|
||||||
}
|
}
|
||||||
|
if hs.Cfg.UnifiedAlerting.RecordingRules.Enabled {
|
||||||
|
frontendSettings.UnifiedAlerting.GrafanaRecordingRulesUrl = hs.Cfg.UnifiedAlerting.RecordingRules.URL
|
||||||
|
}
|
||||||
|
|
||||||
// It returns false if the provider is not enabled or the skip org role sync is false.
|
// It returns false if the provider is not enabled or the skip org role sync is false.
|
||||||
parseSkipOrgRoleSyncEnabled := func(info *social.OAuthInfo) bool {
|
parseSkipOrgRoleSyncEnabled := func(info *social.OAuthInfo) bool {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { chain, isEmpty, truncate } from 'lodash';
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
|
||||||
import { NavModelItem, UrlQueryValue } from '@grafana/data';
|
import { NavModelItem, UrlQueryValue } from '@grafana/data';
|
||||||
|
import { config } from '@grafana/runtime';
|
||||||
import { Alert, LinkButton, Stack, TabContent, Text, TextLink, useStyles2 } from '@grafana/ui';
|
import { Alert, LinkButton, Stack, TabContent, Text, TextLink, useStyles2 } from '@grafana/ui';
|
||||||
import { PageInfoItem } from 'app/core/components/Page/types';
|
import { PageInfoItem } from 'app/core/components/Page/types';
|
||||||
import { useQueryParams } from 'app/core/hooks/useQueryParams';
|
import { useQueryParams } from 'app/core/hooks/useQueryParams';
|
||||||
@@ -13,6 +14,7 @@ import { PromAlertingRuleState, PromRuleType } from 'app/types/unified-alerting-
|
|||||||
|
|
||||||
import { defaultPageNav } from '../../RuleViewer';
|
import { defaultPageNav } from '../../RuleViewer';
|
||||||
import { PluginOriginBadge } from '../../plugins/PluginOriginBadge';
|
import { PluginOriginBadge } from '../../plugins/PluginOriginBadge';
|
||||||
|
import { getAllDataSources } from '../../utils/config';
|
||||||
import { Annotation } from '../../utils/constants';
|
import { Annotation } from '../../utils/constants';
|
||||||
import { makeDashboardLink, makePanelLink } from '../../utils/misc';
|
import { makeDashboardLink, makePanelLink } from '../../utils/misc';
|
||||||
import {
|
import {
|
||||||
@@ -195,10 +197,41 @@ const createMetadata = (rule: CombinedRule): PageInfoItem[] => {
|
|||||||
}
|
}
|
||||||
if (isGrafanaRecordingRule(rule.rulerRule)) {
|
if (isGrafanaRecordingRule(rule.rulerRule)) {
|
||||||
const metric = rule.rulerRule?.grafana_alert.record?.metric ?? '';
|
const metric = rule.rulerRule?.grafana_alert.record?.metric ?? '';
|
||||||
metadata.push({
|
|
||||||
label: 'Metric name',
|
const dSWithRecordingRulesUrl = getDataSourceForRecordingRules();
|
||||||
value: <Text color="primary">{metric}</Text>,
|
|
||||||
});
|
if (dSWithRecordingRulesUrl) {
|
||||||
|
// if we have a datasource with recording rules, we can link to explore with the datasource and metric in the query
|
||||||
|
const exploreLink = createRelativeUrl('/explore', {
|
||||||
|
left: JSON.stringify({
|
||||||
|
datasource: dSWithRecordingRulesUrl.uid,
|
||||||
|
queries: [
|
||||||
|
{
|
||||||
|
refId: 'A',
|
||||||
|
datasource: { type: dSWithRecordingRulesUrl.type, uid: dSWithRecordingRulesUrl.uid },
|
||||||
|
expr: `${metric}{}`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
range: { from: 'now-1h', to: 'now' },
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
metadata.push({
|
||||||
|
label: 'Metric name',
|
||||||
|
value: (
|
||||||
|
<TextLink variant="bodySmall" href={exploreLink} external>
|
||||||
|
{metric}
|
||||||
|
</TextLink>
|
||||||
|
),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// if we don't have a datasource with recording rules, we can just show the metric name
|
||||||
|
// this can happen if the datasource with the url specified in the config is not added as a datasource in Grafana
|
||||||
|
metadata.push({
|
||||||
|
label: 'Metric name',
|
||||||
|
value: <Text color="primary">{metric}</Text>,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (interval) {
|
if (interval) {
|
||||||
@@ -219,6 +252,12 @@ const createMetadata = (rule: CombinedRule): PageInfoItem[] => {
|
|||||||
return metadata;
|
return metadata;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function getDataSourceForRecordingRules() {
|
||||||
|
const urlForRecordingRules = config.unifiedAlerting.grafanaRecordingRulesUrl;
|
||||||
|
const allDs = getAllDataSources();
|
||||||
|
return allDs.find((ds) => ds.url === urlForRecordingRules);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO move somewhere else
|
// TODO move somewhere else
|
||||||
export const createListFilterLink = (values: Array<[string, string]>) => {
|
export const createListFilterLink = (values: Array<[string, string]>) => {
|
||||||
const params = new URLSearchParams([['search', values.map(([key, value]) => `${key}:"${value}"`).join(' ')]]);
|
const params = new URLSearchParams([['search', values.map(([key, value]) => `${key}:"${value}"`).join(' ')]]);
|
||||||
|
|||||||
Reference in New Issue
Block a user