Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

remove gauge_with_time, add expired_stats_collector, add tests #5

Merged
merged 1 commit into from
Dec 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions lib/prometheus_exporter/ext/instrumentation/base_stats.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class << self
end

def initialize(client: PrometheusExporter::Client.default, metric_labels: {})
@metric_labels = metric_labels
@metric_labels = metric_labels.transform_keys(&:to_sym)
@client = client
end

Expand All @@ -25,16 +25,19 @@ def collect

# @param data [Array,Hash]
def collect_data(data)
metric = build_metric(data)
@client.send_json(metric)
data_list = data.is_a?(Array) ? data : [data]
metrics = data_list.map { |data_item| build_metric(data_item) }
metrics.map { |metric| @client.send_json(metric) }
end

# @param data [Hash]
# @return [Hash]
def build_metric(data)
metric = data.dup
metric = data.transform_keys(&:to_sym)
metric[:type] = type
metric[:labels] = (metric[:labels] || {}).merge(@metric_labels)
metric[:labels] ||= {}
metric[:labels].transform_keys!(&:to_sym)
metric[:labels].merge!(@metric_labels)
metric
end
end
Expand Down
7 changes: 0 additions & 7 deletions lib/prometheus_exporter/ext/instrumentation/periodic_stats.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ def start(frequency: 30, client: PrometheusExporter::Client.default, **)
rescue StandardError => e
client.logger.error("#{klass} Prometheus Exporter Failed To Collect Stats")
client.logger.error("#{e.class} #{e.backtrace&.join("\n")}")
@on_exception&.call(e) if defined?(@on_exception)
ensure
sleep frequency
end
Expand All @@ -44,12 +43,6 @@ def stop
end
@thread = nil
end

# Adds handler that will be called when exception is raised in the thread.
# @yieldparam exception [Exception]
def on_exception(&block)
@on_exception = block
end
end
end
end
59 changes: 0 additions & 59 deletions lib/prometheus_exporter/ext/metric/gauge_with_time.rb

This file was deleted.

33 changes: 0 additions & 33 deletions lib/prometheus_exporter/ext/metric/type_registry.rb

This file was deleted.

15 changes: 2 additions & 13 deletions lib/prometheus_exporter/ext/rspec/matchers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,19 @@

module PrometheusExporter::Ext::RSpec
module Matchers
def send_metrics(expected = nil)
def send_metrics(*expected)
expected = nil if expected.empty?
PrometheusExporter::Ext::RSpec::SendMetricsMatcher.new(expected)
end

def a_prometheus_metric(klass, name)
MetricMatcher.new(klass, name)
end

# Matches approximate milliseconds since epoch
# @param date_time [DateTime] default DateTime.now
# @param delta [Integer] default 1000 ms
# @return [RSpec::Matchers::BuiltIn::BeWithin]
def ms_since_epoch(date_time: DateTime.now, delta: 1_000)
be_within(delta).of(date_time.strftime('%Q').to_i)
end

def a_gauge_metric(name)
a_prometheus_metric(PrometheusExporter::Metric::Gauge, name)
end

def a_gauge_with_time_metric(name)
a_prometheus_metric(PrometheusExporter::Ext::Metric::GaugeWithTime, name)
end

def a_counter_metric(name)
a_prometheus_metric(PrometheusExporter::Metric::Counter, name)
end
Expand Down
4 changes: 1 addition & 3 deletions lib/prometheus_exporter/ext/rspec/send_metrics_matcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,7 @@ def description_of(object)
private

def deep_stringify_keys(hash)
hash.transform_keys(&:to_s).transform_values do |value|
value.is_a?(Hash) ? deep_stringify_keys(value) : value
end
JSON.parse JSON.generate(hash)
end
end
end
102 changes: 102 additions & 0 deletions lib/prometheus_exporter/ext/server/base_collector_methods.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# frozen_string_literal: true

require 'prometheus_exporter/metric'

module PrometheusExporter::Ext::Server
module BaseCollectorMethods
class << self
private

def included(klass)
super
klass.singleton_class.attr_accessor :type, :registered_metrics
klass.registered_metrics = {}
klass.extend ClassMethods
end
end

