I’ve gotten a lot of use out of IO.inspect in piped operations, but it’s 
sometimes hard to match up what I’m seeing in output from Logger statements 
with it… I figured it might be nice to add a similar `inspect` function to 
Logger. I got it working, and it was a valuable learning experience, but I 
stumbled over an interesting macro issue along the way. I’ve pushed my code 
to a branch; there are links below to my work in progress. 


(I know this might be a bit esoteric, or maybe there isn’t a way to 
accomplish this in a clean-enough way that you’d want it added. So: it’d be 
perfectly fine to reject this proposal; I’m happy to move my question to 
the forums, because I do want to understand more about macros from this.)

Here’s the @doc I wrote for it - ironically, the example I give 
demonstrates the big problem I had:


```

Log the inspection of an object.


Returns the object unchanged, like `IO.inspect/2`, making it possible to 
"spy" on values by inserting a `Logger.inspect/3` call in the middle of a 
pipeline.


The `:level` option will override the default `debug` logging level. See 
`IO.inspect/2` for remaining options; the `:label` option is especially 
handy.


## Examples


    [1, 2, 3]

    |> Logger.inspect(label: "before")

    |> Enum.map(&(&1 * 2))

    |> Logger.inspect(label: "after", level: :info)


Produces log entries


    18:37:35.412 [debug] before: [1, 2, 3]

    18:37:35.413 [info]  after: [2, 4, 6]

```


After writing a test (based on the existing test for Logger.debug), I first 
wrote a non-macro version 
<https://github.com/bryanstearns/elixir/commit/1ab61d1efb5ab1e20e0504de4f3e4092da03542d>,
 
but the test failed because it didn’t capture the calling module in 
metadata the way the other Logger macros do. 


So I turned my function into a macro 
<https://github.com/bryanstearns/elixir/commit/1d74ab8cdfd32a83846aa8b6e4c2cce1100fdff2>,
 
but when I fed it the example above (two calls to Logger.inspect in the 
same pipeline), I noticed that one of the lines was repeated:


```

20:43:58.228 [debug] before: [1, 2, 3]

20:43:58.228 [info]  after: [2, 4, 6]

20:43:58.228 [debug] before: [1, 2, 3]

```


It took me quite a while to figure out where that extra line is coming from 
— it’s because when the macro is compiled, it’s given the AST of the whole 
expression up to that point. The first `inspect` call works fine, but the 
second is given an AST that includes the earlier call to `inspect`, and 
when that’s evaluated, the logging call is repeated. Or something like that.


After thinking about this for a while, it occurred to me that I could 
return an AST with the earlier Logger.inspect calls replaced by their first 
parameter. It turned out to be surprisingly easy to make this work 
<https://github.com/bryanstearns/elixir/commit/227b17d195fd6dc40169d62856a3cc1e870e9bd2>,
 
though I’m not sure I’m matching the earlier calls exactly correctly.


Or is there a better approach? (and if there isn't, would you look 
favorably on a PR with this code? :-D)


Thanks,

…Bryan Stearns

-- 
You received this message because you are subscribed to the Google Groups 
"elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/elixir-lang-core/c96ee6c7-49ef-4957-93af-ecb13dd511b5%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to