💡
runtime_infoをファイルに出力する
iex には runtime_info/0
という関数が用意されている。実行すると現在動作している VM の情報をターミナルへと表示する。
この実装は関数の中で IO.puts/2
や IO.write/2
を使って行われている。また runtime_info/0
は IO の出力先を変更できるような引数は取らない。この制約下で、通常の IO.puts/2
は標準出力へと出力し、runtime_info
の結果のみをファイルへと出力することはできるだろうか。プログラムを書き換えなくとも Process.group_leader/2
をうまく使うとできることがわかった。
❯ iex
Erlang/OTP 22 [erts-10.6.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe]
Interactive Elixir (1.10.0-rc.0) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> runtime_info()
## System and architecture
Elixir version: 1.10.0-rc.0
Erlang/OTP version: 22
ERTS version: 10.6.2
Compiled for: x86_64-apple-darwin18.7.0
Schedulers: 8
Schedulers online: 8
## Memory
Total: 36 MB
Atoms: 331 KB
Binaries: 256 KB
Code: 5 MB
ETS: 538 KB
Processes: 19 MB
## Statistics / limits
Uptime: 4 seconds
Run queue: 1
Atoms: 11856 / 1048576 (1% used)
ETS: 23 / 8192 (0% used)
Ports: 3 / 65536 (0% used)
Processes: 57 / 262144 (0% used)
Showing topics: [:system, :memory, :limits]
Additional topics: [:allocators, :applications]
To view a specific topic call runtime_info(topic)
# puts_tuntime_info_to_file.exs
#
# セットアップ
#
# 出力の変更先に使うため、ファイルのio_deviceを取得する
file = File.open!("./runtime_info.txt", [:write])
# 変更後また元に戻せるように、デフォルトのgroup_leaderを変数に保持しておく
# (デフォルトのgroup_leaderは文字を標準出力へと出力するio_deviceとなっている)
original = Process.group_leader()
# 新しいgroup_leaderとして、文字をファイルへと出力するio_deviceを設定する
Process.group_leader(self(), file)
#
# 実行
#
IEx.Helpers.runtime_info()
#
# 後始末
#
# group_leaderをデフォルトへと戻す
Process.group_leader(self(), original)
# デフォルトのgroup_leaderに戻っているので、この文字列は標準出力から出力される
IO.puts("back to original group leader")
- 実行前は runtime_info.txt が存在しない
- 実行すると標準出力に
back to original group leader
と表示されている - 実行後は runtime_info.txt が存在し
runtime_info()
の結果が出力されている
ので期待通りに動いていることがわかる。
❯ cat runtime_info.txt
cat: runtime_info.txt: No such file or directory
~/src/niku.github.io source*
❯ elixir puts_runtime_info_to_file.exs
back to original group leader
~/src/niku.github.io source*
❯ cat runtime_info.txt
## System and architecture
Elixir version: 1.10.0-rc.0
Erlang/OTP version: 22
ERTS version: 10.6.2
Compiled for: x86_64-apple-darwin18.7.0
Schedulers: 8
Schedulers online: 8
## Memory
Total: 24 MB
Atoms: 387 KB
Binaries: 14 KB
Code: 7 MB
ETS: 547 KB
Processes: 4 MB
## Statistics / limits
Uptime: 0 seconds
Run queue: 1
Atoms: 14791 / 1048576 (1% used)
ETS: 19 / 8192 (0% used)
Ports: 3 / 65536 (0% used)
Processes: 48 / 262144 (0% used)
Showing topics: [:system, :memory, :limits]
Additional topics: [:allocators, :applications]
To view a specific topic call runtime_info(topic)
このやり方は ExUnit の CaputureIO が標準出力を取得していたのを思い出して調べた結果思いついた。
Discussion