fluentd pluginを作ってみて
最近elasticsearchやらfluentdやらのことについて勉強していて、理解が浅いことに気づいたので、とりあえずfluentdのpluginを作ってみた。
fluent-plugin-nested-hash-filter | RubyGems.org | your community gem host
作ってみて気づいたことをメモ的にまとめておく。間違っていることもおおいにあるだろう。
テストはtest-unit
で
rspec
も使えるらしい記事はいろいろ出ているけど、guard
を併用するとなんか色々めんどくさい(というか諦めた)。
その煩わしさを味合うのは、rspec
を使って気持よく開発をする目的に反するきがしたので、test-unit
を使うことにした。
そもそもfluentdがベーシックにサポートしているのがtest-unit
だから、まぁいいんじゃないか、と。
普通のrubygemsとは異なるディレクトリ構造
普通なら、lib/{gem_name}.rb
を作ってメインでrequire
させるソースを用意して、追加のライブラリはさらにlib/{gem_name}/...
につくってくと思う。
fluentd用のソースは、基本がlib/fluent/plugin/
の下に作っていく。一つのプラグインでinputとoutputをそれぞれ提供するなら、lib/fluent/plugin/
の下に2つ(以上)のソースファイルができることになる。
名前空間を切っておこうとか、あまり考えないほうが楽そう。
fluentdに登録するプラグインのtype
登録するプラグインの種類と、typeの名前、そのソースファイル名は連動している。
https://github.com/fluent/fluentd/blob/master/lib/fluent/plugin.rb
def try_load_plugin(name, type) case name when 'input' path = "fluent/plugin/in_#{type}" when 'output' path = "fluent/plugin/out_#{type}" when 'filter' path = "fluent/plugin/filter_#{type}" when 'buffer' path = "fluent/plugin/buf_#{type}" else return end end
そこんとこ自分は、ドキュメントで読み飛ばしていたかもしれなくて、プラグインが読み込まれないと言って、時間を使ってしまった。
outputプラグインをfilter的に使う場合
タグの名前を変更できるようにするなり、何か工夫しないと、タグの名前が常に同一になるため、ループしてしまう。
今回は、タグ名にプレフィックスをつけてもらうようにしてみた。
Vagrantを使って検証環境を作る
VagrantでVirtualBoxだったりEC2だったりをセットアップから起動まで簡単(?)にできるっぽいのでやってみた。
途中ハマりまくったので、徒然にメモを残しておくレベルでご勘弁。
リポジトリ
https://github.com/sugilog/vagrant.local
環境
クライアント: Mac OSX Yosemite 10.10.3
- v0.4.0
- Chefを使うのにこちらのほうが便利そうだったので。
- Berkshelfもこみこみ。
EC2
手順
環境に描き上げたパッケージは予めインストール。
作業用のディレクトリを作成する。
metadata.rb
を作成する。
- Berkshelfを
init
するときに必要。 - 最低限必要なのは
name 'NAME'
のみ。
berks init
する。
Berksfile
に必要なcookbooks
を追加してインストール。
berks vendor DIRNAME
- chef.ioでレシピを探す。
- 個人で使用するくらいなら、バージョンの指定は省略して良さそう。
Vagrantfile
に設定を書き込む。
- VirtualBox向けの設定
- EC2向けの設定。
- dummy boxの指定。
- urlは
https://github.com/mitchellh/vagrant-aws/raw/master/dummy.box
- urlは
- アクセスキーなどのEC2へのアクセスデータ
- リージョンやサブネットなど設定周りのID。
- Chefの設定
- Provisioningするときのシェルスクリプト的な。
- dummy boxの指定。
- VirtualBoxとEC2向けの設定はうまく設定すれば共通化できる。
- VirtualBoxでセットアップをテストしておけば、EC2でのセットアップを必要最小限にできる。
- Provisioningについて
- rootユーザーでなく実際に作業するときのユーザー向けの設定をする場合は、
privileged: false
にするのを忘れずに。
- rootユーザーでなく実際に作業するときのユーザー向けの設定をする場合は、
- EC2向けのアクセスキーなどの管理。
- バージョン管理の対象から外したファイルに設定を書き込んでおいた。
- 本当はアクセスキーのファイル管理は危ないので、環境変数からの読み込みがいいか。
- うまく行かなかったレシピ。
vagrant up
- まずはVirtualBox向けに。
- Chefでうまくいかないものはどんどん外したほうが良さそう。
- AWSはマネジメントコンソールを開きっぱなしにして、変なリージョンにインスタンスが立ち上がってないかとか、確認しながらが吉。
Vagrantの後
個人利用のみなので、いろいろ手動ですがご容赦を。
- EC2にscpしたいときのために、
vagrant ssh-config
を書き出しておく。 - vimのインストール。
- rbenvからのrubyインストール。
- weighttpのインストール
- ウェブアプリケーションのベンチマークを取るため。
- インストール時にはちょっと工夫。ref: http://qiita.com/saitara/items/f5a9192825026a4051fe
- などなど
参考
先に、参考にした記事とかを。
Heroku via Dropbox; Part 2
HerokuのDropbox Syncが終了するとのこと。おせわになりました。
Support for Dropbox Sync will end on 24 July 2018.
前回からの続き
Heroku via Dropbox - sugilogのブログ
やること
- Bootstrapなテンプレートを適用して、HTMLの中身を書き換える。
- ちなみにサイトここ→ http://sugilog-profile.herokuapp.com/
手順
好きなテンプレートを探す。
たとえば、Start Bootstrapで探してみる。
今回は、ここのGrayscaleなテンプレートを使います。(Download!)
ファイル設置
ダウンロードして展開したファイルの中身をDropboxのディレクトリ(Herokuのサイト向けのディレクトリ)につっこむ。
lessとか本当はいらないけど、とりあえずは細かいことは気にしない。
デプロイ
Herokuの管理画面からデプロイ!
確認してみます。
↓↓↓
うまくいかない場合
デプロイして、失敗する時がある。
- 今やっている方法だと、Herokuにphpで書かれたアプリケーションとして認識されているのだけど、phpファイルが無いと思われる(らしい)。
- そういうときは、phpファイルに空文字を足すとかして編集保存して、わざと変更があった状態にしておくと、うまくいくかもしれない。
Heroku via Dropbox
HerokuのDropbox Syncが終了するとのこと。おせわになりました。
Support for Dropbox Sync will end on 24 July 2018.
Herokuのデプロイ方法に、Dropbox Syncが追加されていたらしいので、試してみる。
とりあえず、できるだけ簡単に、HTMLを設置して表示することを目指す。
前提
- Dropboxアカウントを持っている。
- なければ作ってください。
- Herokuアカウントを持っている。
- なければ作ってください。
- なんか、シングルページのHTMLで、何かしら公開したい人。
- プログラムを組む気はないし、Facebookとかで公開してればいいし、ぐらいな人。
- HTMLを少しいじれる人。
Gitを使わなくて良くなるので、簡単なことはHerokuで、無料でできちゃう、とか思ってます。
手順
Herokuで新しくAppを作成する。
App = 新しいサイト、ということで、まずは設置場所をつくる。
ログインをして
右上の「+」のリンクをクリックして
Appの名前(サイト名っぽいのん)を入力する。
ここで入力した内容は、デフォルトでのサブドメインになる。
Dropboxと連携する。
予め連携したいDropboxのウェブサイトにログインしておくと良いです。
「Deploy」タブで「Dropbox」を選んで
「Connect to Dropbox」な感じで進んで
連携を承認して
おわりです。
Dropboxをみると、Dropbox > Apps > Heroku > (入力したApp名)
でディレクトリが作られる。
ファイル設置
ここだけ、自分のパソコンで作業。
ここでは、index.html
とindex.php
の2つのファイルを設定してみます。
Dropbox > Apps > Heroku > (入力したApp名)
なディレクトリの下に置く感じ。
- その他のディレクトリは無視ってください。
HerokuにDropbox経由でStaticなファイルを設置してみる
デプロイ
HerokuのDropbox Syncは自動的にデプロイされるわけではないので、Herokuの管理画面から作業が必要です。
- おかげで、Dropboxにファイルを設置したまま、作業ができて便利。
「Deploy」タブの「Dropbox」から
「Deploy Changes」のメッセージに変更内容の要約を入力して
「Deploy」押して、少し待つと完了。
表示されました。
Go言語:Channelsのselect
select の話
- selectステートメントで、複数のChannelsを条件分岐できる。
- 受信、送信、どちらも可能。
- Channelsの送信があるのに、受け取りを行ってなかったら、selectをしていない場合と同じで例外になるので注意。
- 複数条件に一致する場合は、ランダムに選択される。
- selectの中のいずれにも該当しない場合の条件を
default
で指定可能。- Channelsに限定した話ではない。注意。
試してみた
実行結果
start? 1 0 0 1 1 2 1 3 2 4 3 5 5 6 8 7 13 8 21 9 34 10 55 11 89 12 144 13 233 14 377 15 610 16 987 17 1597 18 2584 19 4181 quit 0 0 1 1 2 1 3 2 4 3 5 5 6 8 7 13 8 21 9 34 10 55 11 89 12 144 13 233 14 377 15 610 16 987 17 1597 18 2584 19 4181 quit
コード中のコメントアウトしているdefault
内の行を解くと、演算実行の間(繰り返されている間)に、何度もdefault
が呼び出されていることがわかる。
Go言語:数値型の幅
フィボナッチなサンプルを写経して動かしていた時にやっと理解した。
Go言語の数値型(の整数)
- intはジェネリックであり、実行環境に依存したサイズ(値の扱える範囲)を持つ。
- 範囲を超えた場合は、オーバーフローを起こす。
- 数値演算を行った結果、扱える範囲の最小または最大を超える。
- オーバーフローが発生しても例外は発生しない。
- ただし、リテラルの場合は、例外が発生する。
- わかりきったオーバーフローのためと推測。
- オーバーフローしたら破棄され、ラップアラウンドが発生する。
- 扱える範囲の最大値に達した後に、最小値に戻る。
- 扱える範囲の最小値に達した後に、最大値に戻る。
ラップアラウンドが発生するため、
x < x + 1
が常に成り立つとは限らない。ラップアラウンドを発生させる使用であるため、暗黙的な型変換は発生しない。
なぜGoには暗黙的な数値変換がないのですか?
C言語における数値型での自動型変換の利便性は過剰であり、混乱を招く原因となっています。式が符号無しなのはいつか? 値の大きさはどの位? オーバーフローする? 型変換の結果はポータブルで実行されるマシンに非依存? これはコンパイラも複雑にします。「通常の算術変換」の実装は簡単ではなく、アーキテクチャ間で一貫性を保つことも簡単ではありません。私たちは移植性の理由から、コード中で明示的に型変換をする労力を払うことによって、明確で解り易くする決断をしました。それでも、Go言語での定数の定義(符号およびサイズのアノテーションの要らない任意精度の値)は問題をかなり改善しています。
これと関連しますが、C言語とは違い、仮にintが64ビットだったとしても、intとint64は明確に別の型となります。int型はジェネリックです。整数が何ビットあるのかを気にしたい場合、Go言語では明示的に指定することが推奨されます。
試してみる
実行環境は64bitマシン
実行結果
overflowIntWithLiteral 9223372036854775807 + 0 => 9223372036854775807 overflowInt 9223372036854775807 + 0 => 9223372036854775807 9223372036854775807 + 1 => 9223372036854775806 overflowUint8Max 255 + 0 => 255 255 + 1 => 254 overflowUint8Min 0 - 0 => 0 0 - 1 => 255
コード中のコメントアウトを解いて実行すると、
# command-line-arguments ./overflow.go:21: constant 9223372036854775808 overflows int
Rubyで慣れきってて、めちゃくちゃに大きい数値を扱うことが少ないと、下手にラップアラウンドを罠として踏みそう。
大事なのは、明示的にプログラミングすることと、そのための想定。
Go言語:Channesの制限
Channelsの話
- Channelsはバッファにすることができる。
- 容量を指定することが可能。
make
関数の第2引数に指定。
cap
とlen
の実行が可能。- 容量
cap
以上にはバッファ(値の送信)できない。ブロックする。 - バッファサイズ
len
以上には取り出し(値の受信)できない。
- 容量
- 送信する値がなくなったら、Channelsを閉じることができる。
- 受信側で閉じない。
- 閉じることは必須ではない。
- Channelsの受け取り側で、閉じられているかどうかがわかる。
- 受信のチャネルオペレータの2番目のパラメータ(boolean)がcloseかどうかがわかる。
- 閉じられている場合、バッファサイズ以上の取り出し(値の受信)が可能。
- 受信される値は型のデフォルト値(だと思う)。intなら0。
range
で受信すると、閉じられるまで繰り返される。range
を使う場合は、必ず閉じなければいけない。- 実行時エラーになる。
書いてみた1
出力
before send 0 2 after send 2 2 received value 1 2 after receive 0 2
コメントアウトを解いてみると、fatal error
が発生する。
- 容量以上に送信しようとした時。
- バッファサイズ以上に受信しようとした時。
- コンパイル時にエラーにはならないため、実行時エラーとなる。
- エラーの内容から、送信か受信かがわかる。
all goroutines are asleep - deadlock! goroutine N [chan send]:
fatal error: all goroutines are asleep - deadlock! goroutine N [chan receive]:
書いてみた2
range
0 1 1 2 3 5 8 13 21 34
rangeじゃない
0 true 1 true 1 true 2 true 3 true 5 true 8 true 13 true 21 true 34 true 0 false
rangeでcloseしなかった場合。
- 実行時エラーで以下のようなエラーが出る。
- エラーするのは、
range
の行。
fatal error: all goroutines are asleep - deadlock! goroutine N [chan receive]:
rangeを使わない受信でcloseしなかった場合。
- 書いてみた1で記述したとおり、実行時エラーする。