昨年の夏くらいから採用活動を中止していましたが、再開することにしました。
応募条件は変わらず「プログラミングが好きなこと」です。フリーソフトウェアに理解があることが望ましいです。
1名のみの募集ですが、興味のある方は採用情報を参照してください。
モニタリングツールMuninのプラグインの作り方を簡単に紹介します。ざっくり紹介しているので、説明を省いているところもあります。というのも、次の話の準備のための説明だからです。
Muninはネットワークのモニタリングに用いられることが多く、監視対象の各ホストに情報収集デーモン(munin-node)を配置し、そのデーモンがネットワークの情報などを収集します。監視ホストは定期的に情報収集デーモンにアクセスし、監視対象のホストの情報をグラフにします。グラフはHTMLで出力されます。PHPなどを導入しなくてもよいため、導入が楽ですし、リソース消費も少ないです。
監視対象ホスト上でどの情報を収集するかはインストール後に追加・削除できます。情報を収集する部分がプラグイン化されているためです。情報収集デーモンmunin-nodeにプラグインをインストールすればそのプラグインが収集する情報がモニタリング対象となり、自動的に監視ホスト上でグラフ化されます。
Muninはネットワークをモニタリングするために使われることが多いですが、プラグインが収集する情報はネットワーク情報に限定されていないため、仕様に従ったプラグインさえインストールすれば任意の情報をグラフ化することができます。
先日リリースされたmilter manager 1.5.0でもSMTPクライアントの同時接続数や各milterの適用結果をモニタリングするMuninプラグインを提供しています。SMTPクライアントの同時接続数はネットワークっぽい感じがしますが、milterの適用結果はあまりネットワークっぽい感じがしませんね。
それでは、まず、プラグインの仕様です。
Muninプラグインは以下の入力と出力を満たす実行ファイルです。RubyスクリプトでもシェルスクリプトでもC言語で書いてコンパイルしたプログラムでもかまいません。ただ、後述するmunin-node-configureを使いやすいのでスクリプト言語の方がオススメです。
config: 以下のような1行1パラメータというフォーマットでグラフや収集する情報を出力します。パラメータのキーの一覧はprotocol-config - Munin - Trac(英語)にあります。
1 2 3 4 |
echo "graph_title milter manager statistics" echo "graph_category milter-manager" # ... exit 0 |
autoconf: プラグインが利用可能なら"yes"を出力し、終了コード0で終了します。利用不可なら"no"を出力し、終了コード1で終了します。以下はシェルスクリプトでの例です。
1 2 3 4 5 6 7 |
if [ "$available" = "yes" ]; then echo "yes" exit 0 else echo "no (daemon isn't running)" exit 1 fi |
suggest: 利用可能なプラグインのパラメータを1行に1つずつ出力します。(詳しくは後述)
1 2 3 |
echo "report" echo "status" exit 0 |
引数なし: 以下のように収集したデータを出力します。
1 2 3 |
echo "accept.value 4" echo "reject.value 31" exit 0 |
と、このくらいのことは検索すると日本語の情報もいろいろでてきます。が、なぜかautoconfとsuggestのことはあまりでてきません。これがMuninプラグインの便利なところな気がしますが、どうしてでしょう。
ということで、そのあたりの紹介もします。
Muninにはmunin-node-configureというプラグインの追加・削除を自動的に行ってくれるツールがついています。ブログなどに書かれているプラグインの追加方法は以下のように手動でやっていることが多いです。
% sudo ln -s /usr/share/munin/plugins/cpu /etc/munin/plugins/
しかし、手動で追加・削除は面倒です。システム管理をしている人ならなるべく自動化したいと思うことでしょう。
munin-node-configureを使うと、プラグインの引数に"autoconf"を渡して、プラグイン自身に利用可能かを判断させ、その結果に応じて追加・削除することができます。自作プラグインでも"autoconf"に対応することで管理がだいぶ楽になります。ブログなどに載っている自作Muninプラグインは一回限りの利用だけを想定しているからなのか、"autoconf"に対応しているものが少ないように見えます。
"autoconf"に対応していることをmunin-node-configureに伝えるためには以下の行をプラグイン内に埋め込んでおく必要があります。バイナリの実行ファイルよりスクリプトの方がよいと書いたのはこのためです。
1 2 |
#%# family=auto #%# capabilities=autoconf |
このような行があるとmunin-node-configureは"autoconf"引数付きで呼び出してくれます。このときに"yes"と出力すれば自動で追加対象にしてくれます。ConcisePlugins - Munin - Trac(英語)あたりも参照してください。
munin-node-configureを利用した自動追加・削除は以下のコマンドでできます。
% sudo -H /usr/sbin/munin-node-configure --shell --remove-also | sudo -H sh
munin-nodeを再起動すれば反映されます。
% sudo /etc/init.d/munin-node restart
最近だと、/etc/init.d/以下のスクリプトを直接実行するよりもservice(8)を使う方がよいでしょう。
ワイルドカードプラグインとは1つのプラグインで複数のグラフの情報を収集できるプラグインのことです。(1.4からは同じようなことができるマルチグラフプラグインという仕組みも増えています。)
ワイルドカードプラグインはプラグインファイルのファイル名の最後が「_」で終わっています。使うときは、ファイル名の最後にパラメータをつけたシンボリックリンクを張ります。
例えば、「milter_manager_」というワイルドカードプラグインに「status」というパラメータを渡したいときは以下のようにします。
% sudo ln -s /usr/share/munin/plugins/milter_manager_ /etc/munin/plugins/milter_manager_status
プラグイン内では自分のファイル名(シェルやRubyでいえば$0
)を見てパラメータを受けとります。これにより、1つのプラグインファイルで複数の情報を収集することができるようになります。
そして、どのパラメータを指定すればよいかをプラグインに判定させて自動でワイルドカードプラグインを追加・削除することもできます。このときに使われる入力が"suggest"です。この機能に対応していることをmunin-node-configureに教えるためにはプラグイン内に以下のような行を書いておきます。
1 2 |
#%# family=auto #%# capabilities=autoconf suggest |
これを書いておけばmunin-node-configureが"suggest"引数付きでワイルドカードプラグインを実行してくれます。このとき、"status"と"report"というパラメータが利用できるのであれば、以下のように1行につき1パラメータで出力します。
status report
こうすると、1つのワイルドカードプラグインを2種類のプラグインとしてインストールしてくれます。このとき、インストールされるプラグインは「milter_manager_status」、「milter_manager_report」というような名前になります。
追加・削除方法は変わりません。
% sudo -H /usr/sbin/munin-node-configure --shell --remove-also | sudo -H sh
munin-nodeの再起動も忘れないようにしましょう。
% sudo /etc/init.d/munin-node restart
Muninプラグインの作り方を(実例は示さずに)紹介しました。実例を示さない代わりに本家のドキュメントの概要箇所をリンクしています。具体例はドキュメントやインストール済みのプラグインを見てください。プラグインは小さいシェルスクリプトかPerlスクリプトのことが多いので、読むとすぐにわかるでしょう。
また、管理がとても楽になり便利なのに、なぜかあまり触れられていない"autoconf"と"suggest"についても説明しました。自分でMuninプラグインを作るときは"autoconf"に対応することをオススメします。もちろん、ワイルドカードプラグインにする場合は"suggest"にも対応することをオススメします。
いつか、ソフトウェア開発にもMuninを使う例を紹介したいものです。例えば、自動化された単体テストのテスト数やカバレッジ率などもMuninを使ってグラフ化することができます。
C・C++言語用の単体テストフレームワークCutterのバージョン1.1.3をリリースしました。
今回のリリースではデータ駆動テストのサポートを強化しています。サポートしている型が増えたので、これまで以上にテストデータを作りやすくなっています。
例えば、このようにテストデータを作ることができます。
1 2 3 4 5 |
gcut_add_datum("normal case", "expected", G_TYPE_CHAR, 'e', "input", G_TYPE_STRING, "Cutter", "n", G_TYPE_UINT, 4, NULL); |
詳しくはリファレンスマニュアルの便利なテストデータ用API - gcut_add_datum()あたりを見てください。
Cutterが今のようなGLibベースの作りになってから2年半くらい経ちますが、徐々にユーザが増えてきました。最近、nfc-toolsという近距離無線通信(NFC)用のツールを開発しているオープンソースプロジェクトでも使われているのを見つけました。
groongaもCutterを採用しているプロジェクトで、Cutterのカバレッジ支援機能なども使っています。groongaプロジェクトではCutterが提供している支援機能だけではなく、コミットした人毎のカバレッジ率などもグラフ化して公開しています。今後のリリースで、Cutter本体がこのような見せ方を支援する機能を提供したいですね。
Cutter 1.1.3の目玉機能とCutter採用プロジェクトについて紹介しました。
C・C++のプロジェクトで使うテスティングフレームワークを探しているならCutterも検討してみてはいかがでしょうか。
groongaのRubyバインディングrroonga 0.9.3がリリースされました。rroonga 0.9.3に関することはメーリングリストでのアナウンスを見てください。
rroonga 0.9.3ではWindows用のgemも提供するようにしました。このgemにはgroonga/rroongaのビルド済みのバイナリが含まれているのでビルド環境がないことが多いWindowsでも簡単に使えるようになっています。
さて、このgemですが、1つのgemでRuby 1.8.7にもRuby 1.9.1にも対応しています。そもそも、gemにはWindowsや32bit環境などのプラットフォームを指定することはできますが、Rubyのバージョンは指定することができません。そのため、Rubyのバージョン毎にgemを用意することはできません。用意する場合はgemのパッケージ名を"rroonga187"や"rroonga191"などと変えなければいけません。これはカッコワルイですね。
解決法は、1つのgemの中に1.8用のバイナリと1.9用のバイナリを両方いれ、実行時にどちらを使うかを切り替える、です。
まず、以下のようにバイナリを配置します*1。
lib/1.8/groonga.so # <- Ruby 1.8.7のWindows用バイナリ lib/1.9/groonga.so # <- Ruby 1.9.1のWindows用バイナリ
そして、groonga.soを読み込む部分を以下のようにします。
major, minor, micro, = RUBY_VERSION.split(/\./) require "#{major}.#{minor}/groonga.so"
これで、適切なバイナリを読み込むことができます。
この他に、rroongaのように依存しているDLL(libgroonga.dll)がある場合はそのDLLがあるフォルダをPATHに入れなければいけない、などといった注意点がありますが、それはまたいつか機会があったら触れるかもしれません。
それでは、1.8.7でも1.9.1でも使えるWindows用バイナリが入ったgem*2をDebian GNU/Linux上のMinGWで作る方法を紹介します。
まず、Windows用のRuby 1.8.7と1.9.1をMinGWでクロスコンパイルします。これにはrake-compilerが便利です。
% sudo gem install rake-compiler
まず、MinGWをインストールします。
% sudo aptitude install -y mingw32
それでは、Ruby 1.8.7-p249をビルドします。
% rake-compiler cross-ruby VERSION=1.8.7-p249 EXTS=--without-extensions
クロスコンパイルしたrubyはextconf.rbを実行してMakefileを作れればいいだけなので、拡張ライブラリなどはいりません。環境変数として「EXTS=--without-extensions」を指定すると拡張ライブラリはビルドされないのですが、もっとカッコイイ方法がありそうな気がします。
同様にRuby 1.9.1-p378もビルドします。
% rake-compiler cross-ruby VERSION=1.9.1-p378 EXTS=--without-extensions
ただ、これは失敗します。失敗したら以下のパッチを当てます*3。
1 2 3 4 5 6 7 8 9 10 11 12 |
diff -ru ruby-1.9.1-p378.orig/win32/win32.c ruby-1.9.1-p378/win32/win32.c --- ruby-1.9.1-p378.orig/win32/win32.c 2009-12-05 18:40:53.000000000 +0900 +++ ruby-1.9.1-p378/win32/win32.c 2010-04-20 23:10:13.000000000 +0900 @@ -4604,7 +4604,7 @@ ret += written; if (written == len) { - (const char *)buf += len; + buf = (const char *)buf + len; if (size > 0) goto retry; } |
このパッチは以下のように適用できます。
% cd ~/.rake-compiler/sources % patch -p0 < /tmp/ruby-1.9.1-build-fix.diff
もう一度、同じコマンドでビルドすると成功します。
% rake-compiler cross-ruby VERSION=1.9.1-p378 EXTS=--without-extensions
Windows用のRuby 1.8.7とRuby 1.9.1ができたので、これを利用してgem用のバイナリをクロスコンパイルします。これには、rake-compilerが提供するRake::ExtensionTaskが便利です。
Rake::ExtensionTaskの使い方を紹介しますが、ここでは、もうすでにRakefileがあり、その中でGem::Specificationを作っているものとします。
specがGem::Specificationだとすると、Rakefileに以下を追加することでcrossタスクが定義されます。
1 2 3 4 5 |
require 'rake/extensiontask' Rake::ExtensionTask.new("groonga", spec) do |ext| ext.cross_compile = true ext.cross_platform = 'x86-mingw32' end |
Rake::ExtensionTask.new
に"groonga"を指定していますが、このようなRakefileを使うときは、以下のようなファイル構成になっている必要があります。
./ +-- ext/ | +-- groonga/ | +-- extconf.rb | +-- rb-grn.c | +-- ... + Rakefile ...
ext/の下にRake::ExtensionTask.new
で指定した名前と同じディレクトリを作り、その下にextconf.rbを置きます。
crossタスクを使って1.8.7用のバイナリと1.9.1用のバイナリをクロスコンパイルするには以下のようにします。
% rake cross compile RUBY_CC_VERSION=1.8.7:1.9.1
うまくいくとlib/1.8/groonga.soとlib/1.9/groonga.soができます。
これらを両方含んだgemを作るには以下のようにします。
% rake cross native gem RUBY_CC_VERSION=1.8.7:1.9.1
これでpkg/rroonga-0.9.3-x86-mingw32.gemができます。あとは、このgemをrubygems.orgにアップロードすれば完了です。
% gem push pkg/rroonga-0.9.3-x86-mingw32.gem
Ruby 1.8.7/1.9.1のどちらでも使えるWindows用のgemをDebian GNU/Linux上で作成する方法を紹介しました。もし、拡張ライブラリをWindows上でも簡単に使えるようにしたいのであれば、Ruby 1.8.xと1.9.xの両方をサポートしてみてはいかがでしょうか。
この話とは関係ありませんが、Ruby Summer of Codeの学生の応募の締切りは今週の土曜日だそうです。(参考: [ruby-list:47029] [ANN] Ruby Summer of Code)
Rubyとオープンソースに興味のある学生の方は応募してみてはいかがでしょうか。本家のSummer of CodeやRuby Summer of Codeはフリーソフトウェアの開発に関わるよい機会といえます。Rubyベストプラクティスの著者が開発しているPDF生成ライブラリのPrawnなど、いくつものRuby関連のフリーソフトウェアがSummer of Codeのおかげで開発が進んできました。(参考: Summer of Codeと須藤さんとSubversionのRuby bindings - 角谷HTML化計画(2005-10-26))
ぜひ、このような機会を活かして、フリーソフトウェアの開発に積極的に参加してみてください。
Rubyベストプラクティス -プロフェッショナルによるコードとテクニック
オライリージャパン
¥ 3,456
先日、るりまの成果物であるRubyのリファレンスマニュアルを検索するWebアプリケーションるりまサーチを公開しました。
OpenSearchにも対応しているため、Firefoxの右上の検索窓から検索することもできます。
これまでも、るりまの成果物はBitClustを使ってWebブラウザから見ることができました*1。しかし、BitClustのWebインターフェイスは検索機能が弱く、目的の情報にたどり着くのが難しいと感じたことがあったのではないでしょうか。例えば、全文検索ができなかったり、そもそも検索がとても遅かったりしました。
るりまサーチでは全文検索エンジンとしてgroongaを利用することにより、高速な全文検索機能と使いやすい絞り込み機能を実現しています。それでは、るりまサーチの機能とその実装について簡単に紹介します。
るりまサーチは多くの情報を絞り込んでいきながら目的の情報に到達することを意識したインターフェイスになっています。そのため、できるだけ簡単に絞り込んでいけるような機能を組み込んであります。
ここでは、絞り込みに関する機能を2点だけ紹介します。
groongaの得意な機能の1つはドリルダウンと呼ばれる、検索結果の中から特定の値をグループ化し、それぞれのグループのレコード処理を数える処理です。るりまサーチでもこの機能を利用して絞り込みやすいインターフェイスを提供しています。
るりまサーチではページ上部にそのときに絞り込める条件を表示します。例えば、トップページではマニュアルの種類によって絞り込めるリンクを表示しています。
このとき、事前に絞り込んだ後のレコード数も表示しています。この時点で絞り込み後のレコード数を数えているので、絞り込んだ後にレコード数がないリンクを表示しないことができます。つまり、「リンクを辿ったけど絞り込んだらマッチするレコードがない!」という状況を防ぐことができます。
便利に絞り込めるリンクを提供し、その一方で、無駄な絞り込みを行わずに済むようになっています。
簡単に条件を絞り込めるようにするだけではなく、簡単に条件を解除することもできます。これは様々な絞り込みを行いながら目的の情報に辿りつけるようにするためです。
ページ上部にはどのような条件で絞り込んでいったかが表示されるようになっています。それぞれの絞り込み条件は条件の横にあるリンク*2を辿るだけで簡単に解除することができます。
絞り込みすぎてしまったときは、これで条件を解除して違う条件で絞り込んでいくことができます。
るりまサーチはRuby 1.9.1とRackとrroongaを用いて実装されています。rroongaはgroongaをRubyから利用するためのRubyバインディングです。るりまサーチではgroongaをサーバとしてではなく、ライブラリとして利用しています。
rroongaはgroongaの高速な機能を活かしたまま、より使いやすいRubyらしいAPIを提供しています。るりまサーチはそんなrroongaを使って、すっきりとした記述で実現されています。ここでは、rroongaを使ったコードを2つ紹介します。
groongaはRDBと同じようにデータの格納場所毎に型を持っています。groongaにデータを格納する前に格納場所を用意する必要があります。
rroongaでは格納場所の定義(スキーマ)をより宣言的に記述するためのAPIを用意しています。以下は検索対象の情報を保存する「Entries」テーブルの定義です。RDBなどのスキーマを見たことがあるなら、この定義からgroongaがどのようなデータを格納できるようになるかを想像できるのではないでしょうか。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
Groonga::Schema.define do |schema| schema.create_table("Entries", :type => :hash, :key_type => "ShortText") do |table| table.short_text("name") table.short_text("local_name") table.short_text("label") table.text("document") table.text("signature") table.text("description") table.reference("type", "Types") table.reference("class", "Classes") table.reference("module", "Modules") table.reference("object", "Objects") table.reference("version", "Versions") table.reference("visibility", "Visibilities") end end |
このように、Rubyでは宣言的に処理を記述することがわりとよく行われます。これは、内部DSLとも呼ばれ、やりすぎる人も出るほどです。例えば、上記のような記述を以下のようにすることもできますが、これは少しやりすぎではないかと感じます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
Groonga::Schema.define do create_table("Entries", :type => :hash, :key_type => "ShortText") do short_text :name short_text :local_name short_text :label text :document text :signature text :description reference :type, :Types reference :class, :Classes reference :module, :Modules reference :object, :Objects reference :version, :Versions reference :visibility, :Visibilities end end |
rroongaでは検索条件をクエリ文字列ではなく、Rubyの式として記述することができます。
例えば、「name」カラムの値が「Regexp」であるレコードを検索するときは以下のようになります。
1 2 3 |
entries.select do |record| record.name == "Regexp" end |
「name」カラムの値が「Regexp」あるいは「description」カラムに「正規表現」が含まれているレコードを検索するときは以下のようになります。
1 2 3 |
entries.select do |record| (record.name == "Regexp") | (record.description =~ "正規表現") end |
「name」カラムか「description」カラムに「encoding」を含むレコードを検索するときは以下のようになります。ただし、「name」カラムにマッチした場合はスコアをあげて、より上位に表示するようにします。
1 2 3 4 5 6 7 |
entries.select do |record| target = record.match_target do |match_record| (match_record.name * 100) | (match_record.description) end target =~ "encoding" end |
DataMapperやSequelなど文字列ではなくRubyの式で条件を指定できるようにするORマッパーはいくつかありますが、最終的にそれらはSQLになります。しかし、rroongaの場合はRubyで書いた式がそのままgroongaのネイティブな条件式になります。カッコいいですね。
また、ORマッパーも少しやりすぎてしまう傾向がある分野ですが、rroongaはやりすぎることなく、Rubyらしさを保ったまま条件式を指定できているのではないでしょうか。少しやりすぎてしまうと、Symbolにメソッドを追加してしまったりします。
Rubyのリファレンスマニュアルを検索するWebアプリケーション「るりまサーチ」の機能と実装を簡単に紹介しました。
るりまサーチを使うことでるりまプロジェクトの成果物であるRubyのリファレンスマニュアルをより便利に活用することができます。
また、るりまサーチの実装はgroongaのRubyバインディングであるrroongaのよいサンプルでもあります。groongaをRubyから利用しようと考えていた方はGitHub上にある、るりまサーチのソースコードを読んでみるとよいでしょう。ライセンスはLGPLv3+です。
るりまサーチはSinatraなどのフレームワークを使わずに、直接Rackを使っています。そのような場合にどのようにテスト環境を構築するか、というのもいつか紹介できるとよいですね。今、興味のある人はソースコードを見てください。
このように、るりまサーチにはまだおもしろいところが色々あるのですが、今回はこのへんにしておきます。
*1 自分で設定するのが面倒な場合はokkezさんが公開しているBitClustを利用することもできます。
*2 画像にしたいですね。