Search code examples
ruby-on-railsprometheus

Ruby Prometheus: How to fix cardinality of timeseries resulting from uppercase uuid


In a rails application the config.ru includes

use Prometheus::Middleware::Collector

The collector code is here: https://github.com/prometheus/client_ruby/blob/main/lib/prometheus/middleware/collector.rb

One of the most important principles in prometheus is to cause to have low cardinality metrics because otherwise performance crashes and it won't be useful to look at the graphs.

The essential part of the code which achieves it is at:

def generate_path(env)
        full_path = [env['SCRIPT_NAME'], env['PATH_INFO']].join

        strip_ids_from_path(full_path)
      end

      def strip_ids_from_path(path)
        path
          .gsub(%r{/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}(?=/|$)}, '/:uuid\\1')
          .gsub(%r{/\d+(?=/|$)}, '/:id\\1')
      end
    end

So it works fine with lowercase uuids but not with uppercase uuids.

for example

uuid = "f7ec02c0-19b0-4519-8e3e-d8ac4434a389"
irb(main):024:0> strip_ids_from_path("user/#{uuid}")
=> "user/:uuid"
irb(main):025:0> strip_ids_from_path("user/#{uuid.upcase}")
=> "user/F7EC02C0-19B0-4519-8E3E-D8AC4434A389"

I could just copy the middleware and change the code to

strip_ids_from_path(full_path.downcase)

but it is a pity to take the whole code and fix it in this way.

Is there a smarter way to solve this problem. Can a rails magic be used somehow?


Solution

  • Since you have already identified a simple solution e.g. downcasing the string.

    You can use Module#prepend to implement this in an equally simple fashion e.g.

    module PrometheusMiddlewareExtension
      def strip_ids_from_path(path)
        super(path.downcase)
      end
    end
    Prometheus::Middleware.prepend(PrometheusMiddlewareExtension)