Pretty v1.0.5 Pretty View Source

Inspect values with syntax colors despite your remote console.

This module addresses two surprises you'll encounter trying to dump data to the remote console like you did during development with iex -S mix:

  • IO.inspect/1 et al work fine at the iex> prompt but somehow not when called from a :telemetry handler function or other troubleshooting mechanism... unless you think to look at the log output

  • The syntax colors aren't working like you think they should, either

  • The inspection width is 80... just like iex, now that you think of it

Why? See the explanation.

In case of emergency, BREAK GLASS (see below) to get what you need with some copying and pasting.

Usage

To get the right syntax colors and inspection width, replace your calls to IO.inspect/1 with calls to Pretty.inspect/1:

Pretty.inspect(<<0, 1, 2>>, width: 40)

... and IO.inspect/2 with Pretty.inspect/2:

[1, 2, 3]
|> Pretty.inspect(label: "before")
|> Enum.map(&(&1 * 2))
|> Pretty.inspect(label: "after")
|> Enum.sum()

To get the right colors, width, and output device, use Pretty.bind/1 to get an inspector/1 function, and use it instead of IO.inspect/1 or Pretty.inspect/1:

dump = Pretty.bind(label: "Ecto")
handler = fn name, m10s, m6a, nil -> dump.({name, m10s, m6a}) end
:telemetry.attach(self(), [:my_app, :repo, :query], handler, nil)

BREAK GLASS

If you're sitting at a remote console right now and just need some output without taking a new dependency and re-releasing, paste this in to get most of the functionality of Pretty.bind/1 right away:

bind = fn opts ->
  device = Process.group_leader()
  width = with {:ok, n} <- :io.columns(device), do: n, else: (_ -> %Inspect.Opts{}.width)
  opts = Keyword.merge(:rpc.call(:erlang.node(device), IEx.Config, :inspect_opts, []), opts)
  opts = Keyword.merge(opts, pretty: true, width: width)
  reset = Enum.find_value(Keyword.get(opts, :syntax_colors, []), [], fn _ -> IO.ANSI.reset() end)
  fn term -> IO.puts(device, [Kernel.inspect(term, opts), reset]); term end
end
# I never said it'd be Pretty...
# Can you make it shorter? PR or it didn't happen.

... and then use that:

dump = bind.(label: "ecto")
handler = fn name, m10s, m6a, nil -> dump.({name, m10s, m6a}) end
:telemetry.attach(self(), [:my_app, :repo, :query], handler, nil)

What's going on? See the explanation.

Link to this section Summary

Types

Keyword options supported by IO.inspect/2.

A 1-ary inspection function returning its argument unchanged e.g. IO.inspect/1.

Functions

Bind an inspection function to the current standard output.

Bind an inspection function to a particular device.

Inspect an item, writing the report to the standard output. Return the item unchanged.

Inspect an item, writing the report to a device. Return the item unchanged.

Link to this section Types

Specs

inspect_opts() :: keyword()

Keyword options supported by IO.inspect/2.

Specs

inspector(item) :: (item -> item)

A 1-ary inspection function returning its argument unchanged e.g. IO.inspect/1.

Link to this section Functions

Specs

bind(inspect_opts()) :: inspector(any())

Bind an inspection function to the current standard output.

See bind/2 for more details.

Specs

bind(IO.device(), inspect_opts()) :: inspector(any())

Bind an inspection function to a particular device.

The inspector's device and options are resolved when bind/2 is called, not when the inspector is called. If you bind at the remote console prompt, the device and options will remain appropriate for your console no matter which process calls the inspector.

See inspect/3 for details on option handling.

Link to this function

inspect(item, opts \\ [])

View Source

Specs

inspect(item, inspect_opts()) :: item when item: var

Inspect an item, writing the report to the standard output. Return the item unchanged.

Like IO.inspect/2, but with pretty defaults appropriate to the device.

See inspect/3 for details on option handling.

Link to this function

inspect(device, item, opts)

View Source

Specs

inspect(IO.device(), item, inspect_opts()) :: item when item: var

Inspect an item, writing the report to a device. Return the item unchanged.

Like IO.inspect/3, but with pretty defaults appropriate to the device:

  • Set pretty to true
  • Set width according to the device's :io.columns/1 if possible, else the Inspect.Opts default of 80
  • Set syntax_colors according to the device node's IEx.Config.inspect_opts/1