Commit d1972397 authored by Pawel Chojnacki's avatar Pawel Chojnacki

Add group enum to custom metrics model + allow querying custom metrics

parent 152468d4
class PrometheusMetric < ActiveRecord::Base
belongs_to :project, required: true, validate: true
enum group: [:business, :response, :system]
validates :title, presence: true
validates :query, presence: true
def self.to_grouped_query_metrics
self.all.group_by(&:group).map do |name, metrics|
[name, metrics.map(&:to_query_metric)]
end
end
def to_query_metric
Gitlab::Prometheus::Metric.new(title: title, required_metrics: [], weight: 0, y_label: y_label, queries: build_queries)
end
private
def build_queries
[
{
query_range: query,
unit: unit,
label: legend
}
]
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddGroupToPrometheusMetrics < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
add_column :prometheus_metrics, :group, :integer
add_index :prometheus_metrics, :group
end
end
......@@ -6,9 +6,19 @@ module Gitlab
attr_accessor :name, :priority, :metrics
validates :name, :priority, :metrics, presence: true
def self.all
def self.common_metrics
AdditionalMetricsParser.load_groups_from_yaml
end
def self.for_project(project)
common_metrics + custom_metrics(project)
end
def self.custom_metrics(project)
project.prometheus_metrics.to_grouped_query_metrics.map do |name, metrics|
MetricGroup.new(name: name, priority: 0, metrics: metrics)
end
end
end
end
end
......@@ -7,6 +7,7 @@ module Gitlab
def query(deployment_id)
Deployment.find_by(id: deployment_id).try do |deployment|
query_metrics(
deployment.project,
common_query_context(
deployment.environment,
timeframe_start: (deployment.created_at - 30.minutes).to_f,
......
......@@ -7,6 +7,7 @@ module Gitlab
def query(environment_id)
::Environment.find_by(id: environment_id).try do |environment|
query_metrics(
environment.project,
common_query_context(environment, timeframe_start: 8.hours.ago.to_f, timeframe_end: Time.now.to_f)
)
end
......
......@@ -18,7 +18,7 @@ module Gitlab
private
def groups_data
metrics_groups = groups_with_active_metrics(Gitlab::Prometheus::MetricGroup.all)
metrics_groups = groups_with_active_metrics(Gitlab::Prometheus::MetricGroup.common_metrics)
lookup = active_series_lookup(metrics_groups)
groups = {}
......
......@@ -2,10 +2,10 @@ module Gitlab
module Prometheus
module Queries
module QueryAdditionalMetrics
def query_metrics(query_context)
def query_metrics(project, query_context)
query_processor = method(:process_query).curry[query_context]
groups = matched_metrics.map do |group|
groups = matched_metrics(project).map do |group|
metrics = group.metrics.map do |metric|
{
title: metric.title,
......@@ -60,8 +60,8 @@ module Gitlab
@available_metrics ||= client_label_values || []
end
def matched_metrics
result = Gitlab::Prometheus::MetricGroup.all.map do |group|
def matched_metrics(project)
result = Gitlab::Prometheus::MetricGroup.for_project(project).map do |group|
group.metrics.select! do |metric|
metric.required_metrics.all?(&available_metrics.method(:include?))
end
......
module Gitlab
module Prometheus
class Query
include ActiveModel::Model
# include ActiveRecord::Base
attr_accessor :unit, :series_dsl, :label, :type, :track
validates :title, :required_metrics, :weight, :y_label, :queries, presence: true
def initialize(params = {})
super(params)
end
end
end
end
......@@ -4,6 +4,7 @@ FactoryBot.define do
query 'avg(metric)'
y_label 'y_label'
unit 'm/s'
group :business
legend 'legend'
project nil
end
......
......@@ -24,7 +24,7 @@ describe Gitlab::Prometheus::Queries::MatchedMetricsQuery do
context 'with one group where two metrics is found' do
before do
allow(metric_group_class).to receive(:all).and_return([simple_metric_group])
allow(metric_group_class).to receive(:common_metrics).and_return([simple_metric_group])
allow(client).to receive(:label_values).and_return(metric_names)
end
......@@ -70,7 +70,7 @@ describe Gitlab::Prometheus::Queries::MatchedMetricsQuery do
context 'with one group where only one metric is found' do
before do
allow(metric_group_class).to receive(:all).and_return([simple_metric_group])
allow(metric_group_class).to receive(:common_metrics).and_return([simple_metric_group])
allow(client).to receive(:label_values).and_return('metric_a')
end
......@@ -99,7 +99,7 @@ describe Gitlab::Prometheus::Queries::MatchedMetricsQuery do
let(:second_metric_group) { simple_metric_group(name: 'nameb', metrics: simple_metrics(added_metric_name: 'metric_c')) }
before do
allow(metric_group_class).to receive(:all).and_return([simple_metric_group, second_metric_group])
allow(metric_group_class).to receive(:common_metrics).and_return([simple_metric_group, second_metric_group])
allow(client).to receive(:label_values).and_return('metric_c')
end
......
......@@ -12,11 +12,12 @@ RSpec.shared_examples 'additional metrics query' do
let(:client) { double('prometheus_client') }
let(:query_result) { described_class.new(client).query(*query_params) }
let(:environment) { create(:environment, slug: 'environment-slug') }
let(:project) { create(:project) }
let(:environment) { create(:environment, slug: 'environment-slug', project: project) }
before do
allow(client).to receive(:label_values).and_return(metric_names)
allow(metric_group_class).to receive(:all).and_return([simple_metric_group(metrics: [simple_metric])])
allow(metric_group_class).to receive(:common_metrics).and_return([simple_metric_group(metrics: [simple_metric])])
end
context 'metrics query context' do
......@@ -24,13 +25,14 @@ RSpec.shared_examples 'additional metrics query' do
shared_examples 'query context containing environment slug and filter' do
it 'contains ci_environment_slug' do
expect(subject).to receive(:query_metrics).with(hash_including(ci_environment_slug: environment.slug))
expect(subject).to receive(:query_metrics).with(project, hash_including(ci_environment_slug: environment.slug))
subject.query(*query_params)
end
it 'contains environment filter' do
expect(subject).to receive(:query_metrics).with(
project,
hash_including(
environment_filter: "container_name!=\"POD\",environment=\"#{environment.slug}\""
)
......@@ -48,7 +50,7 @@ RSpec.shared_examples 'additional metrics query' do
it_behaves_like 'query context containing environment slug and filter'
it 'query context contains kube_namespace' do
expect(subject).to receive(:query_metrics).with(hash_including(kube_namespace: kube_namespace))
expect(subject).to receive(:query_metrics).with(project, hash_including(kube_namespace: kube_namespace))
subject.query(*query_params)
end
......@@ -72,7 +74,7 @@ RSpec.shared_examples 'additional metrics query' do
it_behaves_like 'query context containing environment slug and filter'
it 'query context contains empty kube_namespace' do
expect(subject).to receive(:query_metrics).with(hash_including(kube_namespace: ''))
expect(subject).to receive(:query_metrics).with(project, hash_including(kube_namespace: ''))
subject.query(*query_params)
end
......@@ -81,7 +83,7 @@ RSpec.shared_examples 'additional metrics query' do
context 'with one group where two metrics is found' do
before do
allow(metric_group_class).to receive(:all).and_return([simple_metric_group])
allow(metric_group_class).to receive(:common_metrics).and_return([simple_metric_group])
end
context 'some queries return results' do
......@@ -113,11 +115,55 @@ RSpec.shared_examples 'additional metrics query' do
end
end
context 'with custom metrics' do
let!(:metric) { create(:prometheus_metric, project: project) }
before do
allow(client).to receive(:query_range).with('avg(metric)', any_args).and_return(query_range_result)
end
context 'without common metrics' do
before do
allow(metric_group_class).to receive(:common_metrics).and_return([])
end
it 'return group data for custom metric' do
queries_with_result = { queries: [{ query_range: 'avg(metric)', unit: 'm/s', label: 'legend', result: query_range_result }] }
expect(query_result).to match_schema('prometheus/additional_metrics_query_result')
expect(query_result.count).to eq(1)
expect(query_result.first[:metrics].count).to eq(1)
expect(query_result.first[:metrics].first).to include(queries_with_result)
end
end
context 'with common metrics' do
before do
allow(client).to receive(:query_range).with('query_range_a', any_args).and_return(query_range_result)
allow(metric_group_class).to receive(:common_metrics).and_return([simple_metric_group(metrics: [simple_metric])])
end
it 'return group data for custom metric' do
custom_queries_with_result = { queries: [{ query_range: 'avg(metric)', unit: 'm/s', label: 'legend', result: query_range_result }] }
common_queries_with_result = { queries: [{ query_range: 'query_range_a', result: query_range_result }] }
expect(query_result).to match_schema('prometheus/additional_metrics_query_result')
expect(query_result.count).to eq(2)
expect(query_result).to all(satisfy { |r| r[:metrics].count == 1 })
expect(query_result[0][:metrics].first).to include(common_queries_with_result)
expect(query_result[1][:metrics].first).to include(custom_queries_with_result)
end
end
end
context 'with two groups with one metric each' do
let(:metrics) { [simple_metric(queries: [simple_query])] }
before do
allow(metric_group_class).to receive(:all).and_return(
allow(metric_group_class).to receive(:common_metrics).and_return(
[
simple_metric_group(name: 'group_a', metrics: [simple_metric(queries: [simple_query])]),
simple_metric_group(name: 'group_b', metrics: [simple_metric(title: 'title_b', queries: [simple_query('b')])])
......
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