Script
Objectif
L'objectif de ce script est de faciliter le monitoring des ressources système.
Il fonctionne en deux parties qui seront détaillées ci-après:
- Log des ressources dans un fichier
- Taux de fonction du processeur (quand il n'est pas idle)
- Taux d'utilisation de la mémoire
- Proportion du volume du disque utilisée
- Affichage web
Ces deux parties sont indépendantes, et seule la première est écrite en BASH.
Partie BASH
Commandes
Date
Afin de loguer les différentes informations, il est important d'avoir la date des mesures.
Puisqu'on aura besoin de comparer les dates pour l'affichage des graphiques, on choisit de les stocker sous forme de secondes écoulées depuis EPOCH.
Ainsi, la commande pour obtenir la date sous ce format est:
Processeur
Nous voulons obtenir le taux d'utilisation du processeur, soit la proportion du temps où il n'est pas en train d'attendre.
- L'occupation du processeur peut être obtenue avec
mpstat
.
- La mesure qui nous intéresse se situe en 12e position, nous la récupérons avec
awk
- Pour obtenir la partie entière, on utilise
cut
pour prendre les valeurs avant la virgule.
La ligne de commande qui en résulte est:
mpstat | awk '$12 ~ /[0-9.]+/ { print 100 - $12 }' | cut -d "," -f 1
Mémoire
Utilisant free
, on a dû faire un calcul pour obtenir le taux de mémoire utilisée en utilisant:
- La quantité totale de mémoire
free | awk 'NR==2{ print $2}'
- La quantité de mémoire utilisée
free | awk 'NR==2{ print $3}'
- Le calcul utilisée*100/totale
(memoryUsed*100/memoryTotal)
Disque
L'espace utilisé peut être trouvé en 5e position dans le résultat de la commande df -t ext4
:
df -t ext4 | awk 'NR==2{ print $5}' | grep -Eo '[0-9]{1,3}'
Log
On utilise les commandes précédemment définies pour générer un fichier CSV de 60 lignes:
script.sh |
---|
| #!/bin/bash
# Fichier contenant les releves
file="/var/www/html/projetlinux.com/script/fichier"
### Recueil et conversion en % des informations
# Date au format ssss
date=$(date +"%s")
# Processeur: 100 - taux de repos
processor=$(mpstat | awk '$12 ~ /[0-9.]+/ { print 100 - $12 }' | cut -d "," -f 1)
# Memoire disponible
memoryTotal=$(free | awk 'NR==2{ print $2}')
# Memoire utilisee
memoryUsed=$(free | awk 'NR==2{ print $3}')
# Memoire en %
memory=$((memoryUsed*100/memoryTotal))
# Disque: volume utilise
disk=$(df -t ext4 | awk 'NR==2{ print $5}' | grep -Eo '[0-9]{1,3}')
### Ecriture du fichier
# Ligne de log
echo "${date};${processor};${memory};${disk};" >> $file
# Troncature du fichier
echo "$(tail -n 60 $file)" > $file
|
Crontab
On veut faire tourner le script automatiquement chaque minute de façon à avoir 1h de logs.
Pour ce faire, nous ajoutons le script dans le crontab:
/etc/crontab/ |
---|
| # /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
# Example of job definition:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# | | | | |
# * * * * * user-name command to be executed
17 * * * * root cd / && run-parts --report /etc/cron.hourly
25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
* * * * * root /root/script.sh
|
La dernière ligne du fichier correspond au script. Les *
signifient que le script tourne a chaque minute, de chaque heure de chaque jour.
Partie web
Script
La partie web consiste en un script en Python qui est lancé par Apache.
Ce script lit le fichier CSV précédemment généré, place ses valeurs dans différents tableaux et les place dans des endroits spécifiques d'un template HTML.
Il retourne ensuite l'HTML qui est interprété par le navigateur web du client.
Le script est construit de la façon qui suit:
- Le fichier CSV est lu et placé dans un tableau.
- Les valeurs de chaque capteur sont recopiées dans un tableau associé (processeur, mémoire et disque) en sautant une case quand la différence de temps entre les mesures est supérieure à une minute
- Les graphiques sont injectés dans le template HTML grâce à la fonction
Draw_Graph
.
Voici le script en entier.
Il a été réalisé entièrement à la main, sans bibliothèques.
Attention aux yeux
Nous avons manqué de temps pour le développement.
Le script a été écrit dans la précipitation, et en partie copié sur le premier script de Tim (voir sources).
Nous vous prions de ne pas lire ce qui suit sans protection oculaire.
/var/www/html/projetlinux.com/script/index.py |
---|
| #!/usr/bin/python
import time
def Draw_Graph(values, type):
max_height = 100
color = ["black", "black"]
if type == 1:
color = ["lightblue", "blue"]
if type == 2:
color = ["pink", "purple"]
if type == 3:
color = ["lightgreen", "green"]
for x in range(len(values)):
value = values[x]
if value == no_data:
print('''<div class="no_data"></div>''')
if value == 0:
print('''<div class="bar" style="height: 0px; margin-top: ''' +
str(max_height) + '''px;"></div>''')
if value > 0:
height = (value/100) * max_height
margin = max_height - height
print('''<div class="bar" style="height:''' + str(height) + '''px; margin-top: ''' +
str(margin) + '''px; background: ''' + str(color[0]) + '''; border-color: ''' + str(color[1]) + '''"></div>''')
# Definitions
# No_data value
no_data = -1
# Arrays of values that will be displayed
processor = [no_data]*60
memory = [no_data]*60
disk = [no_data]*60
# Index of the measure inside the displayed arrays
index = 0
# Table that will have all the measures and timestamps
# Format timetamp;processor;memory;disk
# Timestamp is in seconds since Epoch, the rest in used %
measures = list()
# Total quantity of measures taken
measures_quantity = 0
# Copying measures to table
with open("fichier", 'r') as file:
for line in file:
content_txt = line.split(';')
content_int = [int(content_txt[0]), int(content_txt[1]),
int(content_txt[2]), int(content_txt[3])]
measures.append(content_int)
measures_quantity += 1
# "Deleting" measures that are more than an hour old
y = 0
while measures[y][0]<int(time.time())-60*60 and y < 58:
y += 1
# Assigning values to the display arrays
for x in range(y, measures_quantity-1):
# Adding "holes" if measures where skipped
if x > 0:
y = 0
while measures[x][0] > measures[x-1][0] + 65 + 60*y:
y += 1
index += 1
if index < 60:
processor[index] = measures[x][1]
memory[index] = measures[x][2]
disk[index] = measures[x][3]
index += 1
else:
break
print("Content-type: text/html\n\n")
print('''
<!DOCTYPE html>
<head>
<title>
Performances
</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div class="winwow">
<div class="window_header">
<button class="custom_button" onClick="window.location.reload(true)">Reload</button>
</div>
<div class="window_content">
<div class="metric">
Processor: ''' + str(processor[index-1]) + '''%
<div class="graph">
''')
Draw_Graph(processor, 1)
print('''</div>
</div>
<div class="metric">
Memory: ''' + str(memory[index-1]) + '''%
<div class="graph">
''')
Draw_Graph(memory, 2)
print('''</div>
</div>
<div class="metric">
Disk: ''' + str(disk[index-1]) + '''%
<div class="graph">
''')
Draw_Graph(disk, 3)
print('''</div>
</div>
</div>
</div>
</body>
''')
|
Configuration du système
Télécharger Python 3:
Ajouter Python dans PATH pour la session qui lance le script:
A la suite de .profile |
---|
| export PATH="$PATH:/usr/bin/python:/usr/bin/python3"
|
Configuration d'Apache
Pour qu'Apache exécute le script, il faut:
- Autoriser les scripts
- Ajouter un handler Python
- Charger le module CGI
Chercher et modifier la partie correspondante dans le fichier de configuration d'Apache
/etc/apache2/apache2.conf |
---|
| <Directory /var/www/>
Options Indexes FollowSymLinks ExecCGI
AddHandler cgi-script .cgi .py
LoadModule cgi_module /usr/lib/apache2/modules/mod_cgi.so
AllowOverride None
Require all granted
</Directory>
|
Sources