Ankündigung

Einklappen
Keine Ankündigung bisher.

Async-Support für LoggerEssentials

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Async-Support für LoggerEssentials

    TL;DR
    Ich bin gerade dabei, mir Gedanken rund um asynchronen Support für die LoggerEssentials zu machen. Alles, was an Logging in einer Anwendung passiert, soll die Anwendung bestenfalls nicht verlangsamen oder blockieren.


    Motivation
    Ich habe mehrere Applikationen, wo ich verschiedene Logger wie beispielsweise einen Graylog-Logger (Info oder höher), einen lokalen File-Logger (alles), einen Loggly-Logger (Error oder höher) und einen Pushover-Logger (Critical oder höher). Loggly und Pushover sind Cloudservices und reagieren bislang nur bei Fehlern, da allerdings teilweise sehr langsam. Zum Beispiel, wenn eine Exception festgehalten werden soll, wonach der eigentliche Betrieb des Script normal weiterlaufen soll.


    Mögliche Lösungen
    • Gestern habe ich mit PThreads experimentiert, musste aber nach Stunden dann entnervt feststellen, dass ich damit nicht richtig weiterkomme. Entweder gibt es bei verschiedenen Loggern Dinge, die nicht serialisiert werden können, oder ich bekomme unnachvollziehbare segfaults, was, wenn durchs Logging verursacht, auch immer recht blöd für eine Applikation ist.
    • Dann gibt es noch die Möglichkeit, einen Prozess zu forken und die zu loggenden Daten an diesen zu übergeben. Da muss man dann aber viel drüber wissen, weil man sonst bei der Konfiguration viel falsch machen kann.
    • Zuletzt hab ich dank HHVM noch die Möglichkeit, asynchrone Teilprozesse zu starten. Damit habe ich nicht noch nicht weiter beschäftigt.
    Hat jemand von euch eine Idee, wie man das Thema sinnvoll angehen könnte?

    Ich habe auch schon dran gedacht, eine MessageQueue (Gearman, RabbitMQ, ...) einzuspannen, wobei ein Worker dann das eigentliche Logging übernimmt. So eine MessageQueue habe ich aber nicht überall zur Verfügung.


    Was ist LoggerEssentials? LoggerEssentials ist weniger eine Sammlung von verschiedenen Loggingkomponenten, als vielmehr ein System, um einen komplexen Routingmechanismus zu konfigurieren. Anders als beispielsweise mit Monolog lassen sich hier sehr komplexe Messagerouting-Szenarien mit Filtern, Extendern und Formattern konfigurieren. Ein eher simples Beispiel aus einer DIC-Config wäre:

    PHP-Code:
    $rootdir $container->get('rootdir');
    $logger = new LoggerCollection();

    if(
    php_sapi_name() === 'cli') {
        
    $logger->add(new MaxLogLevelFilter(new TemplateFormatter(new ResourceLogger(STDOUT)), LogLevel::WARNING));
        
    $logger->add(new MinLogLevelFilter(new TemplateFormatter(new ResourceLogger(STDERR)), LogLevel::ERROR));
    } else {
        
    $logger->add(new TemplateFormatter(new StreamLogger($rootdir '/log/events.log')));
    }

    if(!
    function_exists('xdebug_enable')) {
        if(
    $container->has('logger.pushover.user')) {
            
    $pushoverUser $container->get('logger.pushover.user');
            
    $pushoverToken $container->get('logger.pushover.token');
            
    $logger->add(new MinLogLevelFilter(new PushoverLogger($pushoverUser$pushoverToken, array()), LogLevel::CRITICAL));
        }

        if(
    $container->has('logger.loggly.token')) {
            
    $logglyToken $container->get('logger.loggly.token');
            
    $logglyTags $container->get('logger.loggly.tags');
            
    $logger->add(new MinLogLevelFilter(new LogglyLogger($logglyToken$logglyTags), LogLevel::ERROR));
        }

    Standards - Best Practices - AwesomePHP - Guideline für WebApps


  • #2
    Eine möglicher Ansatz wäre, Du schreibst alle Logs grundsätzlich erst mal in lokale Logfiles. Ein anderer Job könnte sich dann z.B. per Cronjob darum
    kümmern bestimmte Logfiles/Logdaten an die Cloudservices weiterzuleiten.

    Nachteil: die CloudLogs hängen ein wenig hinterher

    Eine weitere Möglichkeit wäre die CloudLogJobs als Shell-Hintergrundprozesse auszuführen. Dafür bräuchtest Du für jeden CloudLogger einen entsprechend Wrapper/Adapter + MiniShellscript.

    vg
    jack
    -

    Kommentar


    • #3
      Im ersten Moment ist mir ein altes Problem durch den Kopf gegangen. Dann wird deine Log-Datei immer größer. Einträge, die du bereits verarbeitet hast, kannst du dann nicht aus der Datei löschen, weil gerade möglicherweise auch ein anderer Prozess in die Datei schreibt. Doch vielleicht gibt es eine Möglichkeit, die gar nicht mal so schlecht ist: Du kannst ja pro Prozess eine neue Log-Datei anlegen, diese exklusiv locken und bei Freigabe dann verarbeiten und danach löschen. Dateinamen kannst du auf unterschiedlichste Weise erzeugen (beispielsweise aktueller Timestamp + Rand oder so. Aber auch dann hast du das Dateisystem noch als möglichen Flaschenhals. Das ist in jedem Fall aber wieder etwas, was außerhalb der Applikation passiert und zu schwergewichtig für einfaches Hosting ist. Wenn ich einen Managed-Server habe, dann nutze ich dafür vorrangig Cronjobs, die dann nur einmal pro Minute gestartet werden. Heisst, ich muss mitunter lange auf einen Logeintrag warten und habe meine Log-Konfiguration nicht mehr in der Haupt-Applikation. Wenn ich eine lokale Entwicklungsumgebung habe, dann will ich eigentlich keinen Cronjob installieren müssen.
      Standards - Best Practices - AwesomePHP - Guideline für WebApps

      Kommentar


      • #4
        Bei der zweiten Variante hättest Du die Probleme nicht und Du hättest auch alles innerhalb Deiner App.

        PHP-Code:
        // logger.php
        <?php
        function cloudlog($msg) {
            
        shell_exec('./cloudLoggerWrapper.sh "'.$msg.'" &>/dev/null &');
        }

        cloudlog('Error XYZ');
        PHP-Code:
        //cloudLogger.php
        <?php

        // Hier würdest Du die Logs natürlich direkt in die Cloud schreiben
        sleep(5);
        file_put_contents('cloudLog.txt'$argv[1].PHP_EOLFILE_APPEND);
        Code:
        # cloudLoggerWrapper.sh
        #!/usr/bin/env bash
        php cloudLogger.php "$1" &>/dev/null &
        vg
        jack
        -

        Kommentar


        • #5
          warum nicht per job queue??
          du koenntest RabbitMQ via Gearman oder so etwas reinpushen und dann ueber einen Job den spass ausfuehren lassen: http://php.net/manual/de/gearman.exa...verse-task.php
          https://github.com/Ma27
          Javascript Logic is funny:
          [] + [] => "", [] + {} => object, {} + [] => 0, {} + {} => NaN

          Kommentar


          • #6
            Zitat von Ma27 Beitrag anzeigen
            warum nicht per job queue??
            du koenntest RabbitMQ via Gearman oder so etwas reinpushen und dann ueber einen Job den spass ausfuehren lassen: http://php.net/manual/de/gearman.exa...verse-task.php
            Habe ich beschrieben.
            Standards - Best Practices - AwesomePHP - Guideline für WebApps

            Kommentar


            • #7
              Statt in eine Datei könntest du auch in eine Named Pipe schreiben. Ein zweiter Prozess kann dann von dort lesen und damit dann machen, was immer du machen willst (zb je nach Loglevel in die Cloud loggen, Mails verschicken ect).

              Grüße.

              Kommentar


              • #8
                //OT:
                Ich hab dein problem nicht verstanden, geb ich zu; aber wieso nutzt du nicht syslog,
                oder meinetwegen einen ähnlich aufgebauten logservice in php geschrieben und teil deiner applikation, allerdings nur über ein socket erreichbar?

                Kommentar

                Lädt...
                X