俺のスライドや記事が4つ紹介されてた
2013年Rubyの話題を一挙に振り返るまとめ | Engine Yard Blog JP
「作りました!」と「チュートリアル、Ruby, Railsを始める」に1つ、
「Tips! コーディング」に2つ
既存のwindows用のsyslogクライアントはオープンソースじゃなかったり、有料だったり、windowsのEventLogを全部転送してくれるんだけどEventLogへの書き込みに管理者権限が必要だったりで手軽に使えるものが無かったので作った。
syslogにちょっと書き込みたいだけなのに色んなツール組み合わせないとならないのがおかしい。
Syslog Client for Windows
https://github.com/shokai/syslog-client-for-windows
不具合などは@shokaiかgithubのissueにお願いします
使い方
syslog-client.exeをダウンロードして適当にPATHの通っている場所(C:¥windows¥system32¥とか?)に置いてから
% syslog-client -help
% syslog-client -host syslog.example.com hello world
% syslog-client -host syslog.example.com hello world -tag WARN -pid 100
このようにsyslogに書き込んでくれる。syslog-ngにちゃんと書き込めてたし、その出力をfluentd経由でMongoDBに読み込ませたりもやってる。
例:ログイン・ログアウトした時にユーザー名を送信する
こういう login.bat を作って
syslog-client -host syslog.example.com -tag INFO "%username% login at %COMPUTERNAME%"
Windowsスタートメニューの「ファイル名を指定して実行」から、「gpedit.msc」を起動。
ユーザーの構成→Windowsの設定→スクリプト(ログオン/ログオフ)に、bat追加すると実行してくれる
引数つけて実行するだけでsyslog飛ばせるので便利万歳だと思う。
実装
Rubyで書いてocraでexeに固めた。ocraはrubyスクリプトをインタプリタごと1つのexeに固めてくれるソフトで、gemで提供されている。
% gem install ocraするとmyapp.exeができる。ファイルサイズはだいたい2MBぐらいになる。
% ocra myapp.rb
WinXPでビルドして、Windows7と8でも動いた。よく出来てる。
Rubyで書いたので、exeに固める前のライブラリ部分をTravis CIでテストできるのも精神的衛生上良かった。
windows8ってsystem32に置けないの?
C:¥windows¥system32¥に置くとFatal error: Failed to open executable ~~というようなエラーがでて起動しないんだけど、どこに置くのが作法なのかよくわからない。他の場所に置いてフルパスで実行すればちゃんと動く。
例えば https://gist.github.com/shokai/6667948 の場合、
https://gist.github.com/shokai/6667948.json という風に後ろに.jsonを付けるとメタデータが読める。
JSON内のfiles配列にファイル名が列挙されている。
ファイルの実体を取得するにはraw/ファイル名にアクセスすればいい
https://gist.github.com/shokai/6667948/raw/MainActivity.scala
raw/(hash)/ファイル名だとgitのバージョンハッシュを指定できる。何も無しだとHEADになる。
Rubyで書くとこんな感じ
require 'json'
require 'httparty'
class Gist
attr_reader :data, :code
def initialize(url)
res = HTTParty.get "#{url}.json"
raise "#{url} get error (code:#{res.code})" unless res.code == 200
@data = JSON.parse res.body
code_file = @data['files'].find{|i| i =~ /.+\.rb$/ }
res2 = HTTParty.get "#{url}/raw/#{code_file}"
raise "#{url} get error (code:#{res2.code})" unless res2.code == 200
@code = res2.body
end
end
gist = Gist.new 'https://gist.github.com/shokai/6667948'
puts gist.code
設定ファイルにgistのURL書いたらプラグインとして読み込んでくれるようなのに使える。
weather_jpで降水確率を取得して、30%以上だったら青に、そうでなければ赤く光らせる。
これがあると朝ぱっと天気が目に入るので、傘を忘れることがなくなる。
github.com/shokai/weather-hue
関連:プログラマブル電球hueをRubyから使う
実装
bundle exec ruby weather-hue.rb --city 鎌倉で実行できる。crontabなどに登録して定期的に動かすとよい。
weather-hue.rb
require 'rubygems'
require 'bundler'
Bundler.require
args = ArgsParser.parse ARGV do
arg :city, 'city', :alias => :c, :default => '東京'
arg :rain, '降水確率のしきい値 (%)', :default => 30
arg :help, 'show help', :alias => :h
arg :hue, 'hue light number', :default => 0
on :help do
STDERR.puts help
STDERR.puts "e.g. ruby #{$0} -city 鎌倉"
exit 1
end
end
weather = WeatherJp.get args[:city], :today
puts "#{weather} - #{Time.now}"
light = Hue::Client.new.lights[ args[:hue].to_i ]
puts "light : #{light.name}"
light.on = true
light.saturation = 180
light.brightness = 200
if weather.rain < args[:rain]
light.hue = 60000 # red
else
light.hue = 47000 # blue
end
バイト先(大学)で、syslog-ngに流れてくるログをfluentdに流し込もう事になった。最終的にMongoDBに入れる。
windows/mac/unix系など色々なOSが入り乱れた環境なので、各ホストからはsyslogで飛ばすのがいいらしい。んで、最終的にモダーンなfluentdやmongodbに通して使おうという感じ。
(特にnt-syslogがすごいよくできてて、windowsなのにちゃんとutf-8で送ってくれるしえらい)
fluentdのプラグインを作り始めたけどまだ完成してない。なんか間違ってるとかこうした方がいいという情報あったら教えてください。
(ちなみにgem search fluent –remote | grep tail で見つかる物は全部ソース読んだり試したけど要求仕様を満たすgemは無かったです)
syslogをfluentdに流し込む
fluentdのtailプラグインにはsyslogフォーマットがあるので、こんな感じで読める<source>mongodbに貯まる。
type tail
path /var/log/path/to/syslog_file
tag syslog.test
format syslog
</source>
<match syslog.**>
type mongo
database fluent
collection syslog
host localhost
port 27017
</match>
syslog-ngの出す複数のログファイルをfluentdに流し込みたい
syslog-ngの書き出し先はこんな感じになっていたので
destination d_erns { file (/var/log/syslogs/$HOST_FROM/$HOST_FROM-$YEAR$MONTH.log);};
ログを送りつけてくるホストの数だけディレクトリが生成され、月毎のファイルに書き込まれる。
複数ファイルをtailしなければならない。
ワイルドカードでtailできるfluentd input pluginを作る
tailプラグインを見てみると、fseekなどを駆使して自前でtail -F相当の処理をするように実装されていた。で、ソースを読むとtailプラグインはカンマ区切りで複数ファイルを監視できるようになっている。
じゃあこれをちょっと拡張すればいいのでは?と思って、pathをワイルドカードで指定できるinput pluginを作った。
in_wildtail.rb
module Fluent
class WildTailInput < TailInput
Plugin.register_input('wildtail', self)
def configure(conf)
conf["path"] = Dir.glob(conf["path"]).join(',')
super
end
end
end
/etc/fluent/plugin/in_wildtail.rb として保存して、
<source>
type wildtail
path /var/log/syslogs/*/*.log
tag syslog.test
format syslog
</source>
これで全てのログファイルを追えるようになった。
毎月のログファイル切り替えに追随する
月毎に新しいログファイルに追記されるようになっている。また、新しいホストが増えたら自動的にディレクトリが掘られて、そこにログファイルが書き出される。
ファイルやディレクトリが増えたことを検知する機能をwildtailプラグインに追加したい。しかしThreadで定期的に回すのはfluentdの動作の妨げになりそう。
fluentdのgemspecを見るとcool.ioというイベント駆動ライブラリを使っていた。
cool.ioの作法に従って書けばfluentdの動作の邪魔にはなりにくそう。
というわけでcool.ioでディレクトリ監視するのを試しに書いてみた。
require 'cool.io'
class LogFileWatcher < Cool.io::StatWatcher
def initialize(path)
super path, 0.1
end
def on_change(previous, current)
p previous
p current
puts "-"*5
end
end
reactor = Cool.io::Loop.new
watcher = LogFileWatcher.new "/Users/sho/src/ruby/tmp/coolio"
reactor.attach watcher
reactor.run
扱い方がよくわからないオブジェクトで通知されるけど、とにかく指定したディレクトリで何か変更があるとイベントが起こる。
lsするだけで反応するけど。
これを組み込めばなんとかなるのではないか?
という所までがんばった。
うまくいったらgemする。