RubyKaigi 2026に行きました

id:taiseiueです。4/22~24に北海道は函館で開催されていた「RubyKaigi 2026」に参加しました。

rubykaigi.org

参加にあたっては金銭面だけでなく、飛行機やホテルの手配までSTORESさんにお世話になりました。ありがとうございます!

product.st.inc

函館までの道のり

大変だった。大阪空港発函館空港着で優雅なプランを考えていたところ欠航になり、大阪→新千歳→函館となかなかな旅程になってしまいました。

新千歳空港駅にあった北海道と本州のサイズ比較

Day1

いろいろ聴講していました。

RubyBox、ちょっと前まで名前空間と呼ばれていたやつですね。現在のコードが所属するBoxを取得するテクニックや上手にrequireする方法は目から鱗でした。タイトルも"Box Building"と"函館"がかかっていていいですね。

mruby on C#もよかったです。Kyoto.csを開催している手前、C#話題聞かねばと聴講しました。The state of C#/.NETのスライドがよかったです。C#もまだまだモダンです。

これはmatzとのツーショです。


懇親会にはマグロ解体ショーがありました。 こちらは解体される前のマグロです。

Day2

朝早起きをして函館朝市に行きました。これは海鮮丼(うにいくらまぐろカスタム)です。味噌汁からカニが出てきたのがびっくりポイントでした。

この日はブースラリーを周っていました。ブースラリーを周るとピンバッジがもらえました。メタルな五稜郭がなんともオシャレでいいですね。

この日は以下のセッションを聴講していました。

中でもFFIでの、"CよりRubyで書いたほうが速くなる"というのが印象的でした。そんなばかな....

お昼休みはSmartHRさん提供のワークショップでBoard43というマイコンと入出力機器のセットで遊んでいました。私はこういう、制約が強い環境でプログラミングをするのが好きなので時間を忘れてコードをこねていました。

これはブートローダー的なものを作って遊んでいる様子です。Board43はデフォルトでは/home/app.rbを起動するように出来ているため、ひとつのアプリケーションしか自動起動できないのですが、それをブートローダーとすることでファイルシステム内のファイルを選択して起動できるようにするというやつです。

画像だとちょっとわかりにくいですが、アプリケーションを0f0f0f.rbのようなファイル名で保存しておくと、その色を選択して起動できる、という仕掛けです。

その日の夜はSTORES CAFEというノンアルコールミートアップに参加していました。自分がまだ知らない世界や現場の話をいろいろと伺えて楽しかったです。

hey.connpass.com

その後はDay0にやりそこねた函館観光をしました。 こちらは100万ドルの夜景です。

Day3

この日は早起きして温泉に行きました。会場ほぼ向かいのホテル雨宮館さんです。

函館湯の川温泉・ホテル雨宮館 – 【公式】函館アリーナ徒歩1分。格安宿泊・サウナ・ペット同伴・無料駐車場100台完備。

普通に大浴場に入るとお湯の温度がかなり熱くてびっくりしてしまい、しばらくぬるめの隣の湯船で慣らしていました。湯船熱いですねという温泉コミュニケーションができました。

お風呂上がりの牛乳がおいしかったです。

この日は以下のセッションを聴講しました。

本筋とは関係ないですが正規表現エンジンのOnigumo、名前がかっこよくて好きです。Onigumo(とそれの前身にあたるOniguruma)はRubyのために開発されたものではないため、RubyによるRubyのための正規表現エンジンを開発している、といった話題でした。

KeynoteのSpinelも印象的でした。Spinelは面白い仕掛けで、Prismを使ってRubyをparseした後、そのASTからC言語のコードを生成し、C compilerに生成結果を渡すことでAOTを実現しているのです。一度rubyからCにトランスパイルするという発想は参考になりました。

また、お昼休みは書店にお邪魔していました。思わぬご縁でRuby超入門の著者さんに本をプレゼントしていただきました! igaiga555さんのサインとMatzのサイン両方が入った最強のRuby入門本でRuby入門していこうと思います。

その夜はRubyIlluminationsに参加しました。id:dominion525さんやいべりこさんにはお世話になりました!一緒に縦ノリできてよかったです。

おごもりさんに五稜郭イルミネーションを見せてもらったりもしていました。ゲーミング五稜郭シンバル欲しいすぎる!

Day4

ここからはおまけです。 飛行機まで若干余裕があったので、函館港をお散歩していました。 たまたま見かけたオルゴール堂に入るとオルゴールがいっぱい並んでいてすごかったです。