module ClassMethods
# Registers metric observer.
# @param name [Symbol] metric name.
# @param help [String] metric description.
# @param metric_class [Class<PrometheusExporter::Metric::Base>] observer class.
# @param args [Array] additional arguments for observer class.
# rubocop:disable Metrics/ParameterLists
def register_metric(name, help, metric_class, *args)
# rubocop:enable Metrics/ParameterLists
name = name.to_s
raise ArgumentError, "metric #{name} is already registered" if registered_metrics.key?(name)

registered_metrics[name] = { help:, metric_class:, args: }
end

# Registers PrometheusExporter::Metric::Counter observer.
# @param name [Symbol] metric name.
# @param help [String] metric description.
def register_counter(name, help)
register_metric(name, help, PrometheusExporter::Metric::Counter)
end

# Registers PrometheusExporter::Metric::Gauge observer.
# @param name [Symbol] metric name.
# @param help [String] metric description.
def register_gauge(name, help)
register_metric(name, help, PrometheusExporter::Metric::Gauge)
end

# Registers PrometheusExporter::Metric::Summary observer.
# @param name [Symbol] metric name.
# @param help [String] metric description.
# @param opts [Hash] additional options, supports `quantiles` key.
def register_summary(name, help, opts = {})
register_metric(name, help, PrometheusExporter::Metric::Summary, opts)
end

# Registers PrometheusExporter::Metric::Histogram observer.
# @param name [Symbol] metric name.
# @param help [String] metric description.
# @param opts [Hash] additional options, supports `buckets` key.
def register_histogram(name, help, opts = {})
register_metric(name, help, PrometheusExporter::Metric::Histogram, opts)
end
end

# @return [String]
def type
self.class.type
end

private

# Adds metrics to observers with matched name.
# @param observers [Hash] returned by #build_observers.
# @param obj [Hash] metric data.
def fill_observers(observers, obj)
observers.each do |name, observer|
value = obj[name]
observer.observe(value, obj['labels']) if value
end
end

# Generally metrics sent via PrometheusExporter::Ext::Instrumentation::BaseStats populate labels to `labels` key.
# But PrometheusExporter::Client populate it's own labels to `custom_labels` key.
# Here we merge them into single `labels` key.
# @param obj [Hash]
# @return [Hash]
def normalize_labels(obj)
obj['labels'] ||= {}
custom_labels = obj.delete('custom_labels')
obj['labels'].merge!(custom_labels) if custom_labels
obj
end

# @return [Hash] key is metric name, value is observer.
def build_observers
observers = {}
self.class.registered_metrics.each do |name, metric|
observers[name] = metric[:metric_class].new("#{type}_#{name}", metric[:help], *metric[:args])
end
observers
end
end
end
57 changes: 57 additions & 0 deletions lib/prometheus_exporter/ext/server/expired_stats_collector.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# frozen_string_literal: true

require_relative 'base_collector_methods'
require 'prometheus_exporter/server/metrics_container'

module PrometheusExporter::Ext::Server
module ExpiredStatsCollector
class << self
private

def included(klass)
super
klass.include BaseCollectorMethods
klass.singleton_class.attr_accessor :filter, :ttl
klass.ttl = 60
klass.extend ClassMethods
end
end

module ClassMethods
# Defines a rule how old metric will be replaced with new one.
# @yield compare new metric with existing one.
# @yieldparam new_metric [Hash] new metric data.
# @yieldparam metric [Hash] existing metric data.
# @yieldreturn [Boolean] if true existing metric will be replaced with new one.
def unique_metric_by(&block)
@filter = block
end
end

def initialize
super
@data = PrometheusExporter::Server::MetricsContainer.new(
ttl: self.class.ttl,
filter: self.class.filter
)
end

# Returns all metrics collected by this collector.
# @return [Array<PrometheusExporter::Metric::Base>]
def metrics
observers = build_observers
@data.each do |obj|
fill_observers(observers, obj)
end

observers.values
end

# Collects metric data received from client.
# @param obj [Hash] metric data.
def collect(obj)
normalize_labels(obj)
@data << obj
end
end
end
Loading