株式会社はてなに入社しました
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を使う。
このMCPサーバーはローカル動作を前提としていて、stdioで通信するため、インターネット越しに使えるようにするためにはstdioをHTTPに載せるいい感じのプロキシを使うことになる。 この手のニーズは既にあるようで、今回はその中でもメジャーなsparfenyuk/mcp-proxyを使うことにする。
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を開いて、以下の画像のように開発者ツールから値を取得する。

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サーバーを接続する。

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

試してみる

Skillsの設定
Cosense記法はMarkdownと違うが、なかなかAIはMarkdown記法を使いたがるので、記法をSkillsに入れるようにした。 以下のページをExport for AIしてそれを読ませることでCosense記法をマスターしてもらう。
最終的にはこういうSkillsになった。
cosence-notation-skill.md · GitHub
自分で触った箇所としては、以下のようにClaudeが作成したこと、人間が見ていないことを識別できるようにタグを作成させるようにした。
##必須タグ Claudeがコンテンツを作成・編集する際は、**必ずページの末尾に以下のタグを追加すること**: #author:claude #waiting-review - このタグはClaudeが作成・編集したことを示し、レビュー待ちを意味する - ページの2行目に単独で記述する - 省略不可
試してみる
例えば外出先でCosenseに面白いジョーク集を作りたくなった時に以下のようにやってもらえる。

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

どちらもそこそこちゃんと書けている。日報については、書きかたも空気を読んでいてくれていい感じ。
感想
そこそこ便利だと思ったけど、自分のメモ帳に知らない人が追記しているみたいな感覚でやや不気味だと思った。 ページだけ作っておいて、「あれ結局どういうことやったん」とか聞く分には便利かも。
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さんがダッシュボードを作成してくださりました。

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

定期的にスパイクしている箇所に朝が多いことから、接続時にDHCP割り当てなどのログが増加していることが推測できます。
障害対応フロー
ログが保存できていないことが発覚した場合、OpenRoamingとeduroamを復旧するまで停波してもらう必要があるため、ログ班では障害対応フローを策定しました。ちょっと長いですがこんな感じです。
#j57-noc-server で共有する > みんな
@channel ログで障害が発生中です。${その時点でわかっていることをここに書く}。
担当者は {障害対応フローへのリンク} を確認して対応にあたりましょう。
チームリーダー> @チームリーダー
ログ班> @ログ班
トリアージ > ログ班
各種状態確認
AlloyのGrafanaダッシュボード / Loki / さくらのログストレージ / Splunk (それぞれのリンク)
以下のどれか
- ログの受信ができていない
ログの受信はできていて、Lokiとさくらのストレージのどちらにも送信できていない
=>ログの収集が停止している
eduroam,OpenRoamingを停波してもらう必要がある
ログの受信はできていて、さくらのストレージまたは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という検証用のオプションを付けて実行しています。
- janog57-infra/.github/workflows/log-alloy-validate.yml at main · janog57-noc/janog57-infra
- janog57-infra/.github/workflows/log-rsyslog-dryrun.yml at main · janog57-noc/janog57-infra
最後に
チーム結成から会期中まで、学生リーダーの
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などで入れたもので設定するといい。

NextcloudのジョブをGrafanaで監視できるようにする
こんにちは、
id:taiseiueです。
この記事は、はてなエンジニア Advent Calendar 2025 - Hatena Developer Blogの45日目の記事です。
昨日の記事は、
id:tunacookさんによるNaninovelのシナリオ文字カウントをするVSCode拡張を作った - ツナサンド定食でした。
今日の記事では、Nextcloudのジョブの状態を監視できるようにしてみます。
Nextcloudのジョブが実行されない問題
1年前くらいから、知人とDJスタジオを運営しており、その一環でDJプレイ中の録画を保管しておくためのNextcloudをRaspberry Pi 5で稼動しています。
普段の使用(アクティブユーザー>5くらい)までであれば問題なく動作するんですが、アクセスが集中したり、大容量の録画のプレビューを生成したりすると、上手くバックグラウンドジョブが実行されずに通知が送信されなかったり、管理画面で警告が表示されたりします。
そこで、今回はNextcloudのジョブの状態をGrafanaで監視できるようにすることをゴールにします。
Nextcloudのジョブはどう管理されているか
Nextcloudでジョブはoc_jobsテーブルで管理されています。 Nextcloud Version 32.0.3でのテーブルの構造はこんな感じでした。
MariaDB [nextcloud]> DESCRIBE `oc_jobs`; +--------------------+---------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +--------------------+---------------------+------+-----+---------+----------------+ | id | bigint(20) unsigned | NO | PRI | NULL | auto_increment | | class | varchar(255) | NO | MUL | | | | argument | varchar(4000) | NO | | | | | last_run | int(11) | YES | | 0 | | | last_checked | int(11) | YES | MUL | 0 | | | reserved_at | int(11) | YES | | 0 | | | execution_duration | int(11) | YES | | 0 | | | argument_hash | varchar(64) | YES | | NULL | | | time_sensitive | smallint(6) | NO | MUL | 1 | | +--------------------+---------------------+------+-----+---------+----------------+
last_runはそのジョブが最後に実行された Unix timestamp、execution_durationは直近実行時の処理時間が入っています。 この中のlast_runなどをメトリクスとしてPrometheusに送信できればいいわけですね。
ジョブの状態をPrometheusに送信する
作戦として、今回はexporterを自作するのではなく、cronで定期的にデータベースにジョブの状態を見に行ってテキストファイルに出力し、それをnode_exporterでPrometheusに送信するという素朴な方法を選んでみました。
cronでジョブの状態を見に行く
こんな感じのスクリプトを書いて、データベースにジョブの状態を引きに行ってprom形式で出力してあげます。
あとはcronにスクリプトを毎分実行するように登録しておきます。
* * * * * /usr/local/bin/nc-jobs-textfile.sh 2>&1
これでしばらくたつと/var/lib/node_exporter/textfile/nextcloud_jobs.promにメトリクスが出力されてきます。
Prometheusに送る
sudo systemctl edit prometheus-node-exporterで/var/lib/node_exporter/textfileを収集するようにします。
[Service] ExecStart= ExecStart=/usr/bin/prometheus-node-exporter \ --collector.textfile.directory=/var/lib/node_exporter/textfile
上手くいけばPrometheusにnextcloud_job_execution_duration_secondsなどのメトリクスが送られているはずです。

Grafanaで眺める

Grafanaで、最後のジョブからの経過時間を可視化できるようにしてみました。
Nextcloudのジョブは基本的に5分おきに走るので、最後のジョブからの経過時間が5分を越えると遅れ気味だというわけです。
min(time() - nextcloud_job_last_run_timestamp_seconds)というPromQLで取得しています。
ついでにいつ、どのジョブが走っているかも見れるようにしています。

おわりに
いかがでしたか。これを期に身の周りのジョブを可視化してみたくなりましたか。
この記事は、はてなエンジニア Advent Calendar 2025 - Hatena Developer Blogの45日目の記事でした。
明日(1月14日)は
id:masayosuさんです。よろしくお願いします。
YAPC::Fukuoka 2025 に行きました
id:taiseiueです。11/14〜15に九州は福岡工業大学で開催されていた「YAPC::Fukuoka 2025」に参加しました。
参加にあたっては、学生旅費支援で宿泊費と旅費を支援していただきました。 このような機会をくださった運営の方々に感謝しています。
以下は懇親会で楽しそうなid:taiseiue と仲間達です。
#yapcjapan_memorial #yapcjapan pic.twitter.com/9VBXlhll7g
— rokuo (@rokuosan_dev) 2025年11月15日
インフルでした
帰って早々インフルになっていました。ブログを書くのがだいぶ遅れたのはこれです..
トーク&踊り場
ここからは、聴講させていただいたトークや参加した踊り場の感想を書いていきます。
2025年秋のPerl by charsbar
今ドキの最新Perlの話でした。all/any演算子が入って便利に使えそう。use feature 'all'ではなくてuse feature 'keyword_all'と書くのは全機能を有効化してしまいそうな感じがするからでしょうか。あと、:readerと:writerが個人的便利そう。
大規模OSSに一人で立ち向かうには by Sosuke Suzuki
いい話でした。何かに莫大な情熱を持っている人をエミュレートするには、「時間を可能な限り捻出して、可能な限り集中して使うこと」。この点が言語化されて実感が持てました。他にも、「手を動かしてメンタルモデルを得ること」、「教科書を読むこと」は日常生活の中でも役立ちそうです。
とりあえず散歩に行きます。
「バイブス静的解析」でレガシーコードを分析・改善しよう by hitode909
id:hitode909 さんの発表には特有の凄みがあると思います。何か自然に場の空気を支配される感じ。 今まで画面越しに見ていたそれを生でみられてよかったです。
静的解析をLLMに助けてもらう、確かにVibeCodingよりも相当安心感がありますね。うちのプロジェクトもデッドコードを削除するところからやってもらおうかな。
Perl ブートキャンプ by Takafumi ONAKA
Perlって何??となったので。manみたいにperldocが整備されているの、当たり前に思ってるけど良いですね。 「非常に高い後方互換性」について、確かに互換性を失なった先は狂気ではあるけどバグとの兼ね合いが難しすぎる...という気持ちになっていました。 私もしがないプログラミング言語をメンテナンスしているので、ここは気持ちがわかる気がします。
これは何度も言っているのですが、データにパッケージを紐付けてオブジェクトとするの、原野的な感じがしてすごくいい(語彙力)。
SREのためのテレメトリー技術の探究 — モニタリングSaaS開発からAIOps・AIインフラまで by yuuk1
時系列基盤モデル、初めて聞いた概念だったのですがなかなか便利そう。MackerelでChatOpsから入って、AIOpsへと時代とともに要求が難しくなっていく のにはヒエエとなりました。基盤モデルを作ろうにもデータセットを得るのが難しい、そりゃそうやなとなりました。
OSS開発者なら学生たくさん連れてこれる説 by id:moznion
つれてこられました。尊敬する OSS 開発者の皆さんが横に並んでいて迫力がありました。 OSSコントリビュートするノウハウや継続するコツなど、様々な話が聞けてよかったです。
教科書では知れない令和最新 Perl ワード解説バトル by id:rokuokun
バトルですね。激闘でした。
slidoで素朴なPerlの疑問を賢者の方々に投げかけれるのかなりよかったです。 CPAN Testersが有志でCI(のようなもの)を周してくれている様子には迫力がありました。 Mojoliciousが最近は良いと聞いたので、何かつくるときに使ってみます。
id:rokuokun は司会おつかれさまです!
キーノート by P山
スライドが良かったです。章立てされていて、セクションごとに画像は入っている感じは洋書に近いものを感じました。
"Hacker"であり続けるために、継続的に、よく考えつづける必要があると思いました。精進します。
