Elixir IEx.Helpers.runtime_info/0でシステムの状態を知る

[Elixir]: https://elixir-lang.org/
[Erlang]: https://www.erlang.org/
[IEx]: https://elixirschool.com/ja/lessons/basics/basics/#%E5%AF%BE%E8%A9%B1%E3%83%A2%E3%83%BC%E3%83%89
[IEx.Helpers.runtime_info/0]: https://hexdocs.pm/iex/IEx.Helpers.html#runtime_info/0
[IEx.Helpers.runtime_info/0 - source]: https://github.com/elixir-lang/elixir/blob/0909940b04a3e22c9ea4fedafa2aac349717011c/lib/iex/lib/iex/helpers.ex#L541
[José Valim]: https://github.com/josevalim

[Elixir]を実行しているシステムの状態について知りたいときは、[IEx.Helpers.runtime_info/0]が便利です。

- Elixir 1.12で追加された関数、削除された関数をコード上で確認する
- Elixirバージョンごとにノードをたてて、[:application.get_key/2]の結果を比較する
- ノードは別々の[Docker]コンテナから起動する

https://qiita.com/torifukukaiou/items/17d55cf896c24b13350e

## 論よりRUN

[IEx]を起動します。

```
iex
```

[runtime_info/0][IEx.Helpers.runtime_info/0]関数を呼びます。
 
```sh
runtime_info
```

