Module: Sensu::Daemon
- Includes:
- Utilities
- Included in:
- API::Process, Client::Process, Server::Process
- Defined in:
- lib/sensu/daemon.rb
Constant Summary
Constants included from Utilities
Utilities::EVAL_PREFIX, Utilities::NANOSECOND_RESOLUTION
Instance Attribute Summary collapse
-
#settings ⇒ Object
readonly
Returns the value of attribute settings.
-
#start_time ⇒ Object
readonly
Returns the value of attribute start_time.
Instance Method Summary collapse
-
#initialize(options = {}) ⇒ Object
Initialize the Sensu process.
-
#load_extensions(options = {}) ⇒ Object
Load Sensu extensions and log any notices.
-
#load_settings(options = {}) ⇒ Object
Load Sensu settings.
-
#log_notices(notices = [], level = :warn) ⇒ Object
Log setting or extension loading notices, sensitive information is redacted.
-
#pause ⇒ Object
Pause the Sensu service and set the service state to
:paused. -
#print_settings!(settings) ⇒ Object
Print the Sensu settings (JSON) to STDOUT and immediately exit the process with the appropriate exit status code.
-
#resume ⇒ Object
Resume the paused Sensu service and set the service state to
:running. -
#setup_logger(options = {}) ⇒ Object
Set up the Sensu logger and its process signal traps for log rotation and debug log level toggling.
-
#setup_process(options) ⇒ Object
Manage the current process, optionally daemonize and/or write the current process ID to a PID file.
-
#setup_redis {|Object| ... } ⇒ Object
Set up the Redis connection.
-
#setup_signal_traps ⇒ Object
Set up process signal traps.
-
#setup_spawn ⇒ Object
Set up Sensu spawn, creating a worker to create, control, and limit spawned child processes.
-
#setup_transport {|Object| ... } ⇒ Object
Set up the Sensu transport connection.
-
#start ⇒ Object
Start the Sensu service and set the service state to
:running. -
#stop ⇒ Object
Stop the Sensu service and set the service state to
:stopped. -
#unexpected_error(error) ⇒ Object
Handle an unexpected error.
-
#validate_settings!(settings) ⇒ Object
Determine if the Sensu settings are valid, if there are load or validation errors, and immediately exit the process with the appropriate exit status code.
Methods included from Utilities
#attributes_match?, #check_subdued?, #deep_dup, #deep_merge, #determine_check_cron_time, #eval_attribute_value, #find_attribute_value, #in_time_window?, #in_time_windows?, #object_substitute_tokens, #process_cpu_times, #process_eval_string, #random_uuid, #redact_sensitive, #retry_until_true, #substitute_tokens, #system_address, #system_hostname, #testing?
Instance Attribute Details
#settings ⇒ Object (readonly)
Returns the value of attribute settings.
37 38 39 |
# File 'lib/sensu/daemon.rb', line 37 def settings @settings end |
#start_time ⇒ Object (readonly)
Returns the value of attribute start_time.
37 38 39 |
# File 'lib/sensu/daemon.rb', line 37 def start_time @start_time end |
Instance Method Details
#initialize(options = {}) ⇒ Object
Initialize the Sensu process. Set the start time, initial service state, double the maximum number of EventMachine timers, set up the logger, and load settings. This method will load extensions and setup Sensu Spawn if the Sensu process is not the Sensu API. This method can and optionally daemonize the process and/or create a PID file.
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/sensu/daemon.rb', line 47 def initialize(={}) @start_time = Time.now.to_i @state = :initializing @timers = {:run => []} unless EM::reactor_running? EM::epoll EM::set_max_timers(200000) EM::error_handler do |error| unexpected_error(error) end end setup_logger() load_settings() unless sensu_service_name == "api" load_extensions() setup_spawn end setup_process() end |
#load_extensions(options = {}) ⇒ Object
Load Sensu extensions and log any notices. Set the logger and
settings for each extension instance. This method creates the
extensions instance variable: @extensions.
https://github.com/sensu/sensu-extensions https://github.com/sensu/sensu-extension
186 187 188 189 190 191 192 193 194 195 |
# File 'lib/sensu/daemon.rb', line 186 def load_extensions(={}) = .merge(:extensions => @settings[:extensions]) @extensions = Extensions.get() log_notices(@extensions.warnings) extension_settings = @settings.to_hash.dup @extensions.all.each do |extension| extension.logger = @logger extension.settings = extension_settings end end |
#load_settings(options = {}) ⇒ Object
Load Sensu settings. This method creates the settings instance
variable: @settings. If the validate_config option is true,
this method calls validate_settings!() to validate the latest
compiled configuration settings and will then exit the process.
If the print_config option is true, this method calls
print_settings!() to output the compiled configuration
settings and will then exit the process. If there are loading or
validation errors, they will be logged (notices), and this
method will exit(2) the process.
165 166 167 168 169 170 171 172 173 174 175 176 |
# File 'lib/sensu/daemon.rb', line 165 def load_settings(={}) @settings = Settings.get() validate_settings!(@settings) if [:validate_config] log_notices(@settings.warnings) log_notices(@settings.errors, :fatal) print_settings!(@settings) if [:print_config] unless @settings.errors.empty? @logger.fatal("SENSU NOT RUNNING!") exit 2 end @settings.set_env! end |
#log_notices(notices = [], level = :warn) ⇒ Object
Log setting or extension loading notices, sensitive information is redacted.
111 112 113 114 115 116 |
# File 'lib/sensu/daemon.rb', line 111 def log_notices(notices=[], level=:warn) notices.each do |concern| = concern.delete(:message) @logger.send(level, , redact_sensitive(concern)) end end |
#pause ⇒ Object
Pause the Sensu service and set the service state to :paused.
This method will likely be overridden by a subclass.
230 231 232 |
# File 'lib/sensu/daemon.rb', line 230 def pause @state = :paused end |
#print_settings!(settings) ⇒ Object
Print the Sensu settings (JSON) to STDOUT and immediately exit
the process with the appropriate exit status code. This method
is used while troubleshooting configuration issues, triggered by
a CLI argument, e.g. --print_config. Sensu settings with
sensitive values (e.g. passwords) are first redacted.
144 145 146 147 148 149 |
# File 'lib/sensu/daemon.rb', line 144 def print_settings!(settings) redacted_settings = redact_sensitive(settings.to_hash) @logger.warn("outputting compiled configuration and exiting") puts Sensu::JSON.dump(redacted_settings, :pretty => true) exit(settings.errors.empty? ? 0 : 2) end |
#resume ⇒ Object
Resume the paused Sensu service and set the service state to
:running. This method will likely be overridden by a subclass.
236 237 238 |
# File 'lib/sensu/daemon.rb', line 236 def resume @state = :running end |
#setup_logger(options = {}) ⇒ Object
Set up the Sensu logger and its process signal traps for log
rotation and debug log level toggling. This method creates the
logger instance variable: @logger.
101 102 103 104 |
# File 'lib/sensu/daemon.rb', line 101 def setup_logger(={}) @logger = Logger.get() @logger.setup_signal_traps end |
#setup_process(options) ⇒ Object
Manage the current process, optionally daemonize and/or write the current process ID to a PID file.
215 216 217 218 |
# File 'lib/sensu/daemon.rb', line 215 def setup_process() daemonize if [:daemonize] write_pid([:pid_file]) if [:pid_file] end |
#setup_redis {|Object| ... } ⇒ Object
Set up the Redis connection. Sensu uses Redis as a data store,
to store the client registry, current events, etc. The Sensu
service will stop gracefully in the event of a Redis error, and
pause/resume in the event of connectivity issues. This method
creates the Redis instance variable: @redis.
323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 |
# File 'lib/sensu/daemon.rb', line 323 def setup_redis @logger.debug("connecting to redis", :settings => @settings[:redis]) Redis.logger = @logger Redis.connect(@settings[:redis]) do |connection| @redis = connection @redis.on_error do |error| @logger.error("redis connection error", :error => error.to_s) end @redis.before_reconnect do unless testing? @logger.warn("reconnecting to redis") pause end end @redis.after_reconnect do @logger.info("reconnected to redis") resume end yield(@redis) if block_given? end end |
#setup_signal_traps ⇒ Object
Set up process signal traps. This method uses the STOP_SIGNALS
constant to determine which process signals will result in a
graceful service stop. A periodic timer must be used to poll for
received signals, as Mutex#lock cannot be used within the
context of trap().
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 |
# File 'lib/sensu/daemon.rb', line 254 def setup_signal_traps @signals = [] STOP_SIGNALS.each do |signal| Signal.trap(signal) do @signals << signal end end EM::PeriodicTimer.new(1) do signal = @signals.shift if STOP_SIGNALS.include?(signal) @logger.warn("received signal", :signal => signal) stop end end end |
#setup_spawn ⇒ Object
Set up Sensu spawn, creating a worker to create, control, and limit spawned child processes. This method adjusts the EventMachine thread pool size to accommodate the concurrent process spawn limit and other Sensu process operations.
203 204 205 206 207 208 209 |
# File 'lib/sensu/daemon.rb', line 203 def setup_spawn @logger.info("configuring sensu spawn", :settings => @settings[:sensu][:spawn]) threadpool_size = @settings[:sensu][:spawn][:limit] + 10 @logger.debug("setting eventmachine threadpool size", :size => threadpool_size) EM::threadpool_size = threadpool_size Spawn.setup(@settings[:sensu][:spawn]) end |
#setup_transport {|Object| ... } ⇒ Object
Set up the Sensu transport connection. Sensu uses a transport
API, allowing it to use various message brokers. By default,
Sensu will use the built-in "rabbitmq" transport. The Sensu
service will stop gracefully in the event of a transport error,
and pause/resume in the event of connectivity issues. This
method creates the transport instance variable: @transport.
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 |
# File 'lib/sensu/daemon.rb', line 281 def setup_transport transport_name = @settings[:transport][:name] transport_settings = @settings[transport_name] @logger.debug("connecting to transport", { :name => transport_name, :settings => transport_settings }) Transport.logger = @logger Transport.connect(transport_name, transport_settings) do |connection| @transport = connection @transport.on_error do |error| @logger.error("transport connection error", :error => error.to_s) if @settings[:transport][:reconnect_on_error] @transport.reconnect else stop end end @transport.before_reconnect do unless testing? @logger.warn("reconnecting to transport") pause end end @transport.after_reconnect do @logger.info("reconnected to transport") resume end yield(@transport) if block_given? end end |
#start ⇒ Object
Start the Sensu service and set the service state to :running.
This method will likely be overridden by a subclass. Yield if a
block is provided.
223 224 225 226 |
# File 'lib/sensu/daemon.rb', line 223 def start @state = :running yield if block_given? end |
#stop ⇒ Object
Stop the Sensu service and set the service state to :stopped.
This method will likely be overridden by a subclass. This method
should stop the EventMachine event loop.
243 244 245 246 247 |
# File 'lib/sensu/daemon.rb', line 243 def stop @state = :stopped @logger.warn("stopping reactor") EM::stop_event_loop end |
#unexpected_error(error) ⇒ Object
Handle an unexpected error. This method is used for EM global
catch-all error handling, accepting an error object. Error
handling is opt-in via a configuration option, e.g. "sensu": {"global_error_handler": true}. If a user does not opt-in, the
provided error will be raised (uncaught). If a user opts-in via
configuration, the error will be logged and ignored :itsfine:.
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/sensu/daemon.rb', line 75 def unexpected_error(error) if @settings && @settings[:sensu][:global_error_handler] backtrace = error.backtrace.join("\n") if @logger @logger.warn("global catch-all error handling enabled") @logger.fatal("unexpected error - please address this immediately", { :error => error.to_s, :error_class => error.class, :backtrace => backtrace }) else puts "global catch-all error handling enabled" puts "unexpected error - please address this immediately: #{error.to_s}\n#{error.class}\n#{backtrace}" end else raise error end end |
#validate_settings!(settings) ⇒ Object
Determine if the Sensu settings are valid, if there are load or
validation errors, and immediately exit the process with the
appropriate exit status code. This method is used to determine
if the latest configuration changes are valid prior to
restarting the Sensu service, triggered by a CLI argument, e.g.
--validate_config.
126 127 128 129 130 131 132 133 134 135 |
# File 'lib/sensu/daemon.rb', line 126 def validate_settings!(settings) if settings.errors.empty? puts "configuration is valid" exit else puts "configuration is invalid" puts Sensu::JSON.dump({:errors => @settings.errors}, :pretty => true) exit 2 end end |