趣味は vaporware 造りですv0.0.0
プログラマー三大勉強はしたけど、実装はしたことないものといえば
CPU、OS、コンパイラーなのです1が、先日 ruby30th 誕生日会のキーノートで
matz が “Static Compiler for Ruby” という今はまだない vaporware
として
挙げていたのでこの static compiler を作ろうとなりました。
Goal
Ruby のコードを static compile できるようにする。
コンパイル先のターゲットは x86 とします。 ARM や RISC-V などは今回の実装ではターゲットにしないです。
とはいえすべての Ruby の機能を実装すると時間がかかりすぎるので個人で無理のない範囲 で作ろうとします。無理のない実装範囲は以下なのかなと
- 四則演算
- 変数
- メソッド
- 制御構文
- プリミティブ型
この5つの機能を実装する予定です。
実現する機能以外のことについて
5つの機能を実現すること以上のことはやらない予定です。 やらないこととしては 最適化 、 GC 、 外部ファイルで定義したメソッドやクラスの読み込みは実装しない予定です。 実装しない個人的意見を以下に書いていきます。
最適化は Ruby のコードを単純に 機械語 におとしただけでは現在の RubyVM より速くならないと考えているからです(要確認)。 LLVM IR などへの変換ではなく、 機械語 なのは LLVM をインストールする必要があるなどして 面倒なのが大きいです2。あとバージョン毎に LLVM IR が異なるのも現状では対応しにくい点となっています。
GC (Garbage Collection: ガベージコレクション) についてはそもそもクラスをサポートできない、 変数などのメモリを確保しておく時間が長いプログラムを対象としないので今回はスコープ外としています。
外部ファイル読み込みについてですが、外部ファイルの読み込みして コンパイル するだけなら そこまで問題にはならないと考えていますが、外部ファイルで定義された メソッド や クラス を 事前に コンパイル して最後に リンク するのは型が不定になるのでサポートするのは難しいと考えています。
実装方針
Goal までの実装は 低レイヤを知りたい人のためのCコンパイラ作成入門 を参考にすすめていきます。 最初に コンパイラー を実装するものとして C 言語 がたぶん勉強してきてうかぶと思います3。 C 言語 だと 機械語 や VM のバイトコードへ落とすことのできる資料が多いので選択しています。 とは言っても Ruby からの脳内変換はある程度必要なので慣れているというのもあります。
実装としては AST(Abstract Syntax Tree: 構文抽象木) から愚直に x86 アセンブラ をファイルへ書き出し、
そこから C コンパイラー (gcc
or clang
) をつかって機械語へ コンパイル します。
フルフルの Ruby を実装するわけじゃないので依存する gem の依存も極力減らしたいです。
実装環境
- CPU: Ryzen Thread Ripper 1950x
- gcc: 12.2.1
- clang: 16.0.0
- OS: Gentoo Linux
- Linux Kernel: 6.2 系
パーサー
まず、AST を得るために パーサー が必要なのですが、 Ruby の構文は複雑なのでここは頑張らないようにします。ここをどうやって解決するのかというと RubyVM::AbstractSyntaxTree
や Ripper
をつかうのか、parser.gem
をつかうのかを決めるひつようがあります。今回というかしばらくは parser.gem
を利用して AST を得ることにします。
ゆくゆくは RubyVM::AbstractSyntaxTree
への置き替えはするよていです。
ここはそのまま parser.gem
のチュートリアルどおりにすれば AST が得られます。
require "parser/current"
puts Parser::CurrentRuby.parse("(1 + 2) * 3 / (5 - 4)")
きょうはここまで
とりあえず手を動かしはじめましたが、ななななんと、似たような機能が実は Ruby 3.3 向けに JIT として入ったようです4。 ということでねこの話はね、勉強の話しかないんですが一旦 Goal まで作ってみましょうね。
Update rubygems using Rust for Ruby 3.2
以前このブログで Rust を利用して rubygems を作成した rust_uuid が Ruby 3.2 がリリース によりコンパイルできなくなったのでその修正顛末。
環境
system | failed version | succeed version |
---|---|---|
ruby | 3.2.0 | 3.2.0 |
gem | 3.4.1 | 3.4.2 |
bundler | 2.3.19 | 2.4.2 |
rb-sys | 0.9.29 | 0.9.53 |
magnus | 0.3.2 | 0.4.4 |
what’s happened?
Ruby 3.2 が出てたのでアップデートして試してみるかーとおもいコマンドを実行!!!!
$ bundle exec rake build
.
.
...
error[E0425]: cannot find value `RUBY_ABI_VERSION` in the crate root
--> /path/to/cargo/dir/registry/src/github.com-1ecc6299db9ec823/rb-sys-0.9.29/src/ruby_abi_version.rs:14:73
|
14 | pub const __RB_SYS_RUBY_ABI_VERSION: std::os::raw::c_ulonglong = crate::RUBY_ABI_VERSION as _;
| ^^^^^^^^^^^^^^^^ not found in the crate root
For more information about this error, try `rustc --explain E0425`.
error: could not compile `rb-sys` due to previous error
warning: build failed, waiting for other jobs to finish...
gmake: *** [Makefile:564: target/release/librust_uuid.so] エラー 101
rake aborted!
Command failed with status (2): [/usr/bin/gmake...]
/path/to/rbenv/versions/3.2.0/bin/bundle:25:in `load'
/path/to/rbenv/versions/3.2.0/bin/bundle:25:in `<main>'
Tasks: TOP => build => compile => compile:x86_64-linux => compile:rust_uuid:x86_64-linux => copy:rust_uuid:x86_64-linux:3.2.0 => tmp/x86_64-linux/rust_uuid/3.2.0/rust_uuid.so
(See full trace by running task with --trace)
bundle exec rake build 63.55s user 10.61s system 541% cpu 13.705 total
おーなるほどなるほど、 cargo の rb-sys が Ruby 3.2 に対応していないバージョンつかってるんだなと理解。cargo を更新っするぞい。
うpだて cargo ぱっけーじ
ということで cargo build
が通るようにパッケージを更新するぞい。
cargo も bundler 同様、 cargo update
でいい感じにアップデートしてくれます。
$ cd ext/rust_uuid
$ cargo update
$ cargo build
Compiling magnus v0.3.2
error[E0432]: unresolved import `crate::ruby_sys::ruby_rstring_consts`
--> /path/to/cargo/dir/registry/src/github.com-1ecc6299db9ec823/magnus-0.3.2/src/r_string.rs:23:47
|
23 | use crate::ruby_sys::{rb_str_to_interned_str, ruby_rstring_consts::RSTRING_EMBED_LEN_SHIFT};
| ^^^^^^^^^^^^^^^^^^^ could not find `ruby_rstring_consts` in `ruby_sys`
error[E0599]: no variant or associated item named `RSTRING_EMBED_LEN_MASK` found for enum `ruby_rstring_flags` in the current scope
--> /path/to/cargo/dir/registry/src/github.com-1ecc6299db9ec823/magnus-0.3.2/src/r_string.rs:368:38
|
368 | f &= ruby_rstring_flags::RSTRING_EMBED_LEN_MASK as VALUE;
| ^^^^^^^^^^^^^^^^^^^^^^ variant or associated item not found in `ruby_rstring_flags`
error[E0599]: no variant or associated item named `RSTRING_EMBED_LEN_MASK` found for enum `ruby_rstring_flags` in the current scope
--> /path/to/cargo/dir/registry/src/github.com-1ecc6299db9ec823/magnus-0.3.2/src/r_string.rs:968:42
|
968 | f &= ruby_rstring_flags::RSTRING_EMBED_LEN_MASK as VALUE;
| ^^^^^^^^^^^^^^^^^^^^^^ variant or associated item not found in `ruby_rstring_flags`
Some errors have detailed explanations: E0432, E0599.
For more information about an error, try `rustc --explain E0432`.
error: could not compile `magnus` due to 3 previous errors
cargo update
しましたが、やっぱり駄目でしたね。今度は magnus が駄目そう。
Cargo.toml
を見てみると、 magnus = { version = "0.3", features = ["rb-sys-interop"] }
と指定してあり、 version 0.3 系が駄目そうということが類推されます。ということで公式ページを見ると新しいバージョンが出ているのでこちらにします。
--- a/ext/rust_uuid/Cargo.toml
+++ b/ext/rust_uuid/Cargo.toml
@@ -10,7 +10,7 @@ crate-type = ["cdylib"]
[dependencies]
rb-sys = "0.9"
rb-allocator = "0.9"
-magnus = { version = "0.3", features = ["rb-sys-interop"] }
+magnus = { version = "0.4", features = ["rb-sys-interop"] }
[dependencies.uuid]
version = "1.1.2"
再度ビルド!
$ cargo update
$ cargo build
Compiling rust_uuid v0.1.0 (/home/katsyoshi/Program/Ruby/rust_uuid/ext/rust_uuid)
Finished dev [unoptimized + debuginfo] target(s) in 0.18s
おおっ通りました!やったね!
build
ということ cargo build
通ったので gem install
しましよう。
$ cd /path/to/rust_uuid
$ bundle exec rake build
cd tmp/x86_64-linux/rust_uuid/3.2.0
/usr/bin/gmake
generating target/release/librust_uuid.so (release)
cargo rustc --target-dir target --manifest-path ../../../../ext/rust_uuid/Cargo.toml --lib --release -- -C linker=gcc -L native=/path/to/rbenv/versions/3.2.0/lib -L native=/path/to/rbenv/versions/3.2.0/lib -L native=/home/katsyoshi/.local/lib:-L/home/katsyoshi/.local/lib: -C link-arg=-lm -l pthread
Compiling libc v0.2.139
Compiling proc-macro2 v1.0.49
Compiling quote v1.0.23
Compiling unicode-ident v1.0.6
Compiling clang-sys v1.4.0
Compiling regex-syntax v0.6.28
Compiling syn v1.0.107
Compiling rb-sys-env v0.1.1
Compiling libloading v0.7.4
Compiling nom v7.1.2
Compiling aho-corasick v0.7.20
Compiling magnus v0.4.4
Compiling bindgen v0.60.1
Compiling getrandom v0.2.8
Compiling uuid v1.2.2
Compiling cexpr v0.6.0
Compiling regex v1.7.0
Compiling magnus-macros v0.3.0
Compiling rb-sys-build v0.9.53
Compiling rb-sys v0.9.53
Compiling rb-allocator v0.9.6
Compiling rust_uuid v0.1.0 (/path/to/rust_uuid/ext/rust_uuid)
Finished release [optimized] target(s) in 12.03s
cd -
mkdir -p tmp/x86_64-linux/stage/lib/rust_uuid
/usr/bin/gmake install target_prefix=
generating target/release/librust_uuid.so (release)
cargo rustc --target-dir target --manifest-path ../../../../ext/rust_uuid/Cargo.toml --lib --release -- -C linker=gcc -L native=/path/to/rbenv/versions/3.2.0/lib -L native=/path/to/rbenv/versions/3.2.0/lib -L native=/home/katsyoshi/.local/lib:-L/home/katsyoshi/.local/lib: -C link-arg=-lm -l pthread
Finished release [optimized] target(s) in 0.02s
installing rust_uuid.so to /path/to/rust_uuid/lib/rust_uuid
/usr/bin/install -c -m 0755 rust_uuid.so /path/to/rust_uuid/lib/rust_uuid
cp tmp/x86_64-linux/rust_uuid/3.2.0/rust_uuid.so tmp/x86_64-linux/stage/lib/rust_uuid/rust_uuid.so
rake aborted!
Running `gem build -V /path/to/rust_uuid/rust_uuid.gemspec` failed with the following output:
WARNING: description and summary are identical
WARNING: open-ended dependency on benchmark-ips (>= 0, development) is not recommended
use a bounded requirement, such as '~> x.y'
WARNING: open-ended dependency on rake (>= 13.0.0, development) is not recommended
if rake is semantically versioned, use:
add_development_dependency 'rake', '~> 13.0', '>= 13.0.0'
WARNING: open-ended dependency on rake-compiler (>= 0, development) is not recommended
use a bounded requirement, such as '~> x.y'
WARNING: open-ended dependency on rb_sys (>= 0, development) is not recommended
use a bounded requirement, such as '~> x.y'
WARNING: open-ended dependency on rspec (>= 0, development) is not recommended
use a bounded requirement, such as '~> x.y'
WARNING: See https://guides.rubygems.org/specification-reference/ for help
ERROR: While executing gem ... (Gem::InvalidSpecificationException)
You have specified rust based extension, but Cargo.lock is not part of the gem files. Please run `cargo generate-lockfile` or any other command to generate Cargo.lock and ensure it is added to your gem files section in gemspec.
/path/to/rbenv/versions/3.2.0/bin/bundle:25:in `load'
/path/to/rbenv/versions/3.2.0/bin/bundle:25:in `<main>'
Tasks: TOP => build
(See full trace by running task with --trace)
bundle exec rake build 32.87s user 4.33s system 291% cpu 12.741 total
なるほど? Cargo.lock
ファイルもあるし問題なさそうだな。よくわからんので rubygems のリポジトリでエラーメッセージを探してみます。
すると以下のようなコードが
def validate_rust_extensions(builder) # :nodoc:
rust_extension = @specification.extensions.any? {|s| builder.builder_for(s).is_a? Gem::Ext::CargoBuilder }
missing_cargo_lock = !@specification.files.include?("Cargo.lock")
error <<-ERROR if rust_extension && missing_cargo_lock
You have specified rust based extension, but Cargo.lock is not part of the gem files. Please run `cargo generate-lockfile` or any other command to generate Cargo.lock and ensure it is added to your gem files section in gemspec.
ERROR
end
なろほどなろほど、プロジェクトの root 直下に置いておく必要があるのね。でもそのファイルどういうものなの?
gem, bundler update
ってなわけで、今度は正式に rubygems で正式にサポートされ、 bundler でも gem を作成するときにも bundle gem --ext=rust gem_name
でスケルトンが作成されるようになりました。ということでこれを利用して Cargo.toml
を作ってみましょう
$ bundle gem --mit --ext=rust gem_name
ERROR: "bundle gem" was called with arguments ["rust", "gem_name"]
Usage: "bundle gem NAME [OPTIONS]"
ok, ok, これは bundler のバージョンが古いな
$ bundle version
Bundler version 2.3.19 (2022-07-27 commit 4f496f93e6)
さっきの PR は入ったのは Ruby 3.2 リリース直前なのでまだ入ってないよなとおもったけど、実際は Gemfile.lock
の BUNDLED WITH
が 2.3.19
を指定してるだけだったのです。
なので対象の 2 行を削除して bundle update
を実行し、続いて rust サポートした gem を生成して、 Cargo.toml
を見てみましょう。
$ bundle gem --mit --ext=rust gem_name
Creating gem 'gem_name'...
MIT License enabled in config
Changelog enabled in config
Initializing git repo in /path/to/rust_uuid/gem_name
create gem_name/Gemfile
create gem_name/lib/gem_name.rb
create gem_name/lib/gem_name/version.rb
create gem_name/sig/gem_name.rbs
create gem_name/gem_name.gemspec
create gem_name/Rakefile
create gem_name/README.md
create gem_name/bin/console
create gem_name/bin/setup
create gem_name/.gitignore
create gem_name/.github/workflows/main.yml
create gem_name/LICENSE.txt
create gem_name/CHANGELOG.md
create gem_name/Cargo.toml
create gem_name/ext/gem_name/Cargo.toml
create gem_name/ext/gem_name/extconf.rb
create gem_name/ext/gem_name/src/lib.rs
Gem 'gem_name' was successfully created. For more information on making a RubyGem visit https://bundler.io/guides/creating_gem.html
$ cat Cargo.toml
# This Cargo.toml is here to let externals tools (IDEs, etc.) know that this is
# a Rust project. Your extensions depedencies should be added to the Cargo.toml
# in the ext/ directory.
[workspace]
members = ["./ext/gem_name"]
resolver = "2"
というようなファイルが得られるので真似して作成しちゃいましょう。
[workspace]
members = ["./ext/rust_uuid"]
resolver = "2"
そうしたらもう一度ビルドしてしまいます!
$ cargo generate-lockfile
$ git add Cargo.toml Carog.lock
$ bundle exec rake build
/usr/bin/gmake install target_prefix=
generating target/release/librust_uuid.so (release)
cargo rustc --target-dir target --manifest-path ../../../../ext/rust_uuid/Cargo.toml --lib --release -- -C linker=gcc -L native=/path/to/rbenv/versions/3.2.0/lib -L native=/path/to/rbenv/versions/3.2.0/lib -L native=/home/katsyoshi/.local/lib:-L/home/katsyoshi/.local/lib: -C link-arg=-lm -l pthread
Compiling rust_uuid v0.1.0 (/path/to/rust_uuid/ext/rust_uuid)
Finished release [optimized] target(s) in 0.26s
installing rust_uuid.so to /path/to/rust_uuid/lib/rust_uuid
/usr/bin/install -c -m 0755 rust_uuid.so /path/to/rust_uuid/lib/rust_uuid
cp tmp/x86_64-linux/rust_uuid/3.2.0/rust_uuid.so tmp/x86_64-linux/stage/lib/rust_uuid/rust_uuid.so
rust_uuid 0.1.0 built to pkg/rust_uuid-0.1.0.gem.
$ bundle exec rake install
/usr/bin/gmake install target_prefix=
generating target/release/librust_uuid.so (release)
cargo rustc --target-dir target --manifest-path ../../../../ext/rust_uuid/Cargo.toml --lib --release -- -C linker=gcc -L native=/path/to/rbenv/versions/3.2.0/lib -L native=/path/to/rbenv/versions/3.2.0/lib -L native=/home/katsyoshi/.local/lib:-L/home/katsyoshi/.local/lib: -C link-arg=-lm -l pthread
Finished release [optimized] target(s) in 0.03s
installing rust_uuid.so to /path/to/rust_uuid/lib/rust_uuid
/usr/bin/install -c -m 0755 rust_uuid.so /path/to/rust_uuid/lib/rust_uuid
cp tmp/x86_64-linux/rust_uuid/3.2.0/rust_uuid.so tmp/x86_64-linux/stage/lib/rust_uuid/rust_uuid.so
$ bundle exec ruby -rrust_uuid -e 'puts RustUUID.v4'
2eb053de-8ae7-4669-853b-95f06c872300
ようやっと通ったああぁあ!!!!
conclusion
実際は11月の末あたりに head でコンパイルできないなあと気がついていたのですが、そのうち直るやろと思っててなにもしなかったのです。いざ Ruby 3.2 がリリースされたときに試して動かなかったのでやっと対応してみました。
ということで正式に Rust がサポートされるようになったのでまた YARUKI がでてきますね。
それはそうと今度は、jekyll が Ruby 3.2 で動かなくなった。
お名前ドットコムのメールがうざすぎたので DNS を Cloudflare に移行して快適生活
katsyoshi.org の登録先を お名前ドットコム にしてたけど、広告のようなメールとか届くし 更新案内と広告の違いがわからない感じのメールが大量にくるのでやめようやめようと思ってたのでいいかげん変えてみた話。
準備
準備として移行先のレジストラを選定します。 移行先としては普通のレジストラとクラウド業者がやっているレジストラがあると思いますが、今回は以下3つを候補にしました。
- Google Domains: Google がやっているやつ。メールとか Google なんで DNS まで Google にするのは心理的抵抗が強い。
- Route 53: みんなつかってる AWS のサービス。仕事で利用しているので、プライベートは別のがいいかな。
- Cloudflare の DNS: みんなだいすき低価格 CDN 業者の Cloudflare がやってる DNS サービス。
Google 、 AWS は言わずと知れた巨大企業でサービスがなくなるということはないとおもうが、 仕事で利用したり、情報全部預けたりしているところなので選択する理由が個人的には弱い。 個人利用でガンガン変えたり、 VPC でネットワーク構築するわけじゃないので Cloudflare でいいかなと。
お名前ドットコムでの作業
レジストラを移管する前に現在登録してある WHOIS 情報 を確認します。 これは移管作業で移管作業用コードが WHOIS 登録者にメールが送られてくるのでどのメールアドレスかの確認です。 ここでWHOIS 情報公開代行 を利用している場合は、 WHOIS を一旦登録時のものに変更します1。
移管
移管作業としては新規レジストラで移管依頼を参考に移管依頼ページを開きます。 開いたら、旧サービスから移管コードの発行を行ないます2。 移管コードを Cloudflare 側で入力してしばし待機。
しばらくしたら、レコードが登録されるので完了です。
おわり
ということで DNS の登録を Cloudflare へ移管しました。 お名前ドットコム はあのメールさえなければ続けたのかもしれない。 が更新警告と普通のメールの違いがあまりにもわからないので捨てることにしました。 Cloudflare で不満があったらまた変更すると思いますが、快適な生活になりました(たぶん
Communicate on IPv6 from home
家のネットワークからインターネットへ出るとき IPoE
を使ってたけど、家庭内 LAN のネットワークは IPv6
を off にしていた。
この LAN 内 IPv6
化していなかった理由としては、昔 Linux (だけじゃないかも)が IPv6
が利用できる状態だと
先に IPv6
で繋ぎにいこうとして IPv6
で通信できなかったら IPv4
にフォールバックするという挙動で、すごくストレスフルだった。
この挙動の対処として、カーネルレベルで IPv6
を off にしてました。
そうこうしているうちに契約している ISP が IPv6
オプションなしで IPoE
を利用できるようになったので、
とりあえず IPoE
だけを利用できるようにして、家庭内の LAN はそのままという状態にしていました。
いいかげんこの家庭内 LAN のネットワークを IPv6
化し、インターネットと IPv6
で通信できるようにした顛末をのこす。のこします。
家庭内 LAN 環境
- ゲートウェイ: NEC IP38X/1210 (YAMAHA RTX1200)
- PC: 6.0.0-gentoo
IPoE 化と家庭内 LAN の IPv6 化
設定は YAMAHA の設定例集に載ってあるのでそれを参考にします。
IPoE
化はこの設定例でいけるのですが、どうも設定したときにミスったらしく、 LAN の IP アドレスが IPv4
ではインターネットへ出ることができるが、
IPv6
ではインターネットへ出ることができない状態になってしまいました。
旧設定
どのような設定だったかは以下に
ip route default gateway tunnel 1
ipv6 prefix 1 ra-prefix@lan2::/64
ipv6 lan1 address ra-prefix@lan2::1/64
ipv6 lan1 prefix ra-prefix@lan2::/64
ipv6 lan1 rtadv send 1
ipv6 lan1 dhcp service server
ipv6 lan2 address auto
ipv6 lan2 secure filter in 1010 1011 1012 2000
ipv6 lan2 secure filter out 3000 dynamic 100 101 102 103 104 105 106
ipv6 lan2 dhcp service client ir=on
ngn type lan2 ntt
tunnel select 1
tunnel encapsulation ipip
tunnel endpoint address 2404:8e00::feed:100
tunnel enable 1
ipv6 filter 1010 pass * * icmp6 * *
ipv6 filter 1011 pass * * tcp * ident
ipv6 filter 1012 pass * * udp * 546
ipv6 filter 2000 reject * * * * *
ipv6 filter 3000 pass * * * * *
ipv6 filter dynamic 100 * * ftp
ipv6 filter dynamic 101 * * domain
ipv6 filter dynamic 102 * * www
ipv6 filter dynamic 103 * * smtp
ipv6 filter dynamic 104 * * pop3
ipv6 filter dynamic 105 * * tcp
ipv6 filter dynamic 106 * * udp
この設定ではインターネットとは IPv4
でしか通信できていない状態でした。
でこのトラブルシュートとして知人(@n_kane, @paina) のちからを借りてどこまで通じてどこから通じないかを確認しました。
troubleshooting
とりあえず ping6
、 traceroute6
で通じていないことを確認します。
$ ping6 -c 3 google.com
PING google.com(nrt13s55-in-x0e.1e100.net (2404:6800:4004:824::200e)) 56 データ長(byte)
--- google.com ping 統計 ---
送信パケット数 3, 受信パケット数 0, パケット損失 100%, 時間 2067ミリ秒
$ traceroute6 google.com
traceroute to google.com, 30 hops max, 80 byte packets
1 * * *
2 * * *
3 * * *
4 * * *
5 * * *
6 * * *
7 * * *
8 * * *
9 * * *
10 * * *
11 * * *
12 * * *
13 * * *
14 * * *
15 * * *
16 * * *
17 * * *
18 * * *
19 * * *
20 * * *
21 * * *
22 * * *
23 * * *
24 * * *
25 * * *
26 * * *
27 * * *
28 * * *
29 * * *
30 * * *
通ってないですね。
先述したように PC は IPv6
を on にしたばかりなのでクライアント側の設定でブロックしていないかを確認します。
まずクライアント側で考えられるのは iptables
でのパケットフィルタリングですね。
ルーターの下にある PC なので、ここでブロックすることは低いのですが、確認します。
# ip6tables --list
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
なにもフィルタリングしていないですね。 ということで、クライアント側には問題なさそうですね。 どこまで通じてどこまで通じていないのか別のエンドポイントで確認します。
まず、手元と相手で tcpdump
利用してパケットが送っているか届いているかを確認します。
# tcpdump -nei enp8s0f0 icmp6
dropped privs to pcap
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on enp8s0f0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
22:35:41.158558 00:a0:de:69:40:9d > 33:33:ff:51:5e:63, ethertype IPv6 (0x86dd), length 86: fe80::212:e2ff:fe70:6144 > ff02::1:ff51:5e63: ICMP6, neighbor solicitation, who has 2409:10:a5c0:1f00:d903:ddb5:851:5e63, length 32
22:35:58.765783 ee:60:51:38:43:9c > 33:33:ff:00:00:01, ethertype IPv6 (0x86dd), length 86: 2409:10:a5c0:1f00:5ce3:afcb:9bb2:5c1b > ff02::1:ff00:1: ICMP6, neighbor solicitation, who has 2409:10:a5c0:1f00::1, length 32
22:36:09.249427 ee:60:51:38:43:9c > 33:33:ff:00:00:01, ethertype IPv6 (0x86dd), length 86: 2409:10:a5c0:1f00:5ce3:afcb:9bb2:5c1b > ff02::1:ff00:1: ICMP6, neighbor solicitation, who has 2409:10:a5c0:1f00::1, length 32
送れてはいるようで対向側にも届いていたらしく戻りのパケットは送ってたようですが、手元では戻ってくるパケットは見えていないですね。
ということはやはりルーターの設定が悪そうということが推察されますね。 設定のどこが悪いのかあやしいところを見ていきます。
最初に怪しいとおもったのはルーターのフィルターまわりです。一旦、no ipv6 interface secure filer in
で全部無効化しましょう。しかしとくに変りはないです。これはフィルターが原因ではなさそうですね。
次にあやしい点は以下2つの設定
上のコマンドは ISP から自動で振ってきている IP を割り当てる設定で、下のコマンドは ISP から振ってきた IPv6
のプレフィックスを付けるようにするための設定となります。
どうもこの下のコマンドが邪魔なようです。
no ipv6 interface prefix
で無効化できるので一旦外してみましょう。
すると
$ ping6 -c 3 google.com
PING google.com(nrt20s18-in-x0e.1e100.net (2404:6800:4004:81c::200e)) 56 データ長(byte)
64 バイト応答 送信元 nrt20s18-in-x0e.1e100.net (2404:6800:4004:81c::200e): icmp_seq=1 ttl=57 時間=6.53ミリ秒
64 バイト応答 送信元 nrt20s18-in-x0e.1e100.net (2404:6800:4004:81c::200e): icmp_seq=2 ttl=57 時間=2.73ミリ秒
64 バイト応答 送信元 nrt20s18-in-x0e.1e100.net (2404:6800:4004:81c::200e): icmp_seq=3 ttl=57 時間=2.81ミリ秒
--- google.com ping 統計 ---
送信パケット数 3, 受信パケット数 3, パケット損失 0%, 時間 2002ミリ秒
rtt 最小/平均/最大/mdev = 2.731/4.023/6.532/1.773ミリ秒
のように通りました!勝ったッ!第三部完!
おわり
以前中途半端に設定したおかげで IPv6
有効化に時間が掛ってしまった顛末をまとめました。
これで家のネットワークから IPv6
で通信できるようになりました。
ありがとうございました!
次回 katsyoshi.org お名前.COM やめるってよ
RubyKaigi 最高!
RubyKaigi 2022 に行ってきました! ので感想を
DAY 0
今回も やんちゃハウス に楽をして泊まることにしてたのでなにも気にせず宿へ。 着いて他メンバーが来るまで宿で待機してたが、最寄り駅の周りが思った以上になにもなく、途方に暮れてました。
夕飯
もうひとり宿に着いたので入れ変わりで夕飯へ出かけたが、そもそも最寄り駅前にはなにもないので伊勢駅まで出ることにした。
この判断が間違えてたようで、伊勢駅に出てもとくに変らなかった。しかし幸い伊勢駅前に担々麺屋があったのでそこで食料摂取した。
DAY 1
この日の聞いたセトリと感想は以下のとおり
Ruby meets WebAssembly: presentation
この日のキーノートは Ruby
の wasm
対応の話で wasi
を通じてブラウザで Ruby
が動かすまでのたのしいことをしゃべってたようです。
おなかいたくてトイレ行ってたら面白いところ聞き逃がしてしまった。
ランチ
適当に幕の内弁当を最初に選択。
Making *MaNy* threads on Ruby: presentation
笹田さんの発表で如何に Ruby
で CPU をフルに使えるようにするかの話。 Ruby
での Thread
のはなしから Ractor
を利用してフルフルに CPU 利用するための書きかたとかの話していました。
Building a Lightweight IR and Backend for YJIT: presentation
Ruby 3.1
で YJIT
が入って Ruby 3.2
でサポートされる CPU アーキテクチャが増えたはなし。RubyVM(?) に YJIT
用 Ruby IR
を作成して JIT
を実行するという話。
聞いてて疑問になった点としては、 Ruby IR
では直接機械語に翻訳しているようだったが、このバックエンドに LLVM
を利用していないのはなんでなんだろう。聞き逃がしているという話はあるので、詳しいひと教えて。
Tools for Providing rich user experience in debugger: presentation
debug.gem
を VS Code
だけじゃなく、 Chrome
のリモートデバッグ機能を利用したデバッグの話でした。
この機能自体はすごく便利だと思うのですが、そもそも両方とも宗教上の理由で利用できない体なので聞くだけでした。
TRICK 2022 (Returns): repos
いつも通り 変な エキセントリックなプログラムしか出てこなかったし、いつもの面子が賞もらってたのですごいなーという感想。
夕飯
この日は津駅があまりなさそうだったので、駅近くで飲むのではなく、宿寄りの場所松坂駅で飲むことにした。 ここで、津の夜情報を聞き込んだり、朝ごはん情報自体を仕入れてました。
昨日の夕飯 #rubykaigi pic.twitter.com/G8lmetYX9J
— katsyoshi (@katsyoshi) September 8, 2022
DAY 2
2日目は、ネットワークが不安定になったりしてこちらの集中力が切れたりしたのであまり覚えていない。
朝ごはん
前日の夕飯に教えてもらった市場の人向け食堂が松坂駅前にあり、その食堂で食事をした。
朝メッシ #rubykaigi pic.twitter.com/PvbaUrRUIf
— katsyoshi (@katsyoshi) September 8, 2022
Matz Keynote: presentation
Do Pure Ruby Dream of Encrypted Binary Protocol?: presentation
ノーコメント。
ランチ
この日も一番に弁当を取得。弁当はみんな大好き松坂牛ローストビーフ丼にした。感想としては、もう肉はいいかな。
昼飯 #rubykaigi pic.twitter.com/vpOf6Uwf0K
— katsyoshi (@katsyoshi) September 9, 2022
自キKaigi
きょうも #自キKaigi やります。ランチ食べたらスポンサーエリアの手前あたりにお集まりください #rubykaigi
— 🇺🇦hasumikin🇺🇦 (@hasumikin) September 8, 2022
誘われたので参加しました。iPad で活動しようと思い corne 持っていってたので参加してた。
Ruby x BPF in Action: How important observability is: presentation
Hunting Production Memory Leaks with Heap Sampling: presentation
このあたりネットワークが不安定になり、セッションが中断されたりしたためあまり覚えていない。
立ち話
久し振りの対面での参加だったのでセッションあまり聞かずに受け付け前で立ち話している人たちがいたので、その立ち話に参加した。 たまたま、最近読んでる本の翻訳者がいたのでこれからの話などを聞いたりしていた。
Caching With MessagePack: presentation
Ruby Committers vs The World
夕飯
夕飯は、駅近くのお店でかるく3人で。
いまどこ
— tagomoris (@tagomoris) September 9, 2022
こんなリプライがきてたようなので一緒にいたひとにまかせた。ギリギリまで粘ってたので帰宿後すぐ就寝。
DAY 3
3日目はそもそも前2日の疲れが出たりしたのかほとんど覚えていない。あと ruby puzzle をやっていてセッションをあまり聞けていない。
朝ごはん
今日も一日 #rubykaigi pic.twitter.com/PKnj8sHxwE
— katsyoshi (@katsyoshi) September 9, 2022
Megaruby - Running mruby/c programs on Sega Mega Drive: presentation
これに間に合うように出たはずだったが、間に合わず聞いていた。メガドライブすげえ。
Automatically Find Memory Leaks in Native Gems: presentation
Fast data processing with Ruby and Apache Arrow: presentation
Fixing Assignment Evaluation Order: presentation
Stories from developing YJIT: presentation
まとめ
3年ぶりの現地開催だったので参加してきました。対面での参加はやはりよいもので新しい出会いや、疑問を本人、解っている人に直接聞くことができてすばらしい体験でした。
三重について
三重県の酒のイメージは、行く前は「作」「 而今」「伊勢角谷屋麦酒」というイメージでした。 とくに日本酒は美味しいイメージがあり、知らない日本酒もあったりするんだろうなあと思っていました。 行ってみると日本酒はイメージと変わらないのですが、だいたい似た味の傾向で飽きるというかなんというか 美味しいんだけど、好きじゃないという感想になってしまった。 ビールについては瓶ビールしか飲まなかったので感想はなしで。
三重は大きな街が比較的分散しているようで、津も松坂も伊勢も鳥羽も駅前が小さく感じました。 とくに0日目の食事が大変で、調達が難しかった。
Ruby gem で Rust をつかって爆速にしたい!!!!!!11
Ruby Gems で Rust が Native として利用可能になった のでとりあえず UUIDv4
を生成してみた。
リポジトリ
準備
Ruby 側の gem
に Rust を利用する準備として rb_sys
と rake-compiler
を利用します。この二つの gem
は native compile するためにインストールしておきます。
Rust 側から Ruby へ関数を公開するために rb-sys
と magnus
を利用します。
gem install
とりあえず cargo
で Rust のパッケージを作って Rust を書いてみます。
> bundle gem rust_uuid --mit --ext rust_uuid # --ext を指定してnative build する gem を作成
> cd rust_uuid # 作成した gem のディレクトリへ移動
> cd ext/rust_uuid # ビルドするディレクトリへ移動
> cargo init . --lib # cargo を初期化
> rm -f *.c *.h # C のファイルが生成されるので削除
> cargo add rb-sys rb-allocator
> cargo add magnus --features rb-sys-interop
> cargo add uuid --features v4 # uuid v4 を指定
ext/rust_uuid/extconf.rb
を以下のように編集します。
@@ -1,5 +1,6 @@
# frozen_string_literal: true
require "mkmf"
+require "rb_sys/mkmf"
-create_makefile("rust_uuid/rust_uuid")
+create_rust_makefile("rust_uuid/rust_uuid")
次に ext/rust_uuid/src/lib.rs
を以下の様に変更します。
use magnus::{define_module, function, prelude::*, Error};
use rb_allocator::ruby_global_allocator;
use uuid::Uuid;
ruby_global_allocator!();
// UUIDv4 を文字列として公開
fn v4() -> String {
Uuid::new_v4().to_string()
}
#[magnus::init]
fn init() -> Result<(), Error> {
let module = define_module("RustUUID")?;
// RustUUID.v4 と利用するようにシングルトンメソッドを定義
module.define_singleton_method("v4", function!(v4, 0))?;
Ok(())
}
これまでできたら一旦 Rust をコンパイルしましょう。
> cd ext/rust_uuid
> cargo build
> git add .
> rake build
.... # install cargo dependencies and packages
cp: '/home/katsyoshi/Program/Ruby/rust_uuid/tmp/x86_64-linux/rust_uuid/3.1.2/target/release/librust_uuid.so' を stat できません: そのようなファイルやディレクトリはありません
gmake: *** [Makefile:551: foo_bar.so] エラー 1
rake aborted!
Command failed with status (2): [/usr/bin/gmake...]
Tasks: TOP => build => compile => compile:x86_64-linux => compile:foo_bar:x86_64-linux => copy:rust_uuid:x86_64-linux:3.1.2 => tmp/x86_64-linux/rust_uuid/3.1.2/rust_uuid.so
とエラーになります。
これは ext/rust_uuid/Cargo.toml
の設定が足りていません。そこで以下を追加してみてください。
[lib]
crate-type = ["cdylib"]
追加したら gem
をビルド&&インストール&&試してみましょう!
> rake install
....
> ruby -rrust_uuid -e 'puts RustUUID.v4'
2be6f4d2-200b-4d08-9a1a-11fa523b316b
べんちまーく
以下、 SecureRandom.uuid
との比較用のベンチマークコードを示します。
require "benchmark/ips"
require "securerandom"
require "rust_uuid"
Benchmark.ips do |x|
x.report("standard") { SecureRandom.uuid }
x.report("rust lib") { RustUUID.v4 }
x.compare!
end
結果発表〜
Rust を利用することでだいたい 5 倍ほど速くなっています。
> ruby bentimark.rb
Warming up --------------------------------------
standard 36.437k i/100ms
rust lib 177.585k i/100ms
Calculating -------------------------------------
standard 365.407k (± 1.4%) i/s - 1.858M in 5.086491s
rust lib 1.793M (± 1.8%) i/s - 9.057M in 5.053179s
Comparison:
rust lib: 1792925.9 i/s
standard: 365407.3 i/s - 4.91x (± 0.00) slower
ruby bentimark.rb 9.88s user 4.30s system 99% cpu 14.175 total
TOO HAYAI
まとめ
簡単に Rust を利用して速くしてみました。
思った以上に速くなっていたので重い処理をする場合に C
や C++
以外でも簡単に利用できるようになって
選択肢が増えたのはよいことでした。
実はこの uuid
crate の features に fast-rng
を追加すると 10 倍速くなるんですが、 ruby 側の終了時に SEGV
してしまうので載せていないです。 SEGV
しないように原因を調査などはまた今度。
Hello, Wezterm
tmux
+ Allacritty
が疲れてきたのではてぶで流れてきた wezterm
が sixel
を利用できてよさそうだったので試してみることにした。
設定
設定ファイルが lua でカスタマイズがいろいろとできるのでまずは色を代えてみます。
local wezterm = require 'wezterm'
return {
color_scheme = "Dracula",
}
プログラミング言語でカスタマイズができるので以下のようにアクティブなタブへの移動のキーバインドのカスタマイズができます。
local wezterm = require 'wezterm'
local move_keys = {}
for i = 1, 9 do
table.insert(move_keys, {
key = tostring(i),
mods = "CTRL",
action = wezterm.action{ ActivateTab = i - 1, },
})
end
return {
color_scheme = "Dracula",
disable_default_key_bindings = true, -- 初期のキーバインドは利用しない場合
keys = move_keys,
}
こんな感じで設定できるので便利です。
このキーバインドは任意のイベントも設定でき、任意のイベントを利用してアクションを定義できます。以下の例では、Paneを開い監視用のプログラムを開きます。
local wezterm = require 'wezterm'
wezterm.on("open-nvtop-and-ytop", function(win, pane)
win:perform_action(wezterm.action{ SplitHorizontal = { domain = "CurrentPaneDomain", args = { "nvtop", }, }, }, pane)
win:perform_action(wezterm.action{ SplitVertical = { domain = "CurrentPaneDomain", args = { "ytop", "-ps", }, }, }, pane)
end)
return {
keys = { { key = "r", mods = "CTRL", action = wezterm.action{ EmitEvent = "open-nvtop-and-ytop", }, }, },
}
とすると以下のようになります。
便利!
こんな便利なものということで systemd
でデーモン化しています。
[Unit]
Description=GUI Accellarated terminal
Documentation=
[Service]
Type=forking
ExecStart=/usr/local/bin/wezterm-mux-server --daemonize
Restart=on-failure
[Install]
WantedBy=default.target
で起動しておいています
問題点
と設定ファイルの例書いてみたのですが、とても大きな問題点にブチあたったので書いておきます。
wezterm
には wezterm-mux-server
というマルチプレクサ(tmuxのように扱うため)のサーバーモードプログラムがあるのですが、こいつがどうも wezterm
とは挙動が異なり、前述した監視用のキーバインドが微妙に異なった挙動となってしまっています。サーバーモードに接続した場合の挙動は以下のようになります。
1つ目はpaneの位置が期待したとおりになっていない。2つ目は ytop
が起動していないというので2つ目の方は気にしなければいいのでまあいいかと思っている。1つ目の問題は許容できていないので一旦はこのキーバインドは封印となっています。
おわり
長年利用してた tmux
を捨てて wezterm
を利用しはじめた。
設定が lua
で書けるのが体験的にとても良いのでこれからも利用するかなと。
wezterm
で sixel
利用した画像表示ができるようになったのが便利なので「よしっ!」
冬やすみ
冬やすみの間、やりたいこと、やっといたほうがいいやつをやってました。 ひとつは xremap の設定ともうひとつは CO2-mini から CO2 を見える ようにした。
今回は、 mackerel で見えるようになった CO2 の値を Slack へ定期的に投げるようにします。今回も Rust を利用しています。
準備
準備として、 mackerel 1 と Slack 2 両アプリケーションの投稿 API 用 Token をそれぞれ用意します。 各公式ページにあるように生成、取得するだけでよいです。
mackerel 側は ホストメトリック API を利用します。
Slack 側は chat.postMessage API を利用します。
各 API に対して取得した API Token を用いて curl
で確認しておきます。
実装
今回は対話式の bot ではないので、 RTM を利用せずに、HTTP クライアントだけで構成しています3。 Rust の HTTP クライアントとして hyper4 を利用します。 TLS は hyper_tls を利用しています。
実装とは言っても対象の mackerel の APIを叩き値を取得して、 その値を元に Slack へポストするだけです。
mackerel での値取得時に気をつける点としては、ホストメトリック API では host名
ではなく、
host id
がパラメーターとなっていますので注意が必要です。
まずレスポンスを入れる構造体を定義します。
#[derive(Deserialize)]
pub struct Metric {
pub time: i64,
pub value: i16, // 今回は co2 の値なので i16 としている
}
#[derive(Deserialize)]
pub struct ResponseMetrics {
pub metrics: Vec<Metric>,
}
つぎに以下のようにしてリクエストを組みたてて、値を取得しています。
let https = HttpsConnector::new();
let req = hyper::Request::builder()
.method(hyper::Method::GET)
.uri(url)
.header("X-Api-Key", api_key)
.body(hyper::Body::empty())?;
// https として request する
let client = hyper::Client::builder().build::<_, hyper::Body>(https);
let res = client.request(req).await?;
let body = hyper::body::aggregate(res).await?;
let json: ResponseMetrics = serde_json::from_reader(body.reader())?;
let metrics = json.metrics;
値を取得したら、今度は同じように Slack の方も構造体を定義します。
// リクエスト用構造体
#[derive(Serialize)]
pub struct SlackMessage {
pub channel: String,
pub sub_type: String,
pub text: String,
pub username: String,
pub as_user: bool,
}
// レスポンス用構造体
#[derive(Deserialize)]
pub struct PostMessage {
#[allow(unused)]
channel: String,
}
リクエストを組みたてて、POSTします。 見てわかると思いますが、ほとんど mackerel と変わらないです。
// リクエスト body を json に変換
let json = serde_json::to_string(&SlackMessage {
channel: "channel".to_string(),
sub_type: "bot_message".to_string(),
text: "message".to_string(),
username: "botname".to_string(),
as_user: true,
})?;
let https = hyper_tls::HttpsConnector::new();
let req = hyper::Request::builder()
.method(hyper::Method::POST)
.uri(url)
.header("Content-Type", "application/json")
.header("Authorization", format!("Bearer {}", get_env("SLACK_API_KEY")))
.body(hyper::Body::from(json))?;
let client = hyper::Client::builder().build::<_, hyper::Body>(https);
let res = client.request(req).await?;
let body = hyper::body::aggregate(res).await?;
let _json: PostMessage = serde_json::from_reader(body.reader())?;
ポストするメッセージを作る際に2つのことをしています。
まずは time
の UNIX EPOCH TIME からローカルの時間を表示するようにしています。
それと CO2 の値に依って絵文字を追加するかどうかを入れています。 -1
とか予定していない値が入ってきた場合は panic!
するようにしています。
// chrono を利用して unix time からローカルの文字列へ変換
let t = chrono::Local.timestamp(time);
let v = match value {
0..=700 => ":large_green_circle:",
701..=1000 => ":large_yellow_circle:",
1001.. => ":red_circle:", // なんで slack は :large_red_circle: を用意していないんだろうか
_ => panic!("unexpected number!!"),
};
こうやってポストされたメッセージは以下のようになります。
絵文字つきでポストされましたね。
まとめ
Rust で bot を作ってみました。 と言ってもただの HTTP クライアント な bot なだけですけど。 一旦 Slack でも見えるようになったので今度は Nature Remo と連携して気温や湿度での自動化ができたらいいな。
-
https://mackerel.io/ja/api-docs/ ↩
-
https://slack.com/intl/ja-jp/help/articles/215770388-API-%E3%83%88%E3%83%BC%E3%82%AF%E3%83%B3%E3%81%AE%E7%94%9F%E6%88%90%E3%81%A8%E5%86%8D%E7%94%9F%E6%88%90 ↩
-
公式の README にあるようにこの場合は reqwest を利用するほうがよかったかもしれない。TLS は直接 hyper が対応していなかったりしてすこし面倒です。 ↩
今年飲んだコーヒー豆の種類 2021
今年もコロナでどこにも行くにしても行きにくかったし、 店もどこもあまりやってなかったようだったので今年も酒ではないまとめを。
苦いコーヒーすこし飽きてきたなーとか、あんまり大量にのむのはなーと思ってたところ1に スペシャルティコーヒー専門店が近所にできていて、そこで飲んで教えてもらったコーヒーが 気に入りよく通うように。
普段の飲む量を1日1杯のみに抑えるために多少高くてもおいしい豆で1杯で満足できる豆を買うことにした。
豆
買ったというのがわかっている豆。
- HAMBELA WAMENA, HEIRLOOM, Natural, エチオピア
- Carmo De Minas Santuario Sul, Yellow Bourbon, Citrus Sweetness, ブラジル
- NYERI KARATINA, SL28SL32RUIRU11, Fully Washed, ケニア
- KAKAMEGA ISULU, SL28SL32RUIRU11, Natural Anaerobic, ケニア
- WEST ARSI GORA KONE, HEIRLOOM, Washed, エチオピア
- GEDEB WORKA, HEIRLOOM, Special Process Natural, エチオピア
- EL PARAISO RED FRUITS, CASTILLO, DOUBLE ANAEROBIC WASHED, コロンビア
- EL PARAISO LYCHEE, CASTILLO, DOUBLE ANAEROBIC WASHED, コロンビア
- NYERI MAGANJO, SL28SL32RUIRU11, Fully Washed, ケニア
- Fazenda Guariroba, Yellow Catuai, Double Fermentation Black Honey, ブラジル
感想
を書くつもりが、そもそも感想メモをほとんど残していなかった。いくつか残しているのでそれを。
- EL PARAISO RED FRUITS: 別ロットはピーチティのような感じであったが、今回はかなりフルーティな味でライチな感じです。
- Fazenda Guariroba: 香りが柑橘系というかレモンの香りがする。味はスッキリしてて口に含んだ酸味は少なく、後味としての酸味が強くのこって美味しい。
まとめ
1年くらい前に社内 Slack にコーヒーの感想をまとめるためのチャンネル作ったけど、 まったく活用していなくて感想がほとんど残っていない。 おいしいこと以外は思いだせるわけもなく……
-
ここ1,2年コーヒー飲みすぎると胃が痛くなるのに気がついた。 ↩
custom CO2-mini で CO2 を見えるようにしよう
コロナになって結構前に custom CO2-mini に 話題になった ので買って放置してあったの1 を活用しようと思いたった。 とりあえず値は取得はできているので mackerel との連携をしてグラフに表示できるようにします。 あと mercker-plugin を Rust で書いてみたいとおもったので、やってみることにしました。
以下のリポジトリにコードはあります。
mackerel plugin として作る
mackerel に投稿する前にこの custom CO2-mini が Rust で読めるのかを調査してみましたら、co2mon がピンズドな感じでありました。 確認としてセンサーの読み込みは co2mon の README の通り にやることで読みとることができます。
センサーの値が読み込めるようになったら、今度は mackerel へ投げれるようにします。 と言ってもやることは 公式にあるよう に以下のフォーマットで標準出力に出すだけのようです。
{metric name}\t{metric value}\t{unix epoch time}
ということなので適当に metric name を CO2MINI.co2/temp.living
2 にして出力しています。
mackerel-plugin として動かすために、 mackerel-agent.conf に以下のような設定を追加し、再起動することでグラフが追加できます。
[plugin.metrics.CO2MINI]
command = ["/path/to/build/bin/mackerel-plugin-co2mon"]
グラフは以下のように表示されました!やったね!
おわり
ずっとやろうやろうと思ってた Rust で mackerel のプラグイン作成、 面倒で先延しにしてたのですが、チョットやってみたらすぐにできたのでよかったです。 今後としては CO2 の値に応じて窓開けたりできるようにしたいなあと思っています3。