Commit ccf89acc authored by Pawel Chojnacki's avatar Pawel Chojnacki

expand Namespaces:: and refactoring yaml parsing out of MetricGroup class

parent c7a1da80
...@@ -159,7 +159,7 @@ class Environment < ActiveRecord::Base ...@@ -159,7 +159,7 @@ class Environment < ActiveRecord::Base
def additional_metrics def additional_metrics
if has_additional_metrics? if has_additional_metrics?
project.monitoring_service.reactive_query(Gitlab::Prometheus::Queries::AdditionalMetricsQuery.name, self.id, &:itself) project.monitoring_service.reactive_query(Gitlab::Prometheus::Queries::AdditionalMetricsEnvironmentQuery.name, self.id, &:itself)
end end
end end
......
module Gitlab
module Prometheus
module AdditionalMetricsParser
extend self
def load_groups_from_yaml
additional_metrics_raw.map(&method(:new))
end
private
def metrics_from_list(list)
list.map { |entry| metric_from_entry(entry) }
end
def metric_from_entry(entry)
missing_fields = [:title, :required_metrics, :weight, :queries].select { |key| !entry.has_key?(key) }
raise ParsingError.new("entry missing required fields #{missing_fields}") unless missing_fields.empty?
Metric.new(entry[:title], entry[:required_metrics], entry[:weight], entry[:y_label], entry[:queries])
end
def group_from_entry(entry)
missing_fields = [:group, :priority, :metrics].select { |key| !entry.has_key?(key) }
raise ParsingError.new("entry missing required fields #{missing_fields}") unless missing_fields.empty?
group = MetricGroup.new(entry[:group], entry[:priority])
group.tap { |g| g.metrics = Metric.metrics_from_list(entry[:metrics]) }
end
def additional_metrics_raw
@additional_metrics_raw ||= YAML.load_file(Rails.root.join('config/additional_metrics.yml'))&.map(&:deep_symbolize_keys).freeze
end
end
end
end
module Gitlab::Prometheus module Gitlab
module Prometheus
class Metric class Metric
attr_reader :group, :title, :required_metrics, :weight, :y_label, :queries attr_reader :group, :title, :required_metrics, :weight, :y_label, :queries
...@@ -9,16 +10,6 @@ module Gitlab::Prometheus ...@@ -9,16 +10,6 @@ module Gitlab::Prometheus
@y_label = y_label || 'Values' @y_label = y_label || 'Values'
@queries = queries @queries = queries
end end
def self.metric_from_entry(entry)
missing_fields = [:title, :required_metrics, :weight, :queries].select { |key| !entry.has_key?(key) }
raise ParsingError.new("entry missing required fields #{missing_fields}") unless missing_fields.empty?
Metric.new(entry[:title], entry[:required_metrics], entry[:weight], entry[:y_label], entry[:queries])
end
def self.metrics_from_list(list)
list.map { |entry| metric_from_entry(entry) }
end end
end end
end end
module Gitlab::Prometheus module Gitlab
module Prometheus
class MetricGroup class MetricGroup
attr_reader :priority, :name attr_reader :priority, :name
attr_accessor :metrics attr_accessor :metrics
def initialize(name, priority, metrics = []) def initialize(name:, priority:, metrics: [])
@name = name @name = name
@priority = priority @priority = priority
@metrics = metrics @metrics = metrics
end end
def self.all def self.all
load_groups_from_yaml AdditionalMetricsParser.load_groups_from_yaml
end end
def self.load_groups_from_yaml
additional_metrics_raw.map(&method(:group_from_entry))
end
def self.group_from_entry(entry)
missing_fields = [:group, :priority, :metrics].select { |key| !entry.has_key?(key) }
raise ParsingError.new("entry missing required fields #{missing_fields}") unless missing_fields.empty?
group = MetricGroup.new(entry[:group], entry[:priority])
group.metrics = Metric.metrics_from_list(entry[:metrics])
group
end
def self.additional_metrics_raw
@additional_metrics_raw ||= YAML.load_file(Rails.root.join('config/additional_metrics.yml'))&.map(&:deep_symbolize_keys).freeze
end end
end end
end end
module Gitlab::Prometheus module Gitlab
module Prometheus
ParsingError = Class.new(StandardError) ParsingError = Class.new(StandardError)
end
end end
module Gitlab::Prometheus::Queries module Gitlab
class AdditionalMetricsDeploymentQuery < AdditionalMetricsQuery module Prometheus
module Queries
class AdditionalMetricsDeploymentQuery < BaseQuery
include QueryAdditionalMetrics
def query(deployment_id) def query(deployment_id)
deployment = Deployment.find_by(id: deployment_id) deployment = Deployment.find_by(id: deployment_id)
query_context = { query_context = {
...@@ -12,4 +16,6 @@ module Gitlab::Prometheus::Queries ...@@ -12,4 +16,6 @@ module Gitlab::Prometheus::Queries
query_metrics(query_context) query_metrics(query_context)
end end
end end
end
end
end end
module Gitlab
module Prometheus
module Queries
class AdditionalMetricsEnvironmentQuery < BaseQuery
include QueryAdditionalMetrics
def query(environment_id)
environment = Environment.find_by(id: environment_id)
query_context = {
environment_slug: environment.slug,
environment_filter: %{container_name!="POD",environment="#{environment.slug}"},
timeframe_start: 8.hours.ago.to_f,
timeframe_end: Time.now.to_f
}
query_metrics(query_context)
end
end
end
end
end
module Gitlab::Prometheus::Queries
class AdditionalMetricsQuery < BaseQuery
def query(environment_id)
environment = Environment.find_by(id: environment_id)
query_context = {
environment_slug: environment.slug,
environment_filter: %{container_name!="POD",environment="#{environment.slug}"},
timeframe_start: 8.hours.ago.to_f,
timeframe_end: Time.now.to_f
}
query_metrics(query_context)
end
protected
def query_metrics(query_context)
query_processor = method(:process_query).curry[query_context]
groups = matched_metrics.map do |group|
metrics = group.metrics.map do |metric|
{
title: metric.title,
weight: metric.weight,
y_label: metric.y_label,
queries: metric.queries.map(&query_processor).select(&method(:query_with_result))
}
end
{
group: group.name,
priority: group.priority,
metrics: metrics.select(&method(:metric_with_any_queries))
}
end
groups.select(&method(:group_with_any_metrics))
end
private
def metric_with_any_queries(metric)
metric[:queries]&.count&.> 0
end
def group_with_any_metrics(group)
group[:metrics]&.count&.> 0
end
def query_with_result(query)
query[:result]&.any? do |item|
item&.[](:values)&.any? || item&.[](:value)&.any?
end
end
def process_query(context, query)
query_with_result = query.dup
query_with_result[:result] =
if query.has_key?(:query_range)
client_query_range(query[:query_range] % context, start: context[:timeframe_start], stop: context[:timeframe_end])
else
client_query(query[:query] % context, time: context[:timeframe_end])
end
query_with_result
end
def available_metrics
@available_metrics ||= client_label_values || []
end
def matched_metrics
result = Gitlab::Prometheus::MetricGroup.all.map do |group|
group.metrics.select! do |metric|
metric.required_metrics.all?(&available_metrics.method(:include?))
end
group
end
result.select { |group| group.metrics.any? }
end
end
end
module Gitlab::Prometheus::Queries module Gitlab
module Prometheus
module Queries
class DeploymentQuery < BaseQuery class DeploymentQuery < BaseQuery
def query(deployment_id) def query(deployment_id)
deployment = Deployment.find_by(id: deployment_id) deployment = Deployment.find_by(id: deployment_id)
...@@ -23,4 +25,6 @@ module Gitlab::Prometheus::Queries ...@@ -23,4 +25,6 @@ module Gitlab::Prometheus::Queries
} }
end end
end end
end
end
end end
module Gitlab::Prometheus::Queries module Gitlab
module Prometheus
module Queries
class EnvironmentQuery < BaseQuery class EnvironmentQuery < BaseQuery
def query(environment_id) def query(environment_id)
environment = Environment.find_by(id: environment_id) environment = Environment.find_by(id: environment_id)
...@@ -17,4 +19,6 @@ module Gitlab::Prometheus::Queries ...@@ -17,4 +19,6 @@ module Gitlab::Prometheus::Queries
} }
end end
end end
end
end
end end
module Gitlab::Prometheus::Queries module Gitlab
module Prometheus
module Queries
class MatchedMetricsQuery < BaseQuery class MatchedMetricsQuery < BaseQuery
MAX_QUERY_ITEMS = 40.freeze MAX_QUERY_ITEMS = 40.freeze
...@@ -73,4 +75,6 @@ module Gitlab::Prometheus::Queries ...@@ -73,4 +75,6 @@ module Gitlab::Prometheus::Queries
end end
end end
end end
end
end
end end
module Gitlab
module Prometheus
module Queries
module QueryAdditionalMetrics
def query_metrics(query_context)
query_processor = method(:process_query).curry[query_context]
groups = matched_metrics.map do |group|
metrics = group.metrics.map do |metric|
{
title: metric.title,
weight: metric.weight,
y_label: metric.y_label,
queries: metric.queries.map(&query_processor).select(&method(:query_with_result))
}
end
{
group: group.name,
priority: group.priority,
metrics: metrics.select(&method(:metric_with_any_queries))
}
end
groups.select(&method(:group_with_any_metrics))
end
private
def metric_with_any_queries(metric)
metric[:queries]&.count&.> 0
end
def group_with_any_metrics(group)
group[:metrics]&.count&.> 0
end
def query_with_result(query)
query[:result]&.any? do |item|
item&.[](:values)&.any? || item&.[](:value)&.any?
end
end
def process_query(context, query)
query_with_result = query.dup
query_with_result[:result] =
if query.has_key?(:query_range)
client_query_range(query[:query_range] % context, start: context[:timeframe_start], stop: context[:timeframe_end])
else
client_query(query[:query] % context, time: context[:timeframe_end])
end
query_with_result
end
def available_metrics
@available_metrics ||= client_label_values || []
end
def matched_metrics
result = Gitlab::Prometheus::MetricGroup.all.map do |group|
group.metrics.select! do |metric|
metric.required_metrics.all?(&available_metrics.method(:include?))
end
group
end
result.select { |group| group.metrics.any? }
end
end
end
end
end
require 'spec_helper' require 'spec_helper'
describe Gitlab::Prometheus::Queries::AdditionalMetricsQuery, lib: true do describe Gitlab::Prometheus::Queries::AdditionalMetricsEnvironmentQuery, lib: true do
include Prometheus::MetricBuilders include Prometheus::MetricBuilders
let(:client) { double('prometheus_client') } let(:client) { double('prometheus_client') }
......
...@@ -453,7 +453,7 @@ describe Environment, models: true do ...@@ -453,7 +453,7 @@ describe Environment, models: true do
it 'returns the additional metrics from the deployment service' do it 'returns the additional metrics from the deployment service' do
expect(project.monitoring_service).to receive(:reactive_query) expect(project.monitoring_service).to receive(:reactive_query)
.with(Gitlab::Prometheus::Queries::AdditionalMetricsQuery.name, environment.id) .with(Gitlab::Prometheus::Queries::AdditionalMetricsEnvironmentQuery.name, environment.id)
.and_return(:fake_metrics) .and_return(:fake_metrics)
is_expected.to eq(:fake_metrics) is_expected.to eq(:fake_metrics)
......
...@@ -21,7 +21,7 @@ module Prometheus ...@@ -21,7 +21,7 @@ module Prometheus
end end
def simple_metric_group(name: 'name', metrics: simple_metrics) def simple_metric_group(name: 'name', metrics: simple_metrics)
Gitlab::Prometheus::MetricGroup.new(name, 1, metrics) Gitlab::Prometheus::MetricGroup.new(name: name, priority: 1, metrics: metrics)
end end
end end
end end
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