Class: CloseYourIt::UsageRegistry

Inherits:
Object
  • Object
show all
Defined in:
lib/closeyourit/usage_registry.rb

Overview

CYSK-29 — la telemetria d'uso: registra QUALI simboli girano davvero (route come Controller#action, job, chiavi custom letterali) e li flusha in una POST ogni usage_flush_interval secondi per processo. Sul percorso caldo: una lookup e un increment.

Le regole che rendono il sistema immune alle perdite:

  • i conteggi sono INDICATIVI, solo last_seen_at è portante: un flush perso costa una finestra su un simbolo che si rivede subito dopo;
  • il registro SI SVUOTA a ogni flush: il tetto (usage_max_symbols) limita i simboli distinti visti in una finestra — una grandezza legata al traffico, non alla dimensione del codice;
  • oltre il tetto il flush porta truncated: true, e lato scanner quel flag SQUALIFICA il kind;
  • nessun sampling, mai: un campionamento su una rotta chiamata 3 volte al mese fabbrica esattamente il falso «mai vista» che il sistema esiste per evitare;
  • route è Controller#action, MAI l'URL: niente path, parametri, user, IP.

Constant Summary collapse

SYMBOL_FORMAT =

I simboli vengono da payload di framework o da stringhe letterali: il pattern è il contratto.

%r{\A[A-Za-z0-9_:#./-]{1,200}\z}
KINDS =
%w[route job custom].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(client:, configuration:) ⇒ UsageRegistry

Returns a new instance of UsageRegistry.



26
27
28
29
30
31
32
33
34
# File 'lib/closeyourit/usage_registry.rb', line 26

def initialize(client:, configuration:)
  @client = client
  @configuration = configuration
  @mutex = Mutex.new
  @symbols = {}
  @truncated = false
  @window_started_at = Time.now.utc
  @timer = nil
end

Instance Attribute Details

#timerObject (readonly)

esposto per i test (verifica dell'intervallo configurato)



24
25
26
# File 'lib/closeyourit/usage_registry.rb', line 24

def timer
  @timer
end

Instance Method Details

#flushObject



58
59
60
61
62
63
64
65
66
67
# File 'lib/closeyourit/usage_registry.rb', line 58

def flush
  payload = drain
  return if payload[:symbols].empty? && !payload[:truncated]

  @client.flush_usage(**payload)
rescue StandardError => e
  # Il flush gira sul thread timer: un errore non deve propagare nell'app né uccidere il
  # TimerTask. La semantica portante è last_seen_at: una finestra persa non falsifica niente.
  CloseYourIt.internal_logger.error("CloseYourIt usage registry: #{e.class}: #{e.message}")
end

#record(kind, symbol) ⇒ Object



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/closeyourit/usage_registry.rb', line 36

def record(kind, symbol)
  return unless @configuration.usage_enabled

  kind = kind.to_s
  symbol = symbol.to_s
  return unless KINDS.include?(kind) && symbol.match?(SYMBOL_FORMAT)

  @mutex.synchronize do
    key = [ kind, symbol ]
    entry = @symbols[key]
    if entry
      entry[:count] += 1
      entry[:last_seen_at] = Time.now.utc
    elsif @symbols.size >= @configuration.usage_max_symbols.to_i
      @truncated = true
    else
      @symbols[key] = { count: 1, last_seen_at: Time.now.utc }
    end
    ensure_timer
  end
end

#shutdownObject



69
70
71
72
# File 'lib/closeyourit/usage_registry.rb', line 69

def shutdown
  @timer&.shutdown
  flush
end