понедельник, 22 октября 2007 г.

Пинг по расписанию для мониторинга состояния сети

В нашей локалке в последнее время появились потери до шлюза, когда в сети много людей. Для мониторинга написал скрипт, который пингует шлюз по расписанию, и выводит на сайт результаты.

Сам скрипт пинга:
 #!/bin/bash
 fn=`date +%F.%H:%M:%S`
 dir=/var/www/localhost/htdocs/ping-stat
 ping -i 0.3 -c 500 10.13.0.17 > $dir/$fn.txt
 tail -n 3 < $dir/$fn.txt > $dir/$fn.stat.txt

Запись в crontab:

0,30 * * * * root /path/to/script


Скрипт для показа результатов на сайте: /var/www/localhost/cgi-bin:
 #!/bin/sh
 echo "Content-type: text/html; charset=cp1251"
 echo
 echo "<html><body>"
 echo "<a href='http://$HTTP_HOST/ping-stat-graph/packetlost.php'>График</a><br>"
 echo "<a href='http://$HTTP_HOST/ping-stat-graph/packetlost.php?t'>График таймингов</a><br>"
 echo "<form action='http://$HTTP_HOST/ping-stat-graph/packetlost.php'>"
 echo "Показать последние записи, шт. <input name='s'><input type='submit' value='Показать'><br>"
 echo "Показать последние записи, тайминги, шт. <input name='s'><input type='submit' value='Показать'><input type='hidden' name='t'></form>"
 echo "<table>"
 for i in $( find /var/www/localhost/htdocs/ping-stat/ -type f -not -name "*.stat.txt" -printf "%f\n" | sort )
 do
   base=`expr match "$i" '\([^.]*\.[^.]*\)'`
   echo "<tr><td><a href='/ping-stat/$i'>$base</a><br></td>"
   if [ -e "/var/www/localhost/htdocs/ping-stat/$base.stat.txt" ]
   then
      echo "<td><a href='/ping-stat/$base.stat.txt'>Кратко</a></td><tr>"
   else
      echo "<td>Кратко</td><tr>"
   fi
 done
 echo "</table>"
 echo "</body></html>"

