Naginataという複数NagiosをSSH経由で操作するCLIツールを作りました

Naginataという複数NagiosをSSH経由で操作するCLIツールを作りました。

Nagiosの画面から一度に沢山のサービスに対して通知をOFFにしたり、監視開始したりするオペレーションは結構面倒です。

NagiosにはExternal Commandsという仕組みがあり、nagiosのweb画面上で行える操作をCLI上でも行える仕組みが備わっています。例えば以下のコマンドをNagiosホスト上で実行すると通知OFFすることができます。

echo "[1428291034] DISABLE_SVC_NOTIFICATIONS;host1;service1" > /var/spool/nagios/cmd/nagios.cmd

CGIの画面にアクセスしなくてよくこの仕組みはとても便利ですがNagiosサーバにログインする手間があります。またもし複数のNagiosサーバを管理している場合、Nagiosサーバそれぞれでオペレーションするのは面倒です。

そこで1つのマシンから複数Nagiosサーバに対してSSH越しに上のコマンドを実行するCLIツールを作ればいいんじゃないか、ということで作ったのがNaginataです。複数監視対象を複数nagiosサーバ横断的に通知OFFにしたりすることが1コマンドで出来るツールになってます。

使い方

インストール

SSH接続元となるホストにnaginataをインストールします。

$ gem install naginata

naginataコマンドがインストールされるので、以下のように設定ファイルを作ります。

$ naginata init

カレントディレクトリにNaginatafileというのが出来ます。管理対象のnagiosサーバを書いてください。

以下設定例です

# 管理対象のnagiosサーバを書く
# ログイン先のユーザ名が異なる場合はfoo@のようにユーザ名も指定する
nagios_server 'foo@nagios1.example.com'
nagios_server 'bar@nagios2.example.com'
nagios_server 'baz@nagios3.example.com'

# Global nagios server options 
# nagios_serverのファイルパスを指定する
# またrun_command_as: には nagios.cmd に書き込む時の
# ユーザ名を指定する
set :nagios_server_options, {
  command_file: '/usr/local/nagios/var/rw/nagios.cmd',
  status_file: '/usr/local/nagios/var/status.cmd',
  run_command_as: 'nagios',
}

# Global SSH options
# SSHの秘密鍵を指定する
set :ssh_options, {
  keys: %w(/home/nikushi/.ssh/id_rsa),
}

# nagiosサーバでsudoするのでpty trueにしておく
set :pty, true

セットアップは以上です。nagiosサーバ側にはrubyやnaginataをインストールする必要はありません。

通知を止める,有効にする

例として全nagiosサーバ上の全ホストのPINGとSSHの監視の通知を止めてみます。動作を確かめるため-v (--verbose)オプションを付けて実行してます。

$ naginata notification --all-hosts  --disable  --services PING,SSH -v
..snip..
Following notifications will be disabled
localhost
  - PING
  - SSH
redis01.tokyo.local
  - PING
  - SSH
web01.tokyo.local
  - PING
  - SSH
localhost
  - PING
  - SSH
redis01.osaka.local
  - PING
  - SSH
web01.osaka.local
  - PING
  - SSH
Are you sure? [y|N] y
INFO [71871262] Running /usr/bin/env echo "[1428296330] DISABLE_SVC_NOTIFICATIONS;localhost;PING" > /var/spool/nagios/cmd/nagios.cmd on nagios1
INFO [48a76239] Running /usr/bin/env echo "[1428296330] DISABLE_SVC_NOTIFICATIONS;localhost;PING" > /var/spool/nagios/cmd/nagios.cmd on nagios0
INFO [71871262] Finished in 0.017 seconds with exit status 0 (successful).
INFO [ef4827b7] Running /usr/bin/env echo "[1428296330] DISABLE_SVC_NOTIFICATIONS;localhost;SSH" > /var/spool/nagios/cmd/nagios.cmd on nagios1
INFO [48a76239] Finished in 0.017 seconds with exit status 0 (successful).
INFO [4ffe6eb6] Running /usr/bin/env echo "[1428296330] DISABLE_SVC_NOTIFICATIONS;localhost;SSH" > /var/spool/nagios/cmd/nagios.cmd on nagios0
INFO [ef4827b7] Finished in 0.021 seconds with exit status 0 (successful).
INFO [7ee77545] Running /usr/bin/env echo "[1428296330] DISABLE_SVC_NOTIFICATIONS;redis01.osaka.local;PING" > /var/spool/nagios/cmd/nagios.cmd on nagios1
INFO [4ffe6eb6] Finished in 0.022 seconds with exit status 0 (successful).
INFO [2ef43042] Running /usr/bin/env echo "[1428296330] DISABLE_SVC_NOTIFICATIONS;redis01.tokyo.local;PING" > /var/spool/nagios/cmd/nagios.cmd on nagios0
INFO [2ef43042] Finished in 0.017 seconds with exit status 0 (successful).
INFO [13b54c30] Running /usr/bin/env echo "[1428296330] DISABLE_SVC_NOTIFICATIONS;redis01.tokyo.local;SSH" > /var/spool/nagios/cmd/nagios.cmd on nagios0
INFO [7ee77545] Finished in 0.022 seconds with exit status 0 (successful).
INFO [de883201] Running /usr/bin/env echo "[1428296330] DISABLE_SVC_NOTIFICATIONS;redis01.osaka.local;SSH" > /var/spool/nagios/cmd/nagios.cmd on nagios1
INFO [13b54c30] Finished in 0.018 seconds with exit status 0 (successful).
INFO [13f9ce6c] Running /usr/bin/env echo "[1428296330] DISABLE_SVC_NOTIFICATIONS;web01.tokyo.local;PING" > /var/spool/nagios/cmd/nagios.cmd on nagios0
INFO [de883201] Finished in 0.017 seconds with exit status 0 (successful).
INFO [5458ec38] Running /usr/bin/env echo "[1428296330] DISABLE_SVC_NOTIFICATIONS;web01.osaka.local;PING" > /var/spool/nagios/cmd/nagios.cmd on nagios1
INFO [13f9ce6c] Finished in 0.023 seconds with exit status 0 (successful).
INFO [5458ec38] Finished in 0.021 seconds with exit status 0 (successful).
INFO [be16e918] Running /usr/bin/env echo "[1428296330] DISABLE_SVC_NOTIFICATIONS;web01.tokyo.local;SSH" > /var/spool/nagios/cmd/nagios.cmd on nagios0
INFO [6247dc33] Running /usr/bin/env echo "[1428296330] DISABLE_SVC_NOTIFICATIONS;web01.osaka.local;SSH" > /var/spool/nagios/cmd/nagios.cmd on nagios1
INFO [be16e918] Finished in 0.020 seconds with exit status 0 (successful).
INFO [6247dc33] Finished in 0.021 seconds with exit status 0 (successful).
Done

なお、naginataは強力なフィルタ機能を持っています。上の例は全ホスト対象にしましたが引数にホスト名を指定すると対象ホストを限定できます。

また、ホスト名やサービス名は部分一致の挙動のため一部だけ指定することもできます。grepコマンドの引数のイメージです。また複数指定も出来ます。

$ naginata notification osaka.local tokyo --enable --services Lo,PI
Following notifications will be enabled
redis01.tokyo.local
  - Load
  - PING
web01.tokyo.local
  - Load
  - PING
redis01.osaka.local
  - Load
  - PING
web01.osaka.local
  - Load
  - PING
Are you sure? [y|N] y
Done

正規表現もできる

$ naginata notification ^web  --enable --services 'd$'
Following notifications will be enabled
web01.tokyo.local
  - Load
web01.osaka.local
  - Load
Are you sure? [y|N] y
Done

また、例は割愛しますが--nagiosオプションで対象nagiosサーバを限定できます。

ステータス確認

元々External Command実行フレームワークにする作りをしていましたが、作っていく途中で監視ステータスや通知OFFされているかどうかを確認出来た方がいいなということになって作ってみました。

以下の例ではサービス一覧を複数Nagiosサーバから取得して現在の状態を表示してます。便利、でしょうか?。こちらも上述のフィルタが使えます。

$ naginata services -a
NAGIOS   HOST                 SERVICE          STATUS   FLAGS  OUTPUT
nagios0  localhost            HTTP             WARNING  AC,nt  HTTP WARNING: HTTP/1.1 403 Forbidden - 5152 bytes in 0.001 second response time
nagios0  localhost            Current Load     OK       AC,NT  OK - load average: 0.00, 0.00, 0.00
nagios0  localhost            PING             OK       AC,NT  PING OK - Packet loss = 0%, RTA = 0.04 ms
nagios0  redis01.tokyo.local  Load             CRITICAL AC,NT  Too high load average 15
nagios0  redis01.tokyo.local  PING             OK       ac,NT  PING OK - Packet loss = 0%, RTA = 0.04 ms
nagios0  redis01.tokyo.local  SSH              OK       AC,NT  SSH OK - OpenSSH_5.3 (protocol 2.0)
nagios0  web01.tokyo.local    Load             OK       AC,NT  OK - load average: 0.01, 0.00, 0.00
nagios0  web01.tokyo.local    PING             OK       AC,NT  PING OK - Packet loss = 0%, RTA = 0.04 ms
nagios0  web01.tokyo.local    SSH              OK       AC,NT  SSH OK - OpenSSH_5.3 (protocol 2.0)
nagios1  redis01.osaka.local  Load             OK       AC,NT  OK - load average: 0.00, 0.00, 0.00
nagios1  redis01.osaka.local  PING             OK       AC,NT  PING OK - Packet loss = 0%, RTA = 0.04 ms
nagios1  redis01.osaka.local  SSH              OK       AC,NT  SSH OK - OpenSSH_5.3 (protocol 2.0)

FLAGSという列に見慣れぬ文字列が入ってますが

  • AC = Active Check enabled
  • ac = active check disabled
  • NT = NoTification disabled
  • nt = notification disabled

という意味になってます。

制約など

  • nagiosサーバにはSSHでパスフレーズ無しでログインできる前提です
  • SSHログイン後nagios.cmdに書き込める権限があるユーザか、もしくはSSHログイン後にsudoできるユーザ必要があります

その他

naginata/tree/master/integration-testにVagrantファイルとサンプルの設定ファイルを置いてるのでVagrantがインストールされたMacがあれば動作をお手軽に試せます。vagrant upすると仮想マシンにnagiosをインストールした状態で上がってきます。

$ gem install naginata
$ git clone https://github.com/niku4i/naginata.git
$ cd naginata/integration-test
$ vagrant up 

つづいて/etc/hostsに以下2行を追記する

127.0.0.1       nagios0
127.0.0.1       nagios1

これで動作確認できるとおもいます!

$ naginata services -a

また http://localhost:8880 , http://localhost:8881 で仮想マシン側のnagios画面見れます。

ToDo

  • 現状notificationのon/offのみ対応。その他のコマンドへの対応。
  • ステータスに色を付ける
  • 高速化。現状サービス数、nagiosサーバ数が多くなるとそれなりに遅い。

Updates

2015/08/05 v0.1.6

任意のディレクトリにNaginatafileを置けるようになりました(以前のバージョンではカレントディレクトリにNaginatafile置く必要がありました)

  • ./Naginatafile, ~/.naginata/Naginatafile, /etc/naginata/Naginatafileの順にファイルを探すよう修正
  • –naginatafileオプション、もしくはNAGINATAFILE環境変数にて任意のパスを指定可能

まとめ

Naginataという複数NagiosをSSH経由で操作するCLIツールを作った。

ぜひ使ってみてください!!

vimとTerminal.appのカラースキーマをsolarizedにする

solarizedというカラースキームが良いらしいのでvimとターミナルの配色を変えた。

vim用のカラースキーマと、Terminal.app用のsolarized profileをインストールにして有効にしたら出来た。

なお、Terminal.appのフォントは以前から使っているSource Code Proを引き続き使うことにした。

Before

2014-12-21-solarized-before

After

2014-12-21-solarized-after

良し悪しは分からないが以前よりコントラストが下って目にやさしいような気がするのでしばらく使ってみてみる。

センス入門 を読んだ

センス入門 松浦 弥太郎 (著) という本を読んだ。

読んだきっかけ

奥さんが休日出勤で家にいなくて、僕も予定がなかった先週末、ふらっと出かけた国立新美術館のショップでこの本を見つけて購入した。最近、視野とか考えが狭まってると感じることがあって、柔らかくなればいいな、というくらいの気持ちで手に取ったんじゃないかなきっと。

どんな本だったか

よいなとおもった目次をメモしておく

  • 心を開く事がセンスのよさへの最初の一歩
  • すすめられたことは試してみる
  • なんでも知っている人よりも、なんでも考える人になった方がいい

クールにするだけだと心に何も残らないかもしれない。感動した体験は忘れないし、心を開いて人と話すとその人の記憶にもあなたの印象がとどまる。

すすめられたことは試してみる。これも心を開くこと近い。人がこれは良いよと言ってすすめてくれたものを素直に試してみるとよいとある。例えば、この本良いと言われたらとりあえず読んでみるとか、このレストラン美味しかったと言われたら行ってみるとか。時には自分には良くない合わなかったこともあるだろうが、経験が糧となってセンスになる、とのことらしい。自分はインターネットのレビューとか口コミサイトの点数とか定量的な尺度の情報を信頼する傾向にあったのだけど、今度何かすすめられた素直な気持ちで試してみたい。

考えるということは案外大変。筆者は考えるトレーニングを毎日1時間x2回やっている。とくに朝の1時間は集中力があるのでおすすめとのことだった。

センスを磨く

本物を見る、聴くなど体験すべしと書いてある。例えば美術館とか重要文化財とか。また歴史上の偉人から学ぶことも良いらしい。他にもセンスがいいなこの人という人がいたらその人のやっていることを真似てみるといいとある。

こういうことは洋服や美術、音楽だけに限らず自分の周りの環境にも当てはまるとおもった。エンジニアであれば優秀なエンジニアのコードを読むとか、ライブコーディングを見たり生で見たりするだけでも勉強になる。コードの写経とかも。

おわりに

センス入門を読んだ。

週末に美術館というのは頭の体操になって良いと自分はおもった。この日はチューリッヒ美術館展という企画があり印象派からシェルレアリズムまで幅広い年代のコレクションが凝縮されたお得な展示で、普段そんなに美術館に行かない自分としてはとても満足度高かった。ただ、人は多すぎだったので東京で人気の美術館巡る時は平日だなという教訓も得た。今度はこの本でもおすすめされているとおり私設の美術館を巡ってみたい。

git pushのトピックブランチ名を省略する方法

トピックブランチを完成させたあと git push origin myfix と毎度タイプしてたけどタイプがしんどいので省略する方法を調べた。

gitでカレントブランチをpushする を参考に自分は以下のように ~/.gitconfig を書いた。

#~/.gitconfig
[alias]
  cb             = rev-parse --abbrev-ref HEAD
  current-branch = rev-parse --abbrev-ref HEAD
  pcb            = !git push origin `git rev-parse --abbrev-ref HEAD`

自分は gitg にaliasしているので、g pcb で カレントブランチを origin に push できるようになった。またgit cb or git current-branch はカレントブランチの名前を表示するショートカット。

これでまた少しタイプ数を減らせた。

pushd and popd

pushd と popd を使い始めた。

ほんとうに今更感があるが。学生の時に知っていつの間にか使わなくなり、社会人数年目で再度使うようにして使わなくなってしまった歴史が個人的にある。

使わなくなってしまった理由はタイプ数だと考えているので、タイプ数を少なくすべく以下のようにした。Dan Kogai氏のtips – 君はpushd|popdを知っているか?を参考にさせていただいた。

#~/.bashrc
function mycd {
  if [ -n "$1" ]; then
    pushd $1
  else
    pushd ~/
  fi
}
alias cd=mycd
alias po='popd'
alias  p='popd'

cd で別ディレクトリに移動すると同時にカレントディレクトリが保存され p で元のディレクトリに戻る。mycd 経由なのは pushd 引数無しでも ~/ に帰れるようにするため。

今のところいい感じ。しかしこういう小さい改善系はすぐ忘れてしまって残念な感じになるので、小さなネタでもブログに書いておこう。

ISUCON4本戦に出場しました!! 悔しい!!

週末、ISUCON4本戦に参加しました。

去年に引き続き2度目となる本戦出場です。メンバは前回同様@sonots, @Spring_MT, GoMiamiというチーム名で参加しました。予選はGoでしたが本戦は慣れてるRubyで戦いました。

お題は動画広告システムのパフォーマンス・チューニング。最初は動画広告とかやったことないしな..とおもいましたが、実質的には数MのファイルのPOST(入稿)とそのファイルのGET(impression, conversion)を中心としたサイト構成でした。

結果は30チーム中17位…..! 8017点でした。チームの目標が失格にならないことだった点はクリアしたものの、上位に食い込む…という目標は達成できませんでした。 本戦結果のとおりほとんどのチームが7千から8千点台の中で僅差で並んでて、抜きん出ることは出来きず悔しい感じでした。

今回の問題の本質はベンチが賢い点に気づけるかどうかで、レスポンスヘッダで適切にキャッシュコントロールさせればベンチサイドでキャッシュが効いて0バイトでレスポンス返すことが出来た、ということでした、、、、。本戦後の結果発表まで気づけてなくて本当に悔しかったです。ベンチ(!=ブラウザ)という先入観。

事前準備しことはChefレシピを仕込んでおいたくらいです。sshの鍵、/etc/hostsにエイリアス書く、vimrc、各種秘伝のたれ設定(nginx.conf, redis.conf, my.cnf)、nginxアクセスログ等の集計スクリプト等を開始直後にがっとまくやつ。一応各ホスト間もsshとおしたけどこれは大して意味なかった。あとはtd-agentでメトリクスシステム(事前に用意)に飛ばした。chefのお陰で開始20分くらいで環境整えれました。

@Spring_MTと@sonotsで方針ぎめやって、自分は設計に適宜つっこみ入れつつも基本的に2人にお任せしました。自分はnginxをメインに担当しつつ、その他もろもろ。

後半、local benchでは20000以上出る一方でremote benchだと8000程度でこれは何で…という状況になってその後も策出せず時間切れという感じでした。なんでremote bench遅いの〜〜 と悩む、というかremote benchでスコア出ないの他チームもqueueして遅くなってるんじゃない!?くらいしか考えが及びませんでした。実は仕様(レギュレーションには無かったものの)というところに気づいてどう帯域を使わないでレスポンス返せるか、という点に考えが及ばなかった。remote bench実行時にネットワーク帯域が頭打ってることは早くから気づいてので悔しい限りです!!!

次回に向けた反省。レギュレーションとコードを腰を据えてじっくり読む余裕。ベンチの挙動とアクセスログに向き合う余裕!!

なお超便利だったのは@mikedaさんのtmuxで複数サーバの同時オペレーションでした。chefなくてもかなり捗ったかも。

悔しさ山盛りですが毎度楽しいイベントです。みんな同じコンテキストでお酒飲みながら盛り上がれる懇親会はいいものです!!

最後にこのような素晴らしいコンテストを開催していただきありがとうございます!! 出題者、関係者のみなさま本当にお疲れ様でした!!

binfiles

~/bin/にあったオレオレスクリプトをgithub.com/niku4i/binfilesで管理するようにした。

オレオレスクリプトというのはシェルスクリプトやPerlで書いた自分用の小さなスクリプトだ。githubに置くのは主にバックアップ目的だ。なお、中身は大して充実していないことを最初に言い訳しておく。

私の環境では~/bin/jqとかghqとかサードパティのバイナリ実行ファイルも同居している状態だったので、~/bin/のオレオレスクリプトは削除して~/src/github.com/niku4i/binfiles/bin$PATHに追加することにした。

#~/.bash_profile
if [ -d "$HOME/src/github.com/niku4i/binfiles/bin" ]; then
  export PATH="$HOME/src/github.com/niku4i/binfiles/bin:$PATH"
fi

なお、新しいPCでセットアップする場合は、まずドットファイルをhomesickで復元し、さらにghqをセットアップした後、ghq get github.com/niku4i/binfilesすればよい。

ISUCON 2014 予選の記録 GoMiami

ISUCON4 予選に参加しました。

去年に引き続き2年目、前年同様 @sonots, @Spring_MT と。チーム名はGoMiamiで。今回もマイアミがすこし関係します!!

Go言語を選択すれば成長しないわけがない!!という意気込みのもとGoでいくことが決定。僕は少し前にA Tour of Go をひと通りやった程度。今回はインフラメインで2人はアプリコードメインに戦略立てるって感じで。

予選

事前準備

社内で1回前回大会の復習会をやったのと、チームで休日にあつまって前回予選課題を使って予行練習。当日どういう役割でどう動くかみたいなことを練習しました。この予行練習のお陰て今回予選はかなり余裕でました!! @sonots is our brain!

AM

午前中はボトルネック探しと、ベンチ特性、方針決めを中心にやった。ので午前中はチューニング作業は無し。

  • 開始と同時にメンバ分のインスタンス立ち上げ、本番用インスタンス立ち上げ
  • 本番環境整備(github pull&push環境)
  • ベンチ1回走らせて、プロファイリング。具体的にはnginxのアクセスログ、slowqueryログ、からベンチの特性分析
  • コード読んだり、画面見たり、ざっと。
  • my.cnf, nginx.confを予め用意しておいた内容で置き換え

MySQLのCPUが高いのはindexいれるとして、それ以外データベースであまりやることないことが分かって、事前に決めてた通りアプリにオンメモリで乗せる戦略にした。

MySQLは5.5が動いてて、一応5.6に上げる方針にした(けどこれは最終的にはオンメモリ戦略とるのでこの時点で上げる必要性はなかったかなと)

PM

飯食べながらさくっとMySQL5.6に上げたところで、じつはアプリのオンメモリ戦略の実装待ちで実はやることが無かった(笑)

アプリがfixしないうちに外を闇雲にチューンしてもはまるだけなので、焦っても仕方ないからこの時間帯はコード眺めたりしつつお茶を濁しておりました。やることないと色々手を動かしたくなるのですが、ここはぐっと押さえて。

アプリの改修が無事に終わって、MySQLのindexチューニングもいれて ここでスコアががくっと上がった。 詳細はsonotsブログが充実している。

アプリのオンメモリ戦略にてスコア上がった。さらにベンチ負荷上げて試したけどスコア頭打ち。CPU大して使ってないのにスコア上がらなくて。ネットワーク周りかなということでnetstat -an | grep TIME_WAIT | wc -l ってやると50kくらいポート使ってたので、以下のチューニングしたらport足りなくなる問題は改善しました。

net.ipv4.ip_local_port_range = 10000 64000 
net.ipv4.tcp_tw_recycle=1
net.ipv4.tcp_fin_timeout = 5
net.ipv4.tcp_max_syn_backlog = 1024
net.core.somaxconn = 65535

nginx-アプリ間はtcpで通信させててunix socketに変えれば良かったのだけど、martiniでunix socketに変えるやり方が分からなくて、上のチューニングでtcpで回ったのでよしとした。

結果としては最終的に40kあたりのレンジで他チームと横並びで、本戦出場は厳しそう…な感じですが、結果発表が楽しみです。

反省

Chef

予選はミドルウェアとか毎回同じなのでChefレシピ用意しといてインフラ担当が3人分開発環境まで揃えてあげればよかった。今回開発環境は各自お任せだったのでコード読み書きに専念させてあげればよかったなと。

Go

Go力足りてなくて速読できなかった(笑) Spring_MT氏はrubyでコードを把握した後Goをfixしたよと言っていた。なるほど。

所感

  • 前回大会に比べ今回は余裕をもって想定した力は発揮できたことは進歩
  • 個人的に次週に海外出張控えてて準備等々でISUCON準備できてなかったんですが2人が引っ張ってくれて助かったという感じです。

105 UPDATE

本戦出場決まりました!!!. 出張終えたら復習&&素振りやります。

というわけでリアルにマイアミ出張いってきます。

週末雨だったのでSerfをさわってみた

最近までSerfの意味を波乗りくらいにおもってました。’農奴’らしいです。梅雨で週末雨だったのでSerfを触ってみました。

Vagrantで仮想マシン2台建ててGet Startedをもくもくやってみました。

  • Membership: ノード一覧を管理する。管理するといっても中央サーバはいなくて各ノードが自律分散的に他ノードと会話して全ノードを知っている状態になる。ノードのクラスタへの参加、離脱はeventという形でクラスタ内のノードに即時伝搬する。イベントハンドラの機能により各ノードは任意のスクリプトを実行できる。

  • Failure detection and recovery: nodeは他のノードの(コネクティビティ的意味の)failを検知でき、他のノードにも伝える。また自動で再接続を試みる。これもイベントとして伝搬されイベントハンドラによりスクリプト実行可能。

  • Custom event propagation: ノードの参加、離脱、接続失敗以外にもカスタムなイベントをクラスタ内に伝搬できる。例えば、deploy実行を伝搬させたり、設定を伝搬させたり。またQueryを使えばevent handler経由で各ノードの実行結果を受け取ることもできる。

さわってみた感想としては、インストール楽。serfコマンドをダウンロードして置くだけ。Goの良いとろこ。また学習コストが低くてGet Started読んで試してみれば1, 2時間あればだいたい理解できるとおもいます。

ユースケース || 参考

まとめ

やんごとなき事情により/etc/hostsを使っているシステムを知ってて内部DNSサーバなあと考えてたけどSerf + /etc/hostsの組み合わせいいですね!

あと、個人的にはネットワーク機器みたいな箱物のサービスディスカバリに対する最適解が無いので、良いツールが出て来ないものかとおもっている次第なんだけど、ネットワーク機器がLinuxの箱で置き換わればいいのにとおもってます。

簡単に自立分散システム作れて良い時代になったものですね。

以上!!

Google Apps Script カスタムLoggerでログをspreadsheetに書き出す

Google Apps Scriptの中でLoggerで吐くログをシートに書き出すカスタムLoggerを作ってみた。

こういうシートができあがる。

20140618-mylogger

Logger.log()ではなくて恒久的に保存するためのロガーを作る。例えばTriggerで時限式実行するスクリプトのログを保存しておきたいとかの用途。

いつものとおりライブラリ化する。MyLoggerという名前で。

function log_sheet_() {
  var sheet_name = 'log';
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sh = ss.getSheetByName(sheet_name);
  if (sh == null) {
    var active_sh = ss.getActiveSheet(); // memorize current active sheet;
    sheet_num = ss.getSheets().length;
    sh = ss.insertSheet(sheet_name, sheet_num);
    sh.getRange('A1:C1').setValues([['timestamp', 'level', 'message']]).setBackground('#cfe2f3').setFontWeight('bold');
    sh.getRange('A2:C2').setValues([[new Date(), 'info', sheet_name + ' has been created.']]).clearFormat();
    
    // .insertSheet()を呼ぶと"log"シートがアクティブになるので、元々アクティブだったシートにフォーカスを戻す
    ss.setActiveSheet(active_sh);
  } 
  return sh;
}

function log_(level, message) {
  var sh = log_sheet_();
  var now = new Date();
  var last_row = sh.getLastRow();
  sh.insertRowAfter(last_row).getRange(last_row+1, 1, 1, 3).setValues([[now, level, message]]);
  return sh;
}

function debug(message) {
  log_('debug', message);
}

function info(message) {
  log_('info', message);
}

function warn(message) {
  log_('warn', message);
}

function error(message) {
  log_('error', message);
}

function fatal(message) {
  log_('fatal', message);
}

呼び出す側のプロジェクトでは、先ほど作ったMyLoggerのプロジェクトキーを登録して、こうやって呼び出す。初回呼び出し時に”log”という名前でシートを作成し以降は末尾の行にログが追加される。

MyLogger.info('works!');