9 – Module 6 – Graphique de la bande passante

Pour diverses raisons, il peut intéressant de s’avoir si notre bande passante internet est saturée ou non. Ce module affiche un historique d’environ 5 minutes de l’utilisation de la bande passante descendante (download) et montante (upload). De cette manière, je peux voir en un seul coup d’oeil si quelque chose d’anormal se passe sur mon réseau.

jarvis_screenshot_ifstat

Introduction

Ce module est de loin le plus compliqué de tous. D’une part, il va falloir récupérer le débit instantané utilisé par l’interface réseau de la gateway qui est reliée à la Box internet. Puis, il va falloir transmettre ces données au Pi sur lequel fonctionne le dashscreen. Enfin, il faudra créer un graphique pour représenter ces informations…

En effet, j’ai choisi de ne pas utiliser de soft type mrtg qui sont spécialisés pour ce genre de chose. Je préfère installer le minimum de soft, et utiliser quelques commandes de base. Pour faire quelque chose de simple (comme afficher la bande passante sur la graphique), pas besoin de sortir l’artillerie lourde 🙂 Et puis …si on ne se compliquait pas la vie, ce serait beaucoup moins drôle, n’est ce pas ? 😉

Mesurer la bande passante

ifstat est un petit outil en ligne de commande qui affiche les statistiques d’utilisation d’une interface réseau. Dans un terminal, taper la commande suivante :

ifstat -n -i eth0

Et vous obtiendrait en continue, quelque chose dans le genre :

       eth0       
 KB/s in  KB/s out
    0.45      0.06
    0.71      0.39
    2.85      0.76
    0.57      0.06
    1.86      0.19
    0.45      0.06
    0.45      0.06
    0.45      0.06
    0.57      0.06
    0.59      0.13
    0.45      0.06
    0.45      0.06
    0.59      0.26
    0.57      0.06
    1.74      0.13
    ...

Chaque seconde on obtient le débit instantané (ou presque), en KBytes/s, c’est à dire en Ko/s 🙂 C’est exactement ce qu’il nous faut 🙂 Il convient maintenant d’envoyer ces informations en continue sur notre Pi.

Transmettre les données au Pi à travers le réseau

Le moyen le plus simple de transmettre une info d’un ordinateur à un autre c’est de les envoyer dans des paquets UDP… C’est tellement trivial qu’il ma fallu plusieurs jours avant d’en avoir l’idée !

La commande netcat est tout à fait appropriée pour ce type d’opération. Sur une machine A qui joue le rôle de serveur faites :

nc -u -l 12345
  • -u : pour utiliser l’UDP
  • -l : pour passer en mode écoute (serveur)
  • 12345 : un numéro de port découte

Puis sur une machine B qui joue le rôle de client, faites :

nc -p 8888 -u 10.0.0.1 12345
  • -p 8888 : un port source
  • -u : pour utiliser l’UDP
  • 10.0.0.1 : adresse IP de la machine A (serveur)
  • 12345 : port d’écoute de la machine A (serveur)

Et hop, tout ce que vous tapez au clavier sur B, s’affiche sur A 🙂

Albert Einstein disait « Tout devrait être rendu aussi simple que possible, mais pas plus ! ».

A méditer 😉

Pour transmettre les données renvoyées par la commande ifstat à travers netcat, nous utiliserons un pipe. Voici les deux scripts complets (client/serveur) pour réaliser cette opération :

  • Script serveur à exécuter sur le Pi nc_ifstat_srv.sh :
### BEGIN INIT INFO 
# Provides: nc_ifstat_srv 
# Required-Start: 
# Required-Stop: 
# Default-Start: 2 3 4 5 
# Default-Stop: 0 1 6 
# Short-Description: ifstat for Jarvis 
# Description: Enable service provided by daemon. 
### END INIT INFO

dst_port=12345
dst_dir=/home/jarvis/ifstat
dst_file=eth0.log

nc -u -l $dst_port >> $dst_dir/$dst_file&
  • Script client à exécuter sur votre gateway/routeur nc_ifstat_clt.sh  :
### BEGIN INIT INFO
# Provides:          nc_ifstat_clt
# Required-Start:
# Required-Stop:
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: ifstat for Jarvis
# Description:       Enable service provided by daemon.
### END INIT INFO

src_port=8888
dst_port=12345
dst_host=10.0.0.2
eth=eth0

nc_ifstat()
{
	while [ "true" ]
	do
  		ifstat -n -i $eth | nc -p $src_port -u $dst_host $dst_port
  		sleep 5
	done
}

case "$1" in
        stop)
		echo " Stoping ifstat for Jarvis..."
                killall ifstat
		killall nc
		;;
        start)
		echo " Starting ifstat for Jarvis..."
		nc_ifstat&
		exit 0	
                ;;
        *)
                exit 1
                ;;
esac

exit 0

Pour exécuter le script au démarrage de la machine, placer le dans le répertoire /etc/init.d puis lancer la commande :

update-rc.d nom_du_script.sh defaults

A ce stade, vous devriez avoir un fichier sur votre Pi dans lequel, chaque seconde, la bande passante instantanée y est ajoutée en fin de fichier 🙂 Il ne nous reste plus qu’à lire ce fichier avec un script PHP, et dessiner le graphique pour représenter les données qu’il contient 🙂

Création du graphique en PHP

Ici encore, j’aurais pu utiliser une lib graphique en PHP, en JavaScript ou en n’importe quoi d’autre. Mais au lieux de sous exploiter une usine à gaz difficilement personnalisable, j’ai préféré créer ma propre fonction graphique en PHP. Vous allez voir que c’est beaucoup plus simple que ce qu’on peut s’imaginer 🙂

Voici ma fonction imagickHisto() :

function imagickHisto ($max, $eth = '', $up_down = 'down') {

  $datas = parseData ("eth0.log", $up_down);

  $width            = 304; // largeur du graphique
  $height           = 100; // hauteur du graphique
  $padding          = 1;
  $ticks            = 5;
  $background_color = '#000'; // couleur du fond
  $axes_color       = '#555'; // couleur des axes

  if($up_down == 'down'){
    $data_color       = '#1D1'; // couleur du graphique pour le download
  }
  else{
    $data_color       = '#D11'; // couleur du graphique pour l'upload
  }

  $nb_values        = $width - 2*$padding - 2;
  $max_value        = $height - 2*$padding - 4;

  $nb_datas         = sizeof($datas);
  $trim             = $nb_values - $nb_datas;

  if($trim < 0){$trim = 0;}

  $image = new Imagick();
  $image ->newImage( $width, $height, new ImagickPixel($background_color) );
  $draw  = new ImagickDraw();
  $draw->setStrokeColor( new ImagickPixel($axes_color) );

  $xx1    = $padding;
  $xy1    = $height - $padding - 1;
  $xx2    = $width - $padding - 1;
  $xy2    = $xy1;
  $yx1    = $xx1;
  $yy1    = $xy1;
  $yx2    = $yx1;
  $yy2    = $padding;
  $half_y = $height/2;
  $half_x = $width/2;

  $draw->line  ( $xx1, $xy1, $xx2, $xy2 );
  $draw->line  ( $yx1, $yy1, $yx2, $yy2 );

  $draw->line  ( $yx1, $yy2, $yx1+$ticks, $yy2 );
  $draw->line  ( $yx1, $half_y, $yx1+$ticks, $half_y );

  $draw->setStrokeColor( new ImagickPixel($data_color) );

  $first_x = $xx1 + 1 + $trim;
  $last_x  = $xx2 - 1;
  $first_y = $xy1 - 1;
  $last_y  = $yy2 + 1;

  for($i=0;$i<$nb_values;$i++){
    if(isset($datas[$i])){
      $value   = $datas[$i]*$max_value/$max;
      $value_y = $first_y - $value;
      $value_x = $first_x + $i;
      $draw->line  ( $value_x, $first_y, $value_x, $value_y );
    }
  }

  $image->drawImage( $draw );

  $text_draw = new ImagickDraw();
  $text_draw->setFillColor($axes_color);
  $text_draw->setFontSize( 12 );
  $image->annotateImage($text_draw, $half_x-20, $padding+10, 0, "$eth - $up_down");

  $image->setImageFormat( "png" );
  header( "Content-Type: image/png" );
  echo $image;
  exit;
}

Veuillez accepter mes excuses pour le manque cruel de commentaire dont fait l’objet cette fonction. Pour résumer, la fonction prend trois paramètres :

  • $max : la valeur max (en Ko) pour borner le graphique. Par exemple, mon débit réel maximum atteint 1800 Ko/s. Je choisie donc $max = 2000.
  • $eth : nom de l’interface (exemple eth0)
  • $up_down : « up » ou « down » pour spécifier la couleur du graphique ainsi que les données à afficher issue de ifstat

La fonction lit un tableau de donnée renvoyé par la fonction parseData(), puis dessine sur le graphique une barre de 1px de large par donnée. Avec une largeur de 300px, on peut donc afficher 5 minutes d’historique de données 🙂

Voici la fonction parseData() dont le rôle est de lire le fichier contenant les données issues de la commande ifstat :

  function parseData ($stat_file, $up_down) {
    $datas = array();
    if(filemtime($stat_file) < time()-10){return $datas;}
    $stats = fopen($stat_file, 'r');
    while (($line = fgets($stats)) !== false) {
      $explode_line = str_word_count($line, 1, "0123456789.");
      if($up_down == 'down') {
        $datas[]  = $explode_line[0];
      }
      else{
        $datas[]  = $explode_line[1];
      }
    }
    fclose($stats);
    $datas = array_slice($datas, -300);
    return $datas;
  }

Cette fonction prend deux paramètres :

  • $stat_file : fichier à parser
  • $up_down : « up » ou « down » pour distinguer les données d’upload et de download

Pour la suite, nous reprennons la même démarche que pour les autres modules 🙂

index.php

Il faut une div par graphique ; nous en ajoutons donc deux au fichier index.php, une pour l’upload et une pour le download.

 <div id="ifstat_eth0_up"><img id="img_eth0_up" src="pict/blank.png"></div>
 <div id="ifstat_eth0_down"><img id="img_eth0_down" src="pict/blank.png"></div>

Comme pour le module Xplanet, il convient d’initier la source des balises images <img> avec une image vide blank.png.

style.css

Il suffit ici de positionner nos deux <div> :

/* ifstat */

div#ifstat_oberon_up
{
  right             : 20px;
  bottom            : 20px;
  position          : absolute;
  overflow          : hidden;
  background-color  : rgba(0, 0, 0, 1);
}

div#ifstat_oberon_down
{
  right             : 340px;
  bottom            : 20px;
  position          : absolute;
  overflow          : hidden;
  background-color  : rgba(0, 0, 0, 1);
}

javascript.js

Une simple requête AJAX permet de récupérer les graphiques à afficher.

/* ifstat */

var ifstat_timeout;

function ifstat () {

  var now             = new Date().getTime();

  var url_down = "ajax.php?block=ifstat&eth=wan&up_down=down&max=2000&hour="+now;
  var img_eth0_down = $("<img />").attr("src", url_eth0_down);
  $("#img_eth0_down").attr("src", url_eth0_down);

  var url_up   = "ajax.php?block=ifstat&eth=wan&up_down=up&max=150&hour="+now;
  var img_eth0_up = $("<img />").attr("src", url_eth0_up);
  $("#img_eth0_up").attr("src", url_eth0_up);

  ifstat_timeout = setTimeout("ifstat()", 5000);
}

Même principe que pour le module Xplanet, il convient de précharger les images avant de les afficher. Je fixe le délais de rafraichissement à 5 secondes, ce qui est suffisant.

ajax.php

Le code à ajouter dans ce fichier reste élémentaire comme pour les autres modules. Il ne faut toutefois pas oublier de prendre en compte les paramètres de la fonction imagickHisto() :

  /////////////////////////////////////////////////
  //  IFSTAT
  /////////////////////////////////////////////////

  if($block == 'ifstat'){
    imagickHisto ($_REQUEST['max'], $_REQUEST['eth'], $_REQUEST['up_down']);
  }


inc.php

Dans ce fichier, il suffit de copier-coller les fonctions imagickHisto() et parseData() qui ont été décrites plus haut dans cet article.

Voilà le rendu final en gros plan, lorsque la bande passante est très sollicitée :

ifstat

36 réflexions au sujet de « 9 – Module 6 – Graphique de la bande passante »

  1. Cyril

    Hello,

    Petite question, avec la commande que tu utilises, tu monitores une connexion, mais tu auras l’utilisation de la bande passante de cette connexion, pas forcément celle de ta connexion internet.
    Si sur un réseau tu as une machine 1 qui télécharge, depuis une machine 2, la bande passante pour aller sur internet sera réduite, alors que la bande passante que tu mesures sur cette machine n°2 n’est pas du tout utilisée.
    D’ailleurs, sais tu s’il est possible de différencier la quantité de données échangées sur un réseau « interne » de la quantité de données sur internet ?

    Répondre
    1. Olivier Auteur de l’article

      Salut Cyril,
      En fait, la mesure est effectuée sur l’interface réseau de ma gateway qui est connecté à ma box. Donc je mesure tout ce qui rentre et sort entre Internet et mon réseau interne 🙂 J’ai donc bien la bande passante consommé par tous les équipements qui sont derrière ma gateway 🙂
      Si j’avais un routeur type WRT branché sur ma box, cela reviendra à mesurer le trafic qui traverse l’interface WAN.

      Répondre
  2. axelar

    Bonjour

    avant tout merci de partager toutes ces informations c’est très pratique.

    Une question me vient à l’esprit en voulant reproduire ce module, le fichier de log va gonfler indéfiniement, qu’as tu prévu pour y remédier ?

    Un amateur qui s’essaie aussi au dashscreen 🙂

    Répondre
  3. mika

    bonjour
    j’ai une question, ifstat doit etre exécuté sur le routeur?
    ca implique un routeur sous dd-wrt ou similaire non?
    merci 🙂

    Répondre
    1. Olivier Auteur de l’article

      Hello,
      Effectivement ifstat doit être exécuté sur le routeur ou la passerelle entre ton réseau local et Internet.
      Pour ma part, j’ai une gateway sous Debian, donc pas de souci 🙂
      Sinon, oui un dd-wrt ou openwrt sont nécessaires pour avoir la main sur ton routeur 🙂

      Répondre
  4. jerome

    Salut et merci pour ton tuto je me suis amusé a en faire un mais pour ifstat j’ai pfsense chez moi tu serait comment je pourrait exécuté se système stp merci d’avance

    Répondre
    1. Olivier Auteur de l’article

      Salut,
      Pfsense est basé sur freeBSD, il doit forcément y avoir moyen d’installer ifstat ou un équivalent 🙂

      Répondre
        1. Julien

          Bonjour Jérome et Olivier,
          Je suis dans le même cas de figure un pfsense (avec plusieurs wan par dessus tout mais ça sera dans un second temps ça…) j’aurais bien aimé réussir à faire fonctionner le script… pour ma part sur le pfsense j’ai réussi à install ifstat via « pkg search ifstat » puis « pkg install ifstat »…
          C’est après que les choses se gate… je suis pas expert en freebsd mais il semblerait que le script ne puisse fonctionner… pas tel quel en tout cas…
          Si quelqu’un ayant des connaissances en freebsd/pfsense passe par là merci d’avance du coup de main pour avancer sur ce sujet 😉

          Répondre
  5. Sebastien

    J’ai un petit soucis. Je monitor la bande passante de mon synology. Donc tout est OK niveau client. Niveau serveur aussi. Sauf qu’arrive a un moment mon fichier eth0.log ne se rempli plus. Et donc plus d’affichage. A tu une idée?

    Répondre
  6. jerome

    Salut Sebastien tu serez ok de m’expliquer comment tu a fait car je voulez le mettre sur un pfsense mais il y a aucun tuto sur sa et j’ai aussi un synology et je suis novice dans se domaine la merci d’avance

    Répondre
    1. Sebastien

      Je peut toujours te décrire comment j’ai fait, ces toujours le meme process. Je ne connait pas pf-sense par contre. Si tu a un mail ou autre ?

      Répondre
  7. Cohen Jonathan

    moi j’ai pas de rasperry j’ai en revanche un serveur sur debian ou est installer mon vpn, et j’ai bien cree un fichier txt avec les infos up/down mais j’arrive pas a le mettre en graphique puisque j’utilise pas la fonction netcat je vois pas ou j’enverrai les infos…?

    Répondre
    1. Olivier Auteur de l’article

      Si tu travail en local, tu peux directement stocker les données dans un fichier texte, comme à la sortie de netcat 🙂

      Répondre
  8. Charle

    Bonjour,
    Je rencontre un problème lors de l’installation de ce module,une fois tous les fichiers configuré comme ci-dessus je vais sur le dashscreen mais le graphique ne s’affiche pas.
    J’ai alors fais un test sur wamp qui,au chargement du dashscreen m’a répondu:

    Fatal error: Class ‘Imagick’ not found in C:\wamp\www\dashscreen\test\inc.php on line 156
    (j’ai utilisé les sources mises a disposition)

    Pouvez-vous m’aider a resoudre cette erreur ?
    S.V.P

    Répondre
  9. Charle

    J’ai installe le paquet et je n’ai plus d’erreur ,quand on inspecte l’element(le dashscreen) on voit que l’image est: « ajax.php?block=ifstat&eth=wan&up_down=up&max=150&hour=1427641533927 »
    mais sur le dashscreen,on ne voit rien et quand on entre l’url de l’image (dans mon cas: http://192.168.1.22/dashscreen/ajax.php?block=ifstat&eth=wan&up_down=up&max=150&hour=1427641533927)
    rien ne s’affiche .
    Le fichier log est bien accessible et se presente comme ceci:
    eth0
    KB/s in KB/s out
    17.91 1.15
    18.39 2.63
    16.38 2.58
    19.56 1.54
    19.37 4.73
    15.41 0.82
    18.81 2.33
    15.41 1.23
    20.52 4.23
    15.36 0.87

    Pouvez-vous m’aider ?

    Répondre
  10. larson

    Olivier,
    Je suis en train d’adapter ton source pour récupérer les infos de la bande passante via mon debian, j’aime beaucoup ton module de traffic de site internet, tu pourrais le mettre à disposition ? si ce n’est pas trop demandé 🙂
    Merci!

    Répondre
    1. Olivier Auteur de l’article

      Hello,
      Le graphique de trafic de site internet est directement celui fournis part Google Analytics via son API 🙂

      Répondre
          1. larson

            Cr!Cr! 🙂

            Au fait vous purgez ou vous effacez le fichier log de la bande passante ?
            De mon coté, j’ai mis en place un cron avec un truc du genre ..

            # Cron On vérifie si le log est sup à 5Mo si c’est le cas on l’efface
            */30 * * * * find /home/pi/ifstat/ -name « eth0.log » -size +100000 -exec rm -f eth0.log \;

            Pour cacti, en fait je souhaite mesurer le nombre de connexions E/S depuis le wan sur mon serveur debian et dans ce cas l’api de google ne peut rien pour moi.

            En tout cas je trouve le projet vraiment top !

  11. John

    Bonsoir Olivier,
    Je touche maintenant à ce graphique pour l’adapter a l’affichage de temperatures.
    Mon probleme se situe au niveau de la creation du graph: comment faire pour y integrer des valeurs negatives?

    Merci

    Répondre
    1. Olivier Auteur de l’article

      Hello,
      Pour afficher des valeurs négatives sur ce graphique il faudra recoder une bonne partie de la fonction (c’est une fonction faite maison spécifiquement pour afficher ce graph tel qu’il est).
      Le mieux je pense est d’utiliser la lib Google Chart comme dans l’article sur le suivi conso EDF ou alors l’article sur le module de fréquentation du blog 🙂

      Répondre
      1. john

        Et si je veux me compliquer la vie pour que ça soit beaucoup moins drôle? 🙂

        Je préfère ne pas utiliser de lib comme tu l’as fait mais effectivement il faut revoir toute la fonction de création de l’image alors.

        Je vais voir ça et si je m’en sors pas je prendrais une lib (enfin meme si avec une lib c’est pas dit que je m’en sorte!)

        Répondre
        1. Olivier Auteur de l’article

          Ahah bien dit 😉

          Si tu souhaite attaquer la fonction de création du graphique, voici quelques pistes sur son fonctionnement :

          En gros, la fonction ne fait que dessiner des traits sur l’image.
          En premier lieu, la fonction dessine les axes x et y avec les petit taquets sur les extrémités.
          Ensuite, la fonction trace une barre de 1px de large par valeur (la hauteur de la barre représentant la valeur).
          Donc si le graphique fait 500px de large, tu va pouvoir afficher 500 valeurs.
          Le truc un peu sioux, c’est l’ensemble des calculs réalisés pour tracer tout cela à l’échelle. En gros se sont une série de règle de 3 pour que la hauteur des barres correspondent à un pourcentage de la hauteur du graphique.

          J’espère que ça t’aidera 🙂 Et surtout, n’hésites pas à partager ton travail, ça peut intéresser du monde 😉

          Répondre
          1. John

            Alors en fait j’ai trouvé une astuce très simple pour ne pas se compliquer à refaire une fonction.

            Il suffit de:
            $height = 100; // hauteur du graphique à multiplier par 2 donc ça donne:
            $height = 200;

            Remplacer $max_value = $height – 2*$padding – 4;
            Par $max_value = $height/2 – 2*$padding – 4;

            Remplacer $xy1 = $height – $padding – 1;
            par $xy1 = $height/2 – $padding – 1;

            Le reste est de la modif de visibilité des choses et personnalisation des couleurs donc pas bien grave.

            Le résultat donne un graphique 2 fois plus haut mais qui permet de prendre en compte des valeurs négatives (le zéro se trouve décalé de la moitié de la hauteur)

            😉

  12. Ping : Jejeadsl (jcluzan) | Pearltrees

  13. Le_raspinaute_pas_débrouillard

    Bonsoir ! Je voulais savoir si il était possible d’installer ce module sans avoir de gateway et/ou routeur. Est-ce que ma Freebox pourrait transmettre les données directement au Pi ? Merci d’avance .

    Répondre
    1. Olivier Auteur de l’article

      Bonjour,
      Votre freebox est votre routeur et dispose donc de ces infos 🙂
      En revanche, Free ne vous laisse pas y accéder 🙁
      C’est exactement pour ça que j’ai monté ma propre gateway en laisse la freebox au poste de simple modem ADSL.
      Pour obtenir ce type de graph vous n’avez d’autre choix que de placer un équipement entre votre freebox et votre réseau local :/

      Répondre
  14. Valentin_le_bonobo

    Bonjour à tous,

    D’abord merci pour l’idée et le travail fourni dans ce projet je trouve ça génial !

    Ensuite j’ai eu une idée pour le graphique de bande passante mais je ne sais pas trop si c’est une bonne idée ou une bêtise …

    Etant donné que j’ai une freebox et que je ne veux pas installer de serveur derrière pour redistribuer la bande passante, je ne peux pas tester la bande passante directement dessus avec ifsat (sauf en utilisant une API free mais je voudrais faire au plus simple)

    Mon idée est la suivante, il est possible de tester la bande passante disponible facilement via un script (type : http://www.wikistuce.info/doku.php/javascript/script_de_test_de_la_bande_passante ) et un simple produit en croix. (500 ko DL en 3000ms signifie un débit de 166 ko/s par exemple )

    Une fois cette donnée récupérée, si je connais la valeur maxi de ma bande passante (1.2 Mo/sec chez moi) une simple soustraction pourrait me donner la valeur de la bande passante utilisée non ? Ou est-ce beaucoup trop approximatif ? (1200 – 166 = 1034 ko/s utilisés dans mon exemple) Ça permettrait à mon dashScreen d’être autonome et de se passer de l’API free ou de tout autre matériel que je pourrais être amené à remplacer …

    Qu’en pensez vous ? Je suis conscient que c’est très approximatif comme méthode mais après tout, on cherche simplement à avoir une idée de l’état de la bande passante et non pas la valeur précise au femtomètre …

    Répondre
    1. Olivier Auteur de l’article

      Hello,
      Alors, en fait, non ^^
      Pour deux raisons principales. La première c’est qu’en mesurant le delta entre votre bande passante max et la bande passante mesurée, vous n’avez aucune certitude sur le fait que ce delta vienne de chez vous.
      Le deux gros problème qui rend cette approche totalement caduque, c’est que pour mesurer votre bande passante par ce biais, vous allez consommer de la bande passante… En gros, vous saturez votre bande passante pour prendre la mesure, ce qui est totalement contre productif.

      Répondre
      1. Valentin_le_bonobo

        Très bien j’abandonne cette idée alors … Je vais essayer en utilisant l’API Freebox, je vous ferrais un retour si j’y parviens 🙂

        Merci de votre aide en tout cas !

        Répondre

Laisser un commentaire