← docs.speechwave.live

Debugging cheatsheet

IO.inspect: print and pass through

# In a pipe chain (doesn't break the chain)
data
|> step_one()
|> IO.inspect(label: "after step_one")
|> step_two()

# Inline
IO.inspect(variable, label: "my var")

# Inspect with options
IO.inspect(big_struct, label: "struct", limit: :infinity, pretty: true)

dbg: smart debug print

# At end of pipe: shows every step
data
|> step_one()
|> step_two()
|> dbg()

# Any expression
dbg(some_function(x, y))
dbg(socket.assigns)

dbg shows file:line, the expression text, and the value. The compiler warns about leftover dbg calls.

IEx.pry: interactive breakpoint

# Add to code (both parts required)
require IEx; IEx.pry()

# Must start server with IEx:
iex -S mix phx.server

# In the pry session:
variable_name       # inspect any local variable
socket.assigns      # access nested data
continue            # resume execution
respawn              # give up and restart the shell

Only works with iex -S mix. Freezes the paused process until you continue.

IEx console

# Start console with app loaded
iex -S mix

# Start console with Phoenix server
iex -S mix phx.server

# Recompile after editing files (no restart needed)
recompile()

Runtime inspection

# Database queries
alias Speechwave.{Repo, Talks}
import Ecto.Query
Repo.all(Talks.Talk)
Repo.get_by(Talks.Talk, slug: "my-talk")

# ETS tables
:ets.tab2list(:rate_limiter)
:ets.info(:rate_limiter)
:ets.lookup(:rate_limiter, "session-id")

# Processes
Process.registered()                    # all named processes
Process.whereis(Speechwave.RateLimiter) # find a specific one
:sys.get_state(Speechwave.RateLimiter)  # GenServer internal state

# Application config
Application.get_all_env(:speechwave)

Picking the right tool

NeedTool
Quick value checkIO.inspect(val, label: "x")
Pipe chain debugging|> dbg()
Explore variables interactivelyrequire IEx; IEx.pry()
DB queries / process inspectioniex -S mix
ETS / GenServer state:ets.tab2list/1 / :sys.get_state/1

Cleanup

dbg triggers a compiler warning, caught by mix precommit. IO.inspect does not warn, so remove it manually before committing.