I am trying to write custom logger , as I am tired of writing Logger.xyz() and then interpolate and inspect some variable.
Trying to achieve
pass any number of variable to the macro
macro prints name of variable and its value
why -
tired of writing and passing tuples
tired of inspect var
cant find var name
i am aware of binding but dont know how to use it here
ex:
def some_func(x, y) do
z = func(x, y)
m = funx2(y, z)
if(m, do: :ok, else: log_error("error happend by", x, y, m, z))
end
so it prints error happend by, x: value of x, y: value of y, m: value of m, z: value of z
my custom logger WIP
defmacro log_error(data) do
quote do
require Logger
caller_module = unquote(__CALLER__.module)
caller_function = unquote(__CALLER__.function)
Logger.error(
"[#{caller_module}][#{inspect(caller_function)}]: Error: [[#{inspect(unquote(data))}]]"
)
end
end
That’s not supported in Elixir at all. The only exceptions here are special forms, but they are not written in Elixir. However you can pass a list of variables instead.
Here is an example script:
defmodule Example do
defmacro log_error(data) do
# maps list elements returning list of quoted expressions
ast = Enum.map(data, "ed_kv/1)
prefix =
case __CALLER__ do
%{function: nil, module: nil} ->
""
%{function: nil, module: module} ->
"[#{inspect(module)}]: "
%{function: {function, arity}, module: module} ->
"[#{inspect(module)}][#{function}/#{arity}]: "
end
quote do
data = Enum.join([unquote_splicing(ast)], ", ")
Logger.error(unquote(prefix) <> "Error: " <> "[[#{data}]]")
end
end
# each list element is 3-element tuple
defp quoted_kv({name, _meta, _args} = var) do
quote do
"#{unquote(name)}: #{unquote(var)}"
end
end
end
For this specific problem I’d recommend solving it with an editor snippet instead of an in-project macro. I have a snippet that does a Logger.info and inspects the variable that I’m interested in.