[PHP]Serverüberwachung bitte um Kritik

cb01

Registered User
Hi,

ich habe mal ein kleines Skript zur Serverüberwachung geschrieben und würde mich sehr über Kritik und Änderungsvorschläge freuen, das Skript soll später dann mal per Cronjob alle 20min ausgeführt werden und wenn etwas nicht erreichbar ist eine Mail verschicken.
Hier das Skript:

PHP:
<?php

$server = ""; //Hostname oder IP
$port1  = ""; //HTTP
$port2  = ""; //FTP
$port3  = ""; //MySQL
$port4  = ""; //SMTP
$port5  = ""; //POP3
$port6  = ""; //IMAP

//HTTP SERVER AUF FUNKTION TESTEN   
$http = @fsockopen($server, $port1);

if (!$http)
{
   $httpstatus = 'nicht erreichbar';
}else {
   $httpstatus = 'erreichbar';
}


//FTP SERVER AUF FUNKTION TESTEN   
$ftp = @fsockopen($server, $port2);

if (!$ftp)
{
   $ftpstatus = 'nicht erreichbar';
}else {
   $ftpstatus = 'erreichbar';
}


//MySQL SERVER AUF FUNKTION TESTEN   
$mysql = @fsockopen($server, $port3);

if (!$mysql)
{
   $mysqlstatus = 'nicht erreichbar';
}else {
   $mysqlstatus = 'erreichbar';
}


//SMTP SERVER AUF FUNKTION TESTEN   
$smtp = @fsockopen($server, $port4);

if (!$smtp)
{
   $smtpstatus = 'nicht erreichbar';
}else {
   $smtpstatus = 'erreichbar';
}


//POP3 SERVER AUF FUNKTION TESTEN   
$pop3 = @fsockopen($server, $port5);

if (!$pop3)
{
   $pop3status = 'nicht erreichbar';
}else {
   $pop3status = 'erreichbar';
}


//IMAP SERVER AUF FUNKTION TESTEN   
$imap = @fsockopen($server, $port6);

if (!$imap)
{
   $imapstatus = 'nicht erreichbar';
}else {
   $imapstatus = 'erreichbar';
}

if ($httpstatus == 'nicht erreichbar'or $ftpstatus == 'nicht erreichbar'or $mysqlstatus == 'nicht erreichbar'or $smtpstatus == 'nicht erreichbar'or $pop3status == 'nicht erreichbar'or $imapstatus == 'nicht erreichbar'){
	
$sender_name            = "Server Monitor";

$empfänger_mail_adresse = ""; //Mailadresse

$nachricht = "Folgende Serverdienste sind auf dem Server: $server ausgefallen bzw. nicht erreichbar:
HTTP: $httpstatus an Port: $port1
FTP: $ftpstatus an Port: $port2
MySQL: $mysqlstatus an Port: $port3
SMTP: $smtpstatus an Port: $port4
POP3: $pop3status an Port: $port5
IMAP: $imapstatus an Port: $port6
";

$betreff   = "Serverprobleme";

$headers .= "From: ".$sender_name."";

if (mail($empfänger_mail_adresse, $betreff, $nachricht, $headers));
}
?>

Das Skript an sich funktioniert schon, mich interessiert aber, was man noch besser lösen kann...

Gruß

Chris
 
Ich glaube es ist nicht so wichtig mizuteilen, dass ein Dienst ereichbar ist.
Beschraenke dich einfach darauf, dass ein Dienst nicht erreichbar ist.

PHP:
if ($httpstatus == 'nicht erreichbar'or $ftpstatus == 'nicht erreichbar'or
Dann musst du am Ende auch nur pruefen, ob die jeweilige Variabel gesetzt ist.
PHP:
if(isset($httpstatus)||...


Oder du setzt bei einem Fehler noch eine zusaetzliche Varieble ($error=1).
PHP:
$error=0;
...
if (!$imap){
   $imapstatus = 'nicht erreichbar'; 
  $error++
}
...
if($error){
//Mailsachen
}

Bei dem Skript machen die Aenderungen aber keinen Unterschied; es sei denn du willst sehr viele Server pruefen.
 
Wenn es auf einem anderen Server liegt schon. Das ist hier nicht Gegenstand er Diskussion. Bitte weitere Antworten auf das Script beziehen. DANKE!
 
was man noch besser lösen kann...
Dazu fällt mir viel ein. :D
1.) Die Verbindungen danach auch ordentlich schließen!
2.) Bei manche Server schreiben häßliche Log-Einträge, wenn die Verbindung direkt wieder aufgelöst wird. Ein freundlichen "QUIT" hilft dageben bereits. (z.B. bei SMTP, POP3, IMAP, FTP).
3.) Würde ich die zu prüfenden Dienste in einem Array configurieren:
PHP:
service = array(
    'smtp' => array(port=>25, quit=>'quit'),
    'http' => array(port=>80, quit=>"GET / HTTP/1.0\r\n\r\n"),
...
);
//Das dann auch der jeweilige Status in einem Array gehalten wird ist logisch:
status = array();
4.) Würden mich z.B. auch die Antwortzeiten (gerade beim Webserver) interessieren.
5.) Sollte die Reaktion besser konfigurierbar sein. Z.B. könnte es auch mal Sinn machen eine Aufzeichnung in ein Logfile zu schreiben.
6.) Auch einen automatischen Neustart des jeweiligen Dienstes sollte man evtl. konfigurieren können.
7.) Falls der lokale Mailserver down ist, kann die Mail nicht verschickt werden. In dem Falle wäre es gut, wenn das Skript manuell die Mail von Hand verschickt. (Ist nicht schwer.)

