Skip to content

with_labels doesn't seem to work #225

@onlynone

Description

@onlynone

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions