Marc Reichelt: apachectl - wie Server auf leichte Weise neustarten?

Hallo an alle,

nicht wenigen hier dürfte das Skript apachectl bzw. apache2ctl bekannt vorkommen.

Mit dem Aufruf "apache2ctl graceful" kann ich den Server auf "leichte" Art und Weise neustarten, sprich: Alle offenen Verbindungen werden bis zu ihrem Ende laufen gelassen und allmählich werden alle nicht-root Server-Instanzen gestoppt und durch neue Instanzen ersetzt - anders als bei "apache2ctl restart".

Das funktioniert perfekt, und wird es auch weiterhin.

Mein Problem ist nun: Für ein selbstgeschriebenes logrotate-Skript muss ich den Server neustarten, was ich am Besten über "apache2ctl graceful" machen möchte, da der Server so nach außen hin auch für die (kurze) Zeit des Neustarts verfügbar bleibt und bestehende Verbindungen nicht abgebrochen werden.
Aber: Die erfolgreiche Ausführung des Neustarts kann nicht direkt abgefragt werden (da die Instanzen des Apache erst nach und nach durch neue ersetzt werden).

Daher muss ich im logrotate-Skript nach dem Signal zum Neustarten des Servers eine Wartezeit einbauen (derzeit sind es 300 Sekunden).
Aber die Unsicherheit, dass Apache noch nicht komplett neu gestartet ist, bleibt.
Welche Möglichkeit gibt es, in einem Shell-Skript zu ermitteln, ob alle notwendigen Apache-Instanzen *wirklich* komplett neu gestartet sind? Diese Überprüfung könnte ich dann beispielsweise alle N Sekunden ausführen, um dann (bei erfolgreichem Neustart) weitere Aktionen durchzuführen.

Grüße

Marc Reichelt || http://www.marcreichelt.de/

--
DPRINTK("Last time you were disconnected, how about now?");
        linux-2.6.6/drivers/net/tokenring/ibmtr.c
Selfcode: ie:{ fl:| br:> va:} ls:< fo:} rl:( n4:( ss:) de:> js:| ch:? sh:| mo:) zu:)
  1. Hellihello Marcel,

    Mein Problem ist nun: Für ein selbstgeschriebenes logrotate-Skript muss ich den Server neustarten, was ich am Besten über "apache2ctl graceful" machen möchte, da der Server so nach außen hin auch für die (kurze) Zeit des Neustarts verfügbar bleibt und bestehende Verbindungen nicht abgebrochen werden.
    Aber: Die erfolgreiche Ausführung des Neustarts kann nicht direkt abgefragt werden (da die Instanzen des Apache erst nach und nach durch neue ersetzt werden).

    Leider habe ich darüber auch nur ein bissel gelesen. Ich hätte jetzt gedacht, dass der Apache als ein Prozess läuft und dieser Parent-Prozess eine ProzessID hätte und dieser Parentprozess erst dann gekillt wird, wenn alle laufenden (geforkten?) Prozesse beendet sind. Wäre dem so, könntest Du ja mittels einer while(1)-Schleife abfragen, ob Apache (bzw. der Prozess httpd) noch mit der alten PID läuft.

    Daher muss ich im logrotate-Skript nach dem Signal zum Neustarten des Servers eine Wartezeit einbauen (derzeit sind es 300 Sekunden).
    Aber die Unsicherheit, dass Apache noch nicht komplett neu gestartet ist, bleibt.
    Welche Möglichkeit gibt es, in einem Shell-Skript zu ermitteln, ob alle notwendigen Apache-Instanzen *wirklich* komplett neu gestartet sind? Diese Überprüfung könnte ich dann beispielsweise alle N Sekunden ausführen, um dann (bei erfolgreichem Neustart) weitere Aktionen durchzuführen.

    Dank und Gruß,

    frankx

    --
    tryin to multitain  - Globus = Planet != Welt
  2. Hallo nochmals,

    ich habe mir nun eine halbwegs vernünftige Lösung erstellt: Ein Shell-Skript, welches zuerst alle PIDs der "apache2"-Prozesse des Benutzers "www-data" sichert, dann einen Server-Neustart initialisiert und anschließend jede Sekunde überprüft, ob die Prozesse mit den PIDs noch existieren (denn die neuen Prozesse haben immer eine höhere PID).
    Anschließend werden trotzdem noch 30 Sekunden Sicherheitspause eingelegt, da die beiden Zeilen "apache2pids=pgrep -U www-data apache2" zusammen mit "apache2ctl -k graceful" keine atomare Operation (EN) darstellen.
    In Ausnahmefällen könnte nämlich genau in der Mitte der beiden Operationen ein neuer Prozess gestartet werden, dessen PID nicht in der Variable $apache2ctl zu finden ist und der ergo auch nicht überprüft wird.

    Gibt es eine Möglichkeit, diese kleine Ungereimtheit auch noch zu entfernen? Wenn ihr mir dabei helft haben wir nachher eine schöne Lösung gefunden, wie man einen Apache2-Server "nett" neustarten kann und trotzdem weiß wann er neu gestartet ist. :-)

    Hier das Skript, wie ich es derzeit verwende:

    #!/bin/bash  
      
    function someProcessesLeft () {  
      for pid in $@  
      do  
        if $(ps -p $pid > /dev/null)  
        then  
          return 0  
        fi  
      done  
      
      return 1  
    }  
      
    # -----------------------------------------------------------------------  
    echo "DO SOMETHING HERE (before Apache2 restart)"  
    # -----------------------------------------------------------------------  
      
    # Save processes and init restart  
    apache2pids=`pgrep -U www-data apache2`  
    apache2ctl -k graceful  
    while someProcessesLeft $apache2pids  
    do  
      sleep 1  
      echo -n "."  
    done  
      
    echo  
    echo "Waiting for 30 seconds to ensure the restart was successfully..."  
    sleep 30  
      
    # -----------------------------------------------------------------------  
    echo "DO SOMETHING HERE (after Apache2 restart)"  
    # -----------------------------------------------------------------------
    

    Grüße

    Marc Reichelt || http://www.marcreichelt.de/

    --
    DPRINTK("Last time you were disconnected, how about now?");
            linux-2.6.6/drivers/net/tokenring/ibmtr.c
    Selfcode: ie:{ fl:| br:> va:} ls:< fo:} rl:( n4:( ss:) de:> js:| ch:? sh:| mo:) zu:)
    1. Hallo,

      ich habe mir nun eine halbwegs vernünftige Lösung erstellt: Ein Shell-Skript, welches zuerst alle PIDs der "apache2"-Prozesse des Benutzers "www-data" sichert, dann einen Server-Neustart initialisiert und anschließend jede Sekunde überprüft, ob die Prozesse mit den PIDs noch existieren (denn die neuen Prozesse haben immer eine höhere PID).

      tut nichts zur Sache, also nur nebenbei: Diese Annahme ist falsch. Sind N Prozesse erzeugt worden, fährt das OS mit einer niedrigen Nummerierung fort.

      [...]
      Gibt es eine Möglichkeit, diese kleine Ungereimtheit auch noch zu entfernen?

      Nein und es ist auch nicht hundertprozentig gesichert, daß während pgrep arbeitet, nicht keine Prozesse erzeugt werden.

      Gruß aus Berlin!
      eddi

      1. Hallo Edgar,

        ich habe mir nun eine halbwegs vernünftige Lösung erstellt: Ein Shell-Skript, welches zuerst alle PIDs der "apache2"-Prozesse des Benutzers "www-data" sichert, dann einen Server-Neustart initialisiert und anschließend jede Sekunde überprüft, ob die Prozesse mit den PIDs noch existieren (denn die neuen Prozesse haben immer eine höhere PID).

        tut nichts zur Sache, also nur nebenbei: Diese Annahme ist falsch. Sind N Prozesse erzeugt worden, fährt das OS mit einer niedrigen Nummerierung fort.

        Logischerweise. Aber dies ist im betrachteten Zeitraum sehr unwahrscheinlich.

        [...]
        Gibt es eine Möglichkeit, diese kleine Ungereimtheit auch noch zu entfernen?

        Nein und es ist auch nicht hundertprozentig gesichert, daß während pgrep arbeitet, nicht keine Prozesse erzeugt werden.

        Ich weiß - daher ja der Timeout.
        Man müsste ein Apache-Modul schreiben, dass diese Funktionalität zur Verfügung stellt - dann wäre es möglich.
        Trotzdem funktioniert mein Backup-Skript für Logfiles sehr gut (da die betrachteten Fälle sehr unwahrscheinlich sind), und daher stelle ich es hier jedem, der es brauchen kann, hiermit zur Verfügung:

        #!/bin/bash  
          
        # Options  
        target="/var/www"  
        safewaittime=30  
          
          
          
        function someProcessesLeft () {  
          for pid in $@  
          do  
            if $(ps -p $pid > /dev/null)  
            then  
              return 0  
            fi  
          done  
          
          return 1  
        }  
          
        if test `whoami` != "root"; then  
          echo "Error: Must be root to run this script."  
          exit 1  
        fi  
          
        cd $target  
        echo "Moving log files"  
          
        for dir in *; do  
          if `test -d "$dir"`; then  
            if `test -d "$dir"/logs`; then  
              if `test -f "$dir"/logs/access_log`; then  
                mv "$dir"/logs/access_log "$dir"/logs/access_log.temp  
              fi  
              if `test -f "$dir"/logs/error_log`; then  
                mv "$dir"/logs/error_log "$dir"/logs/error_log.temp  
              fi  
            fi  
          fi  
        done  
          
          
          
        echo "Giving Apache2 the order to restart"  
          
        # Save processes and init restart  
        apache2pids=`pgrep -U www-data apache2`  
        apache2ctl -k graceful  
          
        echo "Waiting for Apache2 to restart..."  
          
        while someProcessesLeft $apache2pids  
        do  
          sleep 5  
          echo -n "."  
        done  
          
        echo  
        echo "Waiting $safewaittime more seconds to ensure the restart is fulfilled..."  
        sleep $safewaittime  
          
          
          
        for dir in *; do  
          if `test -d "$dir"`; then  
            if `test -d "$dir"/logs`; then  
              echo "Compressing log files for \"$dir\"";  
          
              if `test -f "$dir"/logs/access_log.temp`; then  
                nice gzip -c "$dir"/logs/access_log.temp >> "$dir"/logs/access_log.old.gz;  
                rm "$dir"/logs/access_log.temp;  
              fi  
          
          
              if `test -f "$dir"/logs/error_log.temp`; then  
                nice gzip -c "$dir"/logs/error_log.temp >> "$dir"/logs/error_log.old.gz;  
                rm "$dir"/logs/error_log.temp;  
              fi  
            fi  
          fi  
        done
        

        Grüße

        Marc Reichelt || http://www.marcreichelt.de/

        --
        DPRINTK("Last time you were disconnected, how about now?");
                linux-2.6.6/drivers/net/tokenring/ibmtr.c
        Selfcode: ie:{ fl:| br:> va:} ls:< fo:} rl:( n4:( ss:) de:> js:| ch:? sh:| mo:) zu:)
        1. Moin!

          tut nichts zur Sache, also nur nebenbei: Diese Annahme ist falsch. Sind N Prozesse erzeugt worden, fährt das OS mit einer niedrigen Nummerierung fort.

          Logischerweise. Aber dies ist im betrachteten Zeitraum sehr unwahrscheinlich.

          Das würde ich nicht unbedingt sagen.

          Es gibt zwei Fälle, in denen diese Annahme scheitert:

          1. Es gibt schon in normalen Kerneln eine maximale PID, Werte darüber sind nicht erlaubt, es wird die nächste freie PID gesucht, die ab 1 wieder verfügbar ist. Die Wahrscheinlichkeit ist nach längerer Uptime des Servers durchaus als hoch anzusehen.

          2. Gehärtete Kernel vergeben die PIDs unter Umständen nach einem Zufallsprinzip, um es Angreifern nicht zu erlauben, auf vorhersehbare PIDs zu treffen.

          Da dein Skript alle PIDs betrachtet, und keine Annahmen über ein Maximum oder Minimum trifft, hat dieses Detail keinen Einfluß.

          - Sven Rautenberg

          --
          "Love your nation - respect the others."
          1. Hallo Sven,

            tut nichts zur Sache, also nur nebenbei: Diese Annahme ist falsch. Sind N Prozesse erzeugt worden, fährt das OS mit einer niedrigen Nummerierung fort.

            Logischerweise. Aber dies ist im betrachteten Zeitraum sehr unwahrscheinlich.

            Das würde ich nicht unbedingt sagen.

            Es gibt zwei Fälle, in denen diese Annahme scheitert:

            1. Es gibt schon in normalen Kerneln eine maximale PID, Werte darüber sind nicht erlaubt, es wird die nächste freie PID gesucht, die ab 1 wieder verfügbar ist. Die Wahrscheinlichkeit ist nach längerer Uptime des Servers durchaus als hoch anzusehen.

            2. Gehärtete Kernel vergeben die PIDs unter Umständen nach einem Zufallsprinzip, um es Angreifern nicht zu erlauben, auf vorhersehbare PIDs zu treffen.

            Stimmt, so habe ich das noch gar nicht betrachtet. Aber wie du bereits schriebst:

            Da dein Skript alle PIDs betrachtet, und keine Annahmen über ein Maximum oder Minimum trifft, hat dieses Detail keinen Einfluß.

            Genau so ist es. :)
            Das einzige Problem, das auftreten könnte, ist eben dass zwischen dem Ermitteln der PIDs und dem Neustart-Signal an den Apache neue Apache-Prozesse dazukommen könnten - die dann nicht überwacht werden.
            Daher habe ich noch 30 Sekunden Wartezeit eingebaut (die man ja auch noch variieren kann) - eine 100%ige Sicherheit gibt es hier trotzdem nicht.

            Bevor ich vergesse, das noch zu erwähnen - wer es noch nicht durch Lesen des Skriptes herausgefunden hat:

            Die Log-Dateien müssen "access_log" und "error_log" heißen, und sie müssen alle in folgenden Ordnern liegen:

            /var/www/<Ordner>/logs/

            Dies habe ich so eingerichtet, da ich bei mir eine VirtualHost-Umgebung mit Ordnern der Form
            /var/www/example.com/htdocs/
            und
            /var/www/example.com/logs/
            eingerichtet habe.
            Lässt sich aber natürlich leicht an eure Bedürfnisse anpassen. :-)

            Grüße

            Marc Reichelt || http://www.marcreichelt.de/

            --
            panic("Oh boy, that early out of memory?");
                    linux-2.2.16/arch/mips/mm/init.c
            Selfcode: ie:{ fl:| br:> va:} ls:< fo:} rl:( n4:( ss:) de:> js:| ch:? sh:| mo:) zu:)
    2. Hallo Marc!

      Ich habe es (auf Windows) mit einem Perl-Skript gelöst, das ich in den Taskplaner als geplanten Taskt mit Startzeit 00:00 Uhr eingefügt habe.

      Da ich keine Ahnung habe, wie man unter Windows PIDs abfragen kann, nutze ich Win32::Process um den Apache zu stoppen und wieder zu starten. Das Problem dabei ist, dass der Apache beim Stop richtig gekillt wird, es dauert also ca. 20-30 Sekunden, bis er wieder zur Verfügung steht. Für den privaten Gebrauch ist es aber so hinnehmbar, denke ich.

      Es werden Tageslogs erstellt, die zu Beginn eines neuen Monats noch gezippt werden, und zwar in je ein Verzeichnis für error und access-logs.

      Bevor wieder die Bemerkung kommt ;)... das mit den Piped Logs habe ich unter Windows nicht zum Laufen bekommen (lauter Fehlermeldungen), daher habe ich mein eigenes Perl-Süppchen gekocht (selbst gekocht schmekt eh viel besser).

      Falls jemand Interesse hat, kann ich das Skript vorstellen, sind hier und da sicher noch Verbesserungen denkbar!

      Viele Grüße aus Frankfurt/Main,
      Patrick

      --

      _ - jenseits vom delirium - _
      [link:hatehtehpehdoppelpunktslashslashwehwehwehpunktatomicminuseggspunktcomslash]
      Nichts ist unmöglich? Doch!
      Heute schon gegökt?
  3. Hi,

    Mein Problem ist nun: Für ein selbstgeschriebenes logrotate-Skript

    Du hast das Rad neu erfunden?

    http://httpd.apache.org/docs/1.3/logs.html#rotation

    (auch das bei Piped Logs direkt drunter lesen!)

    cu,
    Andreas

    --
    Warum nennt sich Andreas hier MudGuard?
    O o ostern ...
    Fachfragen unaufgefordert per E-Mail halte ich für unverschämt und werde entsprechende E-Mails nicht beantworten. Für Fachfragen ist das Forum da.
    1. Hallo MudGuard,

      Mein Problem ist nun: Für ein selbstgeschriebenes logrotate-Skript

      Du hast das Rad neu erfunden?

      http://httpd.apache.org/docs/1.3/logs.html#rotation

      (auch das bei Piped Logs direkt drunter lesen!)

      rotatelogs (mit Pipe) habe ich verwendet bevor ich das neue Skript geschrieben habe. Mir hat einfach die Methode gefehlt alle Log-Einträge in einer einzigen komprimierten Datei abzulegen.

      Aber trotzdem danke für die Erwähnung - andere fangen damit garantiert mehr an als ich. :-)

      Grüße

      Marc Reichelt || http://www.marcreichelt.de/

      --
      panic("Oh boy, that early out of memory?");
              linux-2.2.16/arch/mips/mm/init.c
      Selfcode: ie:{ fl:| br:> va:} ls:< fo:} rl:( n4:( ss:) de:> js:| ch:? sh:| mo:) zu:)
      1. Moin Moin!

        Du hast das Rad neu erfunden?

        Es lag mir auf der Zunge ...

        http://httpd.apache.org/docs/1.3/logs.html#rotation

        (Funktioniert auch mit 2.0 und 2.2)

        Siehe auch http://httpd.apache.org/docs/2.2/programs/rotatelogs.html#examples

        (auch das bei Piped Logs direkt drunter lesen!)

        rotatelogs (mit Pipe) habe ich verwendet bevor ich das neue Skript geschrieben habe. Mir hat einfach die Methode gefehlt alle Log-Einträge in einer einzigen komprimierten Datei abzulegen.

        Piped Logs können genau das erledigen, OHNE dass Du den Server neu starten mußt. Die einzige Anforderung vom Apachen ist, dass das Programm an STDIN die Log-Zeilen einigermaßen flott einsammelt. Was es dann damit anstellt, ist dem Apachen egal. Es kann unkomprimierte Dateien schreiben und regelmäßig rotieren, dann hast Du rotatelogs. Es kann die Zeilen teilweise parsen und IP-Adressen in den Logs auflösen, dann hast Du logresolve. Es kann die Zeilen parsen, zerlegen und in eine Datenbank-Tabelle schreiben, dann hast Du SQL-basierendes Reporting. Oder es fügt die Log-Zeilen komprimiert an eine komprimierte Datei an.

        Mir will nur nicht in den Kopf, was genau der Vorteil einer riesigen komprimierten Log-Datei sein soll. Sie ist schwer zu handhaben, weil man sie immer wieder dekomprimieren muß, sie ist irgendwann zu groß für gängige Transportmedien, erfordert ab einer gewissen Größe Unterstützung durch Betriebssystem und Dateisystemtreiber, und außer bei rsync werden beim Remote-Zugriff immer tonnenweise uralte Logs durchs Netzwerk geschleppt.

        Für Reporting ist eine SQL-Tabelle deutlich einfacher. Auf Log-Dateien spezialisierte Reporting-Tools kommen auch mit mehreren Log-Dateien klar. Mehrere einzelne, unkomprimierte Log-Dateien sind jeweils kleiner und leichter zu transportieren. Klar, irgendwann sind alte Log-Dateien uninteressant und könnten komprimiert werden. Das wäre ein recht einfacher Patch für Apaches rotatelogs-Programm, das nach dem Wechsel auf eine neue Log-Datei gzip oder bzip2 abforkt und die alte Log-Datei komprimieren läßt. Währenddessen werden neue Log-Zeilen vom Apachen schon wieder in die neue, noch nicht komprimierte Log-Datei geschrieben.

        Alexander

        --
        Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".
        1. Hallo Alexander,

          Piped Logs können genau das erledigen, OHNE dass Du den Server neu starten mußt.

          Sie haben aber zwei große Nachteile:

          1. Es werden eine Menge Prozesse auf dem Rechner gestartet.
          2. Es werden eine ganze Menge Kernel-Resourcen für im Prinzip unnötiges IPC verwendet (eine Pipe pro Log).

          Bei wenigen VHosts ist das noch relativ egal, bei vielen VHosts fällt das aber schon ins Gewicht.

          Gut, bei den Access-Logs könnte man das im Prinzip noch irgendwie eindämmen (ein globales Log für alle Requests mit Info welcher VHost das ist + ein Script, das die aufteilt), aber bei den Error-Logs geht das schon wieder nicht mehr.

          Viele Grüße,
          Christian

  4. Hallo Marc,

    Welche Möglichkeit gibt es, in einem Shell-Skript zu ermitteln, ob alle notwendigen Apache-Instanzen *wirklich* komplett neu gestartet sind?

    Für diesen Zweck ist es sinnvoll, einfach zu überprüfen, ob die Log-Dateien noch offen sind. Wenn dies der Fall ist, so ist der Apache noch nicht komplett neu gestartet - wenn alle Dateien bereits zu sind, schon.

    Auf den SELF-Servern habe ich mir ein paar Python-Scripte für den Zweck programmiert. Hier die relevanten Ausschnitte:

    lrutils.py: Hilfsfunktion, die überprüft, ob bestimmte Dateien noch offen sind:

    #!/usr/bin/env python  
    # -*- coding: utf-8 -*-  
    #  
    # Utility functions for rotating logfiles  
      
    import os  
    from stat import *  
      
    # Check whether any of the specified files is still in use.  
    # Will only work correctly if the files are only opened by programs run under  
    # the current user or when this script is run as root.  
    def filesInUse (files):  
            # Get Inode / Device number for all files to check and save them for  
            # later. Ignore non-existing files.  
            tocheck = []  
            for file in files:  
                    try:  
                            statinfo = os.stat (file)  
                            tocheck.append ((statinfo[ST_INO], statinfo[ST_DEV]))  
                    except OSError:  
                            pass  
      
            # Nothing to check? No file in use  
            if not len (tocheck):  
                    return False  
      
            # Search /proc  
            for pid in os.listdir ("/proc"):  
                    # Only enter PID-type directories  
                    if not pid.isdigit(): continue  
                    try:  
                            # Get all file descriptors for the process and compare  
                            # the inode and device numbers with the inode and  
                            # device numbers of the files we want to check. If at  
                            # least one file is already open, we're done.  
                            for fd in os.listdir ("/proc/%s/fd" % pid):  
                                    try:  
                                            statinfo = os.stat ("/proc/%s/fd/%s" % (pid, fd))  
                                            if tocheck.count ((statinfo[ST_INO], statinfo[ST_DEV])) > 0:  
                                                    return True  
                                    except OSError:  
                                            # Ignore access errors  
                                            pass  
                    except OSError:  
                            # Ignore access errors  
                            pass  
      
            # None of the files was found to be open  
            return False
    

    rotatelogs.py (Teile davon zumindest): Rotieren von Logfiles

    #!/usr/bin/env python  
    # -*- coding: utf-8 -*-  
    #  
    # Rotate logfiles  
      
    # Import needed modules  
    import lrutils, os, time, glob, sys  
      
    # Initial period to wait if not closed immediately  
    interval1 = 20  
    # Interval to wait subsequently  
    interval = 60  
    # The logfiles to copy  
    logfiles = ['/var/log/apache2/access_log', '/var/log/apache2/error_log', '/var/log/apache2/access_log.*', '/var/log/apache2/error_log.*']  
      
    # Get logfiles to rotate  
    logfiles = reduce (lambda x, y: x+y, [glob.glob(y) for y in logfiles])  
    rotated = [x + '.rotated' for x in logfiles]  
      
    # Rotate all logfiles  
    for logfile in logfiles:  
            os.rename (logfile, logfile + '.rotated')  
      
    # Reload apache  
    os.system ('/usr/sbin/apache2ctl graceful')  
      
    # Now definitely sleep at least 1 second - Apache will *never* be  
    # finished reloading *so* quickly  
    time.sleep (1);  
      
    # If logfiles are already closed: we're done  
    if not lrutils.filesInUse (rotated):  
            # Stelle etwas mit den rotierten Logfiles an  
            sys.exit (0)  
      
    # If not, wait first interval  
    time.sleep (interval1)  
      
    # While logfiles are still open: wait normal interval  
    while lrutils.filesInUse (rotated):  
            # Do another reload because sometimes apache does not close the logs  
            # for some reason.  
            os.system ('/usr/sbin/apache2ctl graceful')  
            time.sleep (interval)  
      
    # Stelle was mit den rotierten Logfiles an
    

    Was macht der Code hier?

    1. Die Logfiles werden von $logfile nach $logfile.rotated umbenannt. Der Apache schreibt dann natürlich in die .rotated-Dateien, da der Kernel sich nur um die Inode-Nummern kümmert.

    2. Dem Apache wird ein graceful geschickt. Er macht dann auf jeden Fall die neuen Logfiles auf (d.h. im Verzeichnis existieren $logfile und $logfile.rotated).

    3. In mehreren regelmäßigen Intervallen überprüft das Script, ob die $logfile.rotated noch in Gebrauch sind. Wenn dies nicht der Fall ist, hat der Apache alle Logs zugemacht und das Script kann etwas mit den Logs anstellen (das habe ich hier ausgelassen, weil das SELF-Server-spezifisch ist - wir verschieben die alle auf einen einzigen Server, lassen dort das Statistikprogramm drüberlaufen und löschen die dann allesamt).

    Was noch auf meiner TODO-Liste hierfür steht (allerdings ziemlich weit unten, da nicht kritisch), wäre eine Möglichkeit, nach soundsolanger Zeit (ein paar Stunden z.B.) auch einen restart zu schicken, wenn die Logs dann immer noch nicht freigegeben wurden.

    Wenn jemand was mit dem Code anfangen will, ich stelle ihn (sofern er überhaupt eine Schöpfungshöhe erreicht) unter die MIT-Lizenz.

    Viele Grüße,
    Christian

    1. Hallo Christian,

      Welche Möglichkeit gibt es, in einem Shell-Skript zu ermitteln, ob alle notwendigen Apache-Instanzen *wirklich* komplett neu gestartet sind?

      Für diesen Zweck ist es sinnvoll, einfach zu überprüfen, ob die Log-Dateien noch offen sind. Wenn dies der Fall ist, so ist der Apache noch nicht komplett neu gestartet - wenn alle Dateien bereits zu sind, schon.

      Ja, das macht Sinn - damit wäre das Problem elegant gelöst - denn der entscheidende Moment für das Logrotate-Skript ist ja genau dann gekommen, wenn alle betroffenen Log-Dateien nicht mehr gelesen werden.

      Auf den SELF-Servern habe ich mir ein paar Python-Scripte für den Zweck programmiert.

      Ja, der Python-Code ist sehr schick - aber da ich Python noch nicht kann (ist eine Sprache, die ich in Zukunft erlernen will), werde ich die Idee wohl zunächst in mein Shell-Skript übernehmen.

      Was noch auf meiner TODO-Liste hierfür steht (allerdings ziemlich weit unten, da nicht kritisch), wäre eine Möglichkeit, nach soundsolanger Zeit (ein paar Stunden z.B.) auch einen restart zu schicken, wenn die Logs dann immer noch nicht freigegeben wurden.

      Meinst du damit einen harten restart - oder wieder einen "graceful" restart?

      Grüße

      Marc Reichelt || http://www.marcreichelt.de/

      --
      panic("Oh boy, that early out of memory?");
              linux-2.2.16/arch/mips/mm/init.c
      Selfcode: ie:{ fl:| br:> va:} ls:< fo:} rl:( n4:( ss:) de:> js:| ch:? sh:| mo:) zu:)
      1. Hallo Marc,

        Was noch auf meiner TODO-Liste hierfür steht (allerdings ziemlich weit unten, da nicht kritisch), wäre eine Möglichkeit, nach soundsolanger Zeit (ein paar Stunden z.B.) auch einen restart zu schicken, wenn die Logs dann immer noch nicht freigegeben wurden.

        Meinst du damit einen harten restart - oder wieder einen "graceful" restart?

        Eine harten »restart«. Einen »graceful« schicke ich ja in meinem jetztigen Script sowieso alle paar Minuten.

        Viele Grüße,
        Christian

  5. Hallo,
    ich werf das jetzt einfach mal in den Raum, weil ich mich direkt wunder wieviel Umstände sich hier manche machen...
    Ich handhabe das auf meinem Server so, dass nachts die Logfiles einfach ausgelesen und in eine neue Datei mit Datum versehen geschrieben werden. Danach schreibe ich schlichtweg einen leeren String in die Log-Datei des Apachen.
    Das alles funktioniert problemlos, obwohl der Apache dabei läuft.

    Mir ist klar, dass in der Zeit wo ich die Logdatei kopiere und sie dann lösche theoretisch ein neuer Eintrag eingetragen worden sein kann, aber damit kann ich leben - die Chance dazu ist auf meinem Server nachts sehr gering.

    Wo ist der Fehler, den ich hier mache?

    1. Hallo RFZ,

      ich werf das jetzt einfach mal in den Raum, weil ich mich direkt wunder wieviel Umstände sich hier manche machen...
      Ich handhabe das auf meinem Server so, dass nachts die Logfiles einfach ausgelesen und in eine neue Datei mit Datum versehen geschrieben werden. Danach schreibe ich schlichtweg einen leeren String in die Log-Datei des Apachen.
      Das alles funktioniert problemlos, obwohl der Apache dabei läuft.

      Fast richtig. Das alles funktioniert problemlos, solange nicht der unwahrscheinliche (aber mögliche) Fall eintritt, dass ein Prozess schreibt während der andere liest.

      Mir ist klar, dass in der Zeit wo ich die Logdatei kopiere und sie dann lösche theoretisch ein neuer Eintrag eingetragen worden sein kann, aber damit kann ich leben - die Chance dazu ist auf meinem Server nachts sehr gering.

      Wo ist der Fehler, den ich hier mache?

      Im glücklichen Fall passiert dann das, was du vorhergesagt hast: Es gehen Informationen verloren.
      Wenn du Pech hast kannst du hierdurch aber etwa fehlerhafte Log-Einträge erzeugen (die beispielsweise in der Mitte abgeschnitten sind) und die dann dem Log-File-Auswerter Probleme machen könnten.
      Im schlimmsten Fall könnte eventuell Apache abstürzen (bitte korrigiert mich falls dies so nicht stimmt).

      Sagen wir mal so: Hier siehst du, wie du es besser machen kannst - also pass deine Skripte doch bei Gelegenheit einfach an, um unwahrscheinliche aber mögliche Ungereimtheiten schon jetzt aus dem Weg zu räumen. :-)

      Grüße

      Marc Reichelt || http://www.marcreichelt.de/

      --
      panic("Oh boy, that early out of memory?");
              linux-2.2.16/arch/mips/mm/init.c
      Selfcode: ie:{ fl:| br:> va:} ls:< fo:} rl:( n4:( ss:) de:> js:| ch:? sh:| mo:) zu:)