Sinatra で Controller を分割したくなったら Rack::URLMap を使うとよさそう
こういう感じのアプリケーションがあったとします。
で、この例だとまったくファットじゃないんだけど、Controller がファットになってきてしまった場合に、いい感じに分割したくなることもありますよね。
ということでとりあえずこうしてみた。
各クラスが Sinatra::Base
を継承するではなくて、Base
を設けてそれを継承するようにしているのは、各クラス内でそれぞれ before
を書きたくなかったからです。
が、このように書いてしまうと、リクエストパスによっては 1 回のリクエスト中に before
内の処理が複数回実行されてしまいます。(実際に before
に適当に p 123
とか書いて起動して、アクセスしてみるとわかる)
それだと最悪なので、最終的にこうした。
ルーティングを config.ru
に書きたくなかったので、定数化して呼び出すようにしています。
参考
[Ruby] method の Thread をたてるときに method に引数を渡す
普通にメソッドをスレッド化するとこうなる
#!/usr/bin/env ruby require 'thread' def foo num = 0 loop do sleep 1 num += 1 p num end end t = Thread.new(&method(:foo)) t.join
引数を取るメソッドをスレッド化したい場合
これは Syntax error
#!/usr/bin/env ruby require 'thread' def foo(num) loop do sleep 1 num += 1 p num end end t = Thread.new(&method(:foo), 0) t.join
-:12: syntax error, unexpected ',', expecting ')' t = Thread.new(&method(:foo), 0) ^ shell returned 1
これは ArgumentError
#!/usr/bin/env ruby require 'thread' def foo(num) loop do sleep 1 num += 1 p num end end t = Thread.new(&method(:foo, 0)) t.join
-:12:in `method': wrong number of arguments (2 for 1) (ArgumentError) from -:12:in `<main>' shell returned 1
これが正解
#!/usr/bin/env ruby require 'thread' def foo(num) loop do sleep 1 num += 1 p num end end t = Thread.new(0, &method(:foo)) t.join
とのことです
YAPC::Asia 2014 Tokyo で 40 分の時間をいただいてお話させてもらった
「ブログを書くまでが YAPC::Asia」とのことですので、このエントリを以って僕の YAPC::Asia 2014 が終わってしまいます。
インフラエンジニアは死んだ
インフラエンジニア(狭義)は死んだ - YAPC::Asia Tokyo 2014
トークに応募したきっかけ
「声を上げない層をターゲットにしよう」ということを、トーク募集期間中に実行委員長の和田裕介さんがブログに書かれていました。
僕が2年連続でベストトーク賞をとれた訳 #yapcasia - ゆーすけべー日記
で、よく観察してみると、グレイトな ライブラリやサービスをつくっているハッカーは 「ただ口も声も大きいから」目立っているだけで、1,000人という規模の来場者からしたら 実はごく少数のマイノリティなんすよね。
ああ、なるほど。と思いました。
なんか、いわゆるそういう声の大きい人たちの評判、反応ばかり気にしてしまって、自分の意見を言いづらいみたいな感じに勝手に自分で決めつけてしてしまっていたのかもなぁ、と気付かされました。
「ああ、なんか勘違いしてたかも」と思わせてもらえた。ので、勇気をひねり出してトークに応募してみました。
話したこと
- 自分は何を果たすべきか考える
- 名称に縛られてしまうことで行動を起こさないと死ぬ
- 必要になったときに出来る準備をしておく必要がある
ということを主張してきました。
僕自身、「インフラエンジニアだしプログラミングとか自分のすべきことの範疇の外のことだからするつもりもないし」と思っていた時期がありました。
しかし、それは誤っているのではないかという思いを持つようになり、紆余曲折を経て実際に今ではコードを書くことで解決できる問題に向き合って取り組む時間が多くなりました。
その課程の話をさせていただきました。
伝わりきらず残念だったこと
「なんかいいこと言ってたっぽいけど、結局は人の言葉の引用だよね」みたいなご意見もちらほらといただきました。
まぁ実際に発表内容にはそういう場面も少なくなく、真っ向から否定は出来ないのですが、そういう印象が真っ先に感想として出てきたということは少し残念でした。
実際に何か自分に取って刺さる内容の主張や意見に出会った時に、「刺さった」とか「いい話だった」と感想を持つことは多いと思います。
多くの場合はそこで終了してしまって、その先の自分に活かすための行いを伴うというところまでいかないのではないかなと。
僕の場合は、色々な方々の意見や教えを自分なりに咀嚼して解釈し、それを自分に活かして現在に至るというところがあります。
今回の話はその集大成という意識がありましたので、それをきちんと伝えられるような話し方が出来なくて非常に歯がゆい思いがございます。
なんかもっとこう、実例というか、もっと具体的にやってきたこととかをお話し出来れば良かったのかなぁと反省しております。
次に活かす。
意外と共感の声が聞こえてきた
嬉しいことに多くの共感の声もいただきました。
懇親会でもたくさんの方に声をかけていただき、トークの内容や境遇などについて大勢の方とお話させていただきました。
開発者のお祭だし、共感はあまり得られないだろうなーと思っていたので、同じような思いを持たれて共感してくださる方が意外と大勢参加されたいたんだなぁということに大変驚きました。
YAPC::Asia の幅の広さ、本当にすごい。
YAPC::Asia Ramen Challenge
これもまわってきて、次にまわしたし、これで本当の本当に僕の YAPC::Asia 2014 は終わったと言える。
数年ぶりに食ったなりたけ、すごくうまかったけど、食い終わった後に激しい胃もたれが襲ってきて老いを感じさせられてつらかった。
#yapcramen YAPC::Asia Ramen Challenge - @bayashi Diary
@handlename @repeatedly @studio3104 ラーメン画像UPするか、OSSに貢献してください! #yapcramen http://t.co/AmKXLkQ8MN
— ブラッド・ピット (@kenjiskywalker) September 5, 2014
#yapcramen OSSに貢献するかラーメンを食して画像をあげてください @su_aska @shiyakeita @hattara_tw pic.twitter.com/2DVWRDwZHr
— Satoshi SUZUKI (@studio3104) September 5, 2014
さいごに
今年で3回めの参加でした。本当に楽しかった。
運営スタッフの皆様、スピーカーの皆様、参加者の皆様、本当に素晴らしい場を提供してくださりありがとうございました。
人格というかコミニュケーションというかそういうぼんやりした話
MySQL Casual Talks vol 6.でNata2について発表してきた
MySQLのスロークエリログを一覧したりサマライズしたり出来るNata2
というツールを作ったので、MySQL Casual Talks vol.6で発表させてもらった。
id:oranieさんが早速試してみてくれて、書いてくれたブログエントリにたくさんのブクマがついて大変にありがたい限りです。
MySQLのslow query logを可視化するnata2が大変便利そう - iをgに変えるとorangeになることに気づいたoranieの日記
使い方などをもう少し詳しく
発表当時はドキュメントがまったくなくて大変に雑な感じだったり、発表で説明しきれなかった部分もあったので、ここで改めて少し詳しい解説をします。
Nata2とは
パーズされたスロークエリログをHTTP Postで登録し、件数グラフ、スロークエリログの履歴、mysqldumpslow
相当のサマライズなどの表示が出来るウェブアプリケーションです。
スロークエリログを登録するサーバと、パーズやPostを行うクライアントの2つのコンポーネントがあり、クライアントライブラリは2種類の実装があります。
サーバ、クライアントライブラリすべて、Ruby 2.0以降
で動作します。
Nata2 Server
https://github.com/studio3104/nata2
インストール、データベース準備、起動
git clone
$ git clone https://github.com/studio3104/nata2.git
bundle install
$ cd nata2 $ bundle install
スロークエリログを記録しておくデータベースの準備
データベースは、特に理由のない限りはMySQL
をお使いいただくことを推奨します。
テストではsqlite3
を使ったりはしていますが、他のRDBMS
では動作の確認をしていません。
- 設定ファイル
Sequel
のdburl
をconfig.toml
に記述します。
$ cat ./nata2/config.toml dburl = "mysql2://nata:password@localhost/nata2"
MySQL
にNata2
用のユーザを作成
任意。上述の設定ファイルの通りに接続をしたい場合は、以下の様な感じで。
mysql> GRANT ALL ON nata2.* TO 'nata'@'%' IDENTIFIED BY 'password';
- create database
Nata2
用のデータベース、nata2
を作成します。
$ mysql -uroot -p -e'CREATE DATABASE `nata2`'
- テーブル作成
テーブル作成スクリプトを実行します。
$ bin/nata2server_init_database
起動
unicorn
と組み合わせたり、ポートを変えたりなど、環境に合わせて。
以下のコマンドでは、フォアグラウンドで起動し、0.0.0.0:9292
で待ち受けます。
$ bundle exec rackup
スロークエリの登録
http://nata2.server/api/1/:sarvice_name/:host_name/:database_name
なURLに、以下のようなパラメタをPostしてあげるだけです。
後述のクライアントライブラリを使うとラクですが、自前でパーズなどしてからPostすることももちろん可能です。
{ datetime: 1390883951, user: 'user', host: 'localhost', query_time: 2.001227, lock_time: 0.0, rows_sent: 1, rows_examined:0, sql: 'SELECT SLEEP(2)' }
Postパラメタ
user
とhost
以外は必須です。
- datetime
- スロークエリログ発生日時
- エポックタイム
- user
- クエリの実行ユーザ
- 文字列
- host
- どのホストからのクエリか
- 文字列
- query_time
- クエリ実行時間
- 小数
- lock_time
- ロック時間
- 小数
- rows_sent
- 送信された行数
- 整数
- rows_examined
- 処理対象になった行数
- 整数
- sql
- SQL
- 文字列
- 改行文字を含んでも大丈夫
ビュー
- データベース一覧
同じサービスの中に同名のデータベースが登録されている場合、自動的にComplex
の表示の下に複合ビューへのリンクが生成されます。
Database
の表示の下に表示されるリンクは、各データベースの個別のリンクです。
- スロークエリログ履歴
画像は複合ビューです。同一サービス中の同名データベースがマージされて1つのビュー中に表示されています。
グラフはスロークエリログの件数。
- スロークエリログ個別
mysqldumpslow
相当のサマライズ
画面右上で選択された期間で登録されているスロークエリログをサマライズし、クエリの種類ごとに、合計回数順
、合計クエリ実行時間順
、合計ロック時間順
、合計フェッチ行数順
、平均クエリ実行時間順
、平均ロック時間順
、平均フェッチ行数順
に表示します。
画像は合計回数順
。
クライアントの実装について
MySQL
のスロークエリログは、出力されたuse
句以降は、そのデータベースでのスロークエリログだということがわかるが、どのデータベースのスロークエリだったかということをクエリごとに記録してくれない。
そのため、最後のスロークエリログが発生したデータベースを記録しながらファイルをナメていく実装をしています。
なお、Percona Server
はその限りにあらず、schema
というパラメタをクエリごとに記録してくれる。(設定次第?)
nata2-client
https://github.com/studio3104/nata2-client
- 2つのクライアントライブラリのうちの1つ
- SSHとmysql clientで情報を取得
- スロークエリログ収集対象サーバと、SSH、mysqldの接続情報は設定ファイルに記述
- 処理済み行数と、最後のスロークエリログのデータベース名を
sqlite3
に記録しながら実行する - メモリをギリギリまで使いたいMySQLのサーバで
fluentd
を使うのが不安な場合に使う
インストール
$ git clone https://github.com/studio3104/nata2-client.git $ cd nata2-client $ bundle install
設定
config.toml
に以下のように記述します。
# スロークエリログ収集対象ホストとサービス名を指定 [targets] service1 = [ "host1", "host2" ] service2 = [ "host3", "host4" ] # Nata2 ServerのFQDNと待ち受けポートを指定 [nataserver] fqdn = "nata2.server" port = 9292 [default] # 一度の実行で何行処理するか指定 fetch_lines_limit = 10000 # 個別に指定がないホストのSSH接続情報 [default.ssh] username = "root" password = "password" keys = [ "/home/studio3104/.ssh/id_rsa" ] passphrase = "" port = 20022 # 個別に指定がないホストのmysqld接続情報 [default.mysql] username = "nata" password = "nata" port = 13306 # ホストごとの個別のSSH接続情報 # host1の実行時にdefault.sshを上書きする [host1.ssh] username = "satoshi" keys = [ "/home/satoshi/.ssh/id_rsa" ] passphrase = ""
実行
$ bundle exec bin/nata2-client start
fluent-plugin-nata2
https://github.com/studio3104/fluent-plugin-nata2
http://rubygems.org/gems/fluent-plugin-nata2
- 2つのクライアントライブラリのうちの1つ
fluentd
のプラグイン- 2つのプラグインを内包
- パーズされたスロークエリログを
Nata2
にPostするout_nata2
- スロークエリログをtail&パーズして吐き出す
in_mysqlslowquery_ex
- パーズされたスロークエリログを
- 2つのプラグインを内包
out_nata2
パーズされたスロークエリログをNata2
にポストするプラグインです。
登録API(http://nata2.server/api/1/:sarvice_name/:host_name/:database_name
)の:service_name
と:host_name
はtag
から決定されるので、このプラグインに処理が渡るときにはtagの末尾がservicename.hostname
のようになるように設定して、サービス名とホスト名を指定しておく必要があります。
主な設定項目
- server
- 必須
Nata2 Server
のFQDN
を指定します
- port
- 必須
Nata2 Server
の待ち受けポートを指定します
in_mysqlslowquery_ex
fluent-plugin-mysqlslowquery
というプラグインが既に存在しているが、
SQL
の連続する空白文字と改行文字を省いてしまうFluent::TailInput
を継承しているため、最近のfluentd
のtailプラグインで使える機能が使えない- どのデータベースのスロークエリログかわからなくなってしまう問題の対応として、ログを先頭から読む
read_from_head
を有効にして使いたい
- どのデータベースのスロークエリログかわからなくなってしまう問題の対応として、ログを先頭から読む
の理由から、Fluent::NewTailInput
を継承した別のプラグインを書きました。
主な設定項目
pos_file
- オプション(有効推奨)
- ログファイルをどこまで読んだか記録しておくファイル
last_dbname_file
とは異なるパスを指定
last_dbname_file
- オプション(有効推奨)
- 最後に出力したスロークエリログが発生したデータベースを記録しておくファイルパスを指定
pos_file
とは異なるパスを指定
dbname_if_missing_dbname_in_log
- オプション
- スロークエリログからも、
last_dbname_file
からもどのデータベースでのスロークエリログだったかわからなかった場合に使われるデータベース名
format
- 何を指定しても内部で
none
に書き換えられます
- 何を指定しても内部で
read_from_head
- オプション(有効推奨)
- ログを先頭から読みこむ
path
- 必須
- スロークエリログのパス
tag
- 必須
out_nata
との組み合わせで使う場合、tagの末尾をservicename.hostname
のようにして、サービス名とホスト名を指定しておく必要がある
設定例
とりあえずこんな感じで設定しておけばNata2
にスロークエリログが登録されていきます。
ご利用の環境に合わせて適宜変更してご利用ください。
<source> type mysqlslowquery_ex read_from_head path /path/to/slowquery.log tag slowquery.servicename.hostname pos_file /tmp/slowquery.log.pos last_dbname_file /tmp/slowquery.log.lastdb </source> <match slowquery.**> type nata2 remove_tag_prefix slowquery. server nata2.server port 9292 </match>
今後追加したい機能
EXPLAIN
の取得、登録、参照SHOW CREATE TABLE
の取得、登録、参照
など
おわりに
自分がはじめて参加したMySQL Casual Talksはvol3.でした。
登壇されていた皆さんがすごく輝いて見えたのを今でも覚えているし、まさか回を重ねた同会で自分が登壇するだなんて、当時の自分はまったく考えていなかっただろうなーと思います。
機会をくださったid:myfinderさん、会場を提供してくださった日本オラクル様、本当にありがとうございました。
YAPC::Asia Tokyo 2014 で 40 分間話をする権利をいただきました
トーク採択していただきました。インフラエンジニア(狭義)は死んだ
ソーシャルメディアでの拡散などしてくださった皆様有難うございます!!!1
初日の朝イチでだいぶ早いですが、早起きしてお越しいただけると大変うれしいです。
2014-08-29 10:20:00
に 慶應義塾日吉キャンパス内 協生館 2F 多目的教室2
でお待ちしております。よろしくお願い致します。
HRForecast の EMBED でヘッダとラベルを非表示に出来るようになったよ
HRForecast には EMBED の機能があり、iframe で別のページ(別のアプリケーション)にグラフを埋め込むことが出来ます。
ただ、埋め込む先のアプリケーションによっては、グラフ名と 1週間,1ヶ月,1年 などのレンジ指定、CSVエクスポートが置かれているヘッダ領域
、グラフ名と値が表示される右側のラベル領域
が不要な場合もあるかなと思います。
ので、pull-request して取り込んでもらいました。
suppress graph headers or labels when specified respective options #26
指定するクエリストリングと参考画像
iframe の中の URL のクエリストリングによって表示が変わります。
- ヘッダもラベルも消したい場合
graphheader=0&graphlabel=0
- ヘッダだけ消したい場合
graphheader=0
or graphheader=0&graphlabel=1
- ラベルだけ消したい場合
graphlabel=0
or graphheader=1&graphlabel=0
- ヘッダもラベルも消さず、従来どおりにしたい場合
graphlabel
, graphheader
を指定しない or graphheader=1&graphlabel=1