Und zu guter Letzt:
Meine Erfahrung hat gezeigt, daß 20 Minuten ein verdammt langer Zeitraum sind... :) Da das Script kaum Performance schluckt, darf das ruhig häufiger laufen.

huschi.
 
7.) Falls der lokale Mailserver down ist, kann die Mail nicht verschickt werden. In dem Falle wäre es gut, wenn das Skript manuell die Mail von Hand verschickt.

Ich würde das Pear-Paket Mail installieren, dann kannst Du direkt per sendmail Mails verschicken.
 
Genau das meine ich ja. (Wobei man das ganze auch recht easy ohne Pear::Mail programmieren kann.) Aber man sollte nicht die Methode Sendmail nutzen sondern SMTP. Mit Sendmail wird die Mail nur in die lokale Mailqueue eingespeist, welche evtl. eben nicht abgearbeitet wird. Wärend SMTP eine direkte Connection zum Ziel-Server aufbaut. (Hier gibt es auch ein paar Dinge zu beachten, wie z.B. evtl. vorhandenes Greylisting, etc.)

huschi.
 
Hi,

erstmal vielen Dank für eure Tipps, werde sie soweit wie es mir möglich ist umsetzen!
Eine SMS Benachrichtigung ist denke ich nicht notwendig, zur Not kann ich die Mail ja auch noch an mein Handy leiten...
Habe gleich noch eine Frage, wird die verbindung so jetzt ordentlich geschlossen:

PHP:
//HTTP SERVER AUF FUNKTION TESTEN   
$http = @fsockopen($server, $port1);

if (!$http)
{
   $httpstatus = 'nicht erreichbar';
}
socket_set_timeout($http, 200);
fclose($http);

Gruß

Chris
 
Nein, weil nach einem Socket-Verbindungsfehler ein nicht geöffneter Socket geschlossen werden soll...
PHP:
$http = @fsockopen($server, $port1);
if ($http) {
   socket_set_timeout($http, 200); //Warum Du das auch immer drin haben willst...
   fclose($http);
} else {
   $httpstatus = 'nicht erreichbar';
}

huschi.
 
PHP:
[...]
//HTTP SERVER AUF FUNKTION TESTEN   
$http = @fsockopen($server, $port1);

if (!$http)
{
   $httpstatus = 'nicht erreichbar';
}else {
   $httpstatus = 'erreichbar';
}


//FTP SERVER AUF FUNKTION TESTEN   
$ftp = @fsockopen($server, $port2);

if (!$ftp)
{
   $ftpstatus = 'nicht erreichbar';
}else {
   $ftpstatus = 'erreichbar';
}
[...]
Ich sag nur: Don't repeat yourself!

Und immer schön expressiven code schreiben.
Folgende Zeilen lesen sich etwa so:
- Es wird ein als $ftp bezeichneter Socket geöffnet
- Wenn $ftp unwahr ist, dann...
PHP:
$ftp = @fsockopen($server, $port2);
if (!$ftp) { [...]

So ist es schöner. Hier steht:
- Wenn sich der Socket ($ftp) nicht öffnen lässt, dann ...
PHP:
if (!$ftp = @fsockopen($server, $port2);) { ...

Das sieht zwar nicht sehr spektakulär aus, aber wenn man beim Coden ein Bewusstsein für sowas entwickelt, dann macht das einen guten Style.
(Naja, kommt schon noch auf ein paar andere Dinge an - aber ohne das...)
 
BTW Style. Ich hab das Ding mal etwas umformatiert um zu verdeutlichen, was ich meine. So wäre es schon ganz ok:
PHP:
<?php

# define checkhosts
$hosts = array(
  'host1' => array(
    'hostname'  => 'host1.network.net',
    'services'  => array(
      'http'      => 80,
      'ftp'       => 21,
      'smtp'      => 25,
      //...
    ),
  ),
  'host2' => array(
    'hostname'  => 'host2.network.net',
    'services'  => array(
      'http'      => 80,
      'ftp'       => 21,
      'smtp'      => 25,
      //...
    ),
  ),
  //...
);

# configure mail option
$mail = array(
  'to'      => 'admin@network.net',
  'from'    => 'checkscript@network.net',
  'subject' => 'Service warnings'
);

# collect check results
$errors = array();
foreach ($hosts AS $name => $host) {
  foreach ($host['services'] AS $service => $port) {
    if (do_check($host['hostname'], $port) !== true) {
      $errors[$name][] = $service;
    }
  }
}

# report errors
if ($errors) {
  // create message text
  $message = '';
  foreach ($errors as $host => $service_errors) {
    $message .= "Errors detected on Host '$host':\n";
    foreach ($service_errors AS $service) {
      $message .= "\tCould not connect service '$service'\n";
    }
    $message .= "\n"; // looks nicer
  }

  // send message
  mail($mail['to'], $mail['subject'], $message, 'From: '.$mail['from']);
}

# check action
function do_check($hostname, $port) {
  // exit false when failed
  if (!$conn = @fsockopen($hostname, $port)) return false;
  // success
  fclose($conn);
  return true;
}

?>

PS: Für "richtiges" Überwachen von Hosts und Netzen gibt es übrigens Software wie z.B. Nagios. Was das kann, programmiert man nicht mal eben so neu.
 
Hi elias5000,

danke für deine Tipps, mir ist bewusst, das es auch fertige Lösungen für sowas gibt, mir geht es auch nicht primär um die Serverüberwachung, für mich ist derzeit der Effekt des Lernens von PHP viel wichtiger:) ...

Gruß

Chris
 
Back
Top