Erlport / Python STDOUT捕获到Elixir

时间:2019-07-03 23:48:19

标签: python erlang elixir phoenix-framework gen-server

我正在尝试将STDOUT从Python / Erlport用管道传输回Elixir。我的:python调用工作正常,我只想将Python中的STDOUT内容发送回Elixir进行日志记录,但是我无法全力以赴地实现这一目标。即使使用Python 2.7,我也知道它是possible

我在:python模块周围有一个Genserver包装器,这样我的呼叫就这样工作:

pid = Python.start()
Python.call(pid, :bridge, :register_handler, [self()]) 

Python.call看起来像这样:

def call(pid, module, function, args \\ []) do
  :python.call(pid, module, function, args)
end

除非我明确返回某些内容(显然暂停了该功能),否则:bridge中的任何内容(即bridge.py)都将丢失给STDOUT。如何捕获STDOUT?

我的想法是调用类似Python.call(pid, :builtins, :print, [self()])之类的东西,但这会导致很多错误,我真的不知道这是否是正确的方向。

我实际上想将其传送到Phoenix频道,但这是最简单的部分(我希望如此)。有什么建议吗?谢谢。

2 个答案:

答案 0 :(得分:1)

  

我的想法是调用类似Python.call(pid, :builtins, :print, [self()])之类的东西,但这会导致很多错误,我真的   根本不知道这是正确的方向。

self()不在输出中,而self()print的参数,即python将输出什么。

我认为erlport只能处理MFA调用(模块,函数,参数),并且由于print不是python 2.7中的函数,因此我认为您需要包装一个函数在print周围,例如:

myprint.py:

def print_this(str):
    print str
  

我只想将Python中的STDOUT内容发送回Elixir,以便   日志记录,但我无法解决该问题。我知道   即使我使用的是Python 2.7,也是有可能的

erlport文档说:

  

作为一个方便的功能,ErlPort还支持Python的重定向   STDOUT到Erlang ...

这似乎是默认设置,因此您无需执行任何操作即可将python stdout重定向到elixir stdout。然后问题变成:“如何将elixir stdout登录到文件?”

我可以将长生不老药stdout登录到这样的文件:

friends.ex:

defmodule Friends do

  use Export.Python

  def go do

    #Get path to logfile:

    priv_path = :code.priv_dir(:friends)
    logfile_path = Path.join([priv_path, "log", "mylog.log"])

    #Redirect stdout:

    {:ok, io_pid} = File.open(logfile_path, [:append])
    Process.group_leader(self(), io_pid)

    #Send output to stdout:

    IO.puts "Am I in the log file??!"

    python_path = Path.expand("lib/python") 
    {:ok, py} = Python.start(
                 python: "python2.7",
                 python_path: python_path
               )

    Python.call(py, "myprint", "print_this", ["hello world!"])
    Python.call(py, "myprint", "print_this", ["goodbye..."])

    Python.stop(py)
  end

end

这是我的目录结构:

friends
    /lib
      /friends
      /python
          myprint.py
      friends.ex
   /priv
      /log
          mylog.log

在iex中:

~/elixir_programs/friends$ iex -S mix
Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Compiling 1 file (.ex)
Interactive Elixir (1.8.2) - press Ctrl+C to exit (type h() ENTER for help)

iex(1)> Friends.go
iex(2)>

在日志文件中:

Am I in the log file??!
hello world!
goodbye...
[33m[36m:ok[0m[33m[0m

(我不知道最后一行上的垃圾是什么。编辑:嗯……这是原子:ok被其他东西包围了。)

如果我注释掉python_path行上方go()内的所有内容,那么我得到:

iex(1)> Friends.go
hello world!
goodbye...
:ok

在erlang / elixir文件中,通过启动一个进程来处理I / O,向该进程发送请求以写入文件或读取文件。我认为stdout会发送到group_leader的任何进程,如果进程处理文件的I / O是group_leader,则stdout会发送到该文件。

我不知道在使用group_leader时,弄乱GenServer是否会使事情搞砸。 erlang docs中有一个警告:

  

在具有   监督树,因为OTP承担了他们的组长   流程是其应用程序的主人。

答案 1 :(得分:0)

对于其他陷入这种困境的人:由于我在:python实例周围拥有一台Genserver,因此我只是利用了handle_info

def handle_info({:python, message}, session) do
  message |> String.split("\n", trim: true)
  SomeWeb.Endpoint.broadcast("log", "update", %{body: message})

  {:stop, :normal,  session}
end