3

Had to use Logger in one of my applications today, and remembered that I needed to call require Logger first. So I decided to look at the Logger source code to see why debug, info, error, etc. are macros and not simple functions.

From the code, the macros for debug, info, etc (and even their underlying functions) look very simple. Wasn't it possible to simply export them as methods instead of macros?


From the Logger code:

  defmacro log(level, chardata_or_fn, metadata \\ []) do
    macro_log(level, chardata_or_fn, metadata, __CALLER__)
  end

  defp macro_log(level, data, metadata, caller) do
    %{module: module, function: fun, file: file, line: line} = caller

    caller =
      compile_time_application ++
        [module: module, function: form_fa(fun), file: file, line: line]

    quote do
      Logger.bare_log(unquote(level), unquote(data), unquote(caller) ++ unquote(metadata))
    end
end

From what I can see, it would've been just simpler to make them into functions instead of macros.

Community
  • 1
  • 1
Sheharyar
  • 73,588
  • 21
  • 168
  • 215

2 Answers2

4

It's probably because of the __CALLER__ special form, that provides info about the calling context, including file and line, but is only available in macros.

tompave
  • 11,952
  • 7
  • 37
  • 63
  • Yes, going over the `__CALLER__` docs, that makes sense. I just assumed it was like `__DIR__` and could be accessed anywhere. – Sheharyar Oct 23 '16 at 01:09
  • 2
    Also macros allow you to compile with requested log level. When compiling with log level `error` all calls to debug logs are completely removed from the compiled file. There is no "if log_level > something", which makes it super fast. – tkowal Oct 23 '16 at 09:57
2

Turns out, another reason is so that the calling code can be stripped out during compile time for the logging levels that the application doesn't want.

From the ElixirForum discussion:

It is to allow the code to just entirely not exist for logging levels that you do not want, so the code is never even called and incurs no speed penalty, thus you only pay for the logging levels that you are actively logging.

and

It's so the entire Logger call can be stripped out of the code at compile time if you use :compile_time_purge_level

Sheharyar
  • 73,588
  • 21
  • 168
  • 215