大き目のオルゴールをまじまじ見つめていると、店員さんが鳴らしてくださりました。オルゴールでありながら管楽器やパーカッションまで鳴っていました。調べてみると、これはボア・セレステというオルガン付きオルゴールだそうです。

kawaguchikomusicforest.jp

その後は空港に戻り、北海道に別れをつげる作業をしていました。

これは函館空港にあったパタパタ式表示版です。近畿だとまだ近鉄の駅にありますが、残り少ないそうなので撮ってみました。

帰りの飛行機はポケモンのロコンがテーマの機体でした。座席や機体、乗務員さんのエプロンまでロコン仕様でよかったです。

いかがでしたか

RubyKaigiの参加は去年に引き続き2回目ですが、去年セッションを聴講していたNamespaceのリリース後の話を聞けるなど、2回目にして"当事者感"が味わえて嬉しかったです。言語は生き物で、常に誰かが触りつづけている、そういう実感を改めて持てました。

また、多数のみなさんにお世話になりました。学生支援でお世話になったSTORESさんはもちろん、pixivさんやid:sushichan044さん、id:dominion525さん、igaiga555さん、いべりこさん、おごもりさんなどなど様々な方にお世話になりました。また来年、ないし関西Ruby会議でもよろしくお願いします!

ssh越しでもpbcopy,pbpasteできるようにする

世は大LLM時代。設定ファイルをLLMに食べさせて出力を貼りつける、なんてこともしばしば起きるようになった。

macにはpbcopy,pbpasteというコマンドがあって、pbpaste > config.confとかしてやるとクリップボードの中身がconfig.confに入るので、これをssh越しでも使えるようにしていきたい。

OSC52

世間にはOSC52というのがある。これは何かというと、ESC ] ... ESC \みたいな連続したシーケンスから成っていて、ssh越しでもOSに指令を与えたり、受けたりすることができるものだ。これを使って、pbcopyを実行したときにssh越しにクライアントOSにクリップボードの中身を渡せばいいし、pbpasteを実行したときはssh越しにクライアントOS にクリップボードの中身を要求すればいい。

この手のアプローチは結構有名で、詳細に書かれている先人の記事をあげておく。

zenn.dev

できたもの

できたものがこちら。 これをPATHを通しておくと、こんな風につかえる。

$ cat config.conf | pbcopy
$ pbpaste > config.conf

gist.github.com

便利ですね。

macOSを更新するとNix環境が使えなくなる

定期的に再発するのでメモ。

TL;DR

/etc/zshrcの先頭に以下の行を足してやるといい。

# Nix
if [ -e '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' ]; then
  . '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh'
fi
# End Nix

序論

ある日(YAPC::Fukuoka 2025のDay2に)macOSをアップデートしたらいつも使ってるコマンドにパスが通らなくなった。 おやや?と思って調べてみるとNixで入れたコマンドにパスが通ってなさそう。

このときは何かのはずみでNix環境が壊れたか?と思いNixごと削除して再度インストールしてしのいだ。

本論

macOS26.3に更新したときも再発。 流石に毎回再インストールするのは面倒なので、原因を調査したところ、$NIXPROFILESが空になってることに気付いた。

調べているとなぜかbashではNixが使えていそうなので調べてみると、/etc/zshrcからNix関係の記述が消えている。

$ cat /etc/bashrc | grep nix
            if [ -e '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' ]; then
     . '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh'
$ cat /etc/zshrc | grep nix

どうやらmacOSの更新をすると/etc/zshrcが元にもどってしまうようだ。

結論

macOSの更新後にNix環境が使えなくなったときはnix-daemonが実行されていないことがあるので、/etc/zshrcの先頭に以下の行を足してやるといい。

# Nix
if [ -e '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' ]; then
  . '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh'
fi
# End Nix

MCPパワーでClaudeにCosenseを書いてもらう

スマホからCosense書きにくい問題

私は普段メモ用にCosenseを使っているが、スマホからCosenseを書くのは結構難しい。 上手いことインデントがかけられなかったり、カーソルの移動が難しかったりと、結構普段使うにはむずいところがある。 そこで、yosider/cosense-mcp-server: An MCP Server for Cosenseをインターネット越しに使えるようにすることで、スマホのClaudeからCosenseを読み書きできるようにする。

MCPサーバーの建立

CosenseにアクセスするためのMCPサーバーとして、yosider/cosense-mcp-serverを使う。

github.com

このMCPサーバーはローカル動作を前提としていて、stdioで通信するため、インターネット越しに使えるようにするためにはstdioをHTTPに載せるいい感じのプロキシを使うことになる。 この手のニーズは既にあるようで、今回はその中でもメジャーなsparfenyuk/mcp-proxyを使うことにする。

