Elixir GenServer强制转换和启动链接
这是我的前两个小时的长生不老药,所以这可能是一个不切实际的问题,但我在生成Elixir GenServer强制转换和启动链接,elixir,otp,gen-server,Elixir,Otp,Gen Server,这是我的前两个小时的长生不老药,所以这可能是一个不切实际的问题,但我在生成GenServer并使用它时遇到了一些问题。我正在使用这个模块,它监视系统中某个文件的更改,每次在该文件中添加一个新条目时,我都希望将日志转换到gen服务器,该服务器将对日志进行分析,并根据结果执行任何应该执行的操作 以下是监视更改的模块: defmodule Test.Watcher do use ExFSWatch, dirs: ["/var/log/"] import Test.Receiver,
GenServer
并使用它时遇到了一些问题。我正在使用这个模块,它监视系统中某个文件的更改,每次在该文件中添加一个新条目时,我都希望将日志转换到gen服务器,该服务器将对日志进行分析,并根据结果执行任何应该执行的操作
以下是监视更改的模块:
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
watcher工作得很好,它接收到了新的日志,但是我遇到了使用GenServer
的Test.Receiver
的问题
我的第一个问题是…我从哪里启动这个gen服务器ExFSWatch
有自己的start
方法,我无法覆盖它。每次有新日志传入时,我是否会调用start\u link
(我对此表示怀疑,但我不得不问)
所有我读过的例子我都应该从其他地方开始,抓住它的pid
,并将它作为参数传递给analyze\u log
方法,如果我是对的,我唯一剩下的问题是找到一个好地方来启动Test.Receiver
Genserver并获取它的pid,这样我就可以在回调
方法中使用它
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
好的,为了扩展@Dogbert的答案并为其他开始使用长生不老药的人澄清它,我将为我提供解决方案。这可能不是最优雅的一个,因为我缺乏知识,但工作 正如Dogbert所说,您需要用一个名称注册您的
GenServer
,并用该名称调用它。所以我转到我的主文件,生成了一个监听器,让这些监听器保持活跃,就像这样:
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
如您所见,传递到supervisor调用的第二个参数是我要注册此模块的名称。我想这可能是你喜欢的任何东西,因为我对此不是很确定。第二个参数进入我的接收器的start\u链接
,并以该名称注册:
def start_link(name \\ nil) do
GenServer.start_link(__MODULE__, nil, [name: name])
end
现在,记住接收器上的这个方法,我在pid方面遇到了问题,我不知道从哪里得到:
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
对我来说很有用,欢迎讨论和改进。这是我使用长生不老药的第二天,我开始掌握它的滴答声。来自Python、Ruby和PHP的我,一直以参数和状态的形式获取和传递信息有点困难,但是..我现在看到太阳了。大多数具有这种回调接口的模块也有一个额外的“状态”参数携带此类信息,但由于某种原因,
ExFSWatch
似乎没有。除此之外,我能想到的最简单的方法是生成并用名称注册接收方进程,然后按名称调用它。谢谢