2016-10-09 3 views
2

Dies sind meine ersten 2 Stunden Elixir, also könnte es eine noobish Frage sein, aber ich habe einige Probleme mit einem GenServer laichen und es werfen. Ich benutze dieses Modul, das nach Änderungen in einer Datei in meinem System sucht, und jedes Mal, wenn ein neuer Eintrag in dieser Datei hinzugefügt wird, möchte ich das Protokoll auf einen Gen-Server umwandeln, der es analysiert und tut, was es tun soll auf seine Ergebnisse.Elixir GenServer cast und start_link

Hier ist das Modul, das die Änderungen Uhren:

defmodule Test.Watcher do 
    use ExFSWatch, dirs: ["/var/log/"] 

    import Test.Receiver, only: [analyze_log: 2] 

    def callback(file_path, actions) do 
     if file_path == "/var/log/syslog" do 
      if :modified in actions do 
       #~~~~ WHERE DO I GET THIS pid FROM? 
       analyze_log pid, get_log 
      end 
     end 
    end 

    def get_log do 
     {log, _} = System.cmd("tail", ["-n", "1", "/var/log/syslog"]) 
     log 
    end 
end 

Der Beobachter sehr gut funktioniert und es erhält die neuen Protokolle, aber ich habe ein Problem mit Test.Receiver, die GenServer verwendet.

Meine erste Frage ist ... wo starte ich diesen Gen-Server? ExFSWatch hat seine eigene start Methode und ich kann das nicht überschreiben. Rufe ich jedes Mal, wenn ein neues Protokoll eingeht, start_link an (ich bezweifle das, aber ich musste fragen)?

Ny alle Beispiele, die ich lesen soll ich es woanders beginnen, packen es pid und als param auf die analyze_log-Methode übergeben, so, wenn ich Recht habe, meine einzige verbleibende Problem ist eine gute herauszufinden, Ort, um die Test.Receiver Genserver zu starten und greifen es ist pid, so dass ich es innerhalb der callback Methode verwenden kann.

defmodule Test.Receiver do 
    use GenServer 

    def start_link do 
     GenServer.start_link(__MODULE__, :ok, []) 
    end 

    def analyze_log(pid, log) do 
     GenServer.cast(pid, {:analyze_log, log}) 
    end 

    def init(:ok) do 
     {:ok, %{}} 
    end 

    def handle_cast({:analyze_log, log}, state) do 
     IO.puts log 
     {:noreply, state} 
    end 
end 
+2

Die meisten Module, die solche Callback-Schnittstelle haben, haben auch ein zusätzliches "state" -Argument, um solche Informationen herumzutragen, aber es sieht so aus, als hätte 'ExFSWatch' keins. Der einfachste Weg, an den ich denken kann, besteht darin, den Empfängerprozess mit einem Namen zu spawnen und zu registrieren und ihn namentlich zu nennen. – Dogbert

+1

Ich habe eine Antwort basierend auf Ihrem Kommentar gebildet, da es geholfen hat. Vielen Dank. –

Antwort

0

Ok, erweitern auf @ Antwort des Dogbert und es für andere räumen, die mit Elixir beginnen, werden werde ich die Lösung, die für mich gearbeitet. Es mag nicht der eleganteste sein, da mir das Wissen noch fehlt, aber funktioniert.

Wie Dogbert sagte, müssen Sie Ihre GenServer mit einem Namen registrieren und es mit diesem Namen anrufen. Also ging ich zu meiner Hauptdatei und brachte einen Supervisor, die diese Zuhörer und aktiv wie so hält:

defmodule Test do 
    use Application 

    def start(_type, _args) do 
     import Supervisor.Spec, warn: false 

     Fail2ban.Watcher.start 

     children = [ 
      # ... I have more here but let's keep it simple 
      supervisor(Test.Receiver, [Test.Receiver]), 
     ] 

     opts = [strategy: :one_for_one, name: Test.Supervisor] 
     Supervisor.start_link(children, opts) 
    end 
end 

Wie Sie sehen können, der zweite Parameter auf den Supervisor-Aufruf übergeben ist der Name, unter dem ich mag registrieren dieses Modul. Es kann alles sein, was du magst, nehme ich an, da ich mir darüber nicht sicher bin. Dieser zweite Parameter geht in meinen Receiver start_link und Register unter diesem Namen:

def start_link(name \\ nil) do 
    GenServer.start_link(__MODULE__, nil, [name: name]) 
end 

In diesem Ort nun diese Methode auf dem Empfänger erinnert, dass ich Probleme in Bezug auf die pid hatte, die ich nicht wusste, wo aus zu bekommen:

defmodule Test.Watcher do 
    use ExFSWatch, dirs: ["/var/log/"] 

    import Test.Receiver, only: [analyze_log: 2] 

    def callback(file_path, actions) do 
     if file_path == "/var/log/syslog" do 
      if :modified in actions do 
       # Instead of the pid, pass the name under which it was registered 
       analyze_log Test.Receiver, get_log 
      end 
     end 
    end 

    def get_log do 
     {log, _} = System.cmd("tail", ["-n", "1", "/var/log/syslog"]) 
     log 
    end 
end 

Funktioniert für mich, offen für Diskussionen und Verbesserungen. Es ist nun mein zweiter Tag von Elixir und ich habe angefangen zu verstehen, wie es tickt. Kommend von Python, Ruby, PHP selbst ist es ein wenig hart verschiedene Grabbing und Weitergabe von Informationen als Parameter und Zustand die ganze Zeit aber..ich sehe die Sonne jetzt.

Verwandte Themen