waseigo
DoTrace - Provides a trace/1 macro to trace function calls at runtime, mimicking Clojure's dotrace output
I saw this LinkedIn post:
*Can your programming language do this?
This is a macro in Clojure called `dotrace`. When you surround a piece of code with it, it pretty prints the call tree along with its inputs/outputs, which is incredibly useful for debugging recursive functions.
Many other languages cannot do this with user-level code.
Clojure can because its syntax is “just” data structures and can be processed and rewritten on the fly by code of your own choosing. Like `dotrace`!
Macros effectively extend the compiler into userland, and it’s one of the reasons Lisp is so easy to fall in love with it.*
I don’t know about Lisp, but here’s an attempt in Elixir:
iex> defmodule Math do
def factorial(0), do: 1
def factorial(n) when n > 0, do: n * factorial(n - 1)
end
iex> require DoTrace
iex> DoTrace.trace(Math.factorial(5))
TRACE t1028: (factorial [5])
TRACE t1092: | (factorial [4])
TRACE t1156: | | (factorial [3])
TRACE t1220: | | | (factorial [2])
TRACE t1284: | | | | (factorial [1])
TRACE t1348: | | | | | (factorial [0])
TRACE t1348: | | | | | | => 1
TRACE t1284: | | | | | => 1
TRACE t1220: | | | | => 2
TRACE t1156: | | | => 6
TRACE t1092: | | => 24
TRACE t1028: | => 120
120
Most Liked
mudasobwa
That looks great, but why is it not shaped as a custom backend to Kernel.dbg/2?
Eiji
Very cool feature! I would like to suggest few ideas:
- Add the module name and arity to trace logs
- Use
:owlpackage to generate links that opens specific function source code - Add option to disable trace log prefix to ensure output is clear
- In other case I would use
:owlagain to have borderless table with prefix as first column and log as the second one.
Look that in my case the output looks like:
TRACE t515: (factorial [5])
TRACE t643: | (factorial [4])
TRACE t771: | | (factorial [3])
TRACE t899: | | | (factorial [2])
TRACE t1027: | | | | (factorial [1])
TRACE t1155: | | | | | (factorial [0])
TRACE t1155: | | | | | | => 1
TRACE t1027: | | | | | => 1
TRACE t899: | | | | => 2
TRACE t771: | | | => 6
TRACE t643: | | => 24
TRACE t515: | => 120
t before number is rather useless I think, but it’s not important. Some integers have 4 digits and some only 3. Because of that the output could be more or less harder to read in some cases.
# version 1 (with option to disable prefix set to true - default?)
(Math.factorial/1 [5])
| (Math.factorial/1 [4])
| | (Math.factorial/1 [3])
| | | (Math.factorial/1 [2])
| | | | (Math.factorial/1 [1])
| | | | | (Math.factorial/1 [0])
| | | | | | => 1
| | | | | => 1
| | | | => 2
| | | => 6
| | => 24
| => 120
# version 2 (with option to disable prefix set to false)
TRACE t515: (Math.factorial/1 [5])
TRACE t643: | (Math.factorial/1 [4])
TRACE t771: | | (Math.factorial/1 [3])
TRACE t899: | | | (Math.factorial/1 [2])
TRACE t1027: | | | | (Math.factorial/1 [1])
TRACE t1155: | | | | | (Math.factorial/1 [0])
TRACE t1155: | | | | | | => 1
TRACE t1027: | | | | | => 1
TRACE t899: | | | | => 2
TRACE t771: | | | => 6
TRACE t643: | | => 24
TRACE t515: | => 120
Edit: Oh, looks like there is a bug with pipes:
iex> 5 |> Math.factorial() |> IO.puts() |> DoTrace.trace()
** (UndefinedFunctionError) function IO.puts/0 is undefined or private. Did you mean:
* puts/1
* puts/2
(elixir 1.19.0-rc.0) IO.puts()
iex:13: (file)
dimitarvp
Well, if only Common LISP had the OTP runtime. The LISP folks practically beat most of the computer science game ages ago, including allow one to easily devise business-specific DSLs that compile to quite well optimised LISP.
Popular in Announcing
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance









