我可以自动在所有模块中使用Logger吗?

Nat*_*rot 1 elixir

在我的大多数模块中,我

require Logger
Run Code Online (Sandbox Code Playgroud)

然后做一些日志记录.在我不这样做的模块中,我经常进行更改,包括添加一些日志记录,然后我必须标记我正在使用记录器.

require在每个模块中使用Logger 的成本是多少?有没有一种干净的方法可以随时require使用Logger而不在每个模块中提及它?

Ale*_*kin 7

主要目的require是提供对所需模块中声明的的访问:

模块中的公共函数是全局可用的,但是为了使用宏,您需要通过要求定义它们的模块来选择加入
- 来自docs forKernel.SpecialForms.require/2

此外,来自Elixir指南:

宏是词汇:全局注入代码或宏不可能的.要使用宏,您需要显式地要求或导入定义宏的模块.

重点是我的.这样做是为了您自己的安全:与函数不同,宏可能会彻底修改您现有的AST.Logger这是这种行为的一个很好的例子:当级别小于compile_time_purge_levelconfig中指定的级别时,它不会在AST中留下任何痕迹.没有单一的noop.没有.虚无.

这基本上是为什么Logger实现为宏.


有两种方法可以克服这种行为.

1.简单.不建议.

将您自己的包装器Logger作为一个函数:

defmodule Log do 
  require Logger
  def log(whatever), do: Logger.log(whatever)
end
Run Code Online (Sandbox Code Playgroud)

Log.log现在到处都可用(因为它是一个功能.)

缺点:

  • 在生产中,您将在级别上的代码中noop调用Log.log左侧debug.这可能会影响性能.
  • 元数据(另一个原因Logger必须是宏)将变得无用 - 你无法获取日志行的行号,模块等因为它们总是会给宏调用的站点(来自@NathanielWaisbrot)

2.正确.推荐的.

制作自己的MyApp.Utils模块,但每个项目中都存在比todo-or-tictactoe-exercise略复杂的模块.在此模块中,保存所有实用程序功能等,实现宏回调__using__:

defmodule MyApp.Utils do
  defmacro __using__(opts \\ []) do
    quote do
      require Logger
      require MyApp.Utils # if this module has macros itself

      def helper, do: Logger.log("Hey, I am always included")
      ...
    end

    ...
  end
end
Run Code Online (Sandbox Code Playgroud)

是的,现在在所有模块中使用Logger你必须use MyApp.Utils明确,但由于它包含在应用程序范围内使用的方便助手,因此Logger它本身是免费的.

  • 感谢您的解释和建议。请注意,解决方案 1 的另一个缺点是元数据(Logger 必须是宏的另一个原因)将变得无用——您无法获取日志行的行号、模块等,因为它们总是会给出宏调用的站点。 (2认同)