Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Reasonable logging in BtoB Application
Search
hoshino tsuyoshi
October 10, 2024
Technology
5
110
Reasonable logging in BtoB Application
テーマ: 変更履歴を適切に保持したい
rails ruby
hoshino tsuyoshi
October 10, 2024
Tweet
Share
More Decks by hoshino tsuyoshi
See All by hoshino tsuyoshi
GitHub Actionsで `shell` に `ruby {0}` と書ける話
hoshinotsuyoshi
2
170
RDSのパスワードローテーションについて考えてみた話
hoshinotsuyoshi
1
120
「技術的負債」について私から言えること私から言えないこと
hoshinotsuyoshi
2
1.1k
spreeのrails updateの戦いの歴史と github上のPR作成時の工夫
hoshinotsuyoshi
0
1k
Ruby is fun but difficult
hoshinotsuyoshi
0
390
バッチ処理でhakoを使う話
hoshinotsuyoshi
0
9.7k
docker swarm 触ってみた #dockerlt
hoshinotsuyoshi
0
1.1k
貧者のためのCoreOS(Jenkinsを例に)
hoshinotsuyoshi
1
1.6k
個人で使ってみた Docker と CoreOSとか
hoshinotsuyoshi
7
3.6k
Other Decks in Technology
See All in Technology
Android Audio: Beyond Winning On It
atsushieno
0
3.4k
スクラムガイドに載っていないスクラムのはじめかた - チームでスクラムをはじめるときに知っておきたい勘所を集めてみました! - / How to start Scrum that is not written in the Scrum Guide 2nd
takaking22
2
200
Unlocking the Power of AI Agents with LINE Bot MCP Server
linedevth
0
120
いま注目のAIエージェントを作ってみよう
supermarimobros
0
360
Snowflake×dbtを用いたテレシーのデータ基盤のこれまでとこれから
sagara
0
120
複数サービスを支えるマルチテナント型Batch MLプラットフォーム
lycorptech_jp
PRO
1
960
組織を巻き込む大規模プラットフォーム移行戦略 〜50+サービスのマルチリージョン・マルチプロダクト化で学んだステークホルダー協働の実践〜 / Platform migration strategy engaging all stakeholders
toshi0607
2
140
Oracle Base Database Service 技術詳細
oracle4engineer
PRO
10
75k
Firestore → Spanner 移行 を成功させた段階的移行プロセス
athug
1
500
OCI Oracle Database Services新機能アップデート(2025/06-2025/08)
oracle4engineer
PRO
0
180
「全員プロダクトマネージャー」を実現する、Cursorによる仕様検討の自動運転
applism118
22
12k
品質視点から考える組織デザイン/Organizational Design from Quality
mii3king
0
210
Featured
See All Featured
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
16k
RailsConf 2023
tenderlove
30
1.2k
Docker and Python
trallard
46
3.6k
Facilitating Awesome Meetings
lara
55
6.5k
Faster Mobile Websites
deanohume
309
31k
Product Roadmaps are Hard
iamctodd
PRO
54
11k
What’s in a name? Adding method to the madness
productmarketing
PRO
23
3.7k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
49
3k
Understanding Cognitive Biases in Performance Measurement
bluesmoon
29
1.9k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
131
19k
Designing for humans not robots
tammielis
253
25k
How To Stay Up To Date on Web Technology
chriscoyier
790
250k
Transcript
Roppongi.rb #23 "Proposals on Rails 2024" Reasonable logging in BtoB
Application ROUTE06, Inc. GitHub:@hoshinotsuyoshi 1
Me GitHub:@hoshinotsuyoshi • X:@hoppiestar • • SWE in ROUTE06 •
EDI platform 2023- • NO-CODE platform for building business apps 2024- • Yes, API backend is made with Ruby on Rails • public repo?(TBD) • 2
Outline EDI Platform • テーマ : 変更履歴を適切に保持したい • PaperTrail gemの手法とイベントソーシングについて説明
• 「誰が変更したか」を記録する工夫 • その他の工夫 • まとめ • 3
4
商取引におけるさまざまな事柄 (注文、商品、見積、出荷、承認、 etc.) を扱う。 EDI platform BtoB Applicatoin • many
resource classes • • buying, ordering, shipping ... • many stakeholders • • buyer, supplier, trader ... • ... • 5
テーマ : 変更履歴を適切に保持したい 6
商取引におけるさまざまな事柄について、 「誰が、いつ、どのように変更を加えたか」 を保持したい 目的 ... (今回は分析用途の目的は薄い ) テーマ : 変更履歴を適切に保持したい
システム不具合や障害発生時の調査・分析 • SOC監査対応 • リソースの変更履歴を表示するビューの追加実装 • 7
変更履歴 -> アプリケーションのログに頼る ?? 「アプリケーションのログにモデルの変更を記録する」という手もあるかもしれな いが ... • このログには他の情報も記録しているため、それらが混ざった状態で一定期間保持 する必要がある
• CloudWatchLogsのデータ保持のための料金もかかる • (or Logを分ける ?) • 8
paper_trail gemは、 Railsアプリケーションでモデルの変更履歴を追跡・管理する ための仕組みを提供する。 各モデルの変更を追跡し、 versions テーブルに履歴として保存する。 以下のコマンドを実行し、 versions テーブルを準備する
bundle exec rails generate paper_trail:install [--with-changes] [--uuid] bundle exec rails db:migrate 手法 : paper_trail gem 9
class Article < ApplicationRecord has_paper_trail end 手法 : paper_trail gem
1. バージョンの作成について モデルにバージョン管理を追加 : モデルに has_paper_trail を追加するだけで、そ のモデルの Create/Update/Destroy操作が自動的に追跡される。 • versions テーブルに履歴を保存 : 各変更は versions テーブルに保存され、バージ ョンごとの変更内容が記録される。 • 10
2. バージョンの保持内容について versions テーブルには、以下の情報が含まれる : | id | item_type |
item_id | event | object | ... |-----|-----------|---------|--------|------------------------------------------------------------------------------------| | 1 | Article | 1 | create | null | | 2 | Article | 1 | update | {"title": "First Post", "content": "Hello World!", "author": "Alice"} | | 3 | Article | 1 | update | {"title": "First Post - Revised", "content": "Final revision.", "author": "Alice"} | 手法 : paper_trail gem item_type: 追跡対象モデルのクラス名 (polymorphic) • item_id: 追跡対象モデルの ID(polymorphic) • event: 作成、更新、削除のイベント名 • object: 変更前のオブジェクトの状態を JSON形式 (または YAML)で保存 • object_changes: 各カラムがどのように変わったかを記録 • 11
イベントソーシングは、システム内で発生したすべてのイベントを保存し、そのイベ ントからデータの現在の状態を導き出す手法。 eventが主役となり、データの変化を イベントとして記録する。 1. eventsテーブルでのデータ管理 | aggregate_id | seq
| event_type | event_data |... |--------------|-----|-----------------|----------------------------------------| | Article:1 | 1 | ArticleCreated | {"title": "First Post", "author": "A"} | | Article:1 | 2 | ArticleUpdated | {"content": "New content"} | 参考 : イベントソーシング イベントを events テーブルに記録。 • 各イベントが「いつ、何を変更したか、何が起きたか」という情報を持つ。 • 12
2. Single Source of Truth 3. Projectionで状態を復元 参考 : イベントソーシング
イベントがデータの唯一の信頼できる情報源( Single Source of Truth) 。 • 過去の状態は、イベントの履歴を projection(投影)して再構築することで確認可 能。 • events テーブルのデータを集計・投影することで、アプリケーションで使用する 現在の状態を表現。 • この手法により、過去の任意の時点のデータ状態を再現することが可能。 • 13
イベントソーシング ActiveRecordのコールバックでバージョンを作成する手法 ざっくりまとめると イベントが主役 • gem例 : rails_event_store • リソースが主役
• gem例 : paper_trail • gem例 : audited • 14
1. ActiveRecordとのスムーズな統合 モデルの変更があれば自動的にバージョンが作成され、余分な設定や複雑なロジ ックを書く必要がない。 2. コールバックを活用した直感的な動作 ActiveRecordのコールバックを活用し、 save や update
メソッドの操作時に履 歴が自動で保存される。 Rails標準のメソッドを使うだけで、 paper_trail が自 動的に動作するため、開発中にイベント処理やトランザクションの管理をあまり 気にせずに済む。 paper_trail を採用したモチベーション 15
「誰が変更したか」を記録する工夫 16
「誰が変更したか」を記録する工夫 whodunnit (who done it・誰がやったか ?) の活用 • IPアドレス? •
できれば DBに保存したくない ... • アプリケーションのログに吐く ? • 17
平たく言えば、ユーザー IDを version テーブルの whodunnit カラムとして追加す る。コントローラに設定が必要。 class GraphqlController <
ApplicationController # ... before_action :set_paper_trail_whodunnit # ... whodunnit の活用 次のように書くと、コントローラーで current_user が定義されている場合、 current_user.id が whodunnit 列に保存される (という規約 )。 • current_user は devise gemを使っていてユーザークラスが User の場合に利用 されるメソッド。 • 18
devise を使っていない場合は current_user を定義したりすれば OK。 def current_user # 別途rack middlewareでセットしたユーザーを取得
request.env["xxx.tenant_user"] || raise end whodunnit の活用 19
IPアドレス IPアドレス ? 調査ケースによっては、あると便利な場合がある • 機微情報という見方もできる。できればあまり直接 DBに保存したくない ? • アプリケーションのログに吐く
? • --> AWSのログに頼るのはどうか • 20
--> この IDを追加で versionsテーブルに記録すれば OKでは? IPアドレス 今回の AWSの構成の事情 CloudFrontが ALBや
Railsアプリケーションの前段に配置されている • S3にログを吐く設定にしているので、ソース IPアドレスとリクエストを識別でき る ID( X-AMZ-CF-ID )が残っている • 21
paper_trail の 機能を使う。 例えばコントローラーに以下のように書けば、 x_amz_cf_id を versionsテーブルに記 録できる。 def info_for_paper_trail
{ # CloudFront. "x_amz_cf_id" => request.headers["HTTP_X_AMZ_CF_ID"], } end これで versionsテーブル -> X-AMZ-CF-ID -> S3のログから IPアドレスをたどることが できるようになった ! IPアドレス 22
さらに追加で Amazon X-Rayとアプリケーションログとの紐付け用に情報を足す例 def info_for_paper_trail { # CloudFront. "x_amz_cf_id" =>
request.headers["HTTP_X_AMZ_CF_ID"], # 追加: アプリケーションログと紐づけられるRequestID "request_id" => request.request_id, # 追加: Amazon X-Ray. ALBのログと紐づけられるID. "x_amzn_trace_id" => request.headers["HTTP_X_AMZN_TRACE_ID"], } end 参考 23
これで ...リーズナブルに対応できたのでは ? (分析対応ではなく )障害調査・侵害疑惑調査・監査対応などを目的と想定する場合 はこれで十分 • アプリケーションログ (ECS/CloudWatchLogsを利用 )も肥大化しないしリーズナブル
• CloudFrontのログは S3に置かれるので、 Amazon Athenaによる検索が可能 • 積極的に活用はしていないが、仕組み自体は準備済みであり、 CloudWatchで検索 をかけるよりも金銭コストが低いと思われる • 24
ここまでで 変更履歴が記録できるようになった 何を • いつ • 誰が • AWSのログと組み合わせることで「誰がどこから」もトレース可能に •
25
その他の工夫 26
保存時に必ずコールバックを発火するようにしたい コールバックが発火しないと versionが保存されないので ... update_column(s) , update_all , insert ,
... • -> rubocopの設定で禁止 • Rails/SkipsModelValidations • 27
1つのテーブルが極端にレコード数が増えるのを防ぐため、 クラスごとに versionsテーブルを分割。 # バージョンテーブルの抽象クラス class TenantRecordVersion < TenantRecord self.abstract_class
= true class << self def inherited(subclass) super # ...snip... # PostgresのRLSのための設定をここに書く(今回は説明省略) # ...snip... subclass.include ::PaperTrail::VersionConcern versions テーブルが肥大化することを抑止 28
このように使う : # ActiveRecordのクラス class Image < TenantRecord has_paper_trail versions:
{ class_name: "ImageVersion" } # ...snip... # Imageクラス用のバージョンテーブル class ImageVersion < TenantRecordVersion end versions テーブルが肥大化することを抑止 29
まとめ 30
変更履歴の保持手法について、 paper_trail gemを中心に説明しました。 この手法により、 BtoBアプリケーションにおけるログの管理がより効果的に行える ようになったと考えています。 まとめ 簡便さを重視し、 Railsエンジニアのマインドセットに適した履歴管理を実現 •
ActiveRecordとのスムーズな統合やコールバックを活用することで、エンジニアの 負担を軽減 • whodunnit や CloudFrontログの活用により、誰がどこから変更したかの追跡が可 能に。直感的かつリーズナブルな履歴管理が実現 • 31
「うちはこんな設計にしてる」 「こうしたほうがいいぞ !」みたいな話も聞きたいです ! 質問があれば、いつでもどうぞ! みなさんはどうやっていますか? 32
東京でお会いしましょう ! 👋 さいごに宣伝 33