Скрипт для графика /var/www/localhost/htdocs/ping-stat-graph/packetlost.php (автор скрипта мой друг mvf):
 <?
 $dir  = "/var/www/localhost/htdocs/ping-stat/";
 $filename_date_format = "%Y-%m-%d.%H:%M:%s.";
 $filename_format = "^[[:punct:][:digit:]]{14,30}\.stat\.txt$"; // формат имени файла - для ерега
 $file_content_format ="([[:digit:]]+) packets transmitted, ([[:digit:]]+) received, [[:digit:]]+% packet loss, time [[:digit:]]+ms[[:space:]]*rtt min/avg/max/mdev = ([[:digit:]\.]+)/([[:digit:]\.]+)/([[:digit:]\.]+)/([[:digit:]\.]+) ms";
 /////////////////////////////////////////////////////////////////
 // Returns a date from a string based on a given format
 // кривая штуковина скопированная их хелпов и немного переделанная,
 // но в принципе худо-бедно может прочитать дату из заданного формата
 function parseDate( $date, $format )
 {
  // Builds up date pattern from the given $format, keeping delimiters in place.
  if( !preg_match_all( "/%([YmdHMs])([^%])*/", $format, $formatTokens, PREG_SET_ORDER ) ) {
   return false;
  }
  $datePattern = "";
  foreach( $formatTokens as $formatToken )
   {
    $delimiter = preg_quote( $formatToken[2], "/" );
    if($formatToken[1] == 'Y') {
      $datePattern .= '(.{1,4})'.$delimiter;
    } else {
      $datePattern .= '(.{1,2})'.$delimiter;
    }
   }
  if( !preg_match( "/".$datePattern."/", $date, $dateTokens) ) return false;
  $dateSegments = array();
  for($i = 0; $i < count($formatTokens); $i++) {
   $dateSegments[$formatTokens[$i][1]] = $dateTokens[$i+1];
  }
  return mktime ( $dateSegments["H"], $dateSegments["M"], $dateSegments["s"], $dateSegments["m"], $dateSegments["d"], $dateSegments["Y"]);
 }
 /////////////////////////////////////////////////////////////////
 // для usort
 function cmp_by_date($a, $b)
 {
  if ($a['time'] == $b['time']) {  return 0; }
  return ($a['time'] < $b['time']) ? -1 : 1;
 }
 ////////////////////////////////////////////////////////////////
 //// начало
 ////////////////////////////////////////////////////////////////
 $filenames = scandir($dir);
 $data = array();
 foreach ($filenames as $filename)
  {
   $full_name = $dir.$filename;
   if (!is_dir($full_name) &amp;&amp; $filename != "." &amp;&amp; $filename != ".." &amp;&amp; ereg($filename_format, $filename))
    {
      $ftime = parseDate($filename, $filename_date_format);
      ereg($file_content_format,file_get_contents($full_name),$res);
      $data_piece['time'] = $ftime;
      $data_piece['time_text'] = date("H:i",$ftime);
      if ($res[1]!=0) $data_piece['lost'] = (1 - $res[2]/$res[1])*100; else $data_piece['lost'] = 100;
      $data_piece['transmitted'] = $res[1]+0;
      $data_piece['received'] = $res[2]+0;
      $data_piece['min'] = $res[3]+0.0;
      $data_piece['avg'] = $res[4]+0.0;
      $data_piece['max'] = $res[5]+0.0;
      $data_piece['mdev'] = $res[6]+0.0;
      $data[] = $data_piece;
    } // if (!is_dir ...
  } // foreach ($filenames
 usort($data, "cmp_by_date");
 // по идее тут бы лучше разбить скрипт на два...
 // один которые собирает и сохраняет данные, второй - показывает сохраенные данные.
 if (isset($_GET['s'])) // если указан размер
  {
   $size = count($data);
   $disired_size = 0 + $_GET['s'];
   $croppoint = $size - $disired_size;
   if ($croppoint < 0) $croppoint = 0;
   $data = array_slice($data, $croppoint);
  }
 require('chart.php');
 $time_min = array();
 $time_max = array();
 $time_avg = array();
 $x_axis = array();
 $lost = array();
 foreach ($data as $data_piece)
  {
   $time_min[] = $data_piece['min'];
   $time_max[] = $data_piece['max'];
   $time_avg[] = $data_piece['avg'];
   $x_axis[] = $data_piece['time_text'];
   $lost[] = $data_piece['lost'];
  }
 //plot (array $c1, array $c2 = false, color $color = "black",
 //   string $style = "lines", color $gradient_color = "black",
 //  int $parameter = 0)
 if (isset($_GET['t']))
  {
   $chart = new chart(2000, 500);
   $chart->set_title("Ping timing (10.13.0.17 from 10.13.200.111)");
   $chart->set_x_ticks ($x_axis,"text");
   $chart->set_labels ("time", "ping, ms");
   $chart->set_margins ($left = 50, $right = 10, $top = 20, $bottom = 43);
   $chart->plot($time_max, false, "black");
   $chart->add_legend("Max");
   $chart->plot($time_avg, false, "red", "gradient");
   $chart->add_legend("Avg", "red");
   $chart->plot($time_min, false, "blue", "gradient");
   $chart->add_legend("Min", "blue");
   $chart->stroke();
  } else
  {
   $chart = new chart(2000, 500);
   $chart->set_title("Packet lost (10.13.0.17 from 10.13.200.111)");
   $chart->set_x_ticks ($x_axis,"text");
   $chart->set_labels ("time", "lost, %");
   $chart->set_margins ($left = 50, $right = 10, $top = 20, $bottom = 43);
   $chart->plot($lost, false, "black");
   $chart->stroke();
  }
 ?>

Для отрисовки используется библиотека chart

Результат можно посмотреть здесь

Комментариев нет: