fhem überwachen (watchdog)

Begonnen von Elektrolurch, 05 Juli 2014, 10:08:26

Vorheriges Thema - Nächstes Thema

Elektrolurch

Hallo zusammen,

wer hatte das nicht schon mal, das genau im Urlaub oder wenn sonst niemand zu Hause war, fhem "hängenblieb" oder sich sogar ganz beendete.
Da ich in den letzten Wochen mit einem sporadisch auftretendem Fehler zu kämpfen hatte, habe ich einige "Sicherungsmaßnahmen" implementiert:

1. Damit keine wesentlichen Daten verloren gehen, werden die state/readings regelmäßig automatisch gesichert.
2. Nach dem Start von fhem startet dieses wiederum ein kleines perl-Skript, welches die "Funktionsfähigkeit von fhem überwacht.
fhem schreibt über einen timer (at) regelmäßig (alle 10 Minuten) einen Zeitstempel und seine Prozeß-ID (pid) in eine Datei watchdog.log im fhem-Verzeichnis.
Das perl-Skript watchdog.pl liest nun unabhängig von fhem alle 10 Minuten diese Datei ein. Ist der Zeitstempel älter als 10 Minuten, so scheint fhem zu hängen oder ist abgestürzt.
der watchdog startet fhem dann neu und beendet sich selber, da ja durch den Start von fhem der watchdog initialisiert wird.

1. regelmäßiges Sichern:

define fhem_save_at +*02:22:22 {fhem('save');
return undef; }

Wenn man das direkt in die fhem.cfg schreibt, sind die ";" natürlich zu verdoppeln.
Im Original habe ich noch mehr in den {} -  Klammern stehen, man kann natürlich auf die Perl-Klammern verzichten und direkt den "save - Befehl hinter die Zeitangabe stellen.
define fhem_save_at +*02:22:22 save

2. Regelmäßiges Schreiben des Zeitstempels von fhem aus:

define Watchdog_exec at +*00:10:00 {Wd_exec();}
3. Beim Starten von fehm wird dieses notify ausgeführt. Hier kann man natürlich noch mehr tun. Ich gebe z.B. über einen FS20Sig2 einen Startsound aus und lasse mir eine Mail schicken.
Hier wird nur einmal die Zeitstemple-Datei geschrieben und über "system-call" das  Startskript für den watchdog gestartet.

define fhem_notify notify global:INITIALIZED|REREADCFG {
Wd_exec();
system("./startwatchdog&");
}
Und das muss in die 99_myUtils oder in eine andere 99_myUtils...pm - Datei (Alles was 99_myUtils<und noch irgendwas>.pm heißt, wird von fhem automatisch eingelesen).

sub Wd_exec()
{
my $filename = ">./watchdog.log";
my $pid = getpid();
if (open (WATCHDOGFILE,$filename))
{
printf (WATCHDOGFILE "%d\t%d\n%s",time(),$pid,EventZeit());
close WATCHDOGFILE;
}
return undef;
} # end sub wd_exec
########################
In die zweite Zeile der Datei wird die Zeit noch einmal in lesbarer Form mit EventZeit()) ausgegeben.
Ist eine von mir erstellte Funktion, wobei die Reihenfolge hh:mm:ss dd.mm.yy ist. Hat man eine solche sub nicht, kann man die Ausgabe auch weglassen (das lezte  %s in der Formatangabe streichen, und EventZeit() weglassen) oder durch TimeNow() ersetzen.


Und das ist die Datei watchdog.pl, die ins fhem-Verzeichnis gehört:
#!/usr/bin/perl

################################################################
#

use strict;
use warnings;
use Time::HiRes qw(gettimeofday);



# Main Loop
while(1)
{
my $cycle = 600;
sleep 30;
my $restart = 1;
my $filename = "./watchdog.log";
my ($lt,$pid);
$pid = 0;

if (open (WATCHDOGFILE,$filename))
{
while (<WATCHDOGFILE>)
{
chomp ;
($lt,$pid) = split("\t",$_);
my $diff = time() - $lt;
if($diff <= $cycle)
{
$restart = 0;
}
last;

} # while  reading
close WATCHDOGFILE;
}
if($restart)
{
my $ret = `kill -9 $pid` if($pid);
printf("Watchdog: kill hanging fhem pid=%d: %s\n",$pid, $ret);
exec("./startfhem&");
} # restart
sleep ($cycle - 30);
} # while main loop
1;

Ddatei: startwatchdog (im fhem-Verzeichnis)
#!/bin/sh

home=/var/InternerSpeicher/fhem

cd $home

trap "" SIGHUP
modprobe cdc_acm
modprobe ftdi_sio
sleep 2

ln -sf $home/FHEM/fhemcmd.sh /var/fhemcmd

