在我的凤凰应用程序中,我正在使用我编写的几个宏来为日志数据添加一些额外的自定义格式 - 但是,我在编译应用程序时遇到了一些问题正确地,当使用use
行为时,我将负责HTTP访问日志记录的宏直接添加到plug
管道中的router.ex
。
首先,这是我尝试使用的宏的简化版本:
defmodule MacroTest do
defmacro __using__(_) do
quote do
require Logger
defmacro execute(data) do
quote do: Logger.log(:info, unquote(data))
end
end
end
end
在我的router.ex
中,我想将execute/1
宏提供给 Plug.Accesslog 作为其fun
选项:
defmodule MyApp.Router do
use MyApp.Web., :router
use MacroTest
pipeline :api do
plug Plug.AccessLog,
format: :combined,
formatters: [ Plug.AccessLog.DefaultFormatter ],
fun: &execute/1
end
end
当我像这样编译应用程序时,我收到以下错误:
** (CompileError) web/router.ex:21: undefined function execute/1
(stdlib) lists.erl:1338: :lists.foreach/2
(stdlib) erl_eval.erl:670: :erl_eval.do_apply/6
(elixir) lib/kernel/parallel_compiler.ex:198: anonymous fn/4 in Kernel.ParallelCompiler.spawn_workers/6
然而,我发现如果我定义一个辅助函数并在那里调用宏,这将起作用:
defmodule MyApp.Router do
use MyApp.Web., :router
use MacroTest
def my_fun(data), do: execute(data)
pipeline :api do
plug Plug.AccessLog,
format: :combined,
formatters: [ Plug.AccessLog.DefaultFormatter ],
fun: &__MODULE__.my_fun/1
end
end
这是我能在这里完成我需要的唯一方法,还是有些东西我可以改变以允许我直接将execute/1
传递给plug
而不必将其包裹起来?如果这是唯一的解决方案,那不是什么大问题,但如果可能的话,我更愿意避免使用辅助功能。虽然我无法清楚地说明为什么会发生这种情况,但我很欣赏将宏传递到另一个宏的潜在编译复杂性。
谢谢!
答案 0 :(得分:1)
您根本不需要宏也不需要包装器,只需注入一个函数:
defmodule MacroTest do
defmacro __using__(_) do
quote do
require Logger
def execute(data) do
Logger.log(:info, data)
end
end
end
end
和
defmodule MyApp.Router do
use MyApp.Web, :router
use MacroTest
pipeline :api do
plug Plug.AccessLog,
format: :combined,
formatters: [ Plug.AccessLog.DefaultFormatter ],
fun: &__MODULE__.execute/1
end
end