Skip to content

with_labels doesn't seem to work #225

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

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions