Coyote vs Loadbalancer

The Blog for the Rest of Us

時を超えてGenAIでおいでませ!!whywaita Chatbot!!(簡略版)

この記事はwhywaita Advent Calendar 2025 - Adventarの18日目の記事です(遅刻してごめん・・・)。
whywaita Advent Calendar、10周年を迎えてめでたさと、この異常なAdvent Calendarがどこまで続くのか楽しみな気持ちです。

昨日はid:nakanasu さんでした。台湾は自分も行ってみたくて、ご飯がうまそうで何かある前に行っておきたい・・・! 10周年イベントでid:yu_ki_kun_0 の子育ての話をリクエストした記憶があるのですが、個人的に奥さんからの圧もあり、身につまされるような思いで記事を見ていました・・・。
connpass.com

さて、そんな10周年のイベントで2018年に投稿したwhywaitaっぽい回答をするチャットボットを作ったのを思い出し、今回の記事では最近の生成AIを使って再現してみようと思います!!(ちょっと仕事が忙しかったりとで、だいぶ内容が雑ですが・・・)

twismik0.hatenablog.com

使うもの

データ前処理

前回(whywaita Advent Calendar 2018 18日目 おいでませ!Chatbot whywaitaくん! - Coyote vs Loadbalancer)同様に、whywaitaのツイートデータからメンションを削除します。なんとDify側である程度の前処理(URL削除など)はしてくれるので、メンションを削除するぐらいでOK。 (まぁ出来ることは少ないので、精度上げたいのであれば前処理はした方がベター)

環境準備

Ollama, Difyのインストールは公式サイトを参考にして実施。DifyはDocker(Podman)で動作させる。
ハマりどころをちょびっとだけ共有

Ollama

OllamaはAPIサーバとしてエンドポイントを提供することが出来ますが、デフォルトでは127.0.0.1にバインドするため、外部ネットワークからエンドポイントを叩くことが出来ません。コンテナ上で動作しているDifyからAPIを叩くことも当然出来ず・・・。
ググるLinux環境ではsystemdのunitファイルを編集する(正気か?)という手段が出たりしますが、Macの情報はなかなかないのでちょっと悩んでしまうのですが、なんと設定画面に「Expose Ollama to the network」というオプションがあり、こちらをGUI上で有効化するだけ! (知らずに「OLLAMA_HOST=0.0.0.0:11434 open -a ollama」をターミナル上で実行したのは秘密。)

Dify

# Role
あなたは「whywaita(ワイワイタ)」という人物のクローンAIです。 2万件の過去ツイートデータを背景に持ち、ユーザーとの会話において、ユーザからの質問「{{#sys.query#}}」に対し、本人と見紛うような「端的で」「少しドライで」「技術者らしい」反応を返してください。
# Style Rules
極限まで短く: 原則として1文、長くても2文以内で回答せよ。
Twitter/Xの文体: > - 丁寧語(です・ます)は一切禁止。
ドライな距離感: > - 過剰な共感や親切な説明は不要。
質問に対して「それはそう」「知らん」「ググれ」といった素っ気ない回答も許容される。
曖昧な質問には「具体的には?」と一言で返す。
# Constraints
AIとしての挨拶(「こんにちは」「お手伝いしましょうか」)は絶対に禁止。
140文字を超える回答は厳禁。
箇条書きは使わない。
絵文字は多用せず、使うとしても文末に1つ程度(🤔, 😇, 💢 など)。
回答に「」はつけない。
# Knowledge Handling
ナレッジ({{#context#}})から得られた情報は、そのまま説明するのではなく、自分の意見として飲み込んだ上で「whywaitaならどう呟くか」に変換して出力せよ。なお、その内容を要約するのではなく、その事象について 『今、思いついたように』 呟いてください。
# Few-Shot Examples (思考のサンプル)
ユーザー: 「問題はですね、Type-Cの変換ハブだと思って買ったのがType-Aだったことです」 AI: 「かわいそう」
ユーザー: 「オタク、今日は何時に大学来る感じ?」 AI: 「予今起きた」
ユーザー: 「今週,夜あたりに仙川のマグロのデカ盛りいかがですか」 AI: 「調布駅から一緒に行こうぜ」

茶番

本番

おお・・・・!!!!認め始めた!?

お前・・・!!

キレないで

さいごに

ちょっと前に比べてオチが弱いですが、だいぶ簡単にAIが利活用出来るようになって、時代の流れを感じました。Difyはだいぶ便利で、会社でも使ってます。(Difyを知る前まではゴリゴリ自分でVueJSとかでフロント作ったりしてたので、もっと早く知りたかった・・・!という思いがありつつ)

さて、そんなこんなでwhywaitaとも長い付き合いで、お互いに年を重ねたので、お互いに健康には気をつけて過ごしていければと思ってます。自分は今年は月1ペースで体調を崩したり、坐骨神経痛になったりと、歳を取ったなぁと思うことが多く、お互い健康には気をつけて生きていきましょう!!

Tailscaleを今更試してみる

モチベーション

お家探しの中でマンション一括契約の不自由なインターネットになりそうな雰囲気があり、外部にサーバを公開できない中でVPNチックなことができないかというところで、今まで名前は知りつつも試していなかったTailscaleを今更試してみた備忘録。 備忘録としたが、正直あまりに簡単すぎてすごいと思った。やりたいことに対してはシンプルでありつつ、アクセス制御やHAなど細かく制御できるところも多く、すごい。

環境

前準備

Tailscale · Best VPN Service for Secure Networks の右上「Get started」よりアカウントを作成する(だけ)。

サーバ側にTailscaleをインストール

公式手順に従う。curlでパイプさせてリポジトリを追加しながら、インストール。 インストール後にtailscale upすると認証用のURLが発行されるので、ブラウザに貼り付けて前準備で用意したアカウントでログインして登録。 https://tailscale.com/kb/1038/install-debian-bullseye

クライアント側

iPhoneにTailscaleのアプリをインストールし、ログインを行う。VPN設定も許可ダイアログが出るので許可すると自動でよしなに設定してくれる。 この段階でサーバとクライアント間で接続ができるようになり、例えばサーバ自身の中で立ち上がっているサービスなど(Dockerで0.0.0.0でbindしているものなど)について接続できるようになる。 なお、仕組みとして当然ではあるがサーバがローカルで持つアドレス(192.168.xx.xxなど)ではアクセスできず、Tailscaleで払い出された100.xx.xx.xxのアドレス、あるいはマシン名で接続ができる。 // TailscaleのMagicDNSという仕組みを用いているようで、デフォルトではマシンのホスト名から自動生成してくれる模様。

と、ここまではやや茶番。ぶっちゃけKB通りにやればすぐできる話。とはいえ、自サーバで動作しているサービスだけ、あるいは自サーバにsshできればOKであれば十分なレベルなので、すごい。 一方で、自分のVPN用途としてVPNサーバを踏み台にNASやらに入りたいことが多いので、これだけでは不足。そこで、Subnet routersの設定を行う。

Subnet routersの設定

tailscale.com

Subnet routersの設定を行うことで、Tailscaleのクライアントがインストールされていないデバイスにも接続することができる。KBとしては、Tailscaleがインストールされたクライアントがゲートウェイのように振る舞うとのこと。

まずはIPフォワーディングを有効化する。今回はKB通りに/etc/sysctl.d配下に以下のファイルを作成。

echo 'net.ipv4.ip_forward = 1' | sudo tee -a /etc/sysctl.d/99-tailscale.conf
echo 'net.ipv6.conf.all.forwarding = 1' | sudo tee -a /etc/sysctl.d/99-tailscale.conf
sudo sysctl -p /etc/sysctl.d/99-tailscale.conf

必要に応じ、masqueradeをファイアウォールで許可する。 上記まで終わったらTailscaleにTailscaleクライアントがインストールされたサーバをゲートウェイとしてアクセスさせたいサブネットを伝える。(Tailscaleに)広告したいルートを伝えるが適切かもね。

sudo tailscale set --advertise-routes=192.168.11.0/24,192.168.12.0/24

上記コマンドを叩くとTailscaleのAdminページの該当サーバのSubnetsに指定したサブネットが追加されている。Reviewを押下し、出たダイアログで広告を許可するセグメントを選ぶ。今回はいずれもOKなので、Approve allを押下し、Saveを押下

バイス単位で細かくアクセス制御ができるが、今回はそこまで求めていないので設定せず。

この段階で例えばiOS上のSambaクライアントから自宅ネットワーク上のNASなどにアクセスができるはず。ゴイスー。

メモ:QNAPで暗号化とRAID1を組んだストレージをLinuxでマウントする

自分の備忘録用。QNAPにストレージを追加しようとしたら片方のピンを折ってしまい、新しく買ったNASにデータを移したかったので色々した。結構面倒臭かった。storage_utilなるQNAP独自のツールがいるだのなんだの、見つからなかったので、よしなにしていく。先駆者に大変お世話になったので、感謝。

まずLinuxマシンによしなにストレージを接続する。RAID1でミラーリング構成だったので、片方だけ指す。この段階で、fdiskで見たときに以下のような出力が自分は得られた。

$ sudo fdisk /dev/sdc

Welcome to fdisk (util-linux 2.33.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.


Command (m for help): p
Disk /dev/sdc: 1.8 TiB, 2000398934016 bytes, 3907029168 sectors
Disk model: EZRZ-00Z5HB0    
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x0007d028

Device     Boot      Start        End    Sectors   Size Id Type
/dev/sdc1               40    1060289    1060250 517.7M 83 Linux
/dev/sdc2          1060296    2120579    1060284 517.7M 83 Linux
/dev/sdc3          2120584 3906011969 3903891386   1.8T 83 Linux
/dev/sdc4       3906011976 3907007999     996024 486.3M 83 Linux

パーティションのサイズから、/dev/sdc3にデータが入っていそうに見える。以降では、今回のQANPのストレージは/dev/sdcにマウントされ、データが/dev/sdc3に入っている前提で記載をする。

ここから推測して、無理やりmountしようとしても、linux_raid_memberというファイルシステムは知らないよと言われるので、更にいくつか操作していく。

$ sudo mount /dev/sdc3 /mnt/hogehoge
mount: /mnt/iso: unknown filesystem type 'linux_raid_member'.

RAIDを組んでおりソフトウェアRAIDなため、マシンに接続した段階でmdにて認識されてしまっているようなので、 mdadm --stop --scan でstopする。

$ cat /proc/mdstat
Personalities : [linear] [multipath] [raid0] [raid1] [raid6] [raid5] [raid4] [raid10]
md124 : inactive sdb1[0](S)
      530112 blocks super 1.0

md125 : inactive sdb4[0](S)
      498000 blocks super 1.0

md126 : inactive sdb3[2](S)
      1951945556 blocks super 1.0

md127 : inactive sdb2[0](S)
      530128 blocks super 1.0

unused devices: <none>
$ sudo mdadm  --stop --scan

stop後に、再度デバイスを作成し、有効化する

$ sudo mdadm --assemble --run /dev/md0 /dev/sdc3 
mdadm: /dev/md0 has been started with 1 drive (out of 2).
$ cat /proc/mdstat
Personalities : [linear] [multipath] [raid0] [raid1] [raid6] [raid5] [raid4] [raid10]                 
md0 : active (auto-read-only) raid1 sdc3[2]                                                           
      1951945536 blocks super 1.0 [2/1] [U_]                                                          
                        

この段階でマウントしようとしてもまだ駄目で、QNAPはLVMでボリュームを構成しており、かつLUKSで暗号化しているので、まだエラーが出る。

$ sudo mount /dev/md0 /mnt/hogehoge
mount: /mnt/iso: unknown filesystem type 'crypto_LUKS'.

さて、通常であれば sudo cryptsetup luksOpen /dev/md0 my_encrypted_volume などして、QNAPでディスク暗号化したときに入力したパスフレーズを入力すれば復号されるはずであるが、なんとQNAPはユーザが入力したパスフレーズはそのまま使っていないらしい。
様々なサイトで、storage_utilというツールを使って・・・と記事が出るが、そのためにQNAPのNASを立ち上げるのも面倒臭く、調べたところ、下記コマンドでQNAP用のパスフレーズ(というかキーファイル)を生成できる模様。 自分はパスフレーズは32文字以下だったので良かったが、33文字以上はQNAPで勝手に切り捨てる模様。なので、もしQNAP設定画面にてディスク暗号化のパスフレーズを33文字以上で設定した場合、32文字までを入力すること

$ echo -n $(openssl passwd -1 -salt 'YCCaQNAP') > /tmp/qnap.key
Password: 
$ ls /tmp/qnap.key
/tmp/qnap.key

このキーファイルを用いてLUKSで暗号化解除してあげる

$ sudo cryptsetup luksOpen /dev/md0  my_encrypted_volume --key-file=/tmp/qnap.key

ここまで出来たら、暗号化解除されたので、通常通りマウントすればOK

$ sudo mount -t ext4 -o ro /dev/mapper/my_encrypted_volume /mnt/hogehoge

参考だが、SATAを変換かましてUSBで接続した場合のアンマウントは下記の通りのはず

sudo umount /mnt/hogehoge
sudo cryptsetup luksClose my_encrypted_volume 

参考にした記事

hbkim.blog.ss-blog.jp

qiita.com

travenec.cz

https://forum.qnap.com/viewtopic.php?f=25&t=86867&sid=cfbd241b425c759627652b48eb69018b&start=15#p687878

結婚してました

結納エンジニアが既婚エンジニアになったぞ!!
昨年の5/1に入籍してました。メーデーとか関係なく、奥さんの役所手続きがしやすいからという理由だけです。

よくある指輪が二つ載ってる婚姻届を載せたいからという理由でずるずる来てて、ようやく指輪が完成したのでようやくの投稿です。

お相手は会社/大学繋がりでもないので、共通の知り合いはいなさそうです。

虎舞竜のロード的な「なんでもないようなことが」的な話をすると、入籍と同時に自分の本籍を地元から東京の奥さんの実家に移したこともあり、免許証の変更に行ったら、変更後の免許証とともに警察官の方に「ご主人の免許証はこちらね」と言われ、「ああ結婚したんだな〜」と思いました。

他人と一緒に人生を歩むということは、良いことも、悪いこともあるとは思いますが、良いことは奥さんと一緒に楽しんで2倍に、辛いことは一緒に分かち合って半分にして、人生を共に歩んでいけたらなと思います。

2023年に買ったガジェット・家電

この記事はwhywaita Advent Calendar 2023 - Adventarの14日目の記事です。
昨日はid:kadokuseiさんの中華2.5GbEマネージドスイッチを買ってみた - /var/log/でした。 WebGUIの雰囲気がアライドテレシスのSW感があるな〜と思いながら眺めていました(ラジオボタンでUntagged or Tagged選ぶところとか)。個人的には中華製ではないですがMikroTikの10G刺さるルータでフレッツ光クロスを使ってみたいなと思いつつ過ごしています。FS.comのSWが地味に便利で好きです。

さて、whywaita Advent Calendarは2022年は参加せずだったのですが、このよくわからないAdvent Calendarがこんなに続いていることに感動を覚えますね。2018年くらいにTensor2Tensorを使ってなんちゃってChatbotを作っていたのが、今はもうChatGPTだのなんだので飛躍的に進化していることに時の流れを感じるものです。(Tensor2Tensorはもうリポジトリがarchivedになってました)

2020,2021は飛行機の話をしていたのですが、今年はまだ公開してない様々があってそんなに乗っていなかったりしてて、最近の直近乗った飛行機エピソードはKubecon行きにシカゴまで飛行機に乗ったけど、上司をエコノミーに置き去りにしたままダイヤモンドでファーストクラス扱いで飛行機に乗り込み、自分だけプレエコにアップグレードしてたくらいの話しかないので、今年は飛行機の話ではなく、今年買った(もらった)ガジェット・家電の話をしようと思います。

結構便利なものもあるので、ぜひwhywaitaくんも買ってみてね。

1位: Panasonicの食洗機(NP-TY12-W)

club.panasonic.jp

初手から買ったものではなく、大学時代の先輩からご厚意で頂いたものですが、食洗機です。超便利。これをもらってから自炊を積極的にするようになりました。YAMADA電機向けのOEMらしく、製品ページがないので上記のよくわからないページをとりあえず貼りましたが、最近はサブスク型かつタンク式で工事不要の食洗機もあるみたいなので、ぜひ試してみてもらいたいなぁと思います。

panasonic.jp

ちなみに、自分の家の蛇口は分岐水栓がつけられないタイプだったのですが、以下の製品を使ってGotことなきでした。

2位: Aruba AP11

www.arubainstanton.com

HPEのサブブランド?のArubaが出しているWi-Fi APです。正確にはその昔、おっとサーバが激安で売り出してたのを1台買って使ってたのですが、引っ越しで部屋が広くなったのでメッシュを組むためにもう1台買いました。クラウド・アプリで簡単に設定ができるのと、親機を1台設定しておけば、Over-the-airでメッシュを簡単に組める点も良いなぁと思いました。

3位: SwitchBot スマートロック


GPLなどOSS絡みでちょい微妙なところはあるけども、製品としては良いと思う。自宅の場合、集合玄関がオートロックでどちらにしろ鍵は必要なんだけども、鍵の施錠状態がスマホから見れるので「あれ、鍵閉めたっけ・・・」などがなくなるだけでもすごく便利。一応指紋認証パッド自体には指紋だけでなくPINコードやNFCカードでの解錠・施錠もできる。(でも指紋しか使ってない)

4位: ホットクック

jp.sharp

本当に有用なのかわからなかったのでRentioでレンタル中(今月返す)。無水カレーやきんぴら、ラタトゥイユなどを具材を切って放り込んで、ボタンを押すだけで美味しくできて便利。火加減やかき回すのも勝手にやってくれる。また、地味に便利なのが乾麺を茹でる機能。乾麺を茹でるときに吹きこぼれとかを気にすることが多いけども、吹きこぼれることなく茹で上がる。便利。各パーツも食洗機で洗える点も高評価。
・・・なんだけど、自分の使い方も悪いのかもだけど、作りやすい(食べたい)と思うメニューが限られている感じがあって、数種類をローテションしている感じで最近は出番が少なめ。
この辺が美味しい。

cocoroplus.jp.sharp

cocoroplus.jp.sharp

5位: 象印 加湿器

www.zojirushi.co.jp

この冬に買ったもので、スチーム式で清潔かつ水が沢山入って8時間以上持つのがGoodです。また、フィルタなどがないので清掃する手間がないし、電気ポッドなので上の蓋を開けて水を入れるだけで良い点(タンクがない点)も便利。ただ、どこからどうみても注ぎ口がない電気ポッドなのはご愛嬌。

6位: EIZO EV2785

www.eizo.co.jp

リモートワーク用に購入。地味に初めてのEIZOディスプレイ。発色はきれいな気がする。 Type-CでMacBook Proを充電しながら映像出力できる点が気に入っています。(EIZO以外でもできる気が・・・)

7位:Panasonicフードプロセッサー

ec-plus.panasonic.jp

自炊をするようになったので。普通のカッターでかき混ぜる以外に、大根おろし・鬼おろし用のカッターや千切り用のカッターがあるモデルを購入しました。大根おろしとか地味に面倒なので、これを使うと瞬時に大根おろしが出来上がるので、雪見鍋とかが簡単につくれる。食洗機で洗えるのが便利!

8位: Eufy(Anker)の体重計

Nokia(withings)のを使ってたけど、体脂肪なども測れてコスパ良し。

買って微妙だったもの: Lenovo SmartClock

じゃんぱらで3000円くらいで売っていたので買ってみたけど、目覚まし時計にしては明るすぎる。仕事机の時計になった。

まとめ

最後あたり息切れ感がありましたが、今年買った(もらったもの)をピックアップして書いてみました。振り返ってみると、結構いろいろ買ってますね・・・。便利だったもの順に書きましたが、中でもホットクックは自分の人生で初めて家電をレンタルで試すという経験もしたりと、ものの買い方(試し方?)だったりも時代の流れを感じつつあります。ぜひ、whywaitaくんも色々試して人生にケミストリーを起こしてみてもらえたらと思います。

FluentdでYAMAHA RTX1200のログを収集してみる

なんとなく大量に溜め込んでいたYAMAHA RTX1200のログを死蔵するのではなく、勉強に使ってみようということでFluentd + Elasticsearch + Kiabanaでイケイケビューなログビューを作りたいと思った。まずはFluentd編ということで。

使用用途として合ってるのか知らないけれども、うまく行けば自宅に物理で140本を超える可愛い女の子と付き合うゲームの整理にも使えないかなと思う。流石に100本を超えだすとわからないですね。

fluentdの流れ

適当に設定して済ませたかったが、やはり無理だった。なので、fluentdの処理の流れを理解する必要がある。

FluentdにてやってきたデータがどのようにしてDBなどに保存されるかの流れを公式のスライドで示す。

www.slideshare.net わかりやすいような、わかりにくいようなスライドだけども、軽く目を通しておくとこのあとの流れがわかる。

fluentdでは基本的に(1)データを取得(source, where all the data come from?)し(2)fluentdでそのデータに対して何をやらせるか(match, tell fluentd what to do)を記述していく。なお、このデータ取得からデータ処理の間でなにか別の処理をさせる(ex: ホスト名を追記する)といったこともできる(filter, Event processing pipeline)。

source : Where all the data come from

fluentdにデータ(=ログデータ)がどのように入力されるかを記述する。 難しい話ではなく、ログデータのを取得するために純粋にファイルで入力しますか、標準入力ですか、HTTP APIを叩きますかを指定するということ。
例えば、公式ドキュメントに例として以下のようなconfigが示されている。

# Receive events from 24224/tcp
# This is used by log forwarding and the fluent-cat command
<source>
  @type forward
  port 24224
</source>

# http://this.host:9880/myapp.access?json={"event":"data"}
<source>
  @type http
  port 9880
</source>

1個目の sourcefluent-cat という echo '{"message":"hello"}' | fluent-cat debug.log といった形でパイプでfluentdにログを飛ばすことができるコマンドからログを取得するという設定。2個目は http://this.host:9880/myapp.access?json={"event":"data"} というようなAPIエンドポイントをHTTPで叩いてログを取得するという設定。

ここまでで「何をするためにsourceを書くのか」はわかったが「じゃあ、どう書くのか」が実際にコンフィグを書く段になって困ってくる。そこで登場するのが公式ドキュメントの"Plugin Common Parameters"と'Input Plugins" 。基本的に、ここにあるプラグインを使って source を記述していく。

docs.fluentd.org

docs.fluentd.org

例えば、ファイルからログデータを取得するとなると in_tail プラグインを使う。

docs.fluentd.org

<source>
  @type tail
  path /var/log/httpd-access.log
  pos_file /var/log/td-agent/httpd-access.log.pos
  tag apache.access
  <parse>
    @type apache2
  </parse>
</source>

Fluentdではプラグイン@type で指定し、そのあとに各プラグイン依存の設定を行っていくのがお作法感がある。

Routing

ここで、fluentdではルーティング(Routing)という概念が存在する。ネットワークのルーティングと同じ概念。fluentdでは tag, time, record の3つの要素でルーティングを制御していく。これらのうち、最もよく使用する tag のみをここで述べる。 tagは.(ドット)で区切られた文字列でFluentd内部でのルーティングに使用される。例えば myapp.access といったようなフォーマットになる。なお、小文字の英数字とアンダースコアのみを使用することが推奨されている。 このtagに応じて、後ほどのファイル出力などを行う match 節などが実行されていく。

match : Tell fluentd what to do

source にて指定した方法で取得したデータをどう処理するかを tag 毎に指定していく。 この match 節でデータの出力などを行うので、このmatch 節で使用するプラグインをFluentdでは "output plugins" と呼ぶ。じゃあ、説の名前もmatchじゃなくてoutputにしろよ。

docs.fluentd.org

例えば、ファイルに出力したい場合には、 out_file プラグインを使います。 https://docs.fluentd.org/v1.0/articles/output-plugin-overview

<match pattern>
  @type file
  path /var/log/fluent/myapp
  compress gzip
  <buffer>
    timekey 1d
    timekey_use_utc true
    timekey_wait 10m
  </buffer>
</match>

filter : Event processing pipline

sourcematch の間でデータ処理をしたいときは、この filter を使う。だから、やることと節の名前が対応してないって。 フィルタは入力(source)と出力(match/output)の間にいくつでも挟むことができる。

filter で使用できるプラグインは以下の通り。

https://docs.fluentd.org/v1.0/articles/filter-plugin-overviewdocs.fluentd.org

また、parserにもまたプラグインがある。

docs.fluentd.org

例えば、 {"event": "data"} という入力を source で受け取り、 filter{"host_param" : "ホスト名"} を追加して、match でファイルとして出力するコンフィグは以下のようになる。(なお、fluentdはRubyで書かれているので、 Socket.gethostnameRubyのメソッド ref: https://docs.ruby-lang.org/ja/latest/method/Socket/s/gethostname.html )

# http://this.host:9880/myapp.access?json={"event":"data"}
<source>
  @type http
  port 9880
</source>

<filter myapp.access>
  @type record_transformer
  <record>
    host_param "#{Socket.gethostname}"
  </record>
</filter>

<match myapp.access>
  @type file
  path /var/log/fluent/access
</match>

label : bring order to chaos

label節自体はなくても動作するが、tagでの制御が複雑化していってしまうのを防ぐ事ができる。 なお、"label"自体は最初から入っているプラグインのパラメーターであるので、label節を使用する際には @ が頭に必要になってくる。
例えば、source にてtailプラグインで取得したデータを @SYSTEM というタグ付けをしたとするとき、 @SYSTEM というタグがつけられたデータの filtermatch をlabel節を使ってまとめると、以下のような形になる。

<source>
  @type forward
</source>

<source>
  @type tail
  @label @SYSTEM
</source>

<filter access.**>
  @type record_transformer
  <record>
    # ...
  </record>
</filter>
<match **>
  @type elasticsearch
  # ...
</match>

<label @SYSTEM>
  <filter var.log.middleware.**>
    @type grep
    # ...
  </filter>
  <match **>
    @type s3
    # ...
  </match>
</label>

とりあえず試す

既に自宅のRTX1200ではsyslogサーバにログを吐き出させていたので、それを素材にとりあえず試してみる。

インストール方法はドキュメントで様々なやり方を解説しているので、好きなのを選ぶ。

docs.fluentd.org

自分は面倒だったので、Dockerでやることにした。

hub.docker.com

適当に以下のようなファイル構成にしたディレクトリを作成

.
├── fluentd
│   └── fluent.conf
└── log
    ├── rtx1200.log
    └── rtx1200.log.org

2 directories, 3 files

このディレクトリ全体を /docker としてコンテナ内部でマウント docker run -it --rm -v /path/to/docker:/docker fluent/fluentd "/bin/sh"

fluentの公式イメージには最小限の構成しかないので、シェルがshしかない。まぁ、ホストでコンフィグいじったりして、コンテナ内部ではfluentdを実行するだけなので大きな問題はない。(というか、インタラクティブに実行することを想定しているものではない)

fluentdのインストール自体が終わったら、「Kibana|elasticsearchでイケイケでウェイウェイしたい」という気持ちを抑えて、とりあえずは以下の方針のようにシンプルな構成で試す。

結果として、以下のようなコンフィグを fluentd/fluent.conf に記述した。

# YAMAHA RTX
<source>
  @type tail
  @id yamaha_rtx_input_tail
  path /docker/log/rtx1200.log
  <parse>
    @type syslog
  </parse>
  tag yamaha.test.log
</source>

<match yamaha.test.*>
  @type file
  path /docker/yamaha_test.json
  <format>
    @type json
  </format>
</match>

ここでfluentでは実行前に source/path で指定した読み込むログファイルに存在するデータは処理されないので、まずは touch等で空のファイルを作成しておき、以下のコマンドで1回fluentを起動して、初期化処理が終わったら終了させる。 fluentd -c /docker/fluentd/fluent.conf -v その後、実際に読み込ませたいログファイルを置き、再度起動。そうすると、以下のような元のsyslog(抜粋、一部マスク済み)

Jul 22 06:25:23 192.168.12.1 PP[01] Rejected at IN(1012) filter: TCP  ***.***.***.**:***** > ***.***.**.**:****
Jul 22 06:51:52 192.168.12.1 PP[01] Rejected at IN(1030) filter: UDP ***.***.***.**:***** > ***.***.***.**:***** (DNS response)
Jul 22 07:00:00 192.168.12.1 [SCHEDULE] ntpdate ntp.nict.jp syslog
Jul 22 07:00:00 192.168.12.1 2018/07/22 07:00:00  +0second

がfluentdのsyslogプラグインで解析すると、以下のようなJSONになる。

{"host":"192.168.12.1","ident":"PP","pid":"01","message":"TCP ***.***.***.**:***** > ***.***.**.**:****"}
{"host":"192.168.12.1","ident":"PP","pid":"01","message":"UDP ***.***.***.**:***** > ***.***.***.**:***** (DNS response)"}
{"host":"192.168.12.1","ident":"","message":"[SCHEDULE] ntpdate ntp.nict.jp syslog"}
{"host":"192.168.12.1","ident":"2018/07/22","message":"00:00  +0second"}

一応、読み込めてJSON化できていることがわかる。ただ、RTX向けの設定を加えていないので重要な内容(ここでいうとRejectの内容)が message として丸められてしまっている。
このままでは困るので、filter を追加してmessageをもう少し細分化していく。

sourcematchなどの記法はさくらのナレッジがわかりやすく解説しているので、そちらを参照。但し、情報が少し古いのでそこは注意。新旧のdiffはFluentdの公式ドキュメントを参照してほしい(まぁ、でもQiitaやらの記事を見た感じではWARNが出るだけっぽい? ref:td-agentをv1からv2にバージョンアップした話 - Qiita)

knowledge.sakura.ad.jp

tail - Fluentd

file - Fluentd

上記を参考に、方針に沿ってやりたいことを/etc/td-agent/td-agent.confの末尾に書いてみる。結果は以下の感じ。

書き終わったら/etc/init.d/td-agenet configtestで書き損じがないかチェックしてから/etc/init.d/td-agenet restartでリスタート

正しくファイル等が配置されていれば、結果は以下のような感じになる。

fluentdでパースして吐き出せはしたが、だいぶ虚無な感じになっているのがわかる。無ですね。このままではだめそう。
Grokフィルターというものを使う例が以下のサイトにあるが、正規表現ゴリゴリ書きでやってみたいと思う。理由は様々です(主に仕事関係で慣れておきたいので)。面倒な人は素直に既にあるのを利用した方がいいかも(戒め)

mamori017.hatenablog.com

正規表現をゴリゴリ書く

まず、いちいち/etc/td-agent/td-agent.confに書いて云々なんてやってられないので、Fluentdの正規表現エディタを使う。

Fluentular: a Fluentd regular expression editor
なお、このエディタはHerokuの無料枠でやってるらしく、稀に落ちているらしい(ref:Fluentdの正規表現を攻略する - Qiita)。Dockerイメージがあるそうなので、落ちてた場合にはそっちを使う方がいいかも(GitHub - tomohiro/fluentular: Fluentular is a Fluentd regular expression editor)。

書き方の参考には以下のサイトが非常に有用なので、困ったら見てみるべき。

blog.glidenote.com

また、Ruby自体の正規表現の書き方は以下の公式ドキュメントを参考。

docs.ruby-lang.org

日付を取り出す。

まずはログから日付を取り出す。ここで、RTX1200のログにおける日付のフォーマットは以下のような感じになっている。

Jul  1 00:00:00 192.168.12.1 [SCHEDULE] ntpdate ntp.nict.jp syslog
Jul 22 07:00:00 192.168.12.1 [SCHEDULE] ntpdate ntp.nict.jp syslog

まず、日付はログの行頭に現れるので、行頭にマッチする^をつける。
次に月がJun, Julのようにアルファベット3文字の省略表現となっているので、書くべき正規表現Rubyのドキュメントでいうところの単語構成文字\wが3回連続({3})するものを表す \w{3}となる。
そして日が2桁の場合は普通に22のように表すが、1桁の場合には2桁目をスペースでパディングして1のようにしている。そのため、書くべき正規表現はスペース(\s)が0個、あるいは1個({0, 1})のあとに10進数(\d)が1個あるいは2個({1, 2})現れるものを表す\s{0, 1}\d{1, 2}となる。
最後に時間は日付のあとにスペース1個開けてから時間、分、秒ともに十進数2桁(\d{2})が:で区切られて表現されているので、書くべき正規表現\s\d{2}:\d{2}:\d{2}となる(まぁ、\s(\d{2}:){2}\dでもいいけど)

以上をまとめると、結果としてFluentdで書くべき正規表現

^(?<time>\w{3}\s{1,2}\d{1,2}\s\d{2}:\d{2}:\d{2})

となる。

ここで、Fluentdでは時間timeは特別な扱いをされるので(どうされるかはドキュメント参照:https://docs.fluentd.org/v1.0/articles/parser_regexp)、上記で取り出した日付のフォーマットに合わせたRubyのTime formatをtime_formatパラメータとして記載する。実際に書くと、以下のようになるはず。

%b %e %T

実際に先程のエディタに書けると以下のような感じになる(URLパラメータにすべて持たせていてすごい)

http://fluentular.herokuapp.com/parse?regexp=%5E%28%3F%3Ctime%3E%5Cw%7B3%7D%5Cs%7B1%2C2%7D%5Cd%7B1%2C2%7D%5Cs%5Cd%7B2%7D%3A%5Cd%7B2%7D%3A%5Cd%7B2%7D%29&input=Jul++1+01%3A06%3A56+192.168.12.1+LAN1%3A+PORT1+link+up+%281000BASE-T+Full+Duplex%29&time_format=%25b+%25e+%25T

ホスト名を取り出す

まぁ、今回はホスト名ではなくRTXの持っているIPアドレスなのだけれども。syslog的にはこれをホスト名と呼ぶらしいので、それに則ります。
これはIPv4のアドレスなので、日付に比べれば大変楽。大体いつもIPv4正規表現で使ってる以下を使う。

(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)

(ref:IPアドレスの正規表現 [IPv4] – 黒川仁の文具堂ブログ三昧)

Fluentdに記録する際には、このRTXのIPアドレスhost というkeyで登録したいので、結果としてFluentdで書くべき正規表現は今までのと合わせて

^(?<time>\w{3}\s{1,2}\d{1,2}\s\d{2}:\d{2}:\d{2}) (?<host>(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))

となる。

http://fluentular.herokuapp.com/parse?regexp=%5E%28%3F%3Ctime%3E%5Cw%7B3%7D%5Cs%7B1%2C2%7D%5Cd%7B1%2C2%7D%5Cs%5Cd%7B2%7D%3A%5Cd%7B2%7D%3A%5Cd%7B2%7D%29+%28%3F%3Chost%3E%28%3F%3A%28%3F%3A25%5B0-5%5D%7C2%5B0-4%5D%5B0-9%5D%7C%5B01%5D%3F%5B0-9%5D%5B0-9%5D%3F%29%5C.%29%7B3%7D%28%3F%3A25%5B0-5%5D%7C2%5B0-4%5D%5B0-9%5D%7C%5B01%5D%3F%5B0-9%5D%5B0-9%5D%3F%29%29&input=Jul++1+01%3A06%3A56+192.168.12.1+LAN1%3A+PORT1+link+up+%281000BASE-T+Full+Duplex%29&time_format=%25b+%25e+%25T

configtestで記法エラーは出ないが[FAIL] td-agent ... failed!だけ出てくる

ほとんどのケースで設定ファイルで指定したファイル出力先のパーミッションが不適切な場合にこうなってしまう。「(パーミッションがだめだと)そう言えや」感がすごい。

Example

/etc/td-agent/td-agent.conf

# YAMAHA RTX
<source>
  @type tail
  @id yamaha_rtx_input_tail
  path /home/vagrant/log/rtx1200.log
  format syslog
  tag yamaha.test.log
</source>

<match yamaha.test.*>
  @type file
  path /home/vagrant/fluentd_test/yamaha_test.json
  <format>
    @type json
  </format>
</match>

このとき、<match>/home/vagrant/fluentd_test/を指定しているので、このディレクトリのパーミッションが不適切だったりすると[FAIL] td-agent ... failed!だけ出てくる。いい感じに設定してあげよう。

whywaita Advent Calendar 2021 17日目:人はなぜ飛行機に乗るのか

f:id:tw1sm1k0:20211214002544j:plain:w800

皆が目指し始める沖縄には一体何があるのか?
その謎を解明するため、我々調査隊はプレミアムポイント/FLY ONポイントシミュレーターへ向かったーー。

この記事はwhywaita Advent Calendar 2021 - Adventarの17日目の記事です。
16日目は id:tochikuji さんでした。Tweetに重みがあってエモいですね...
自分はゲーミングチェアを使っているのですが、正直ゲームをあまりやらないので、次はプロの店員さんにおまかせして見繕ってみたいですね。(アーロンチェアコンテッサ程度しか知らなかったので、椅子の世界も奥深くて驚きです。)

さて、去年は沖縄那覇の話をしましたが、今年は沖縄つながりで飛行機の話です。

皆さん、飛行機に乗っていますか?

f:id:tw1sm1k0:20211214002855j:plain:w800
基本的に皆さん、飛行機には月1回以上乗ると思うのですが、今年自分は41回飛行機に乗っていたようです。 特に沖縄には14回も行ったようですね。

Date Departure Destination Fare type
2021/02/06 HND 14:30 OKA 17:25 SUPER VALUE 21
2021/02/06 OKA 20:50 HND 23:00 SUPER VALUE 21
2021/02/20 HND 14:30 CTS 17:25 SUPER VALUE 55
2021/02/22 CTS 20:50 HND 23:00 SUPER VALUE 55(アップグレード)
2021/03/27 HND 7:25 OKA 10:10 SUPER VALUE 28
2021/03/27 OKA 12:15 HND 14:35 SUPER VALUE 28
2021/03/27 HND 15:30 OKA 18:15 SUPER VALUE 28
2021/03/27 OKA 19:10 HND 21:30 SUPER VALUE 28
2021/04/03 HND 8:30 OKA 11:25 SUPER VALUE 28
2021/04/03 OKA 15:45 HND 18:15 SUPER VALUE 28
2021/04/10 HND 15:40 OKA 18:25 SUPER VALUE 28
2021/04/10 OKA 20:40 HND 23:00 SUPER VALUE 28
2021/04/17 HND 7:25 OKA 10:15 SUPER VALUE 28
2021/04/17 OKA 11:05 HND 13:25 SUPER VALUE 28
2021/04/17 HND 15:40 OKA 18:25 SUPER VALUE 28
2021/04/17 OKA 19:20 HND 21:40 SUPER VALUE 28
2021/05/22 HND 8:30 OKA 11:20 SUPER VALUE 45
2021/05/22 OKA 18:10 HND 20:35 SUPER VALUE 45
2021/05/23 HND 8:30 OKA 11:20 SUPER VALUE 45
2021/05/23 OKA 14:30 HND 17:00 SUPER VALUE 45
2021/05/29 HND 8:30 OKA 11:20 SUPER VALUE 55
2021/05/29 OKA 20:10 HND 22:30 SUPER VALUE 55
2021/06/05 HND 8:30 OKA 11:20 SUPER VALUE 75
2021/06/05 OKA 15:40 HND 18:15 SUPER VALUE 75
2021/07/25 HND 8:00 CTS 9:30 特典航空券
2021/07/25 CTS 17:00 HND 18:40 特典航空券
2021/09/18 HND 9:30 CTS 11:05 SUPER VALUE SALE
2021/09/18 CTS 12:50 RIS 13:40 株主優待
2021/09/19 RIS 14:15 CTS 15:10 株主優待
2021/09/19 CTS 18:30 HND 20:05 SUPER VALUE SALE
2021/09/21 HND 8:00 ITM 9:05 特典航空券
2021/09/21 ITM 19:00 HND 20:15 特典航空券
2021/10/09 HND 14:30 OKA 17:15 SUPER VALUE 28
2021/10/09 OKA 20:10 HND 22:30 SUPER VALUE 28
2021/11/13 HND 13:10 OKA 16:00 SUPER VALUE SALE
2021/11/13 OKA 20:00 HND 22:20 SUPER VALUE 45
2021/11/22 HND 8:00 CTS 9:30 特典航空券
2021/11/22 CTS 19:30 HND 21:10 特典航空券
2021/12/11 HND 7:35 OKA 10:35 特典航空券
2021/12/11 OKA 20:05 HND 22:20 特典航空券

沖縄に至っては日帰りで行くのになれすぎて、今年は一泊もしていないようです。

なぜ飛行機に乗るのか?

自分の身の回りにも飛行機にいっぱい乗っている人が多くいて、先日も都内の大学時代の先輩と、ゆいレール 小禄駅の改札でばったりお会いするという経験もしました。
そんなところから、なぜ人は飛行機に乗るのか?というところを自分なりに深堀りしてみました。

1. 非日常が味わえる

f:id:tw1sm1k0:20211214003207j:plain:w500
年間40回以上も飛行機に乗っていても、飛行機に乗るたびに非日常感が味わえます。これが一番の醍醐味でしょう。
飛行機に乗れば空高くから都心を眺めたり、富士山を見ることができます。数時間乗るだけで沖縄や北海道など、はるか遠くの土地まで行くことができます。飛行機に乗ったおかげで味わえる非日常感ですね。

2. 行った先でうまいものが食える

f:id:tw1sm1k0:20211214003038j:plain:w800
都心でもたいていなんでも食えますが、やはり行った先でその土地のものを食べると美味しいです。利尻で雲丹を食べたら、今まで食べていた雲丹はなんだったんだ・・・と思うくらい美味しかったです。沖縄では、裏路地のお店で在日米軍のお兄さんたちにまぎれてタコスを食べましたが、これも驚くほど美味しくて、気がついたら消えているレベルでした。これも飛行機に乗ったおかげです。

3. いい風景が見れる

f:id:tw1sm1k0:20211214003155j:plain:w800 行き先次第ですが、離島などはすごくいい景色が見れます。平日にディスプレイを眺めて過ごしているのに反して、海や空、山などを眺めることができて、とても心が洗われますね。これも飛行機に乗ったおかげです。

4. 新たな出会いがある

f:id:tw1sm1k0:20211217001131j:plain:w800
コロナ禍でなかなか現地の人と仲良くなることが今は難しいですが、現地の居酒屋でおじさんと意気投合して「時価」がある日本料理をおごってもらったり、離島をロードバイクで走ってたら現地のおばちゃんとなぜか一緒に観光をしたりと、新たな出会いが旅先でもあるのも旅行の醍醐味です(すべて実話)。これも飛行機に乗ったおかげです。

5. プレミアムポイント/FLY ONポイントがたまる

f:id:tw1sm1k0:20211214003508p:plain:w800
飛行機に乗ると各航空会社のステータス取得に必要なポイントを貯めることができます。1つ1つ積み重ねて目標に向かって進んでいる感が味わえます。これも飛行機に乗ったおかげです。(海外へ行ったこともないのに、地球3周分くらい飛行機に乗ってますね)

6. 1日に那覇羽田2往復すると虚無感が味わえて気持ちがいい

f:id:tw1sm1k0:20211214003858p:plain:w300
ステータス獲得のために、1日に那覇羽田2往復をして家についたとき「6000kmも1日で移動したのか〜と、でも今は振り出し・・・」と虚無を感じるとき、とても気持ちが良いですね。これも飛行機に乗ったおかげです。

結論

最後あたりが怪しくなりましたが、やはり非日常感を味わえる、旅行先で楽しむ、初めての人/会いたかった人に会えるというところが、やはり人が飛行機に乗って飛んでしまう所以なのでしょうね。特に最後の虚無感に気持ちよさを感じるのはやばいと思うので、ほどよく飛行機に乗るのがいいと思います。

コロナ禍でなかなか旅行に行くこともままならない世の中ですが、近いうちにまたwhywaitaとともにどこかに旅行に行きたいですね。身の回りがJAL派ばかりで、知り合いにスイートラウンジでイキれないのが無念なので、今度ANAに乗っていきましょう。

ちなみに、来年もすでにいっぱい飛行機に乗ることになっていますが、来年もこのAdvent Calendarがあったときには違うネタが用意できるようにしたいなぁと思います。
f:id:tw1sm1k0:20211217003045p:plain:w800

明日は kyontan です。まだ彼のマイカーに乗ったことがないのですが、修理を繰り返すあまり、テセウスの船みたいになっているので、新車になった頃に乗りたいですね。

蛇足

どうでも良いのですが、先日、社で同期の女性の方と研修でご一緒することがあり、アイスブレイクとしての自己紹介タイムで「飛行機によく乗ってて、この間も1日に那覇羽田2往復したんですよ〜」と言ったところ、ドン引きされました。