Interesting.
Both i
and inspect
are using protocols.
As the others said, you can customise inspect
to log the underlying map (including the __struct__
key) by passing the structs: false
option. I don’t think there’s a built-in way to log an equivalent to the raw representation section from i
.
Here follows TMI about protocol implementations 

Elixir includes a default Inspect
implementation to log structs that have not implemented the Inspect protocol:
iex(1)> defmodule Example, do: defstruct [:foo]
{:module, Example, <<...>>, %Example{foo: nil}}
iex(2)> %Example{}
%Example{foo: nil} # <-- default implementation
But DateTime
has its own implementation of the Inspect protocol that serialises it as a sigil:
iex(3)> DateTime.utc_now
~U[2025-06-24 14:01:48.773039Z] # <-- DateTime's implementation
i
is actually overriding any type-specific Inspect
implementations to dump the raw representation using the default Inspect.Any
implementation.
Here’s what IEx.Info
is doing internally, vs. what happens when you call inspect
normally on a DateTime
. Note the use of Inspect.Any
, which is the default implementation IEx.Info
calls explicitly, vs. Inspect.DateTime
, which is what you get when you pass a DateTime
struct to inspect
.
iex(4)> DateTime.utc_now |> Inspect.Any.inspect(%Inspect.Opts{}) |> Inspect.Algebra.format(:infinity) |> IO.iodata_to_binary
"%DateTime{year: 2025, month: 6, day: 24, hour: 14, minute: 7, second: 18, time_zone: \"Etc/UTC\", zone_abbr: \"UTC\", utc_offset: 0, std_offset: 0, microsecond: {379886, 6}, calendar: Calendar.ISO}"
iex(5)> DateTime.utc_now |> Inspect.DateTime.inspect(%Inspect.Opts{}) |> Inspect.Algebra.format(:infinity) |> IO.iodata_to_binary
"~U[2025-06-24 14:07:23.538947Z]"