Module: NewRelic::Agent::Instrumentation::PumaStats
- Defined in:
- lib/new_relic/agent/instrumentation/puma.rb
Defined Under Namespace
Modules: StatsObjectRegistration
Class Method Summary collapse
-
.arm_late_install ⇒ Object
Prepends a one-shot interceptor on
Puma.stats_object=so the agent installs when the launcher registers its runner (+rails server+ boot order). -
.install(runner) ⇒ Object
Started in the master before workers fork, so forked workers do not inherit the sampling thread.
-
.install_in_master(runner) ⇒ Object
:nodoc:.
-
.install_on_register(runner) ⇒ Object
Invoked by the interceptor when Puma registers a runner.
-
.install_or_arm ⇒ Object
:nodoc:.
-
.log_puma_6x_preload_warning(runner) ⇒ Object
Puma 6.x doesn't apply
preload_appdefaults from the config block, so a clustered 6.x app withworkers 2but no explicitpreload_app!(true)silently gets no metrics. -
.master?(runner) ⇒ Boolean
True only where the agent should sample: single mode (one process) or clustered with
preload_app!(where the agent is loaded in the master process). -
.register_stop(runner, sampler) ⇒ Object
Stops the sampler on Puma shutdown/restart.
-
.runner ⇒ Object
Puma stores the runner via
Puma.stats_object=.
Class Method Details
.arm_late_install ⇒ Object
Prepends a one-shot interceptor on Puma.stats_object= so the agent
installs when the launcher registers its runner (+rails server+ boot
order). The prepend is permanent, so @late_install_armed does the real
gating: disarming it on the first registration keeps a Puma hot restart
from starting a second sampler.
64 65 66 67 |
# File 'lib/new_relic/agent/instrumentation/puma.rb', line 64 def arm_late_install # :nodoc: @late_install_armed = true ::Puma.singleton_class.prepend(StatsObjectRegistration) end |
.install(runner) ⇒ Object
Started in the master before workers fork, so forked workers do not inherit the sampling thread.
95 96 97 98 99 100 101 102 103 |
# File 'lib/new_relic/agent/instrumentation/puma.rb', line 95 def install(runner) # :nodoc: sampler = NewRelic::Agent::PumaStatsSampler.new(runner) register_stop(runner, sampler) Thread.new { sampler.start } sampler rescue => e NewRelic::Agent.logger.error('Failed to start the New Relic Puma stats sampler', e) nil end |
.install_in_master(runner) ⇒ Object
:nodoc:
36 37 38 39 40 41 42 43 44 |
# File 'lib/new_relic/agent/instrumentation/puma.rb', line 36 def install_in_master(runner) # :nodoc: unless master?(runner) log_puma_6x_preload_warning(runner) return end NewRelic::Agent.logger.info('Installing Puma stats instrumentation') install(runner) end |
.install_on_register(runner) ⇒ Object
Invoked by the interceptor when Puma registers a runner. One-shot: disarm before installing so the registration is handled exactly once.
71 72 73 74 75 76 |
# File 'lib/new_relic/agent/instrumentation/puma.rb', line 71 def install_on_register(runner) # :nodoc: return unless @late_install_armed @late_install_armed = false install_in_master(runner) end |
.install_or_arm ⇒ Object
:nodoc:
31 32 33 34 |
# File 'lib/new_relic/agent/instrumentation/puma.rb', line 31 def install_or_arm # :nodoc: current = runner current ? install_in_master(current) : arm_late_install end |
.log_puma_6x_preload_warning(runner) ⇒ Object
Puma 6.x doesn't apply preload_app defaults from the config block,
so a clustered 6.x app with workers 2 but no explicit preload_app!(true)
silently gets no metrics.
49 50 51 52 53 54 55 56 57 |
# File 'lib/new_relic/agent/instrumentation/puma.rb', line 49 def log_puma_6x_preload_warning(runner) # :nodoc: return unless runner&.respond_to?(:options) return unless runner.[:workers].to_i > 1 && !runner.[:preload_app] return unless defined?(::Puma::Const::VERSION) && ::Puma::Const::VERSION.start_with?('6.') NewRelic::Agent.logger.warn( 'Did not install Puma instrumentation. Set preload_app!(true) explicitly in your puma.rb to enable Puma metrics.' ) end |
.master?(runner) ⇒ Boolean
True only where the agent should sample: single mode (one process) or
clustered with preload_app! (where the agent is loaded in the master process).
23 24 25 26 27 28 29 |
# File 'lib/new_relic/agent/instrumentation/puma.rb', line 23 def master?(runner) # :nodoc: return false if runner.nil? return true if defined?(::Puma::Single) && runner.is_a?(::Puma::Single) return false unless runner.respond_to?(:options) !!runner.[:preload_app] end |
.register_stop(runner, sampler) ⇒ Object
Stops the sampler on Puma shutdown/restart. Registers both Puma 7+
events (+:before_restart+/+:after_stopped+) and Puma 6.x events
(+:on_restart+/+:on_stopped+), plus :state for single mode (the
clustered master runs no Puma::Server). stop is idempotent, so
overlapping events are harmless.
110 111 112 113 114 115 116 117 118 119 |
# File 'lib/new_relic/agent/instrumentation/puma.rb', line 110 def register_stop(runner, sampler) # :nodoc: launcher = runner.instance_variable_get(:@launcher) return unless launcher.respond_to?(:events) events = launcher.events events.register(:state) { |state| sampler.stop if %i[halt restart stop].include?(state) } %i[before_restart after_stopped on_restart on_stopped].each do |event| events.register(event) { sampler.stop } end end |
.runner ⇒ Object
Puma stores the runner via Puma.stats_object=. No public accessor,
so read the ivar that the setter writes.
15 16 17 18 19 |
# File 'lib/new_relic/agent/instrumentation/puma.rb', line 15 def runner # :nodoc: return nil unless defined?(::Puma) && ::Puma.instance_variable_defined?(:@get_stats) ::Puma.instance_variable_get(:@get_stats) end |