diff --git a/lib/prometheus/client/push.rb b/lib/prometheus/client/push.rb index 2d3588d9..1490c82d 100644 --- a/lib/prometheus/client/push.rb +++ b/lib/prometheus/client/push.rb @@ -23,7 +23,7 @@ class HttpClientError < HttpError; end class HttpServerError < HttpError; end DEFAULT_GATEWAY = 'http://localhost:9091'.freeze - PATH = '/metrics/job/%s'.freeze + PATH = '/metrics'.freeze SUPPORTED_SCHEMES = %w(http https).freeze attr_reader :job, :gateway, :path @@ -87,7 +87,14 @@ def parse(url) end def build_path(job, grouping_key) - path = format(PATH, ERB::Util::url_encode(job)) + # Job can't be empty, but it can contain `/`, so we need to base64 + # encode it in that case + if job.include?('/') + encoded_job = Base64.urlsafe_encode64(job) + path = "#{PATH}/job@base64/#{encoded_job}" + else + path = "#{PATH}/job/#{ERB::Util::url_encode(job)}" + end grouping_key.each do |label, value| if value.include?('/') diff --git a/spec/prometheus/client/push_spec.rb b/spec/prometheus/client/push_spec.rb index e4fede99..4af55ad5 100644 --- a/spec/prometheus/client/push_spec.rb +++ b/spec/prometheus/client/push_spec.rb @@ -93,6 +93,14 @@ expect(push.path).to eql('/metrics/job/test-job/foo/bar/baz/qux') end + it 'encodes the job name in url-safe base64 if it contains `/`' do + push = Prometheus::Client::Push.new( + job: 'foo/test-job', + ) + + expect(push.path).to eql('/metrics/job@base64/Zm9vL3Rlc3Qtam9i') + end + it 'encodes grouping key label values containing `/` in url-safe base64' do push = Prometheus::Client::Push.new( job: 'test-job',