allow passing opts to Histogram and Summary from client. w/ burnettk (#46)

allow passing opts to Histogram and Summary from client. w/ burnettk (#46)

  • allow passing opts to Histogram and Summary from client. w/ burnettk

  • default opts to nil and let collector create the hash when needed and added client tests for it. w/ burnettk

diff --git a/lib/prometheus_exporter/client.rb b/lib/prometheus_exporter/client.rb
index 1f1d357..a128bb0 100644
--- a/lib/prometheus_exporter/client.rb
+++ b/lib/prometheus_exporter/client.rb
@@ -4,16 +4,16 @@ require 'socket'
 require 'thread'
 
 module PrometheusExporter
-
   class Client
     class RemoteMetric
       attr_reader :name, :type, :help
 
-      def initialize(name:, help:, type:, client:)
+      def initialize(name:, help:, type:, client:, opts: nil)
         @name = name
         @help = help
         @client = client
         @type = type
+        @opts = opts
       end
 
       def standard_values(value, keys, prometheus_exporter_action = nil)
@@ -25,6 +25,7 @@ module PrometheusExporter
           value: value
         }
         values[:prometheus_exporter_action] = prometheus_exporter_action if prometheus_exporter_action
+        values[:opts] = @opts if @opts
         values
       end
 
@@ -39,7 +40,6 @@ module PrometheusExporter
       def decrement(keys = nil, value = 1)
         @client.send_json(standard_values(value, keys, :decrement))
       end
-
     end
 
     def self.default
@@ -83,8 +83,8 @@ module PrometheusExporter
       @custom_labels = custom_labels
     end
 
-    def register(type, name, help)
-      metric = RemoteMetric.new(type: type, name: name, help: help, client: self)
+    def register(type, name, help, opts = nil)
+      metric = RemoteMetric.new(type: type, name: name, help: help, client: self, opts: opts)
       @metrics << metric
       metric
     end
diff --git a/lib/prometheus_exporter/server/collector.rb b/lib/prometheus_exporter/server/collector.rb
index 6dfe5b7..d650f98 100644
--- a/lib/prometheus_exporter/server/collector.rb
+++ b/lib/prometheus_exporter/server/collector.rb
@@ -72,6 +72,7 @@ module PrometheusExporter::Server
     def register_metric_unsafe(obj)
       name = obj["name"]
       help = obj["help"]
+      opts = symbolize_keys(obj["opts"] || {})
 
       metric =
         case obj["type"]
@@ -80,9 +81,9 @@ module PrometheusExporter::Server
         when "counter"
           PrometheusExporter::Metric::Counter.new(name, help)
         when "summary"
-          PrometheusExporter::Metric::Summary.new(name, help)
+          PrometheusExporter::Metric::Summary.new(name, help, opts)
         when "histogram"
-          PrometheusExporter::Metric::Histogram.new(name, help)
+          PrometheusExporter::Metric::Histogram.new(name, help, opts)
         end
 
       if metric
@@ -91,5 +92,9 @@ module PrometheusExporter::Server
         STDERR.puts "failed to register metric #{obj}"
       end
     end
+
+    def symbolize_keys(hash)
+      hash.inject({}) { |memo, k| memo[k.first.to_sym] = k.last; memo }
+    end
   end
 end
diff --git a/test/client_test.rb b/test/client_test.rb
index 6f30a3d..9202ca6 100644
--- a/test/client_test.rb
+++ b/test/client_test.rb
@@ -41,4 +41,14 @@ class PrometheusExporterTest < Minitest::Test
     result = client.find_registered_metric('counter_metric', type: :counter, help: 'helping')
     assert_equal(counter_metric, result)
   end
+
+  def test_standard_values
+    client = PrometheusExporter::Client.new
+    counter_metric = client.register(:counter, 'counter_metric', 'helping')
+    assert_equal(false, counter_metric.standard_values('value', 'key').has_key?(:opts))
+
+    expected_quantiles = { quantiles: [0.99, 9] }
+    summary_metric = client.register(:summary, 'summary_metric', 'helping', expected_quantiles)
+    assert_equal(expected_quantiles, summary_metric.standard_values('value', 'key')[:opts])
+  end
 end
diff --git a/test/server/collector_test.rb b/test/server/collector_test.rb
index 4bfe4fc..36d20a4 100644
--- a/test/server/collector_test.rb
+++ b/test/server/collector_test.rb
@@ -110,6 +110,133 @@ class PrometheusCollectorTest < Minitest::Test
     assert_equal(text, collector.prometheus_metrics_text)
   end
 
+  def test_it_can_export_summary_stats
+    name = 'test_name'
+    help = 'test_help'
+    collector = PrometheusExporter::Server::Collector.new
+    json = {
+      type: :summary,
+      help: help,
+      name: name,
+      keys: { key1: 'test1' },
+      value: 0.6
+    }.to_json
+
+    collector.process(json)
+    collector.process(json)
+    text = <<~TXT
+      # HELP test_name test_help
+      # TYPE test_name summary
+      test_name{key1=\"test1\",quantile=\"0.99\"} 0.6
+      test_name{key1=\"test1\",quantile=\"0.9\"} 0.6
+      test_name{key1=\"test1\",quantile=\"0.5\"} 0.6
+      test_name{key1=\"test1\",quantile=\"0.1\"} 0.6
+      test_name{key1=\"test1\",quantile=\"0.01\"} 0.6
+      test_name_sum{key1=\"test1\"} 1.2
+      test_name_count{key1=\"test1\"} 2
+    TXT
+
+    assert_equal(text, collector.prometheus_metrics_text)
+  end
+
+  def test_it_can_pass_options_to_summary
+    name = 'test_name'
+    help = 'test_help'
+    collector = PrometheusExporter::Server::Collector.new
+    json = {
+      type: :summary,
+      help: help,
+      name: name,
+      keys: { key1: 'test1' },
+      opts: { quantiles: [0.75, 0.5, 0.25] },
+      value: 8
+    }
+    collector.process(json.to_json)
+
+    %w[3 3 5 8 1 7 9 1 2 6 4 0 2 8 3 6 4 2 4 5 4 8 9 1 4 7 3 6 1 5 6 4].each do |num|
+      json[:value] = num.to_i
+      collector.process(json.to_json)
+    end
+
+    # In this case our 0 to 10 based data is skewed a bit low
+    text = <<~TXT
+      # HELP test_name test_help
+      # TYPE test_name summary
+      test_name{key1=\"test1\",quantile=\"0.75\"} 6.0
+      test_name{key1=\"test1\",quantile=\"0.5\"} 4.0
+      test_name{key1=\"test1\",quantile=\"0.25\"} 3.0
+      test_name_sum{key1=\"test1\"} 149.0
+      test_name_count{key1=\"test1\"} 33
+    TXT
+
+    assert_equal(text, collector.prometheus_metrics_text)
+  end
+
+  def test_it_can_export_histogram_stats
+    name = 'test_name'
+    help = 'test_help'
+    collector = PrometheusExporter::Server::Collector.new
+    json = {
+      type: :histogram,
+      help: help,
+      name: name,
+      keys: { key1: 'test1' },
+      value: 6
+    }.to_json
+
+    collector.process(json)
+    collector.process(json)
+    text = <<~TXT
+      # HELP test_name test_help
+      # TYPE test_name histogram
+      test_name_bucket{key1=\"test1\",le=\"+Inf\"} 2
+      test_name_bucket{key1=\"test1\",le=\"10.0\"} 2
+      test_name_bucket{key1=\"test1\",le=\"5.0\"} 0
+      test_name_bucket{key1=\"test1\",le=\"2.5\"} 0
+      test_name_bucket{key1=\"test1\",le=\"1\"} 0
+      test_name_bucket{key1=\"test1\",le=\"0.5\"} 0
+      test_name_bucket{key1=\"test1\",le=\"0.25\"} 0
+      test_name_bucket{key1=\"test1\",le=\"0.1\"} 0
+      test_name_bucket{key1=\"test1\",le=\"0.05\"} 0
+      test_name_bucket{key1=\"test1\",le=\"0.025\"} 0
+      test_name_bucket{key1=\"test1\",le=\"0.01\"} 0
+      test_name_bucket{key1=\"test1\",le=\"0.005\"} 0
+      test_name_count{key1=\"test1\"} 2
+      test_name_sum{key1=\"test1\"} 12.0
+    TXT
+
+    assert_equal(text, collector.prometheus_metrics_text)
+  end
+
+  def test_it_can_pass_options_to_histogram
+    name = 'test_name'
+    help = 'test_help'
+    collector = PrometheusExporter::Server::Collector.new
+    json = {
+      type: :histogram,
+      help: help,
+      name: name,
+      keys: { key1: 'test1' },
+      opts: { buckets: [5, 6, 7] },
+      value: 6
+    }.to_json
+
+    collector.process(json)
+    collector.process(json)
+    text = <<~TXT
+      # HELP test_name test_help
+      # TYPE test_name histogram
+      test_name_bucket{key1=\"test1\",le=\"+Inf\"} 2
+      test_name_bucket{key1=\"test1\",le=\"7\"} 2
+      test_name_bucket{key1=\"test1\",le=\"6\"} 2
+      test_name_bucket{key1=\"test1\",le=\"5\"} 0
+      test_name_count{key1=\"test1\"} 2
+      test_name_sum{key1=\"test1\"} 12.0
+    TXT
+
+    assert_equal(text, collector.prometheus_metrics_text)
+  end
+
   def test_it_can_collect_sidekiq_metrics
     collector = PrometheusExporter::Server::Collector.new
     client = PipedClient.new(collector)

GitHub sha: 4a91bba4