github.com

mcp-proxyの導入

Node.js、pnpm、Cloudflare Tunnelの導入が別途必要

$ pnpm install -g mcp-proxy

あとは、

$ COSENSE_PROJECT_NAME=your_project_name \
   COSENSE_SID=your_sid \
   mcp-proxy --port 8080 -- pnpm -s dlx @yosider/cosense-mcp-server

で動作する。

your_project_nameは操作対象のプロジェクト名(例えばhttps://scrapbox.io/taiseiue なら"taiseiue")、your_sidはCosenseのセッションIDで置換する。 セッションIDはChromeでCosenseを開いて、以下の画像のように開発者ツールから値を取得する。

sidの取得

systemdで管理する

毎回コマンドを叩くのは面倒なので、サービスにしてsystemdで管理するようにする。

/etc/systemd/system/cosense-mcp.serviceに以下のように書く。your_usernameとyour_project_name、your_sidは各自置換されたい。

[Unit]
Description=Cosense MCP Server (mcp-proxy)
After=network.target

[Service]
Type=simple
User=your_username
WorkingDirectory=/home/your_username

Environment=COSENSE_PROJECT_NAME=your_project_name
Environment=COSENSE_SID=your_sid

ExecStart=mcp-proxy --port 8080 -- pnpm -s dlx @yosider/cosense-mcp-server

Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

後はインストールする

$ sudo systemctl daemon-reload
# 起動する
$ sudo systemctl start cosense-mcp

# ログを眺める
$ sudo journalctl -u cosense-mcp -f
Feb 25 13:23:26 lily systemd[1]: cosense-mcp.service: Scheduled restart job, restart counter is at 25.
Feb 25 13:23:26 lily systemd[1]: Started cosense-mcp.service - Cosense MCP Server (mcp-proxy).
Feb 25 13:23:26 lily systemd[1]: cosense-mcp.service: Main process exited, code=exited, status=203/EXEC
Feb 25 13:23:26 lily systemd[1]: cosense-mcp.service: Failed with result 'exit-code'.

パスが通っていなさそうなので、/etc/systemd/system/cosense-mcp.serviceにPATHを追加する。

[Service]
+ Environment=PATH=/usr/local/bin:/usr/bin:/bin:/home/your_username/.local/share/pnpm:/home/your_username/.local/share/mcp-proxy

その後、

$ sudo systemctl daemon-reload
$ sudo systemctl start cosense-mcp

$ sudo journalctl -u cosense-mcp -f

これで動作したので最後に以下のようにOS起動時に自動起動させる。

$ sudo systemctl enable cosense-mcp

Cloudflare Tunnelで公開する

動かしたMCPサーバーをCloudflare Tunnelで公開する。タダ乗りされると嫌なのでCloudflare Accessで認証も行う。

Cloudflare Tunnelでの公開は各自されたい。Cloudflare ZeroTrust>ネットワーク>トンネルから行える。

Cluodflare Accessで認証を設定する。まずはサービス資格情報を作成する。ここで生成された認証情報がOAuthトークンとシークレットになる。

サービス資格情報を作成する

次にポリシーから、先ほど作成した認証情報で認証を行うポリシーを作成する。

ポリシーの作成

最後にAccessアプリケーションを、セルフホスト用テンプレートで作成する。

アプリケーションの作成

これでMCPサーバーの構築は完了。

ClaudeにMCPサーバーを接続する

ClaudeのカスタマイズからMCPサーバーを接続する。

MCPサーバーの追加

上手く接続できるとこのようになる。

接続後の様子

試してみる

Cosenseの中身をリストさせている

Skillsの設定

Cosense記法はMarkdownと違うが、なかなかAIはMarkdown記法を使いたがるので、記法をSkillsに入れるようにした。 以下のページをExport for AIしてそれを読ませることでCosense記法をマスターしてもらう。

scrapbox.io

最終的にはこういうSkillsになった。

cosence-notation-skill.md · GitHub

自分で触った箇所としては、以下のようにClaudeが作成したこと、人間が見ていないことを識別できるようにタグを作成させるようにした。

##必須タグ
Claudeがコンテンツを作成・編集する際は、**必ずページの末尾に以下のタグを追加すること**:

#author:claude #waiting-review

- このタグはClaudeが作成・編集したことを示し、レビュー待ちを意味する
- ページの2行目に単独で記述する
- 省略不可

試してみる

例えば外出先でCosenseに面白いジョーク集を作りたくなった時に以下のようにやってもらえる。

iPhoneのClaudeアプリで書いてもらっている様子

より実践的な例だと、今日の日記を書いておいてもらえる。

日記もとい日報を書いてもらっている様子

どちらもそこそこちゃんと書けている。日報については、書きかたも空気を読んでいてくれていい感じ。

感想

そこそこ便利だと思ったけど、自分のメモ帳に知らない人が追記しているみたいな感覚でやや不気味だと思った。 ページだけ作っておいて、「あれ結局どういうことやったん」とか聞く分には便利かも。

JANOG57 NOCでログ班として活動していました

こんにちは。id:taiseiueです。 2/11~13に大阪で開催されていた、「JANOG57」にNOCとして参加していました。

私はサーバーチーム所属でログ班として、主にログの収集分析を担当していました。 この記事ではログ班の活動の様子を書いていきます。

構成

今回の構成は以下のような感じです。

ログの配送構成図

左側が受信形式、右側が配送先、中央がルーティングを行っている部分となります。

配送先にはGrafanaでアラートを発報したりダッシュボードを表示するためのGrafana Lokiに加え、OpenRoamingおよびeduroamを提供するにあたってのログ保存義務を全うするためにさくらのクラウドにあるさくらのログストレージに配送し、ログを保存しています。

また、Ciscoさまより提供いただいたSplunkにも配送することで、ログ分析を行いました。

様々なsyslog

今回、ログ配送にはGrafana Alloyを使用することにしました。 これは、promtailの後継として開発され、標準的な"整理された"syslog形式であるRFC5424を処理できます。また、ログのパースやラベル付けも可能です。

しかし、世間には様々なsyslogの形式があります。 今回のJANOGでは、以下のような形式のsyslogを受け取りました。

RFC3164: <PRI>TIMESTAMP HOSTNAME TAG: MSG
RFC5424: <PRI>VERSION TIMESTAMP HOSTNAME APP-NAME PROCID MSGID [STRUCTURED-DATA] MSG
YAMAHA: <PRI>MSG

RFC3164

RFC3164(BSD Syslog)は古くから存在するsyslogの形式です。 ネットワーク機器などでは、デフォルトでこれを送信するものが存在し、このためGrafana Alloyに直接送信させず、rsyslogで受け取りそれをrsyslogからGrafana Alloyに配送することで、RFC3164->RFC5424の変換を行いました。

具体的には、PRIの次のセクションに、TIMESTAMPが来るかVERSIONが来るかでsyslogの種類を識別し、正規表現の置換を使ってそれぞれを再配置していきました。

具体的には、以下のような処理を書いています。

janog57-noc/janog57-infra/ansible/roles/log/templates/rsyslog/20-generic.conf#L25-L38

YAMAHA形式

今回使用したYAMAHA製のルーターは、デフォルトではYAMAHA形式という独自のsyslog形式でログを送信するようでした。このため、こちらもrsyslogに一度送信し、YAMAHA->RFC5424の変換を行いました。

# YAMAHA形式(再掲)
<PRI>MSG

YAMAHA形式は、このようにVERSIONやTIMESTAMPがなくそのままメッセージセクションで始まるのが特徴です。このため、VERSIONもTIMESTAMPもない場合にYAMAHA形式として処理を行うようにしました。

具体的には、以下のような処理を書いています。

janog57-noc/janog57-infra/ansible/roles/log/templates/rsyslog/20-generic.conf#L39-L54

ログストレージ送信時のレート制限対策

次に、ログの送信先についてです。 先述の通り、今回はOpenRoamingおよびeduroamを提供するにあたってのログ保存義務を全うするためにさくらのクラウドにあるさくらのログストレージに配送していますが、さくらのログストレージには1000行/secのレート制限が存在します。 仮に5000台のクライアントが接続していて、同時にDHCP割り当てが起きた場合、余裕でレート制限に到達してしまう換算です。(このシナリオはDHCPサーバーの障害などで再割り当てを実行する必要があるときなどにありうる)

このため、一度ログをキューに保存し、1秒毎(実際には念のため1100ms)に1000行を上限にバッチ送信する作戦をとりました。キューは6000行設定しています。キューが溢れた分のログは破棄されます。

この値は負荷試験を実施して得ましたが、今考えると参加登録人数が6000人超で、ひとり2台(PC+スマホ)、1000行は処理できることを考えると、6000 * 2 -1000 = 11000、1万1000行程度は確保できるとよかったのかなと思います。

この部分は以下のコードのように定義しています。

janog57-noc/janog57-infra/ansible/roles/log/templates/alloy/config.alloy#L142-L172

ダッシュボード

前述の通りログのキューがあふれるとログの破棄が起きてしまい問題となるため、Grafana Alloyのメトリクスをscrape可能にし、メトリクス班のid:nekoy3さんがダッシュボードを作成してくださりました。

Grafana Alloyのダッシュボード

心配していたAlloyのキューですが、会期中は一度もあふれることなく、使用率も1%以下になっていました。

Alloyの送信キュー推移

定期的にスパイクしている箇所に朝が多いことから、接続時にDHCP割り当てなどのログが増加していることが推測できます。

障害対応フロー

ログが保存できていないことが発覚した場合、OpenRoamingとeduroamを復旧するまで停波してもらう必要があるため、ログ班では障害対応フローを策定しました。ちょっと長いですがこんな感じです。

#j57-noc-server で共有する > みんな

@channel ログで障害が発生中です。${その時点でわかっていることをここに書く}。

担当者は {障害対応フローへのリンク} を確認して対応にあたりましょう。

チームリーダー> @チームリーダー

ログ班> @ログ班

トリアージ > ログ班

各種状態確認

AlloyのGrafanaダッシュボード / Loki / さくらのログストレージ / Splunk (それぞれのリンク)

以下のどれか

  1. ログの受信ができていない
  2. ログの受信はできていて、Lokiとさくらのストレージのどちらにも送信できていない

    =>ログの収集が停止している

    eduroam,OpenRoamingを停波してもらう必要がある

  3. ログの受信はできていて、さくらのストレージまたはSplunkにログが送信できていない

    => ログの収集はできている

エスカレーション

eduroam,OpenRoamingを停波してもらう必要があるとき実施

全体周知

@channel サーバーチームのログ担当です。

ログが受信/保存できなくなっている疑いがあり対応中です。 この後ログの保存が必要なeduroamとOpenRoamingを停波していただきます。

会場: ${ここにスレッドのリンク}

APチーム

@channel サーバーチームのログ担当です。

ログが受信/保存できなくなっている疑いがあり、eduroamとOpenRoamingを一時的に停波していただきたいです。

会場: ${ここにスレッドのリンク}

告知 > 大人と相談

障害が起きはじめた時間を特定する

AlloyのGrafanaダッシュボード を見て決める

リーダーに続報を報告

復旧したら

eduroamとOpenRoamingを再開してもらう必要があるため、APチームに連絡する

会期後

logcliを使ってさくらのストレージに送れなかったログを調べる必要があるため、本番サーバーで下記コマンド実行

docker run --rm -it \
  --network monitoring_network
  -e LOKI_ADDR="http://loki:3100" \
  grafana/logcli:latest query '{job="syslog"}' --limit=0 --output=jsonl \
  --from="2026-02-09T00:00:00+09:00"  --to="2026-02-09T01:00:00+09:00"

開発環境改善

今回、Grafana Alloyとrsyslogの設定ファイルを書く機会が非常に多かったため、コードレビュー前に気付き、レビュー漏れをなくすためにCIとしてGitHubActions上で設定ファイルをdry-runするようにしました。

GrafanaAlloyはalloy validateという専用コマンドを、rsyslogは-N1という検証用のオプションを付けて実行しています。

最後に

チーム結成から会期中まで、学生リーダーのid:crashrtさんを始めチームのみなさんに非常にお世話になりました!特に最初の頃はAnsibleまったくわからんところから始まり、様々お手伝いしていただいたり沢山コードレビューをお願いしていました。 今回得た学びは今後のNOC活動にぜひ活かしていきたいと思います。

nixのhome-managerで入れたffmpegをAudacityで使う

Audacityでm4aなどを開きたくなったのでメモ。

Audacityでは、mp3やwav以外のファイルを開きたい場合はffmpegのライブラリ(具体的にはavformat-*.dylib)を使う必要がある。 しかし、普通にffmpegをhome-managerで入れると、ffmpegの実行バイナリしか出力されず、ライブラリが使えない。

解決

こう書く。

 home.packages = pkgs.lib.flatten (
    (with pkgs; [
    ffmpeg
    ffmpeg.lib
    ]));

こうすることで、ffmpegで使っているライブラリを~/.nix-profile/libで使うことができる。

Audacityの環境設定でffmpegの場所を手動で「~/.nix-profile/lib/」に設定する

余談

Nixで入れたAudacityはなぜか環境設定からffmpegライブラリの場所をえらべないので、brew caskなどで入れたもので設定するといい。

Nixで入れたAudacityの環境設定

brew casksで入れたAudacityの環境設定