Class: NewRelic::Agent::PumaStatsSampler
- Inherits:
-
Object
- Object
- NewRelic::Agent::PumaStatsSampler
- Defined in:
- lib/new_relic/agent/puma_stats_sampler.rb
Overview
Samples Puma's clustered server statistics from the master process and
records them as timeslice metrics under Ruby/Puma/*.
Only the master exposes cluster-wide stats (per-worker thread-pool
backlog, running threads, pool_capacity, max_threads,
requests_count), so sampling happens there.
This class restarts the harvest thread in the master via
NewRelic::Agent.after_fork(force_reconnect: true) to deliver the
sampled metrics. This starts an additional agent connection in the master.
Records only integer gauges/counters via NewRelic::Agent.record_metric
(no request, query, or user data), so it is fully functional under High
Security Mode.
Defined Under Namespace
Classes: UnrecognizedStatsError
Constant Summary collapse
- METRIC_NAMESPACE =
'Ruby/Puma'- INSTRUMENTATION_NAME =
'Puma'- WORKER_STAT_KEYS =
Per-worker stat keys, summed across the cluster.
requests_countis a cumulative counter (userate()in NRQL); the rest are point-in-time gauges.pool_capacityis spare request capacity: idle threads plus unspawned threads still allowed up tomax_threads. %i[backlog running pool_capacity max_threads requests_count].freeze
- RUNNER_INFO_KEYS =
Runner metadata reported by
Puma::Runner#statsalongside (or, before the runner'sPuma::Serverexists, instead of) the per-worker keys. %i[started_at versions].freeze
- DEFAULT_SAMPLE_RATE =
60- LOG_FAILURE_INTERVAL =
10- LOG_FAILURE_TIME_FLOOR_SECONDS =
Caps how long a persistent failure can go unlogged: forces a re-log once ~5 min have elapsed, instead of waiting for the backed-off "every Nth" cadence (~55 min at the default sample rate).
300- BACKOFF_EXPONENT_CAP =
Caps backoff growth at 2**3 = 8 sample intervals.
3
Instance Method Summary collapse
-
#initialize(stats_source) ⇒ PumaStatsSampler
constructor
A new instance of PumaStatsSampler.
-
#start ⇒ Object
Runs the sampling loop on the background thread the instrumentation spawns in the master.
-
#stop ⇒ Object
Thread-safe: #stop runs on the Puma event thread, #start on the background thread.
Constructor Details
#initialize(stats_source) ⇒ PumaStatsSampler
Returns a new instance of PumaStatsSampler.
50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/new_relic/agent/puma_stats_sampler.rb', line 50 def initialize(stats_source) @stats_source = stats_source @sample_rate = resolve_sample_rate @lock = Mutex.new @stop_signal = ConditionVariable.new @running = false @stopped = false @consecutive_failures = 0 @last_failure_logged_at = nil @consecutive_report_failures = 0 @last_report_failure_logged_at = nil end |
Instance Method Details
#start ⇒ Object
Runs the sampling loop on the background thread the instrumentation spawns in the master. Blocks until #stop is called from a Puma lifecycle event. Single-shot: the instrumentation builds one sampler per Puma boot, so #start is never re-entered on the same instance.
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/new_relic/agent/puma_stats_sampler.rb', line 67 def start return unless ensure_master_is_reporting NewRelic::Agent.record_instrumentation_invocation(INSTRUMENTATION_NAME) @lock.synchronize do return if @stopped @running = true begin while @running sample # Wait one interval (releases the lock); #stop wakes us early. # Re-check @running because the signal may have flipped it. @stop_signal.wait(@lock, next_wait_interval) if @running end ensure # Keep @running consistent if the loop aborts via an exception. @running = false end end rescue => e # The instrumentation starts this loop on a bare +Thread.new+, so an # unhandled exception would silently kill the sampler thread. Log # StandardError; log and re-raise Exception so interrupts still propagate. ::NewRelic::Agent.logger.error('NewRelic Puma stats sampler thread exited with error', e) rescue Exception => e ::NewRelic::Agent.logger.error('NewRelic Puma stats sampler thread exited with exception. Re-raising in case of interrupt.', e) raise end |
#stop ⇒ Object
Thread-safe: #stop runs on the Puma event thread, #start on the background thread.
100 101 102 103 104 105 106 |
# File 'lib/new_relic/agent/puma_stats_sampler.rb', line 100 def stop @lock.synchronize do @running = false @stopped = true @stop_signal.signal end end |