やわらかテック

興味のあること。業務を通して得られた発見。個人的に試してみたことをアウトプットしています🍵

bulletのログファイルをパースするgemをリリースしました

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の方に頂けると嬉しいです。

GitHub - okabe-yuya/bullet_parser: 🔫: Parse 'bullet' log files and converts them other format for simplified analysis and storage.

作成のきっかけ

個人的にRui Ueyamaさんのコンパイラ作成のオンラインブックに取り組んでいます。
といっても過去に2回ぐらい挫折しているので、おそらく3回目の挑戦です。前に取り組んだ時はやり切ることに全力投球だったんですが、今回はゆっくりでもいいから...と1つ1つの理解を優先するようにしています。

www.sigbus.info

すると、再帰下降構文解析や生成規則といった美しい実装方法に衝撃を受けました。
「あー、こうやってプログラミング言語って作れるんだ!」と思うと、何か作りたくてうずうずしていました。
そんな中、ログファイルをパースしたいという絶好の機会がやってきたのです。

gemのリリースに関して

自作のライブラリを公開するとなると難しそうなイメージがありますが、非常に簡単でした。

  • bundle gem bundle_parserを実行
  • 公開に必要なファイルが生成される
  • .gemspecを更新する
  • ライブラリを実装する
  • rubygemにアカウントを作成してAPI KEYを発行する
  • rake buildを実行してリリース用のファイルを作成する
  • rake releaseを実行してリリース完了

qiita.com

もし良いアイディアや実装があれば、皆さんもgemをリリースしてみてください。
少しでも「ええな〜」と思ったらはてなスター・はてなブックマーク・シェアを頂けると励みになります。