PATH=$home:$PATH
export PATH

export LD_LIBRARY_PATH=$home/lib
export PERL5LIB=$home/lib/perl5/site_perl/5.12.2/mips-linux:$home/lib/perl5/site_perl/5.12.2:$home/lib/perl5/5.12.2/mips-linux:$home/lib/perl5/5.12.2

perl watchdog.pl

Test:
Hat man alles eingerichtet, so kann man wie folgt testen:
1. Mit telnet sich anmelden.
2. Ins fhem - Verzeichnis wechseln.
3. ps | grep fhem
zeigt die ProzessID (pid) von ./startfhem an.
Wurde fhem noch nicht neu gestartet, so sollte der watchdog natürlich auch noch nicht laufen.
prüfen mit:
ps | grep watchdog
Außer dem Linux - watchdog sollte da noch nichts anderes sein.
Nun kann man mit
kill -9 <pid> (pid ist die Prozess-ID, die wir oben ermittelt haben), fhem beenden.
Nun gibt man
./startwatchdog
in die shell ein.
Hat man keine Tippfehler gemacht, so läuft nun der watchdog für 30 Sekunden und sollte dann prüfen, ob
a) die watchdog.log - Datei von fhem überhaupt schon geschrieben wurde. Wenn nicht, wird dhem nun gestartet
b) Wie alt der Zeitstempel in der Datei ist. Ist dieser älter als 10 Minuten, so wird dann fhem neu gestartet.

Also, entweder kommt der shell-Prompt bereits wieder nach 30 Sekunden oder nach ca. 10 Minuten.

Soweit der Test.
Ansonsten solte das ganze automatisch funktionieren.
Getestet auf einer FB7390, unter Windows dürfte das allerdings so nicht funktionieren.

Man kann auch fhem einfach neu starten (shutdown restart).
Dann sollte in der Datei watchdog.log der aktuelle Zeitstempel stehen und mit
ps | grep watchdog
sollte man das perl-Skript watchdog.pl als laufenden Prozess angezeigt bekommen.


Gruß

Elektrolurch

configDB und Windows befreite Zone!

Groby

#1
Hallo Elektrolurch,

super Tool! Das habe ich schon ewig gesucht!

Ich hatte nach einen fhem shutdown restart den watchdog bzw. das startscript als Prozess doppelt vorhanden. Deshalb habe ich mit meinen bescheidenen perl Kenntnissen Dein Script erweitert, um den alten watchdog Process zu löschen. Folgender Block wurde vor main eingefügt die nachfolgenden my Definitionen entsprechend angepasst:

use POSIX;
my ($lt,$pid);
my $filename = "./watchdog.pid";
if (open (WATCHDOGFILE,$filename))
{
while (<WATCHDOGFILE>)
{
chomp ;
($lt,$pid) = split("\t",$_);
my $ret = `kill -9 $pid` if($pid);
printf("Watchdog: kill previous watchdog pid=%d: %s\n",$pid, $ret);
last;
} # while  reading
close WATCHDOGFILE;
}

$filename = ">./watchdog.pid";
$pid = getpid();
if (open (WATCHDOGFILE,$filename))
{
printf (WATCHDOGFILE "%d\t%d",time(),$pid);# EventZeit()
close WATCHDOGFILE;
}

Beim Start von watchdog.pl wird die $PID in das File watchdog.pid geschrieben, um sie beim erneuten watchdog restart mit kill entfernen zu können. Zusätzlich habe ich noch folgendes global:SHUTDOWN notify hinzugefügt um die watchdog.log Datei beim shutdown zu leeren:

define fhem_shutdown notify global:SHUTDOWN "> ./watchdog.log"

So startet fhem nach einem shutdown / Fritz reboot sofort nach 30 Sekunden.

Ich denke jetzt läuft es einigermassen rund.

Danke für den Lösungsansatz! Die upgedatete watchdog.pl íst im Anhang.

MfGroby

Elektrolurch

Hallo,

eigentlich dürfte der watchdog-Prozess nicht doppelt vorhanden sein, denn ind der watchdog.pl wird ja fhem mit:

exec('./startfhem&');

gestartet.
exec() beendet den gleichen Prozess und startet einen anderen.
Wenn dann fhem wieder startet, startet es auch watchdog.pl über das Skript ./startwatchdog.
Ich habe jetzt alle möglichen Varianten durchgespielt, wenn man in fhem shutdown eingibt, dann dauert es max. 10 Minuten und fhem ist wieder da.
Der watchdog hat sich durch das exec beendet und wird wieder über das notify in fhem neu gestartet (andere pid für den watchdog).

Gruß

Elektrolurch
configDB und Windows befreite Zone!

Groby

Guten Morgen,

Gute Frage. Du hast Recht der watchdog läuft tadellos. Entweder nach 30 sek oder spätestens nach 10 min. ist fhem wieder da. Aber wenn ich mit dem original Script ein shutdown restart oder rereadcfg mache, kommt folgendes dabei heraus:

# ps | grep watchdog
    4 root         0 SW<  [watchdog/0]
2190 root      1280 S    {startwatchdog} /bin/sh ./startwatchdog
2195 root      4844 S    perl watchdog.pl
2197 root      1280 S    {startwatchdog} /bin/sh ./startwatchdog
2202 root      4844 S    perl watchdog.pl
2206 root      1280 S    {startwatchdog} /bin/sh ./startwatchdog
2213 root      4844 S    perl watchdog.pl
2217 root      1280 S    {startwatchdog} /bin/sh ./startwatchdog
2222 root      4844 S    perl watchdog.pl

Das Ganze nach 3 mal rereadcfg trotz ./startwatchdog& und ./startfhem&. Frag mich warum, aber egal denn jetzt geht es ja...

Gruss, Groby

Elektrolurch

Hallo,

ok, jetzt verstehe ich: über "shutdown restart" wird natürlich ein neuer watchdog gestartet ohne das der alte watchdog sich vorher beendet hat.
Der beendet sich ja nur, wenn er selbst fhem startet.
An den Fall hatte ich nicht gedacht.
Man könnte alternativ zum Starten des watchdogs über fhem natürlich auch das ./startfhem - Skript um die Zeile
perl ./startwatchdog.pl&
ergänzen oder in fhem Abfragen, ob ein watchdog schon läuft.

Gruß


Elektrolurch
configDB und Windows befreite Zone!

tagedieb

Hallo zusammen

ich finde dieses Projekt sehr interessant, zumal auch ich schon mehrmals erlebt habe, das mein FHEM nicht erreichbar war
da ich im Bereich Unix jedoch immer noch zur Kategorie "Dummi" gehöre, möchte ich folgende Dinge noch einmal nachfragen:
Beziehen sich diese Pfadehome=/var/InternerSpeicher/fhem
ln -sf $home/FHEM/fhemcmd.sh /var/fhemcmd
auf das Verzeichnis der FB? und ich muss sie beim Cubietruck ändern?
oder könnte ich alles 1:1 übernehmen?

Für Eure helfenden Antworten, schon einmal vielen Dank im voraus

gruss tagedieb
FHEM 5.6 auf Cubitruck
CUL und Cul 868 und 2 HM LAN an Zbox
Remoteserver auf 2.Zboxi
HM-CC-RT-DN,HM-LC-Bl1PBU-FM,HM-LC-SW1-FM,HM-LC-SW4-PCB,HM-LC-Sw1PBU-FM,HM-PB-2-WM55,HM-PB-6-WM55,HM-SCI-3-FM,HM-SEC-RHS,HM-SEC-SC,HM-SEC-SC-2,HM-SEC-TIS,HM-WDS10-TH-O u.viele mehr
diverse IT Empfänger und LW3

Elektrolurch

Hallo Tagedieb,

in meiner ursprünglichen Version habe ich keine absoluten Pfade verwendet. Ich adressiere das Verzeichnis aus dem fhem und der watchdog gestartet wird, mit "./".
Das Skript "startwatchdog" ist eins zu eins das gleiche Skript wie startfhem, nur die letzte Zeile ist ausgetauscht.Du kannst also mit
cp ./startfhem ./startwatchdog
Dir das Skript kopieren und dann die Zeile mit dem perl-Aufruf abändern.
perl ./watchdog.pl

Dann müsste es funktionieren.

Gruß

Elektrolurch
configDB und Windows befreite Zone!

tagedieb

Hallo Elektrolurch

Dankeschön, es funktioniert prima

Gruss tagedieb
FHEM 5.6 auf Cubitruck
CUL und Cul 868 und 2 HM LAN an Zbox
Remoteserver auf 2.Zboxi
HM-CC-RT-DN,HM-LC-Bl1PBU-FM,HM-LC-SW1-FM,HM-LC-SW4-PCB,HM-LC-Sw1PBU-FM,HM-PB-2-WM55,HM-PB-6-WM55,HM-SCI-3-FM,HM-SEC-RHS,HM-SEC-SC,HM-SEC-SC-2,HM-SEC-TIS,HM-WDS10-TH-O u.viele mehr
diverse IT Empfänger und LW3

willybauss

klingt super! Ich hatte bislang mit einem Shell Script geprüft, ob der fhem Prozess läuft und ggf. gestartet:

#!/bin/sh

# command line to be executed
EXECUTE="/etc/init.d/fhem start"


