ActiveRecord上のN+1問題を検知するbullet
というgemがあります。
bullet
を仕込んでおく事でbullet.log
ファイルに該当箇所でN+1問題が発生している旨のログが出力されるようになります。どんな対応をすれば良いかまで提案してくれる...非常に賢いですね。
2023-08-15 15:20:31[WARN] user: okabe GET /api/v1/products/tags USE eager loading detected Product => [:product_tags] Add to your query: .includes([:product_tags]) Call stack /Users/okabe/ruby/app/product_tags_controller.rb:18:in `map'
非常に便利なのですが、結構な量のログが出力されるため、1つ1つ確認しようと思うと辛いです。
特に重複したログもガンガン書き込まれるため、N+1問題の改善のために「発生箇所のユニークな一覧が見たい!」と思っても絞り込むには骨が折れます。
gemをリリースした
bullet_parser | RubyGems.org | your community gem host
というわけでbullet
が出力するログを解析してトークンかし任意のフォーマットで保存するためのbullet_parser
たるgemをリリースしました。
何気に人生で初めてのgemリリースです。お盆休みで時間があったのでサクッと作ってみました。
使い方はREADME.mdに書いた通りですが少し説明しておくとbullet
が出力したbullet.log
ファイルのパスを指定することで、ログファイルを解析してログ1つ1つをトークンへと変換します。
tokens = BulletParser.tokens('bullet.log') # tokens [#<struct BulletParser::Tokenizer::Token detected_at="2023-08-15 15:20:31", log_level="WARN", detected_user="okabe", http_method="GET", end_point="/api/v1/products/tags", problem="USE eager loading detected\n Product => [:product_tags]\n Add to your query: .includes([:product_tags])\n", root_line=" /Users/okabe/ruby/app/product_tags_controller.rb:18:in `map'\n", callstack= " /Users/okabe/ruby/app/product_tags_controller.rb:18:in `map'\n /Users/okabe/ruby/app/product_tags_controller.rb:18:in `block in <class:ProductTagsCotroller>'\n /Users/okabe/ruby/spec/requests/products/tags_spec.rb:30:in `block (3 levels) in <main>'\n">]
変換したトークンをどう使うかは自由です。
現状ではCSVファイルに変換したトークンを1行ずつ保存するという機能をサポートしています。
分析機能を追加しておいた方が良いかなと思いましたが「それRubyでやる必要あるっけ」と感じたので、CSVを読み込んでPythonなりでやってもらうことを想定しています。
もしバグや機能追加してほしい...という声があれば Githubの方に頂けると嬉しいです。
作成のきっかけ
個人的にRui Ueyamaさんのコンパイラ作成のオンラインブックに取り組んでいます。
といっても過去に2回ぐらい挫折しているので、おそらく3回目の挑戦です。前に取り組んだ時はやり切ることに全力投球だったんですが、今回はゆっくりでもいいから...と1つ1つの理解を優先するようにしています。
すると、再帰下降構文解析や生成規則といった美しい実装方法に衝撃を受けました。
「あー、こうやってプログラミング言語って作れるんだ!」と思うと、何か作りたくてうずうずしていました。
そんな中、ログファイルをパースしたいという絶好の機会がやってきたのです。
gemのリリースに関して
自作のライブラリを公開するとなると難しそうなイメージがありますが、非常に簡単でした。
bundle gem bundle_parser
を実行- 公開に必要なファイルが生成される
- .gemspecを更新する
- ライブラリを実装する
- rubygemにアカウントを作成してAPI KEYを発行する
rake build
を実行してリリース用のファイルを作成するrake release
を実行してリリース完了
もし良いアイディアや実装があれば、皆さんもgemをリリースしてみてください。
少しでも「ええな〜」と思ったらはてなスター・はてなブックマーク・シェアを頂けると励みになります。