Class: Hyperion::Metrics::PathTemplater

Inherits:
Object
  • Object
show all
Defined in:
lib/hyperion/metrics/path_templater.rb

Overview

2.4-C — turn raw request paths into low-cardinality templates so the per-route histogram doesn’t blow up to one label-set per ‘/users/<id>`.

The default rules collapse ‘/users/123` → `/users/:id` and `/orders/3fa85f64-5717-4562-b3fc-2c963f66afa6` → `/orders/:uuid`. They cover the bulk of real-world REST paths; operators with Rails-style routes (`/articles/cool-slug-2024`) plug in their own rules via `Hyperion::Config#metrics.path_templater = MyTemplater.new`.

An LRU cache keyed on the raw path side-steps repeating the regex walk on every keep-alive request to the same handler. 1000 entries is sized for typical Rails-shape apps (sub-1000 unique route templates); apps with more should pass ‘lru_size:` explicitly.

Constant Summary collapse

DEFAULT_RULES =
[
  [/\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/i, ':uuid'],
  [/\b\d+\b/, ':id']
].freeze
DEFAULT_LRU_SIZE =
1000

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(rules: DEFAULT_RULES, lru_size: DEFAULT_LRU_SIZE) ⇒ PathTemplater

Returns a new instance of PathTemplater.



28
29
30
31
32
33
# File 'lib/hyperion/metrics/path_templater.rb', line 28

def initialize(rules: DEFAULT_RULES, lru_size: DEFAULT_LRU_SIZE)
  @rules    = rules
  @lru_size = lru_size
  @cache    = {} # Insertion-ordered Hash doubles as an LRU.
  @mutex    = Mutex.new
end

Instance Attribute Details

#lru_sizeObject (readonly)

Returns the value of attribute lru_size.



26
27
28
# File 'lib/hyperion/metrics/path_templater.rb', line 26

def lru_size
  @lru_size
end

Instance Method Details

#cache_sizeObject



57
58
59
# File 'lib/hyperion/metrics/path_templater.rb', line 57

def cache_size
  @mutex.synchronize { @cache.size }
end

#template(path) ⇒ Object

Translate a raw request path into its template form. The result is memoized in the LRU; a cache hit is a single Hash#[] + re-insert (touch). On miss we run the regex chain and trim the oldest entry if we exceed ‘lru_size`.



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/hyperion/metrics/path_templater.rb', line 39

def template(path)
  return path if path.nil? || path.empty?

  @mutex.synchronize do
    if (cached = @cache.delete(path))
      # Re-insert to mark "recently used" (Ruby Hashes preserve
      # insertion order, oldest = first key).
      @cache[path] = cached
      return cached
    end

    templated = compute(path)
    @cache[path] = templated
    @cache.shift if @cache.size > @lru_size
    templated
  end
end