# check if running
if (  /etc/init.d/fhem status | grep not )
then
echo "$NAME NOT running! Restarting..."
/etc/init.d/fhem start &
fi

exit 0



In der crontab steht dann

# m  h  dom mon dow   command
0  *  *   *   *     /opt/fhem/CheckIfRunsAndRestart


Das funktioniert auch soweit, nur einen hängenden (aber vorhandenen) fhem Prozess findet das Script natürlich nicht. Ich werde deshalb Elektrolurch's Lösung zusätzlich einbauen.
FHEM auf Raspberry Pi B und 2B; THZ (THZ-303SOL), CUL_HM, TCM-EnOcean, SamsungTV, JSONMETER, SYSMON, OBIS, STATISTICS

willybauss

Ich sehe beim durchlesen der Beiträge, dass es doch im Lauf der Diskussion noch Verbesserungen gab. Wäre es zu viel verlangt, um die finalen Dateien zu bitten, z.B. als Anhang zum Beitrag?  :)
FHEM auf Raspberry Pi B und 2B; THZ (THZ-303SOL), CUL_HM, TCM-EnOcean, SamsungTV, JSONMETER, SYSMON, OBIS, STATISTICS

Elektrolurch

Hallo,

habe das mit dem watchdog nun so korrigiert, dass es auch bei reread und shutdown restart funktioniert und nicht mehrere Instanzen vom watchdog erzeugt werden:

define fhem_not global:INITIALIZED|REREADCFG {fhem_not();}

und für die 99_myUtils:


sub fhem_not()
{
Wd_exec();
# alte watchdogs vorsichtshalber löschen
my $ret = `ps | grep watchdog.pl`;
my @lines = split("\n",$ret);
my @retval;
foreach my $l (@lines)
{
if($l =~m/.*perl watchdog.pl.*/)
{
my ($wpid) = split(' ',$l);
push(@retval,"killed: ".$l);
$l = `kill -9 $wpid`;
} # if watchdog
} # end foreach
Log(1,join("\n",@retval));
# und neu starten

system("./startwatchdog&");
} # end sub fhem_not
###############################

Damit braucht man nicht die pid des watchdogs in eine eigene Datei schreiben.

Die wd_exec sieht bei mir jetzt so aus. Da bei mir vmtl. aus thermischen Gründen vor einigen Tagen ein CUNO ausgefallen ist (er geht dann von STATE Initialized auf was anderes) frage ich die CULs noch ab.


sub Wd_exec()
{
my $filename = ">./watchdog.log";
my $pid = getpid();
if (open (WATCHDOGFILE,$filename))
{
printf (WATCHDOGFILE "%d\t%d\n%s",time(),$pid,EventZeit());
close WATCHDOGFILE;
}
# falls man die Funktionsüberprüfung der CULs nicht braucht,
# dann bis zum Ende der Prozedur alles löschen
my $cs = $defs{"CUNO_1"}{STATE} ;
if($cs ne 'Initialized')
{
# AktivMon('ALARM',"CUNO_1 status $cs");
Log(1,"CUNO_1 status $cs");
}
$cs = $defs{"CUL_0"}{STATE} ;
if($cs ne 'Initialized')
{
# AktivMon('ALARM',"CUL_0 status $cs");
Log(1,"CUL_0 status $cs");
}
# bis hier löschen
return undef;
} # end sub wd_exec
#########################

Gruß

Elektrolurch

configDB und Windows befreite Zone!

raspklaus

Hallo,

wäre wirklich nett wenn die finalen Versionen als Download angehängt werden würden.


AET_FHEM

Hallo also ich hab das etwas anderster gelöst, da bei mir schon Monit läuft um ein paar Dateien und Programme zu checken


---> eigentlich ganz einfach

ein dummy in fhem eingerichtet welcher jede 3 minuten in ein Log schreibt, diese Datei lass ich jetzt von Monit überprüfen.......
easy

super Sach!!

P.A.Trick

Ein "apt-cache search monit" bringt keine Treffer, dass ist dann auch nicht einfach :-)
Cubietruck,RPI,QNAP Ts-419p+, FS20, FRITZ!DECT200, 7 MAX! Thermostate, 3 MAX! Fensterkontakte, Kodi, CUL V3.3, EM1000S, LW12, LD382, HUE, HM-CFG-USB-2, 1x HM-LC-SW1-FM, 2x HM-LC-SW2-FM, 2x HM-LC-Sw1PBU-FM, 3xHM-LC-Bl1PBU-FM,HM-SEC-RHS, 2xHM-SEC-SD,HM-WDS30-T-O, 3x HM-LC-Dim1TPBU-FM, RPI+AddOn

AET_FHEM

Ein "apt-get install monit" bringt abhilfe
auf jeden fall hier auf meinem Rasberry .....