# encoding: utf-8 require "logstash/outputs/base" require "logstash/namespace" require "open3" # The nagios_nsca output is used for sending passive check results to Nagios # through the NSCA protocol. # # This is useful if your Nagios server is not the same as the source host from # where you want to send logs or alerts. If you only have one server, this # output is probably overkill # for you, take a look at the 'nagios' output # instead. # # Here is a sample config using the nagios_nsca output: # [source,ruby] # output { # nagios_nsca { # # specify the hostname or ip of your nagios server # host => "nagios.example.com" # # # specify the port to connect to # port => 5667 # } # } class LogStash::Outputs::NagiosNsca < LogStash::Outputs::Base config_name "nagios_nsca" # The status to send to nagios. Should be 0 = OK, 1 = WARNING, 2 = CRITICAL, 3 = UNKNOWN config :nagios_status, :validate => :string, :required => true # The nagios host or IP to send logs to. It should have a NSCA daemon running. config :host, :validate => :string, :default => "localhost" # The port where the NSCA daemon on the nagios host listens. config :port, :validate => :number, :default => 5667 # The path to the 'send_nsca' binary on the local host. config :send_nsca_bin, :validate => :string, :default => "/usr/sbin/send_nsca" # The path to the send_nsca config file on the local host. # Leave blank if you don't want to provide a config file. config :send_nsca_config, :validate => :path # The nagios 'host' you want to submit a passive check result to. This # parameter accepts interpolation, e.g. you can use `@source_host` or other # logstash internal variables. config :nagios_host, :validate => :string, :default => "%{host}" # The nagios 'service' you want to submit a passive check result to. This # parameter accepts interpolation, e.g. you can use `@source_host` or other # logstash internal variables. config :nagios_service, :validate => :string, :default => "LOGSTASH" # The format to use when writing events to nagios. This value # supports any string and can include `%{name}` and other dynamic # strings. config :message_format, :validate => :string, :default => "%{@timestamp} %{host}: %{message}" public def register #nothing for now end public def receive(event) # exit if type or tags don't match # catch logstash shutdown return if event == LogStash::SHUTDOWN # skip if 'send_nsca' binary doesn't exist if !command_file_exist? @logger.warn("Skipping nagios_nsca output; send_nsca_bin file is missing", "send_nsca_bin" => @send_nsca_bin, "missed_event" => event) return end # interpolate params nagios_host = event.sprintf(@nagios_host) nagios_service = event.sprintf(@nagios_service) # escape basic things in the log message # TODO: find a way to escape the message correctly msg = event.sprintf(@message_format) msg.gsub!("\n", "
") msg.gsub!("'", "’") status = event.sprintf(@nagios_status) if status.to_i.to_s != status # Check it round-trips to int correctly msg = "status '#{status}' is not numeric" status = 2 else status = status.to_i if status > 3 || status < 0 msg "status must be > 0 and <= 3, not #{status}" status = 2 end end # build the command # syntax: echo '!!!' | \ # /usr/sbin/send_nsca -H -d '!' -c " message = "#{nagios_host}:#{nagios_service}:#{status}:#{msg}" @logger.debug("Running send_nsca command", :nagios_nsca_command => cmd.join(" "), :message => message) begin send_to_nagios(cmd, message) rescue => e @logger.warn( "Skipping nagios_nsca output; error calling send_nsca", :error => $!, :nagios_nsca_command => cmd.join(" "), :message => message, :missed_event => event ) @logger.debug("Backtrace", :backtrace => e.backtrace) end end # def receive def command_file_exist? File.exists?(@send_nsca_bin) end def cmd return @cmd if @cmd @cmd = [@send_nsca_bin, "-H", @host, "-p", @port, "-d", ":"] @cmd = @cmd + ["-c", @send_nsca_config] if @send_nsca_config @cmd end def send_to_nagios(cmd, message) Open3.popen3(*cmd) do |i, o, e| i.puts(message) i.close end end end # class LogStash::Outputs::NagiosNsca