root/sys_alive.pl

Revision 10, 31.0 kB (checked in by twidi, 2 months ago)

ajout d alertes sur la ram utilisee

  • Property svn:executable set to
Line 
1 #!/usr/bin/perl
2 ###############################################################
3 #                  sys_alive.pl  v1.5.3                       #
4 ###############################################################
5 #    Programme de surveillance de serveur web sous Linux      #
6 #               par Twidi (scripts@twidi.com)                 #
7 ###############################################################
8 # Ce programme est libre, vous pouvez le redistribuer et/ou   #
9 # le modifier selon les termes de la Licence Publique         #
10 # Générale (GPL) GNU publiée par la Free Software Foundation. #
11 #                                                             #
12 # Ce programme est distribué car potentiellement utile, mais  #
13 # SANS AUCUNE GARANTIE, ni explicite ni implicite, y compris  #
14 # les garanties de commercialisation ou d'adaptation dans un  #
15 # but spécifique. Reportez-vous à la Licence Publique         #
16 # Générale (GPL) GNU pour plus de détails.                    #
17 #                                                             #
18 #         -> http://www.april.org/gnu/index.html <-           #
19 #                                                             #
20 ###############################################################
21 # DerniÚre version sur : http://scripts.twidi.com/            #
22 # Informations : http://b.twidi.com/index.php/tag/sys_alive   #
23 ###############################################################
24 # Contributeurs :                                             #
25 # Twidi (scripts@twidi.com) : Programme de base               #
26 # eB (fdl@ebusiness.be) : Base de la v 1.2.4                  #
27 # Et vous ?                                                   #
28 ###############################################################
29 # Historique :                                                #
30 # v 1.5.3: 2008-09-23 : ajout d'alertes sur la ram utilisee   #
31 # v 1.5.2: 2007-11-26 : meilleure gestion du brute stop       #
32 #                       et on ne kill pas sys_alive !!        #
33 # v 1.5.1: 2007-11-21 : mode "demon" utilisable en tant que   #
34 #                       script de démarrage (/etc/init.d)     #
35 # v 1.5  : 2007-11-19 : mode "demon", tentatives supll.       #
36 #                       d'arrets de demons                    #
37 # v 1.2.8: 2007-05-07 : Séparation rép conf, data & log       #
38 #                       + affichage "ps faux" au lieu de top  #
39 #                       par défaut (modifiable en conf)       #
40 # v 1.2.7: 2006-08-22 : Correction gestion mémoire pour       #
41 #                       compatibilité noyaux 2.4 et 2.6       #
42 # v 1.2.6: 2005-03-13 : Ajoute de la possibilité d'ignorer    #
43 #                       temporairement un démon en créant     #
44 #                       (par exemple via touch) un fichier    #
45 #                       ignore_nomdudemon dans le répertoire  #
46 #                       du fichier de configuration           #
47 # v 1.2.5: 2003-12-16 : Ajout du test de la variable d'env.   #
48 #                       "TERM", et présence des secondes dans #
49 #                       le top, et use strict (pas de -w a    #
50 #                       cause de warnings type $main::)       #
51 #                       + diverses petites modifications      #
52 # v 1.2.4: 2002-11-18 : Ajout de l'activité apache et mysql,  #
53 #                       + choix du fichier log + possibilité  #
54 #                       d'interdire de tuer les process root  #
55 # v 1.2.3: 2002-02-17 : Ajout du test sur le user des demons  #
56 # v 1.2.2: 2002-02-07 : Correction bug sur l'envoi du mail    #
57 # v 1.2.1: 2002-02-01 : Modification de la façon d'écrire     #
58 #                       dans le fichier de données, et mise   #
59 #                       en log du résultats des appels        #
60 #                       systÚme (arrêts, relances...)         #
61 # v 1.2  : 2002-01-30 : Externalisation des informations de   #
62 #                       configuration (sys_alive.conf) +      #
63 #                       fichier de log + corrections mineures #
64 # v 1.1  : 2002-01-25 : ParamÚtres stop et start + 2eme       #
65 #                       niveau d'alerte avec arrêt de démons  #
66 # v 1.0.1: 2002-01-22 : License GPL                           #
67 # v 1.0  : 2002-01-16 : PremiÚre version                      #
68 ###############################################################
69
70 ###############################################################
71 #    CE PROGRAMME DOIT ETRE INSTALLE ET EXECUTE EN ROOT       #
72 #             et doit être exécutable (chmod 755)             #
73 #-------------------------------------------------------------#
74 # Installation :                                              #
75 # 1) copier sys_alive.pl et sys_alive.conf dans un répertoire #
76 # 2) adapter la configuration dans le fichier sys_alive.conf  #
77 # 3) mettre la configuration en chmod 600                     #
78 # 4) mettre le script en cron(4.1) ou le lancer en demon(4.2) #
79 # 4.1) mettre le script en cron (en root) toutes les minutes: #
80 #    Mettre en conf mode_demon.actif à 0                      #
81 #    Lancer, en root : crontab -e                             #
82 #    Et ajouter : * * * * * /chemin/de/sys_alive/sys_alive.pl #
83 # 4.2) lancer le script en demon                              #
84 #    Mettre en conf mode_demon.actif à 1                      #
85 #    Le lancer : /chemin/de/sys_alive/sys_alive.pl start      #
86 #    Le lier par exemple vers /etc/init.d/sys_alive et mettre #
87 #    à jour les scripts de démarrage pour un lancement        #
88 #    automatique (en fonction de votre distribution)          #
89 ###############################################################
90
91 use strict;
92
93 use Proc::Daemon;
94 use File::Pid;
95
96 #------------------------------------------------------------------------------#
97 # répertoire des données : remplacer *éventuellement* GetLocalRep() par
98 # le répertoires où est stocké le fichier de configuration, uniquement s'il ne
99 # doit pas être stocké dans le même répertoire que ce programme ou si sys_alive
100 # est configuré pour tourner en mode démon
101
102 my $rep_conf = GetLocalRep();
103 #------------------------------------------------------------------------------#
104
105 #------------------------------------------------------------------------------#
106 ####  CORPS DU PROGRAMME  ####
107 #------------------------------------------------------------------------------#
108 # fichier de configuration
109 die 'Fichier conf non trouvé' if ! -e $rep_conf.'/sys_alive.conf';
110 require($rep_conf.'/sys_alive.conf');
111
112 # autres répertoires
113 $main::rep_data = $rep_conf if !$main::rep_data;
114 $main::rep_log  = $rep_conf if !$main::rep_log;
115
116 # variables globales
117 my $version = '1.5.3';
118 my $arg = lc(shift(@ARGV));
119 if (!$main::logfile) { $main::logfile = $main::rep_log.'/sys_alive.log'; }
120 my $datafile = $main::rep_data.'/sys_alive.dat';
121 my %infos = LireFichier();
122 my %ignore;
123 my %pid = (
124         obj   => undef,
125         file  => $main::mode_demon{'pid_file'} || '/var/run/sys_alive.pid',
126         value => 0,
127 );
128
129 my $demon_running = demon_running();
130 my $mode_demon_actif = $main::mode_demon{'actif'} || $demon_running;
131
132 my $term = $ENV{'TERM'} ? '' : 'TERM=vt100; export TERM;'; # on simule un terminal si la variable d'environnement n'est pas définie
133
134 # on arrête ou on relance sys_alive si demandé
135 if ($arg eq 'stop') {
136         SetInfo('stopped', 1);
137         if ($mode_demon_actif) {
138                 $pid{'obj'} = File::Pid->new({
139                         file => $pid{'file'},
140                         pid  => $demon_running,
141                 });
142                 $pid{'value'} = $demon_running;
143         } else {
144                 WriteLog('Désactivation de sys_alive');
145         }
146 } elsif ($arg eq 'start') {
147         SetInfo('stopped', 0);
148         WriteLog('Réactivation de sys_alive') if !$mode_demon_actif;
149 } elsif ($mode_demon_actif) {
150         WriteLog('Usage en mode demon : /chemin/de/sys_alive/sys_alive.pl start|stop', 1);
151 }
152
153 exit if $infos{'stopped'};
154
155 if ($mode_demon_actif) {
156         mode_demon();
157 } else {
158         sys_alive();
159 }
160
161 # mode demon
162 sub mode_demon {
163         WriteLog('Erreur : Sys_alive est déjà lancé en mode démon (pid='.$demon_running.')', 1) if $main::mode_demon{'actif'} and $demon_running;
164
165         Proc::Daemon::Init;
166         $pid{'obj'} = File::Pid->new({
167                 file => $pid{'file'},
168                 pid  => $$,
169         });
170
171         if ($pid{'value'} = $pid{'obj'}->write()) {
172                 WriteLog('Sys_alive lancé en mode démon (pid='.$pid{'value'}.')');
173         } else {
174                 WriteLog('Erreur : ProblÚme en écrivant le fichier pid : '.$@, 1) if $@;
175         }
176
177         while(1) {
178                 %infos = LireFichier();
179                 last if $infos{'stopped'};
180                 sys_alive();
181                 sleep($main::mode_demon{'wait'} || 60);
182         }
183 } # fin de sub mode_demon
184
185
186 # fonction principale
187 sub sys_alive {
188
189         # variables locales
190         my @alertes;
191         my $alertes_niveau2 = 0;
192         my $alerte_importante = 0;
193         my %data;
194         my @killed_process;
195         my @restarted_demons;
196         my %process;
197
198         # on ne vas gérer le tout que si sys_alive n'est pas stoppé
199         if (!$infos{'stopped'}) {
200                 # récupération des données
201                 my %datetime = GetTime();
202                 ($data{'ram_physique'}, $data{'ram_reelle'}, $data{'ram_swap'}) = GetInfosRam();
203                 ($data{'cpu_1'}, $data{'cpu_5'}, $data{'cpu_15'}, $data{'nb_process'}) = GetInfosCPU();
204                 my $top = `$term top b n 1`; # récupération des process
205                 my $free = `free -t`;
206
207                 ###### gestion des alertes
208                 if ($main::gestion{'seuil_alerte'}) {
209
210                         # gestion de l'alerte swap
211                         if ($main::seuil_alertes{'swap'}) {
212                                 if ($data{'ram_swap'} > $main::seuil_alertes{'swap'}) { # en cas de dépassement
213                                         push @alertes, 'swap';
214                                         WriteLog("Seuil 1 du swap dépassé : $data{'ram_swap'} > $main::seuil_alertes{'swap'}");
215                                 } # fin de if data > seuil
216                         } # fin de if swap
217
218                         # gestion de l'alerte ram_used
219                         if ($main::seuil_alertes{'ram_used'}) {
220                                 if ($data{'ram_reelle'} > $main::seuil_alertes{'ram_used'}) { # en cas de dépassement
221                                         push @alertes, 'ram_used';
222                                         WriteLog("Seuil 1 de la ram réelle dépassé : $data{'ram_reelle'} > $main::seuil_alertes{'ram_used'}");
223                                 } # fin de if data > seuil
224                         } # fin de if ram_used
225
226                         # gestion de l'alerte load_average
227                         if ($main::seuil_alertes{'load_average'}) {
228                                 if ($data{'cpu_1'} > $main::seuil_alertes{'load_average'}) { # en cas de dépassement
229                                         push @alertes, 'load_average';
230                                         WriteLog("Seuil 1 du load average dépassé : $data{'cpu_1'} > $main::seuil_alertes{'load_average'}");
231                                 } # fin de if data > seuil
232                         } # fin de if load_average
233
234                         # gestion de l'alerte nb_process
235                         if ($main::seuil_alertes{'nb_process'}) {
236                                 if ($data{'nb_process'} > $main::seuil_alertes{'nb_process'}) { # en cas de dépassement
237                                         push @alertes, 'nb_process';
238                                         WriteLog("Seuil 1 du nb de process dépassé : $data{'nb_process'} > $main::seuil_alertes{'nb_process'}");
239                                 } # fin de if data > seuil
240                         } # fin de if nb_process
241
242                 } # fin de if gestion seuil_alerte
243
244                 #### si on a enregistré des alertes, avant les kills éventuels on va récupérer certaines valeurs du systÚme
245                 my ($mysql_activity_msg, $apache_activity_msg);
246                 if (@alertes+0) {
247                         if ($main::mysql_activity) {    $mysql_activity_msg = Execute($main::mysql_activity, 1); }
248                         if ($main::apache_activity) {   $apache_activity_msg = Execute($main::apache_activity, 1); }
249                 } # fin de if alertes
250
251
252                 ###### gestion des alertes de niveau 2
253                 if ($main::gestion{'stop_alerte'}) {
254
255                         # gestion de l'alerte swap
256                         if ($main::seuil_alertes_niveau2{'swap'}) {
257                                 if ($data{'ram_swap'} > $main::seuil_alertes_niveau2{'swap'}) { # en cas de dépassement
258                                         if (!$alertes_niveau2) { unshift @alertes, '--ALERTE--'; }
259                                         $alertes_niveau2++;
260                                         $alerte_importante = 1;
261                                         WriteLog("Seuil 2 du swap dépassé : $data{'ram_swap'} > $main::seuil_alertes_niveau2{'swap'}");
262                                 } # fin de if data > seuil
263                         } # fin de if swap
264
265                         # gestion de l'alerte ram_used
266                         if ($main::seuil_alertes_niveau2{'ram_used'}) {
267                                 if ($data{'ram_reelle'} > $main::seuil_alertes_niveau2{'ram_used'}) { # en cas de dépassement
268                                         if (!$alertes_niveau2) { unshift @alertes, '--ALERTE--'; }
269                                         $alertes_niveau2++;
270                                         $alerte_importante = 1;
271                                         WriteLog("Seuil 2 de la ram reelle dépassé : $data{'ram_reelle'} > $main::seuil_alertes_niveau2{'ram_used'}");
272                                 } # fin de if data > seuil
273                         } # fin de if ram_used
274
275                         # gestion de l'alerte load_average
276                         if ($main::seuil_alertes_niveau2{'load_average'}) {
277                                 if ($data{'cpu_1'} > $main::seuil_alertes_niveau2{'load_average'}) { # en cas de dépassement
278                                         if (!$alertes_niveau2) { unshift @alertes, '--ALERTE--'; }
279                                         $alertes_niveau2++;
280                                         $alerte_importante = 1;
281                                         WriteLog("Seuil 2 du load average dépassé : $data{'cpu_1'} > $main::seuil_alertes_niveau2{'load_average'}");
282                                 } # fin de if data > seuil
283                         } # fin de if load_average
284
285                         # gestion de l'alerte nb_process
286                         if ($main::seuil_alertes_niveau2{'nb_process'}) {
287                                 if ($data{'nb_process'} > $main::seuil_alertes_niveau2{'nb_process'}) { # en cas de dépassement
288                                         if (!$alertes_niveau2) { unshift @alertes, '--ALERTE--'; }
289                                         $alertes_niveau2++;
290                                         $alerte_importante = 1;
291                                         WriteLog("Seuil 2 du nb de process dépassé : $data{'nb_process'} > $main::seuil_alertes_niveau2{'nb_process'}");
292                                 } # fin de if data > seuil
293                         } # fin de if nb_process
294
295                         # si on est en alerte niveau 2, on va stopper les démons à stopper
296                         if ($alertes_niveau2) {
297                                 foreach my $demon (keys(%main::demons_to_stop)) { # pour chaque demon
298                                 if (!IgnoreDemon($demon)) { # si on ne doit pas l'ignorer
299                                         my $canstop = ($top =~ /\s$demon\s*$/m); # on arrete le demon s'il est lancé
300                                         SetInfo('skip_demon_'.$demon, time(), 1); # on met le demon dans la liste des démons à ne pas relancer
301                                         if ($canstop) {
302                                                 WriteLog("Alerte de niveau 2 : arrêt de $demon pour $main::demons_to_stop{$demon} secondes");
303                                                 Execute($main::demons_stop{$demon});
304                                                 # essais supplémentaires si encore des traces
305                                                 if (my $max_brute = $main::demons_brute_stop{$demon}) {
306                                                         my $essai = 1;
307                                                         while ((my $top2 = `$term top b n 1`) =~ /\s$demon\s*$/m) {
308                                                                 WriteLog("Trop d'essai pour forcer l'arrêt de $demon qui semble tourner encore"), last if $essai > $max_brute;
309                                                                 my @pids; map { push @pids, $1 if /^\s*(\d+).+\s$demon\s*$/} split(/\n/, $top2);
310                                                                 if (@pids+0) {
311                                                                         WriteLog("Suite alerte de niveau 2 : force arrêt de $demon, essai $essai (kill @pids)");
312                                                                         Execute('kill -9 '.join(' ', @pids));
313                                                                 }
314                                                                 $essai++;
315                                                         } # fin de while
316                                                 } # fin de if max brute
317                                         } else {
318                                                 WriteLog("Alerte de niveau 2 : impossible de stopper $demon car il n'est pas lancé");
319                                         }
320                                 } # fin de if !ignore
321                                 } # fin de foreach
322                         } # fin de if
323
324                 } # fin de if gestion stop_alerte
325
326                 ###### gestion des process trop longs
327                 if ($main::gestion{'kill_process'} or $main::gestion{'reload_demons'}) {
328
329                         # préparation du top à être interprété
330                         my @top = split(/\n/, $top);
331                         splice(@top, 0, 7);
332                         chomp(@top);
333                         # travail sur chaque ligne
334                         foreach my $ligne (@top) {
335                                 if ($ligne =~ /(\d+)\s*(\w*)\s*.*?((\d*):(\d*\.?\d*)) (.*?)\s*$/) {
336                                         my %info_process = (
337                                                 pid => $1,
338                                                 user => $2,
339                                                 duree => $3,
340                                                 minutes => $4,
341                                                 secondes => $5,
342                                                 process => $6,
343                                         );
344                                         # recherche des demons à relancés
345                                         if ($main::gestion{'reload_demons'}) {
346                                                 # on enregistre le fait que ce process est lancé
347                                                 $process{$info_process{'process'}}->{'present'} = 1;
348                                                 # et l'utilisateur concerné
349                                                 $process{$info_process{'process'}}->{$info_process{'user'}} = 1;
350                                         } # fin de gestion reload demons
351
352                                         # recherche des process à killer
353                                         if ($main::gestion{'kill_process'}) {
354                                                 $info_process{'nb_sec'} = $info_process{'minutes'} * 60 + $info_process{'secondes'}; # calcul du nb de secondes
355                                                 # en cas de process trop long
356                                                 if ($info_process{'nb_sec'} > $main::delai_max_process) {
357                                                         my $to_del = 0;
358                                                         # on regarde s'il est à tuer
359                                                         foreach my $to_kill (@main::process_to_kill) { if ($info_process{'process'} =~ /$to_kill/) { $to_del = 1; } }
360                                                         # on regarde s'il est à garder
361                                                         foreach my $to_keep (@main::process_to_keep) { if ($info_process{'process'} =~ /$to_keep/) { $to_del = 0; } }
362                                                         # on ne tue le process root que si autorisé
363                                                         if (($info_process{'user'} eq 'root') and (!$main::kill_root_process)) {        $to_del = 0; }
364                                                         # on tue le process...
365                                                         if ($to_del) { # s'il est à tuer
366                                                                 push @killed_process, \%info_process; # on sauvegarde l'info
367                                                                 $alerte_importante = 1; # pour forcer l'envoie de mail quelque soit le délai entre les mails
368                                                                 WriteLog("Process $info_process{'process'} tué car trop long (durée=$info_process{'duree'}, pid=$info_process{'pid'}, user=$info_process{'user'})");
369                                                                 Execute("kill -9 $info_process{'pid'}"); # on kill le process
370                                                         } # fin de if to_del
371                                                 } # fin de if info_process > alerte
372                                         } # fin de if kill_process
373                                 } # fin de if ligne =~
374                         } # fin de foreach
375                         if (@killed_process+0 > 0) { push @alertes, 'kill'; }
376                 } # fin de if gesion kill_process or gestion reload_demons
377
378                 ###### gestion des demons
379                 if ($main::gestion{'reload_demons'}) {
380                         # on va gerer chaque demon
381                         foreach my $demon (keys(%main::demons_start)) { if (defined($demon)) {
382                                 if (!IgnoreDemon($demon)) { # si on ne doit pas l'ignorer
383                                         # check du demon
384                                         my $present = ($process{$demon}->{'present'} and (defined($main::demons_user{$demon}) ? $process{$demon}->{$main::demons_user{$demon}} : 1));
385                                         # si le demon n'est pas présent et qu'il n'est pas à l'état "skip"
386                                         if (!$present and ($infos{'skip_demon_'.$demon} + $main::demons_to_stop{$demon} < time())) {
387                                                 push @restarted_demons, $demon; # sauvegarde de l'information
388                                                 $alerte_importante = 1; # pour forcer l'envoie de mail quelque soit le délai entre les mails
389                                                 if ($infos{'skip_demon_'.$demon}) {
390                                                         WriteLog("Démon $demon relancé, durée de $main::demons_to_stop{$demon} secondes écoulée");
391                                                 } else {
392                                                         WriteLog("Démon $demon relancé car absent");
393                                                 }
394                                                 SetInfo('skip_demon_'.$demon, 0); # on annule l'état "skip" s'il y etait
395                                                 Execute($main::demons_start{$demon}); # on relance le demon
396                                         } #fin de if
397                                 } # fin de if !ignore
398                         }} # fin de foreach demon if defined
399                         if (@restarted_demons+0 > 0) { push @alertes, 'demon'; }
400                 } # fin de if gesion reload_demons
401
402                 ###### envoi du mail (si alerte importante ou ecart entre 2 mails respecté)
403                 if (!$alerte_importante and ((@alertes+0 > 0) and ($datetime{'nb_sec'} - $infos{'date_msg'} < $main::ecart_alerte))) {
404                         WriteLog(" -> Aucun mail envoyé car le dernier date de moins de $main::ecart_alerte secondes");
405                 }
406                 if ($alerte_importante or ((@alertes+0 > 0) and ($datetime{'nb_sec'} - $infos{'date_msg'} >= $main::ecart_alerte))) {
407                         # alerte de niveau 2
408                         my ($alerte2, $alerte2sms);
409                         if ($alertes_niveau2) {
410                                 $alerte2 = "\nIMPORTANT : Une alerte de niveau 2 a été détectée. Les démons suivants ont été arrétés :\n";
411                                 $alerte2sms = "Démons tués:";
412                                 foreach my $demon (keys(%main::demons_to_stop)) { # pour chaque demon
413                                         if (!IgnoreDemon($demon)) { # si on ne doit pas l'ignorer
414                                                 $alerte2 .= $demon.' ('.$main::demons_to_stop{$demon}.' secondes.) - ';
415                                                 $alerte2sms .= "$demon,";
416                                         } # fin de if !ignore
417                                 } # fin de foreach
418                                 $alerte2 .= "\n";
419                         }
420                         # composition du message
421                         my $proc_activity_msg = $main::proc_activity ? Execute($main::proc_activity, 1) : $top;
422                         my $msg_mail = <<"ENDMAIL";
423
424 Alerte du $datetime{'date'} à $datetime{'hour'}h$datetime{'min'}
425 $alerte2
426 Données :
427 ---------
428 Mem. physique : $data{'ram_physique'}
429 Mem. réelle   : $data{'ram_reelle'}
430 Mem. Swap     : $data{'ram_swap'}
431
432 Load average : $data{'cpu_1'} / $data{'cpu_5'} / $data{'cpu_15'}
433 Nb process   : $data{'nb_process'}
434
435 Informations RAM  :
436 -------------------
437 $free
438
439 Informations CPU :
440 ------------------
441 $proc_activity_msg
442 ENDMAIL
443
444                 my $msg_sms = <<"ENDSMS";
445
446 $datetime{'date'} $datetime{'hour'}h$datetime{'min'}
447
448 Ram : $data{'ram_physique'}/$data{'ram_reelle'}/$data{'ram_swap'}
449
450 Load : $data{'cpu_1'}/$data{'cpu_5'}/$data{'cpu_15'}
451
452 Proc : $data{'nb_process'}
453 ENDSMS
454
455                         # ajout des infos sur les process tués
456                         if (@killed_process+0 > 0) {
457                                 $msg_mail .= "\nListe des process tués :\n------------------------\n";
458                                 my $nb_process_killed = @killed_process+0;
459                                 $msg_sms .= "\nKilled: ";
460                                 foreach my $process (@killed_process) { # pour chaque process
461                                         $msg_mail .= " - Process : $process->{'process'}, User : $process->{'user'}, PID : $process->{'pid'}, Durée : $process->{'minutes'}:$process->{'secondes'}\n";
462                                         $msg_sms .= "$process->{'process'}($process->{'user'}),";
463                                 } # fin de foreach process
464                         } # fin de if @killed_process
465
466                         # ajout des infos sur les démons relancés
467                         if (@restarted_demons+0 > 0) {
468                                 $msg_mail .= "\nListe des démons relancés :\n-----------------------------\n";
469                                 $msg_sms .= "\nDemons: ";
470                                 foreach my $demon (@restarted_demons) { # pour chaque démon
471                                         $msg_mail .= " - $demon\n";
472                                         $msg_sms .= "$demon,";
473                                 } # fin de foreach demon
474                                 $msg_sms = substr($msg_sms, 0, length($msg_sms)-1);
475                         } # fin de if @restarted_demons
476
477                         # ajout de l'alerte 2 pour les sms
478                         $msg_sms .= "\n".$alerte2sms;
479
480                         # 20 derniÚres lignes de log
481                         if ($main::joint_log) {
482                                 sleep(10);
483                                 my $tail_log = qx(tail -n20 $main::logfile);
484                                 $msg_mail .= "\nLog :\n-----\n".$tail_log;
485                         }
486
487
488                         if ($mysql_activity_msg) {
489                                 $msg_mail .= <<"ENDMAIL";
490
491
492 Informations MySQL :
493 --------------------
494 $mysql_activity_msg
495 ENDMAIL
496                         }
497
498                         if ($apache_activity_msg) {
499                                 $msg_mail .= <<"ENDMAIL";
500
501
502 Informations Apache :
503 ---------------------
504 $apache_activity_msg
505 ENDMAIL
506                         }
507
508                         $msg_mail .= <<"ENDFINMAIL";
509
510 --
511 Mail envoyé par sys_alive.pl, programme de surveillance serveur v$version
512 http://scripts.twidi.com/ ou http://b.twidi.com/index.php/tag/sys_alive
513 ENDFINMAIL
514
515                         # composition du sujet
516                         my $sujet = 'Alerte';
517                         foreach (@alertes) { $sujet .= ' '.$_; };
518
519                         # envoi du mail
520                         my %mail = (
521                                 sujet => $sujet,
522                                 msg => $msg_mail,
523                         );
524                         foreach (@main::mails) {
525                                 $mail{'to'} = $_;
526                                 SendMail(%mail);
527                                 WriteLog("Envoi d'un mail à $mail{'to'}");
528                         }
529
530                         # envoi du sms
531                         my %sms = (
532                                 sujet => $sujet,
533                                 msg => $msg_sms,
534                         );
535                         foreach (@main::mails_sms) {
536                                 $sms{'to'} = $_;
537                                 SendMail(%sms);
538                                 WriteLog("Envoi d'un mail format sms à $sms{'to'}");
539                         }
540
541                         # enregistrement de la date de dernier envoie de mail
542                         SetInfo('date_msg', time(), 1);
543
544                 } # fin de if ... (envoi mail)
545
546         } # fin de if (!$infos{'stopped'}) {
547
548 } # fin de sub sys_alive
549
550 #------------------------------------------------------------------------------#
551 ####  FONCTIONS  ###
552 #------------------------------------------------------------------------------#
553
554 #------------------------------------------------------------------------------#
555 # GetTime : RécupÚre la date et l'heure et renvoie un hash avec les éléments
556 #------------------------------------------------------------------------------#
557 sub GetTime {
558         my($time) = @_;
559         if (!$time) { $time = time; }
560
561         my(%dt);
562         $dt{'nb_sec'} = $time;
563
564         ($dt{'dayinyear'}, $dt{'year'}, $dt{'month'}, $dt{'day'}, $dt{'hour'}, $dt{'min'}, $dt{'sec'}) = (localtime($time))[7,5,4,3,2,1,0];
565
566         $dt{'month'}++;
567         $dt{'year'} += 1900;
568         if ($dt{'month'} > 12) { $dt{'month'} = 0; }
569
570         foreach (qw(sec min hour day month)) { $dt{$_} = sprintf("%02d", $dt{$_}); }
571
572         $dt{'date'} = sprintf("%04d-%02d-%02d",$dt{'year'},$dt{'month'},$dt{'day'});
573         $dt{'time'} = sprintf("%02d:%02d:%02d",$dt{'hour'},$dt{'min'},$dt{'sec'});
574
575         return %dt;
576 }
577 #------------------------------------------------------------------------------#
578
579 #------------------------------------------------------------------------------#
580 # GetInfosRam : Renvoie la ram physique, la ram reellement prise et le swap
581 #------------------------------------------------------------------------------#
582 sub GetInfosRam {
583         my %infos;
584         open (F,"/proc/meminfo");
585         while (<F>) {
586                 $infos{$1} = $2 if /^(\w+):\s*(\d+) kB$/;
587         }
588         close(F);
589
590         my $ram_physique = $infos{'MemTotal'} - $infos{'MemFree'};
591         my $ram_reelle = $ram_physique - $infos{'Buffers'} - $infos{'Cached'};
592         my $ram_swap = $infos{'SwapTotal'} - $infos{'SwapFree'};
593
594         return ($ram_physique, $ram_reelle, $ram_swap);
595 }
596 #------------------------------------------------------------------------------#
597
598 #------------------------------------------------------------------------------#
599 # GetInfosCPU : Renvoie le load average sur 1 mn, 5 mn et 15 mn, et  le nb de process en cours
600 #------------------------------------------------------------------------------#
601 sub GetInfosCPU {
602         open (F,"/proc/loadavg"); my $loadavg=<F>; close(F);
603         my ($cpu_1, $cpu_5, $cpu_15, $temp1, $temp2) = split(/\s+/, $loadavg);
604         my ($temp3, $nb_process) = split(/\//, $temp1);
605
606         return ($cpu_1, $cpu_5, $cpu_15, $nb_process);
607 }
608 #------------------------------------------------------------------------------#
609
610 #------------------------------------------------------------------------------#
611 # LireFichier => Lit le fichier de données
612 #------------------------------------------------------------------------------#
613 sub LireFichier {
614         my($key, $val, %infos);
615         open(FILE, "<".$datafile);   # Ouverture du fichier
616         my @tab = <FILE>;            # Lecture
617         close(FILE);                 # Fermeture
618
619         foreach  (@tab) {                      # Pour chaque ligne (donc, pour chaque paire)
620                 chop;                              # Retirer le caractÚre de fin de ligne
621                 ($key, $val) = split(/=/, $_, 2);
622                 $infos{$key} = $val;               # Et faire la séparation
623         }
624
625         return %infos
626 }
627 #------------------------------------------------------------------------------#
628
629 #------------------------------------------------------------------------------#
630 # EcrireFichier => Ecrit le fichier de données
631 #------------------------------------------------------------------------------#
632 sub EcrireFichier {
633         my(%infos) = @_;
634
635         LockFichier($datafile, 1);        # On interdit le ficher en écriture (pour sys_alive)
636         open(FILE, ">".$datafile);        # Ouverture du fichier
637         foreach (keys(%infos)) {          # Pour chaque paire
638                 print FILE "$_=$infos{$_}\n"; # l'écrire avec un \n
639         }
640         close(FILE);                      # Fermeture
641         LockFichier($datafile, 0);        # On autorise de nouveau l'écriture
642 }
643 #------------------------------------------------------------------------------#
644
645 #------------------------------------------------------------------------------#
646 # SendMail => Envoie un mail
647 #------------------------------------------------------------------------------#
648 sub SendMail {
649         my(%mail) = @_;
650         open(MAIL,"|$main::sendmail $mail{'to'}");
651         print MAIL "To: $mail{'to'}\n";
652         print MAIL "From: $main::from\n";
653         print MAIL "Subject: $mail{'sujet'}\n";
654         print MAIL "$mail{'msg'}\n";
655         close (MAIL);
656 }
657 #------------------------------------------------------------------------------#
658
659 #------------------------------------------------------------------------------#
660 # WriteLog => Ajoute une ligne dans le fichier de log
661 #------------------------------------------------------------------------------#
662 sub WriteLog {
663         my ($texte, $die) = @_;
664         print $texte."\n" if $die;
665         LockFichier($main::logfile, 1);
666         my %d = GetTime();
667         my $ligne = $d{'date'}.' '.$d{'time'}.' > '.$texte."\n";
668         open(LOG, '>>'.$main::logfile);
669         print LOG $ligne;
670         close(LOG);
671         LockFichier($main::logfile, 0);
672         exit 1 if $die;
673         return 1;
674 }
675 #------------------------------------------------------------------------------#
676
677 #------------------------------------------------------------------------------#
678 # GetLocalRep => Récupération du répertoire de données
679 #------------------------------------------------------------------------------#
680 sub GetLocalRep {
681         use FindBin qw($Bin);
682         return $Bin;
683 }
684 #------------------------------------------------------------------------------#
685
686 #------------------------------------------------------------------------------#
687 # SetInfo => Met l'information indiquée dans le fichier de données
688 # on met $time à 1 si $valeur est une durée en secondes et que l'on ne veut
689 # mettre à jour l'info que si $valeur est supérieur à celle déjà dans le fichier
690 # de données
691 #------------------------------------------------------------------------------#
692 sub SetInfo {
693         my ($nom, $valeur, $time) = @_;
694         %infos = LireFichier();
695         if (!$time or ($valeur > $infos{$nom})) { $infos{$nom} = $valeur; }
696         EcrireFichier(%infos);
697 }
698 #------------------------------------------------------------------------------#
699
700 #------------------------------------------------------------------------------#
701 # Execute => Lance un process et écrit le résultat en log
702 #------------------------------------------------------------------------------#
703 sub Execute {
704         my($cmd, $no_log) = @_;
705         my $result;
706         if ($no_log) {
707                 $result = `$term $cmd`;
708         } else {
709                 LockFichier($main::logfile, 1);
710                 my $resultat = system($term.' '.$cmd.' >>'.$main::logfile);
711                 LockFichier($main::logfile, 0);
712                 $result = '';
713         }
714         return $result;
715 }
716 #------------------------------------------------------------------------------#
717
718 #------------------------------------------------------------------------------#
719 # IgnoreDemon => Indique si on doit ignorer un démon
720 #------------------------------------------------------------------------------#
721 sub IgnoreDemon {
722         my ($demon) = @_;
723         if (!exists($ignore{$demon})) {
724                 $ignore{$demon} = (-e $rep_conf.'/ignore_'.$demon) ? 1 : 0;
725                 WriteLog('Démon '.$demon.' ignoré') if $ignore{$demon};
726         }
727         return $ignore{$demon};
728 }
729 #------------------------------------------------------------------------------#
730
731
732 # =================================================================
733 # LockFichier => Verrou de fichier
734 #
735 #- fichier => nom du fichier à locker
736 #- lock    => à 1 si on lock, à 0 pour libérer
737 #-
738 #- Le systÚme consiste à créer un fichier temporaire, correspondant au fichier
739 #- passé en paramÚtre auquel on ajoute ".lock"
740 #- Si ce fichier existe, c'est que le fichier est locké, sinon, il est libre
741 #- Et si le fichier est locké, on attend sa libération
742 # =================================================================
743 sub LockFichier {
744         # Récupération des paramÚtres
745         my($Fichier, $Lock) = @_;
746
747         # Création du nom du fichier temporaire.
748         my($FichierLock) = $Fichier;
749         $FichierLock .= ".lock";
750
751         # En cas de vérouillage
752         if ($Lock==1) {
753
754                 my($time);
755                 # Si ce fichier de lock existe, on lit l'heure enregistrée
756                 if (-e $FichierLock) {
757                         open(LOCKFILE, "<".$FichierLock);
758                         $time = <LOCKFILE>;
759                         close(LOCKFILE);
760                 }
761
762                 # Tant que le fichier lock existe,
763                 while (-e $FichierLock) {
764                         # Soit le temps maximum est atteint et le fichier est libéré
765                         if (time > ($time+30)) { LockFichier($Fichier, 0); }
766                         # Soit on attend un dixiÚme de seconde avant de re-tester
767                         select(undef, undef, undef, 0.1);
768                 }
769
770                 # DÚs qu'il n'existe plus, on le crée
771                 open(LOCKFILE, ">".$FichierLock);
772                 print LOCKFILE time;
773                 close(LOCKFILE);
774
775
776         # Et en cas de dévérouillage
777         } else {
778
779                 # Quand on a fini avec le fichier, on le dévérouille, en supprimant le fichier lock
780                 unlink($FichierLock);
781         }
782 }
783 # =================================================================
784
785 # test si un demon sys_alive tourne deja
786 sub demon_running {
787         $pid{'obj'} = File::Pid->new({
788                 file => $pid{'file'},
789                 pid  => $$,
790         });
791
792         my $current_pid;
793         if (-e $pid{'file'}) {
794                 eval { $current_pid = $pid{'obj'}->running(); };
795                 WriteLog('Erreur : ProblÚme en accédant au fichier pid : '.$@, 1) if $main::mode_demon{'actif'} and $@;
796         }
797
798         return $current_pid;
799 } # fin de demon_running
800
801 # END : appelé à la fin du script : supprime le fichier pid si besoin
802 sub END {
803         if ($mode_demon_actif and $pid{'obj'} and $pid{'value'}) {
804                 $pid{'obj'}->remove();
805                 Execute('kill -15 '.$pid{'value'}) if $pid{'value'} != $$;
806                 WriteLog('Sys_alive stoppé en mode démon (pid='.$pid{'value'}.')');
807         }
808 } # fin de END
Note: See TracBrowser for help on using the browser.