Perl: get Nagios status information

The classical way of accessing the current status of your hosts and services is by reading and parsing the file status.dat, which is created by Nagios on a regular basis. The update interval is configured via status_update_interval in nagios.cfg. A typical value is 10 seconds. If your installation is getting larger, you might have to increase this value in order to minimize CPU usage and disk IO. The nagios web interface uses status.dat for displaying its data.

#!/usr/local/bin/perl
 
use strict;
 
####
# Read Nagios statusfile
# More info: http://nagios.sourceforge.net/docs/3_0/statetypes.html
####
 
open(NAGIOS_STATUS, "< /usr/local/nagios/var/status.dat");
my $index = 0;
my %services = ();
while (my $line = <NAGIOS_STATUS>) {
  chomp($line);
  $line =~ s/^\s+(.*)/$1/;
  next if $line eq "" || $line eq "}";
  $index++ if ($line =~ /.*\{$/);
  push(@{$services{$index}}, $line);
}
close(NAGIOS_STATUS);
 
####
# Parse Nagios statusfile
####
 
my $status = ();
 
# Statusfile data
$status->{HOSTS} = {};
$status->{SERVICES} = {};
 
# Evaluated statusfile data
$status->{HOSTS_CRITICALS} = [];
$status->{SERVICES_CRITICALS} = [];
 
# Start parsing
foreach my $index (keys %services) {
  my $type = "";
 
  # Assign an empty list
  my %hash = ();
 
  for (my $i = 0; $i < scalar(@{$services{$index}}); $i++) {
    if ($i == 0 && ${$services{$index}}[$i] =~ /^(host|service)status\s\{/)	{
      $type = uc($1) . "S";
    } else {
      if (${$services{$index}}[$i] =~ /^([\w]+)=(.*)$/) {
        # Add a key/value pair to our hash
	$hash{$1} = $2;
      }
    }
  }
 
  if ($type eq "HOSTS") {
    $hash{'service_description'} = "HOST";
    $status->{$type}->{$hash{'host_name'}} = \%hash;
  } elsif ($type eq "SERVICES") {
    $status->{$type}->{"$hash{'host_name'}_$hash{'service_description'}"} = \%hash;
  }
}
 
####
# Evaluate Nagios statusfile data
####
 
# Evaluate the hosts status data
foreach my $statusobjectname (keys %{$status->{'HOSTS'}}) {
  # Note: ignore soft states (current_state != last_hard_state)
  # Note: ignore disabled notifications
  if (($status->{'HOSTS'}->{$statusobjectname}->{'current_state'} == 1) && 
      ($status->{'HOSTS'}->{$statusobjectname}->{'current_state'} == $status->{'HOSTS'}->{$statusobjectname}->{'last_hard_state'}) &&
      ($status->{'HOSTS'}->{$statusobjectname}->{'notifications_enabled'})) {
        # Found a critical host status
        push(@{$status->{'HOSTS_CRITICALS'}}, $statusobjectname);
  }
}
 
# Evaluate the services status data
foreach my $statusobjectname (keys %{$status->{'SERVICES'}}) {
  # Note: ignore soft states (current_state != last_hard_state)
  # Note: ignore service errors if host is down
  # Note: ignore disabled notifications
  if ((grep(/$status->{'SERVICES'}->{'host_name'}/, @{$status->{'HOSTS_CRITICALS'}}) < 1) && 
      ($status->{'SERVICES'}->{$statusobjectname}->{'current_state'} == 2) && 
      ($status->{'SERVICES'}->{$statusobjectname}->{'current_state'} == $status->{'SERVICES'}->{$statusobjectname}->{'last_hard_state'}) &&
      ($status->{'SERVICES'}->{$statusobjectname}->{'notifications_enabled'})) {
      # Found a critical service status
      push(@{$status->{'SERVICES_CRITICALS'}}, $statusobjectname);
  }
}
 
###
# Compose message
###
 
my $message = '';
foreach my $alert (@{$status->{"HOSTS_CRITICALS"}}) {
  $message .= "Host:" . $alert . " down.\n";
}
 
foreach my $alert (@{$status->{"SERVICES_CRITICALS"}}) {
  $message .= $alert . "\n";
}

Leave a Reply