When I create a new Counter object from another by using the Prometheus::Client::Metric#with_labels method, it seems like the new Counter uses a different store from the original, so its metrics are never reported (say to the push client). And if I try to register the new Counter with the registry, I get an error because the original Counter is already registered with that name.
#!/usr/bin/env ruby
require 'cgi'
require 'prometheus/client'
require 'prometheus/client/counter'
require 'prometheus/client/push'
counter1 = Prometheus::Client::Counter.new(
:with_labels_counter,
docstring: "with_labels counter",
labels: [:foo]
)
counter1.increment(labels: {foo: "bar"})
counter1.increment(labels: {foo: "baz"})
counter1.increment(labels: {foo: "bat"})
counter2 = counter1.with_labels(foo: "bar")
counter2.increment
# I would expect this to print: [2.0, 1.0, 1.0]
# but it prints: [1.0, 1.0, 1.0]
puts "The counter values:"
puts ['bar', 'baz', 'bat'].map{|foo| counter1.get(labels: { foo: foo })}.inspect
puts ""
registry = Prometheus::Client.registry
registry.register(counter1)
push = Prometheus::Client::Push.new('with_labels_job', 'with_labels_instance')
push.add(registry)
resp = Net::HTTP.get_response(URI(push.gateway) + "metrics")
# I would expect the following to print:
#
# push_failure_time_seconds{instance="with_labels_instance",job="with_labels_job"} 0
# push_time_seconds{instance="with_labels_instance",job="with_labels_job"} 1.6208445893150244e+09
# # HELP with_labels_counter with_labels counter
# # TYPE with_labels_counter counter
# with_labels_counter{foo="bar",instance="with_labels_instance",job="with_labels_job"} 2
# with_labels_counter{foo="bat",instance="with_labels_instance",job="with_labels_job"} 1
# with_labels_counter{foo="baz",instance="with_labels_instance",job="with_labels_job"} 1
#
# But it prints:
#
# push_failure_time_seconds{instance="with_labels_instance",job="with_labels_job"} 0
# push_time_seconds{instance="with_labels_instance",job="with_labels_job"} 1.6208445893150244e+09
# # HELP with_labels_counter with_labels counter
# # TYPE with_labels_counter counter
# with_labels_counter{foo="bar",instance="with_labels_instance",job="with_labels_job"} 1
# with_labels_counter{foo="bat",instance="with_labels_instance",job="with_labels_job"} 1
# with_labels_counter{foo="baz",instance="with_labels_instance",job="with_labels_job"} 1
puts "What the push gateway has after the first push:"
puts resp.body.split("\n").select{|l| l.match(/with_labels/)}
puts ""
# Since the metrics recorded with counter2 aren't being stored with counter1,
# then I'd hope registering counter2 with the registry would at least work
#
# but it results in:
#
# with_labels_counter has already been registered(Prometheus::Client::Registry::AlreadyRegisteredError)
begin
registry.register(counter2)
rescue Prometheus::Client::Registry::AlreadyRegisteredError
puts "Can't register counter2"
puts ""
end
# So maybe I could create a separate registry for counter2 and add that to my
# push gateway separately
registry2 = Prometheus::Client::Registry.new
registry2.register(counter2)
push.add(registry2)
resp = Net::HTTP.get_response(URI(push.gateway) + "metrics")
# I would expect the following to print:
#
# push_failure_time_seconds{instance="with_labels_instance",job="with_labels_job"} 0
# push_time_seconds{instance="with_labels_instance",job="with_labels_job"} 1.6208457827718859e+09
# # HELP with_labels_counter with_labels counter
# # TYPE with_labels_counter counter
# with_labels_counter{foo="bar",instance="with_labels_instance",job="with_labels_job"} 2
# with_labels_counter{foo="bat",instance="with_labels_instance",job="with_labels_job"} 1
# with_labels_counter{foo="baz",instance="with_labels_instance",job="with_labels_job"} 1
#
# But it clobbers the other labels and prints:
#
# push_failure_time_seconds{instance="with_labels_instance",job="with_labels_job"} 0
# push_time_seconds{instance="with_labels_instance",job="with_labels_job"} 1.6208457827718859e+09
# # HELP with_labels_counter with_labels counter
# # TYPE with_labels_counter counter
# with_labels_counter{foo="bar",instance="with_labels_instance",job="with_labels_job"} 1
puts "What the push gateway has after the second push:"
puts resp.body.split("\n").select{|l| l.match(/with_labels/)}
puts ""
Should the implementation of push_labels possibly be changed to something like:
def with_labels(labels)
metric = self.class.new(name,
docstring: docstring,
labels: @labels,
preset_labels: preset_labels.merge(labels),
store_settings: @store_settings)
metric.instance_variable_set(:@store, @store)
return metric
end
When I create a new
Counterobject from another by using thePrometheus::Client::Metric#with_labelsmethod, it seems like the newCounteruses a different store from the original, so its metrics are never reported (say to the push client). And if I try to register the newCounterwith the registry, I get an error because the originalCounteris already registered with that name.Should the implementation of
push_labelspossibly be changed to something like: