Commit 830743b2 authored by Vitali Tatarintev's avatar Vitali Tatarintev Committed by Imre Farkas

Move embedded metric for Prometheus alerts to Core

Part of migrating Alert to CE
parent 839037bf
...@@ -7,6 +7,7 @@ module Projects ...@@ -7,6 +7,7 @@ module Projects
GENERIC_ALERT_SUMMARY_ANNOTATIONS = %w(monitoring_tool service hosts).freeze GENERIC_ALERT_SUMMARY_ANNOTATIONS = %w(monitoring_tool service hosts).freeze
MARKDOWN_LINE_BREAK = " \n".freeze MARKDOWN_LINE_BREAK = " \n".freeze
INCIDENT_LABEL_NAME = IncidentManagement::CreateIssueService::INCIDENT_LABEL[:title].freeze INCIDENT_LABEL_NAME = IncidentManagement::CreateIssueService::INCIDENT_LABEL[:title].freeze
METRIC_TIME_WINDOW = 30.minutes
def full_title def full_title
[environment_name, alert_title].compact.join(': ') [environment_name, alert_title].compact.join(': ')
...@@ -119,9 +120,63 @@ module Projects ...@@ -119,9 +120,63 @@ module Projects
Array(hosts.value).join(' ') Array(hosts.value).join(' ')
end end
def metric_embed_for_alert; end def metric_embed_for_alert
url = embed_url_for_gitlab_alert || embed_url_for_self_managed_alert
"\n[](#{url})" if url
end end
def embed_url_for_gitlab_alert
return unless gitlab_alert
metrics_dashboard_project_prometheus_alert_url(
project,
gitlab_alert.prometheus_metric_id,
environment_id: environment.id,
**alert_embed_window_params(embed_time)
)
end
def embed_url_for_self_managed_alert
return unless environment && full_query && title
metrics_dashboard_project_environment_url(
project,
environment,
embed_json: dashboard_for_self_managed_alert.to_json,
**alert_embed_window_params(embed_time)
)
end
def embed_time
starts_at ? Time.rfc3339(starts_at) : Time.current
end
def alert_embed_window_params(time)
{
start: format_embed_timestamp(time - METRIC_TIME_WINDOW),
end: format_embed_timestamp(time + METRIC_TIME_WINDOW)
}
end
def format_embed_timestamp(time)
time.utc.strftime('%FT%TZ')
end end
end
Projects::Prometheus::AlertPresenter.prepend_if_ee('EE::Projects::Prometheus::AlertPresenter') def dashboard_for_self_managed_alert
{
panel_groups: [{
panels: [{
type: 'line-graph',
title: title,
y_label: y_label,
metrics: [{
query_range: full_query
}]
}]
}]
}
end
end
end
end
---
title: Moves embedded metrics for Prometheus alerts to Core
merge_request: 31203
author:
type: changed
# frozen_string_literal: true
module EE
module Projects
module Prometheus
module AlertPresenter
extend ::Gitlab::Utils::Override
METRIC_TIME_WINDOW = 30.minutes
override :metric_embed_for_alert
def metric_embed_for_alert
url = embed_url_for_gitlab_alert || embed_url_for_self_managed_alert
"\n[](#{url})" if url
end
private
def embed_url_for_gitlab_alert
return unless gitlab_alert
metrics_dashboard_project_prometheus_alert_url(
project,
gitlab_alert.prometheus_metric_id,
environment_id: environment.id,
**alert_embed_window_params(embed_time)
)
end
def embed_url_for_self_managed_alert
return unless environment && full_query && title
metrics_dashboard_project_environment_url(
project,
environment,
embed_json: dashboard_for_self_managed_alert.to_json,
**alert_embed_window_params(embed_time)
)
end
def embed_time
starts_at ? Time.rfc3339(starts_at) : Time.current
end
def alert_embed_window_params(time)
{
start: format_embed_timestamp(time - METRIC_TIME_WINDOW),
end: format_embed_timestamp(time + METRIC_TIME_WINDOW)
}
end
def format_embed_timestamp(time)
time.utc.strftime('%FT%TZ')
end
def dashboard_for_self_managed_alert
{
panel_groups: [{
panels: [{
type: 'line-graph',
title: title,
y_label: y_label,
metrics: [{
query_range: full_query
}]
}]
}]
}
end
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe Projects::Prometheus::AlertPresenter do
let_it_be(:project) { create(:project) }
let(:presenter) { described_class.new(alert) }
let(:payload) { {} }
let(:alert) { create(:alerting_alert, project: project, payload: payload) }
let(:markdown_line_break) { ' ' }
let(:starts_at) { '2018-03-12T09:06:00Z' }
describe '#issue_summary_markdown' do
shared_examples_for 'markdown with metrics embed' do
let(:expected_markdown) do
<<~MARKDOWN.chomp
#### Summary
**Start time:** #{presenter.starts_at}#{markdown_line_break}
**full_query:** `avg(metric) > 1.0`
[](#{url})
MARKDOWN
end
context 'without a starting time available' do
around do |example|
Timecop.freeze(starts_at) { example.run }
end
it { is_expected.to eq(expected_markdown) }
end
context 'with a starting time available' do
before do
payload['startsAt'] = starts_at
end
it { is_expected.to eq(expected_markdown) }
end
end
subject { presenter.issue_summary_markdown }
context 'for gitlab-managed prometheus alerts' do
let(:gitlab_alert) { create(:prometheus_alert, project: project) }
let(:metric_id) { gitlab_alert.prometheus_metric_id }
let(:env_id) { gitlab_alert.environment_id }
before do
payload['labels'] = { 'gitlab_alert_id' => metric_id }
end
let(:url) { "http://localhost/#{project.full_path}/prometheus/alerts/#{metric_id}/metrics_dashboard?end=2018-03-12T09%3A36%3A00Z&environment_id=#{env_id}&start=2018-03-12T08%3A36%3A00Z" }
it_behaves_like 'markdown with metrics embed'
end
context 'for alerts from a self-managed prometheus' do
let!(:environment) { create(:environment, project: project, name: 'production') }
let(:url) { "http://localhost/#{project.full_path}/-/environments/#{environment.id}/metrics_dashboard?embed_json=#{CGI.escape(embed_content.to_json)}&end=2018-03-12T09%3A36%3A00Z&start=2018-03-12T08%3A36%3A00Z" }
let(:title) { 'title' }
let(:y_label) { 'y_label' }
let(:query) { 'avg(metric) > 1.0' }
let(:embed_content) do
{
panel_groups: [{
panels: [{
type: 'line-graph',
title: title,
y_label: y_label,
metrics: [{ query_range: query }]
}]
}]
}
end
before do
# Setup embed time range
payload['startsAt'] = starts_at
# Setup query
payload['generatorURL'] = "http://host?g0.expr=#{CGI.escape(query)}"
# Setup environment
payload['labels'] ||= {}
payload['labels']['gitlab_environment_name'] = 'production'
# Setup chart title & axis labels
payload['annotations'] ||= {}
payload['annotations']['title'] = 'title'
payload['annotations']['gitlab_y_label'] = 'y_label'
end
it_behaves_like 'markdown with metrics embed'
context 'without y_label' do
let(:y_label) { title }
before do
payload['annotations'].delete('gitlab_y_label')
end
it_behaves_like 'markdown with metrics embed'
end
context 'when not enough information is present for an embed' do
let(:expected_markdown) do
<<~MARKDOWN.chomp
#### Summary
**Start time:** #{presenter.starts_at}#{markdown_line_break}
**full_query:** `avg(metric) > 1.0`
MARKDOWN
end
context 'without title' do
before do
payload['annotations'].delete('title')
end
it { is_expected.to eq(expected_markdown) }
end
context 'without environment' do
before do
payload['labels'].delete('gitlab_environment_name')
end
it { is_expected.to eq(expected_markdown) }
end
context 'without full_query' do
let(:expected_markdown) do
<<~MARKDOWN.chomp
#### Summary
**Start time:** #{presenter.starts_at}
MARKDOWN
end
before do
payload.delete('generatorURL')
end
it { is_expected.to eq(expected_markdown) }
end
end
end
end
end
...@@ -152,6 +152,148 @@ describe Projects::Prometheus::AlertPresenter do ...@@ -152,6 +152,148 @@ describe Projects::Prometheus::AlertPresenter do
end end
end end
end end
context 'with embedded metrics' do
let(:starts_at) { '2018-03-12T09:06:00Z' }
shared_examples_for 'markdown with metrics embed' do
let(:expected_markdown) do
<<~MARKDOWN.chomp
#### Summary
**Start time:** #{presenter.starts_at}#{markdown_line_break}
**full_query:** `avg(metric) > 1.0`
[](#{url})
MARKDOWN
end
context 'without a starting time available' do
around do |example|
Timecop.freeze(starts_at) { example.run }
end
it { is_expected.to eq(expected_markdown) }
end
context 'with a starting time available' do
before do
payload['startsAt'] = starts_at
end
it { is_expected.to eq(expected_markdown) }
end
end
context 'for gitlab-managed prometheus alerts' do
let(:gitlab_alert) { create(:prometheus_alert, project: project) }
let(:metric_id) { gitlab_alert.prometheus_metric_id }
let(:env_id) { gitlab_alert.environment_id }
before do
payload['labels'] = { 'gitlab_alert_id' => metric_id }
end
let(:url) { "http://localhost/#{project.full_path}/prometheus/alerts/#{metric_id}/metrics_dashboard?end=2018-03-12T09%3A36%3A00Z&environment_id=#{env_id}&start=2018-03-12T08%3A36%3A00Z" }
it_behaves_like 'markdown with metrics embed'
end
context 'for alerts from a self-managed prometheus' do
let!(:environment) { create(:environment, project: project, name: 'production') }
let(:url) { "http://localhost/#{project.full_path}/-/environments/#{environment.id}/metrics_dashboard?embed_json=#{CGI.escape(embed_content.to_json)}&end=2018-03-12T09%3A36%3A00Z&start=2018-03-12T08%3A36%3A00Z" }
let(:title) { 'title' }
let(:y_label) { 'y_label' }
let(:query) { 'avg(metric) > 1.0' }
let(:embed_content) do
{
panel_groups: [{
panels: [{
type: 'line-graph',
title: title,
y_label: y_label,
metrics: [{ query_range: query }]
}]
}]
}
end
before do
# Setup embed time range
payload['startsAt'] = starts_at
# Setup query
payload['generatorURL'] = "http://host?g0.expr=#{CGI.escape(query)}"
# Setup environment
payload['labels'] ||= {}
payload['labels']['gitlab_environment_name'] = 'production'
# Setup chart title & axis labels
payload['annotations'] ||= {}
payload['annotations']['title'] = 'title'
payload['annotations']['gitlab_y_label'] = 'y_label'
end
it_behaves_like 'markdown with metrics embed'
context 'without y_label' do
let(:y_label) { title }
before do
payload['annotations'].delete('gitlab_y_label')
end
it_behaves_like 'markdown with metrics embed'
end
context 'when not enough information is present for an embed' do
let(:expected_markdown) do
<<~MARKDOWN.chomp
#### Summary
**Start time:** #{presenter.starts_at}#{markdown_line_break}
**full_query:** `avg(metric) > 1.0`
MARKDOWN
end
context 'without title' do
before do
payload['annotations'].delete('title')
end
it { is_expected.to eq(expected_markdown) }
end
context 'without environment' do
before do
payload['labels'].delete('gitlab_environment_name')
end
it { is_expected.to eq(expected_markdown) }
end
context 'without full_query' do
let(:expected_markdown) do
<<~MARKDOWN.chomp
#### Summary
**Start time:** #{presenter.starts_at}
MARKDOWN
end
before do
payload.delete('generatorURL')
end
it { is_expected.to eq(expected_markdown) }
end
end
end
end
end end
describe '#show_performance_dashboard_link?' do describe '#show_performance_dashboard_link?' do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment