├── .gitignore ├── config.php.example ├── README.markdown ├── default.css └── index.php /.gitignore: -------------------------------------------------------------------------------- 1 | status.dat* 2 | config.php 3 | *.swp 4 | *.swo 5 | -------------------------------------------------------------------------------- /config.php.example: -------------------------------------------------------------------------------- 1 | seconds ago 17 | // Set this to a higher value then status_update_interval in your 18 | // nagios.cfg 19 | // $statusFileTimeout = 60; 20 | 21 | // Enable fortune output 22 | // $enableFortune = false; 23 | // $fortunePath = "/usr/games/fortune"; 24 | 25 | // Uncomment to show custom heading 26 | // $nagliteHeading = ''; 27 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | Naglite3 2 | ======== 3 | 4 | Nagios/Icinga status monitor for a NOC or operations room. 5 | 6 | Inspired by Naglite (http://www.monitoringexchange.org/inventory/Utilities/AddOn-Projects/Frontends/NagLite) 7 | and Naglite2 (http://laur.ie/blog/2010/03/naglite2-finally-released/). 8 | 9 | Written by Steffen Zieger . 10 | Licensed under the GPL. 11 | 12 | In case of any problems or bug fixes, feel free to contact me. 13 | 14 | Requirements 15 | ------------ 16 | 17 | Naglite3 is only tested with Nagios3, but it should also work with Nagios2. 18 | If you're running Nagios2, please let me know. 19 | 20 | [nkadel](https://github.com/nkadel) has reported, that it's also working with Icinga. 21 | 22 | - Web server of your choice with PHP support 23 | - PHP 5.2 or newer 24 | - git 25 | 26 | Naglite3 must be installed on the same host where Nagios is running, as it 27 | needs to read status.dat from Nagios. 28 | 29 | Installation 30 | ------------ 31 | 32 | 1. Switch to a directory accessible through your web server (e.g. /var/www/). 33 | 2. git clone git://github.com/saz/Naglite3.git 34 | 3. Copy config.php.example to config.php if you need to change a setting. 35 | 4. Open a browser and point it to your Naglite3 installation. 36 | 37 | Customization 38 | ------------- 39 | 40 | For all possible config options have a look at config.php.example 41 | 42 | ### CSS 43 | 44 | If you want to change colors, create a file called 'custom.css' in the 45 | directory where Naglite3 is placed and add your changes. 46 | 47 | ### Refresh interval 48 | 49 | You can change the refresh interval (in seconds) through a GET parameter, too. 50 | 51 | Example: 52 | http://your-host/Naglite3/?refresh=100 53 | -------------------------------------------------------------------------------- /default.css: -------------------------------------------------------------------------------- 1 | * { 2 | padding: 0px; 3 | margin: 0px; 4 | } 5 | 6 | html, body { height: 99%; } 7 | 8 | body { 9 | font-family: Verdana, Tahoma, Helvetica, Arial, sans-serif; 10 | background-color: #000000; 11 | font-size: 14px; 12 | text-align: center; 13 | } 14 | 15 | table { 16 | width: 100%; 17 | border: none; 18 | border-spacing: 2px; 19 | white-space: nowrap; 20 | } 21 | 22 | th, td { padding: 2px 10px; } 23 | th, td.hostname { background-color: #d3d3d3; } 24 | 25 | .output { 26 | white-space: normal; 27 | text-align: left; 28 | } 29 | 30 | .subhosts { 31 | margin: 2px; 32 | padding: 1px; 33 | font-size: 12px; 34 | text-align: left; 35 | } 36 | 37 | h1 { 38 | text-align: center; 39 | font-weight: bold; 40 | color: #ffffff; 41 | } 42 | 43 | h2.title { 44 | text-align: left; 45 | font-weight: bold; 46 | padding-bottom: 5px; 47 | font-size: 1.2em; 48 | } 49 | 50 | h3.title { 51 | text-align: left; 52 | font-weight: bold; 53 | padding: 10px 2px 0px 2px; 54 | font-size: 12px; 55 | color: #ffffff; 56 | } 57 | 58 | #content { 59 | height: 97.0%; 60 | margin: 10px; 61 | } 62 | 63 | .section { 64 | color: #ffffff; 65 | font-weight: bold; 66 | overflow: auto; 67 | padding: 20px 2px 0px 2px; 68 | margin-top: 10px; 69 | } 70 | 71 | .subsection { font-size: 12px; } 72 | 73 | .stats { 74 | float: right; 75 | margin-top: -2em; 76 | } 77 | 78 | .stat { 79 | display: inline; 80 | padding: 3px; 81 | margin-left: 10px; 82 | } 83 | 84 | div.state { 85 | font-size: 20px; 86 | font-weight: bold; 87 | color: #ffffff; 88 | margin: 0px 2px 3px 2px; 89 | padding: 3px; 90 | } 91 | 92 | .up, .ok { background-color: green; } 93 | .warning { background-color: yellow; } 94 | .critical, .down { background-color: red; } 95 | .pending { background-color: #488acf; } 96 | .unknown { background-color: #00ffff; } 97 | .notification { background-color: #69b3b3; } 98 | .scheduled_downtime { background-color: #cc66cc; } 99 | .acknowledged { background-color: #d3d3d3; } 100 | .unreachable { background-color: orange; } 101 | 102 | .fortune { 103 | margin-top: 10px; 104 | color: #ffffff; 105 | } 106 | 107 | .statusFileState { 108 | color: #ffffff; 109 | } 110 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | 8 | * @version 1.6 9 | * @license GPL 10 | **/ 11 | 12 | /** 13 | * 14 | * Please do not change values below, as this will make it harder 15 | * for you to update in the future. 16 | * Rename config.php.example to config.php and change the values there. 17 | * 18 | **/ 19 | 20 | // Set file path to your nagios status log 21 | $statusFile = '/var/cache/nagios3/status.dat'; 22 | 23 | // Default refresh time in seconds 24 | $refresh = 10; 25 | 26 | // Show warning state if status file was last updated seconds ago 27 | // Set this to a higher value then status_update_interval in your nagios.cfg 28 | $statusFileTimeout = 60; 29 | 30 | // Enable fortune output 31 | $enableFortune = false; 32 | $fortunePath = "/usr/games/fortune"; 33 | 34 | // Uncomment to show custom heading 35 | //$nagliteHeading = ''; 36 | 37 | /* 38 | * Nothing to change below 39 | */ 40 | 41 | // If there is a config file, require it to overwrite some values 42 | $config = 'config.php'; 43 | if (file_exists($config)) { 44 | require $config; 45 | } 46 | 47 | // Disable E_NOTICE error reporting 48 | $errorReporting = error_reporting(); 49 | if ($errorReporting & E_NOTICE) { 50 | error_reporting($errorReporting ^ E_NOTICE); 51 | } 52 | 53 | // Disable caching and set refresh interval 54 | header("Pragma: no-cache"); 55 | if (!empty($_GET["refresh"]) && is_numeric($_GET["refresh"])) { 56 | $refresh = $_GET["refresh"]; 57 | } 58 | header("Refresh: " .$refresh); 59 | 60 | // Nagios Status Map 61 | $nagios["host"]["ok"] = 0; 62 | $nagios["host"]["down"] = 1; 63 | $nagios["host"]["unreachable"] = 2; 64 | $nagios["host"] += array_keys($nagios["host"]); 65 | $nagios["service"]["ok"] = 0; 66 | $nagios["service"]["warning"] = 1; 67 | $nagios["service"]["critical"] = 2; 68 | $nagios["service"]["unknown"] = 3; 69 | $nagios["service"] += array_keys($nagios["service"]); 70 | 71 | /** 72 | * 73 | * Functions 74 | * 75 | **/ 76 | 77 | function duration($end) { 78 | $DAY = 86400; 79 | $HOUR = 3600; 80 | 81 | $now = time(); 82 | $diff = $now - $end; 83 | $days = floor($diff / $DAY); 84 | $hours = floor(($diff % $DAY) / $HOUR); 85 | $minutes = floor((($diff % $DAY) % $HOUR) / 60); 86 | $secs = $diff % 60; 87 | return sprintf("%dd, %02d:%02d:%02d", $days, $hours, $minutes, $secs); 88 | } 89 | 90 | function serviceTable($nagios, $services, $select = false, $type = false) { 91 | if (false === $type) { 92 | print("\n"); 93 | } else { 94 | print(sprintf("
\n", $type)); 95 | } 96 | print("\n"); 97 | print(""); 98 | 99 | foreach ($select as $selectedType) { 100 | if ($services[$selectedType]) { 101 | foreach ($services[$selectedType] as $service) { 102 | $state = $nagios["service"][$service["current_state"]]; 103 | if (false === $type) { 104 | $rowType = $state; 105 | } else { 106 | $rowType = $type; 107 | if ("acknowledged" !== $type) { 108 | $state = $type; 109 | } 110 | } 111 | print(sprintf("\n", $rowType)); 112 | print(sprintf("\n", $service['host_name'])); 113 | print(sprintf("\n", $service['service_description'])); 114 | print(sprintf("\n"); 119 | print(sprintf("\n", duration($service['last_state_change']))); 120 | print(sprintf("\n", $service['current_attempt'], $service['max_attempts'])); 121 | print(sprintf("\n", strip_tags($service['plugin_output'], ''))); 122 | print("\n"); 123 | } 124 | } 125 | } 126 | print("
HostServiceStatusDurationAttemptsPlugin Output
%s%s%s", $state)); 115 | if ($service["current_attempt"] < $service["max_attempts"]) { 116 | print(" (Soft)"); 117 | } 118 | print("%s%s/%s%s
\n"); 127 | } 128 | 129 | function sectionHeader($type, $counter) { 130 | print(sprintf('
', $type)); 131 | print(sprintf('

%s Status

', ucfirst(str_replace("_", " ", $type)))); 132 | print('
'); 133 | foreach($counter[$type] as $type => $value) { 134 | print(sprintf('
%s %s
', $type, $value, ucfirst(str_replace("_", " ", $type)))); 135 | } 136 | print('
'); 137 | } 138 | 139 | /** 140 | * 141 | * Parse Nagios status 142 | * 143 | **/ 144 | 145 | // Check if status file is readable 146 | if (!is_readable($statusFile)) { 147 | die("Failed to read nagios status from '$statusFile'"); 148 | } 149 | 150 | $statusFileMtime = filemtime($statusFile); 151 | $statusFileState = 'ok'; 152 | if ((time() - $statusFileMtime) > $statusFileTimeout) { 153 | $statusFileState = 'critical'; 154 | } 155 | 156 | $nagiosStatus = file($statusFile); 157 | $in = false; 158 | $type = "unknown"; 159 | $status = array(); 160 | $host = null; 161 | 162 | $lineCount = count($nagiosStatus); 163 | for($i = 0; $i < $lineCount; $i++) { 164 | if(false === $in) { 165 | $pos = strpos($nagiosStatus[$i], "{"); 166 | if (false !== $pos) { 167 | $in = true; 168 | $type = substr($nagiosStatus[$i], 0, $pos-1); 169 | if(!empty($status[$type])) { 170 | $arrPos = count($status[$type]); 171 | } else { 172 | $arrPos = 0; 173 | } 174 | continue; 175 | } 176 | } else { 177 | $pos = strpos($nagiosStatus[$i], "}"); 178 | if(false !== $pos) { 179 | $in = false; 180 | $type = "unknown"; 181 | continue; 182 | } 183 | 184 | // Line with data found 185 | list($key, $value) = explode("=", trim($nagiosStatus[$i]), 2); 186 | if("hoststatus" === $type) { 187 | if("host_name" === $key) { 188 | $host = $value; 189 | } 190 | $status[$type][$host][$key] = $value; 191 | } else { 192 | $status[$type][$arrPos][$key] = $value; 193 | } 194 | } 195 | } 196 | 197 | // Initialize some variables 198 | $counter = array(); 199 | $states = array(); 200 | 201 | foreach (array_keys($status) as $type) { 202 | switch ($type) { 203 | case "hoststatus": 204 | $hosts = $status[$type]; 205 | foreach ($hosts as $host) { 206 | if ((int)$host['scheduled_downtime_depth'] > 0) { 207 | continue; 208 | } else if ($host['problem_has_been_acknowledged'] == '1') { 209 | $counter['hosts']['acknowledged']++; 210 | $states['hosts']['acknowledged'][] = $host['host_name']; 211 | } else if ($host['notifications_enabled'] == 0) { 212 | $counter['hosts']['notification']++; 213 | $states['hosts']['notification'][] = $host['host_name']; 214 | } else if ($host['has_been_checked'] == 0) { 215 | $counter['hosts']['pending']++; 216 | $states['hosts']['pending'][] = $host['host_name']; 217 | } else { 218 | switch ($host['current_state']) { 219 | case $nagios['host']['ok']: 220 | $counter['hosts']['ok']++; 221 | break; 222 | case $nagios['host']['down']: 223 | $counter['hosts']['down']++; 224 | $states['hosts']['down'][] = $host; 225 | break; 226 | case $nagios['host']['unreachable']: 227 | $counter['hosts']['unreachable']++; 228 | $states['hosts']['unreachable'][] = $host['host_name']; 229 | break; 230 | } 231 | } 232 | } 233 | break; 234 | 235 | case "servicestatus": 236 | $services = $status[$type]; 237 | foreach ($services as $service) { 238 | // Ignore all services if host state is not ok 239 | $state = $status['hoststatus'][$service['host_name']]['current_state']; 240 | if ($nagios['host']['ok'] != $state) { 241 | continue; 242 | } 243 | 244 | if ((int)$service['scheduled_downtime_depth'] > 0) { 245 | $counter['services']['scheduled_downtime']++; 246 | $states['services']['scheduled_downtime'][] = $service; 247 | } else if ($service['problem_has_been_acknowledged'] == '1') { 248 | $counter['services']['acknowledged']++; 249 | $states['services']['acknowledged'][] = $service; 250 | } else if ($service['notifications_enabled'] == '0') { 251 | $counter['services']['notification']++; 252 | $states['services']['notification'][] = $service; 253 | } else if ($service['has_been_checked'] == '0') { 254 | $counter['services']['pending']++; 255 | $states['services']['pending'][] = $service; 256 | } else { 257 | switch ($service['current_state']) { 258 | case $nagios['service']['ok']: 259 | $counter['services']['ok']++; 260 | break; 261 | case $nagios['service']['warning']: 262 | $counter['services']['warning']++; 263 | $states['services']['warning'][] = $service; 264 | break; 265 | case $nagios['service']['critical']: 266 | $counter['services']['critical']++; 267 | $states['services']['critical'][] = $service; 268 | break; 269 | case $nagios['service']['unknown']: 270 | $counter['services']['unknown']++; 271 | $states['services']['unknown'][] = $service; 272 | break; 273 | } 274 | } 275 | } 276 | break; 277 | } 278 | } 279 | 280 | /** 281 | * 282 | * Status output 283 | * 284 | **/ 285 | 286 | echo "\n"; 288 | echo "\n"; 289 | echo "\n"; 290 | echo " Nagios Monitoring System - Naglite3\n"; 291 | echo " \n"; 292 | echo " \n"; 293 | if (is_readable("custom.css")) { 294 | echo " \n"; 295 | } 296 | echo "\n"; 297 | echo "\n"; 298 | echo '
'; 299 | if($nagliteHeading) { 300 | echo '

'.$nagliteHeading.'

'; 301 | } 302 | 303 | 304 | ############################################################################################ 305 | # Hosts section 306 | ############################################################################################ 307 | sectionHeader('hosts', $counter); 308 | 309 | if ($counter['hosts']['down']) { 310 | echo ""; 311 | echo ""; 312 | foreach($states['hosts']['down'] as $host) { 313 | $state = $nagios["host"][$host["current_state"]]; 314 | echo "\n"; 315 | echo "\n"; 316 | echo "\n"; 317 | echo "\n"; 318 | print(sprintf("\n", htmlspecialchars($host['plugin_output']))); 319 | echo "\n"; 320 | } 321 | echo "
HostStatusDurationStatus Information
{$host["host_name"]}{$state}".duration($host["last_state_change"])."%s
"; 322 | } else { 323 | echo "
ALL MONITORED HOSTS UP
\n"; 324 | } 325 | 326 | foreach(array('unreachable', 'acknowledged', 'pending', 'notification', 'scheduled_downtime') as $type) { 327 | if ($counter['hosts'][$type]) { 328 | print(sprintf('
%s: %s
', $type, ucfirst(str_replace("_", " ", $type)), implode(', ', $states['hosts'][$type]))); 329 | } 330 | } 331 | 332 | ############################################################################################ 333 | # Services section 334 | ############################################################################################ 335 | sectionHeader('services', $counter); 336 | 337 | if ($counter['services']['warning'] || $counter['services']['critical'] || $counter['services']['unknown']) { 338 | serviceTable($nagios, $states['services'], array('critical', 'warning', 'unknown')); 339 | } else { 340 | print("
ALL MONITORED SERVICES OK
\n"); 341 | } 342 | 343 | foreach(array('acknowledged', 'scheduled_downtime', 'notification', 'pending') as $type) { 344 | if ($counter['services'][$type]) { 345 | print(sprintf('

%s

', ucfirst(str_replace("_", " ", $type)))); 346 | print('
'); 347 | serviceTable($nagios, $states['services'], array($type), $type); 348 | print('
'); 349 | } 350 | } 351 | 352 | if($enableFortune === true) { 353 | echo "
"; 354 | print(shell_exec($fortunePath)); 355 | echo "
"; 356 | } 357 | 358 | print("
\n"); 359 | print(sprintf('
', $statusFileState)); 360 | print(sprintf('Status file last updated at %s', date(DATE_RFC2822, $statusFileMtime))); 361 | print("
\n"); 362 | print("\n"); 363 | print("\n"); 364 | --------------------------------------------------------------------------------