2021-01-05 09:10:15 +00:00
# frozen_string_literal: true
module Gitlab
module Usage
class MetricDefinition
METRIC_SCHEMA_PATH = Rails . root . join ( 'config' , 'metrics' , 'schema.json' )
2021-03-05 15:09:12 +00:00
BASE_REPO_PATH = 'https://gitlab.com/gitlab-org/gitlab/-/blob/master'
2021-04-05 09:09:05 +00:00
DEPRECATED_METRIC_STATUSES = %w[ deprecated removed ] . to_set . freeze
2021-01-05 09:10:15 +00:00
attr_reader :path
attr_reader :attributes
def initialize ( path , opts = { } )
@path = path
@attributes = opts
end
def key
2021-01-21 09:08:52 +00:00
key_path
2021-01-05 09:10:15 +00:00
end
def to_h
attributes
end
2021-03-25 18:09:07 +00:00
def json_schema_path
return '' unless has_json_schema?
" #{ BASE_REPO_PATH } / #{ attributes [ :object_json_schema ] } "
end
def has_json_schema?
attributes [ :value_type ] == 'object' && attributes [ :object_json_schema ] . present?
end
2021-03-05 15:09:12 +00:00
def yaml_path
" #{ BASE_REPO_PATH } #{ path . delete_prefix ( Rails . root . to_s ) } "
end
2021-01-05 09:10:15 +00:00
def validate!
2021-01-25 12:09:07 +00:00
unless skip_validation?
self . class . schemer . validate ( attributes . stringify_keys ) . each do | error |
2021-03-16 18:11:53 +00:00
error_message = << ~ ERROR_MSG
Error type : #{error['type']}
Data : #{error['data']}
Path : #{error['data_pointer']}
Details : #{error['details']}
Metric file : #{path}
ERROR_MSG
Gitlab :: ErrorTracking . track_and_raise_for_dev_exception ( Gitlab :: Usage :: Metric :: InvalidMetricError . new ( error_message ) )
2021-01-25 12:09:07 +00:00
end
2021-01-05 09:10:15 +00:00
end
end
alias_method :to_dictionary , :to_h
class << self
def paths
2021-03-30 12:10:51 +00:00
@paths || = [ Rails . root . join ( 'config' , 'metrics' , '[^agg]*' , '*.yml' ) ]
2021-01-05 09:10:15 +00:00
end
2021-03-25 12:09:19 +00:00
def definitions ( skip_validation : false )
@skip_validation = skip_validation
2021-01-05 09:10:15 +00:00
@definitions || = load_all!
end
def schemer
@schemer || = :: JSONSchemer . schema ( Pathname . new ( METRIC_SCHEMA_PATH ) )
end
private
def load_all!
paths . each_with_object ( { } ) do | glob_path , definitions |
load_all_from_path! ( definitions , glob_path )
end
end
def load_from_file ( path )
definition = File . read ( path )
definition = YAML . safe_load ( definition )
definition . deep_symbolize_keys!
self . new ( path , definition ) . tap ( & :validate! )
rescue = > e
2021-03-15 18:09:05 +00:00
Gitlab :: ErrorTracking . track_and_raise_for_dev_exception ( Gitlab :: Usage :: Metric :: InvalidMetricError . new ( e . message ) )
2021-01-05 09:10:15 +00:00
end
def load_all_from_path! ( definitions , glob_path )
Dir . glob ( glob_path ) . each do | path |
definition = load_from_file ( path )
if previous = definitions [ definition . key ]
2021-03-15 18:09:05 +00:00
Gitlab :: ErrorTracking . track_and_raise_for_dev_exception ( Gitlab :: Usage :: Metric :: InvalidMetricError . new ( " Metric ' #{ definition . key } ' is already defined in ' #{ previous . path } ' " ) )
2021-01-05 09:10:15 +00:00
end
definitions [ definition . key ] = definition
end
end
end
private
def method_missing ( method , * args )
attributes [ method ] || super
end
2021-01-25 12:09:07 +00:00
def skip_validation?
2021-04-05 09:09:05 +00:00
! ! attributes [ :skip_validation ] || @skip_validation || DEPRECATED_METRIC_STATUSES . include? ( attributes [ :status ] )
2021-01-25 12:09:07 +00:00
end
2021-01-05 09:10:15 +00:00
end
end
end
2021-01-07 21:10:18 +00:00
Gitlab :: Usage :: MetricDefinition . prepend_if_ee ( 'EE::Gitlab::Usage::MetricDefinition' )