![](https://user-images.githubusercontent.com/7563926/204177082-bbb0fb23-c574-42f6-8fee-c0fc04b52a5e.png)

:tada: 以上！

## ソースコードから学ぶ

[IEx.Helpers.runtime_info/0のソースコード][IEx.Helpers.runtime_info/0 - source]を読んでみるとどこからどのように情報を仕入れているのかわかります。アイデアも満載です。

[Elixir]言語作者の[José Valim]さんが書かれたコードなので、お手本中のお手本と言えるでしょう。

https://github.com/elixir-lang/elixir/commit/af548e31941bf293429e23ea9c7ab2921103619b


## System and architecture

```elixir
System.version()
System.otp_release()
:erlang.system_info(:version)
:erlang.system_info(:system_architecture)
:erlang.system_info(:schedulers)
:erlang.system_info(:schedulers_online)
```

## Memory

- メモリの値を変換するコードがめっちゃ簡潔に綺麗に書かれています。
- `format_bytes/1`から`format_bytes/2`への2段階の処理が面白いです。
- `memory_unit/1`を（定数にせず）あえて関数にしている発想が参考になります。

```elixir
defmodule MyFormatter do
  def format_bytes(bytes) when is_integer(bytes) do
    cond do
      bytes >= memory_unit(:GB) -> format_bytes(bytes, :GB)
      bytes >= memory_unit(:MB) -> format_bytes(bytes, :MB)
      bytes >= memory_unit(:KB) -> format_bytes(bytes, :KB)
      true -> format_bytes(bytes, :B)
    end
  end

  def format_bytes(bytes, unit) when is_integer(bytes) and unit in [:GB, :MB, :KB] do
    value =
      bytes
      |> div(memory_unit(unit))
      |> round()
    "#{value} #{unit}"
  end

  def format_bytes(bytes, :B) when is_integer(bytes), do: "#{bytes} B"

  defp memory_unit(:GB), do: 1024 * 1024 * 1024
  defp memory_unit(:MB), do: 1024 * 1024
  defp memory_unit(:KB), do: 1024
end

MyFormatter.format_bytes(:erlang.memory(:total))
MyFormatter.format_bytes(:erlang.memory(:atom))
MyFormatter.format_bytes(:erlang.memory(:binary))
MyFormatter.format_bytes(:erlang.memory(:code))
MyFormatter.format_bytes(:erlang.memory(:ets))
MyFormatter.format_bytes(:erlang.memory(:processes))
```

## Statistics / limits

```elixir
:c.uptime()

:erlang.statistics(:run_queue)

print_percentage = fn min, max ->
  percentage = trunc(min / max * 100)
  IO.puts("#{min} / #{max} (#{percentage}% used)")
end

min = :erlang.system_info(:atom_count)
max = :erlang.system_info(:atom_limit)
print_percentage.(min, max)

min = :erlang.system_info(:ets_count)
max = :erlang.system_info(:ets_limit)
print_percentage.(min, max)

min = :erlang.system_info(:port_count)
max = :erlang.system_info(:port_limit)
print_percentage.(min, max)
```

## Phoenix LiveDashboard

Phoenix LiveDashboardにも似たようなものがあります。

https://github.com/phoenixframework/phoenix_live_dashboard/blob/d0f776f4bc2ba119e52ec1e0f9f216962b9b6972/lib/phoenix/live_dashboard/system_info.ex

## ご参考までに

https://speakerdeck.com/elijo/elixirkomiyunitei-falsebu-kifang-guo-nei-onrainbian

https://qiita.com/piacerex/items/e0b6e46b1325bb931122

https://qiita.com/torifukukaiou/items/1edb3e961acf002478fd

https://qiita.com/piacerex/items/e5590fa287d3c89eeebf

[Elixir]: https://elixir-lang.org/
[Erlang]: https://www.erlang.org/
[Phoenix]: https://www.phoenixframework.org/
[Nerves]: https://hexdocs.pm/nerves
[Livebook]: https://livebook.dev/
[IEx]: https://elixirschool.com/ja/lessons/basics/basics/#%E5%AF%BE%E8%A9%B1%E3%83%A2%E3%83%BC%E3%83%89
[Node | hexdocs]: https://hexdocs.pm/elixir/Node.html
[otp_distribution | elixirschool]: https://elixirschool.com/ja/lessons/advanced/otp_distribution
[Node.ping/1]: https://hexdocs.pm/elixir/Node.html#ping/1
[Node.connect/1]: https://hexdocs.pm/elixir/Node.html#connect/1
[Node.spawn/2]: https://hexdocs.pm/elixir/Node.html#spawn/2
[Node.list/0]: https://hexdocs.pm/elixir/Node.html#list/0
[Node.set_cookie/2]: https://hexdocs.pm/elixir/Node.html#set_cookie/2
[Node.get_cookie/0]: https://hexdocs.pm/elixir/Node.html#get_cookie/0
[Node.start/3]: https://hexdocs.pm/elixir/Node.html#start/3
[epmd]: https://www.erlang.org/doc/man/epmd.html
[Elixirの分散処理(Node)とMnesia]: https://qiita.com/sand/items/c5c9dab1dce3d5c526ee
[Elixir Distribution, ELI5]: https://medium.com/@pawel_dawczak/elixir-distribution-eli5-309193004119
[Node.start/3でエラーが出る場合にはepmdをバックグラウンド起動する]: https://qiita.com/zacky1972/items/cb3aa801a179322c56d6
[コマンドラインインタプリタ]: https://ja.wikipedia.org/wiki/%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%83%A9%E3%82%A4%E3%83%B3%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%97%E3%83%AA%E3%82%BF
[端末エミュレータ]: https://ja.wikipedia.org/wiki/%E7%AB%AF%E6%9C%AB%E3%82%A8%E3%83%9F%E3%83%A5%E3%83%AC%E3%83%BC%E3%82%BF
[Distributed Erlang]: https://www.erlang.org/doc/reference_manual/distributed.html
[ホスト名]: https://ja.wikipedia.org/wiki/%E3%83%9B%E3%82%B9%E3%83%88%E5%90%8D
[hexpm/elixir]: https://hub.docker.com/r/hexpm/elixir
[Distributed Erlang]: https://www.erlang.org/doc/reference_manual/distributed.html
[Erlang Runtime System]: https://www.erlang.org/doc/system_architecture_intro/sys_arch_intro#erlang-runtime-system
[Linux]: https://ja.wikipedia.org/wiki/Linux
[Docker]: https://ja.wikipedia.org/wiki/Docker
[:rpc.call/4]: https://www.erlang.org/doc/man/rpc.html
[:application.get_key/2]: https://www.erlang.org/doc/man/application.html#get_key-2
[:code.all_loaded/0]: https://www.erlang.org/doc/man/code.html#all_loaded-0
[IEx.Helpers.runtime_info/0]: https://hexdocs.pm/iex/IEx.Helpers.html#runtime_info/0