Class: CloseYourIt::Client

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

Overview

Compone Transport + BackgroundWorker: applica before_send e dispatcha l'invio in modo fire-and-forget.

Constant Summary collapse

LOGS_MAX_BATCH =

Tetto di log per singola richiesta a /logs. Il backend rifiuta un batch oltre questo limite (413 R413-LOG-002) scartando l'INTERA richiesta — e il buffer è già stato drenato → log persi. Deve restare ≤ del limite server (LOGS_MAX_BATCH backend = 1000). Vedi #flush_logs.

1000

Instance Method Summary collapse

Constructor Details

#initialize(configuration) ⇒ Client

Returns a new instance of Client.



12
13
14
15
16
17
18
19
# File 'lib/closeyourit/client.rb', line 12

def initialize(configuration)
  @configuration = configuration
  @transport = Transport.new(configuration)
  @worker = BackgroundWorker.new(
    threads: configuration.async_threads,
    max_queue: configuration.background_worker_max_queue
  )
end

Instance Method Details

#capture_event(event) ⇒ Object



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/closeyourit/client.rb', line 21

def capture_event(event)
  payload = event.to_h
  payload = @configuration.before_send.call(payload) if @configuration.before_send
  if payload.nil?
    # before_send ha scartato l'evento (ritorna nil): scarto voluto, reso visibile (CYRB-12).
    CloseYourIt.stats.increment(:dropped)
    CloseYourIt.notify_diagnostic(:drop, reason: :before_send)
    return nil
  end

  path = event.ingest_path(@configuration.project_id)
  accepted = @worker.perform { @transport.send_event(payload, path: path) }
  if accepted
    CloseYourIt.stats.increment(:enqueued)
    CloseYourIt.notify_diagnostic(:enqueue, path: path)
  end
  payload
rescue StandardError => e
  # La telemetria non deve MAI propagare nel path dell'app ospite: capture_event è invocato dal
  # subscriber sql.active_record, che gira nel thread della query. to_h (scrubber su bind
  # malformato) e before_send sono valutati qui in modo sincrono → se sollevano, assorbiamo,
  # logghiamo e scartiamo l'evento invece di disturbare la query ospite. Vedi CYRB-2.
  CloseYourIt.internal_logger.error("CloseYourIt client: #{e.class}: #{e.message}")
  CloseYourIt.stats.increment(:dropped)
  CloseYourIt.notify_diagnostic(:drop, reason: :error, error: e.class.name)
  nil
end

#flush_logs(events) ⇒ Object

Invia un batch di log come ARRAY a /logs (l'endpoint accetta singolo o array). before_send è applicato a ciascun payload; quelli scartati (nil) non vengono inviati. I payload oltre LOGS_MAX_BATCH sono spezzati in più POST sequenziali (un chunk = un POST), così un flush grande non viene rigettato in blocco dal backend e perso — vedi R3 / LOGS_MAX_BATCH. Un flush entro il limite resta un singolo POST.



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/closeyourit/client.rb', line 54

def flush_logs(events)
  return nil if events.nil? || events.empty?

  payloads = events.map(&:to_h)
  if @configuration.before_send
    kept = payloads.filter_map { |payload| @configuration.before_send.call(payload) }
    # I log che before_send porta a nil sono scarti voluti: contabilizzali come gli errori/metriche
    # (parità con #capture_event), altrimenti sparirebbero silenziosamente dai contatori (CYRB-12).
    (payloads.size - kept.size).times do
      CloseYourIt.stats.increment(:dropped)
      CloseYourIt.notify_diagnostic(:drop, reason: :before_send)
    end
    payloads = kept
  end
  return nil if payloads.empty?

  path = events.first.ingest_path(@configuration.project_id)
  payloads.each_slice(LOGS_MAX_BATCH) do |chunk|
    accepted = @worker.perform { @transport.send_event(chunk, path: path) }
    next unless accepted

    CloseYourIt.stats.increment(:enqueued)
    CloseYourIt.notify_diagnostic(:enqueue, path: path, batch: chunk.size)
  end
  payloads
end

#shutdownObject



81
82
83
# File 'lib/closeyourit/client.rb', line 81

def shutdown
  @worker.shutdown
end