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
59
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
110
RDSのパスワードローテーションについて考えてみた話
hoshinotsuyoshi
1
95
「技術的負債」について私から言えること私から言えないこと
hoshinotsuyoshi
2
1k
spreeのrails updateの戦いの歴史と github上のPR作成時の工夫
hoshinotsuyoshi
0
890
Ruby is fun but difficult
hoshinotsuyoshi
0
330
バッチ処理でhakoを使う話
hoshinotsuyoshi
0
9.5k
docker swarm 触ってみた #dockerlt
hoshinotsuyoshi
0
1.1k
貧者のためのCoreOS(Jenkinsを例に)
hoshinotsuyoshi
1
1.5k
個人で使ってみた Docker と CoreOSとか
hoshinotsuyoshi
7
3.5k
Other Decks in Technology
See All in Technology
RSGT Walk Through
kawaguti
PRO
2
380
Cosmos DB で持続可能な RAG を実現しよう!~ AOAI Dev Day ふりかえりを添えて / Sustainable RAG with Cosmos DB with recap AOAI Dev Day
miyake
0
180
RDS for Db2 データ移行編 - Part2:S3経由のバックアップ・リストアでデータ移行 /20241011-RDSforDb2-dojo
mayumihirano
0
140
WSUSが非推奨に!? Windowsの更新管理を改めて勉強する!
ebibibi
0
550
Rist_Meetup_Kaggleは業務の役にたつ - ビジネスコンテンツ情報を活用する BtoB 事業編 - / rist-meetup-20241012
taro_masuda
0
280
【㈱アイモバイル】エンジニア向け会社説明資料
imobile
0
480
Microsoft 365 でデータセキュリティを強化しよう
sophiakunii
2
450
太田博三(@usagisan2020)
otanet
0
140
マルチテナントのサービスインフラに大きなテナントを受け入れるまで
7474
0
560
管理画面とユーザー機能の調和を取り戻す!~クエリパフォーマンス改善の成功物語~ / Restore harmony between administrative and user functions!
minisera
1
200
VueとViteで作るUIコンポーネントライブラリ ~デザインシステムとプロダクトの理想的な分離を目指して~ / 20241019_cloudsign_VueFesJapan2024_1
bengo4com
8
3.1k
CData Virtuality を活かせるキーシナリオと製品デモ
cdataj
0
430
Featured
See All Featured
Building a Scalable Design System with Sketch
lauravandoore
459
33k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
4
250
Designing Experiences People Love
moore
138
23k
Designing the Hi-DPI Web
ddemaree
280
34k
5 minutes of I Can Smell Your CMS
philhawksworth
202
19k
Building Better People: How to give real-time feedback that sticks.
wjessup
362
19k
Code Review Best Practice
trishagee
63
17k
Visualization
eitanlees
143
15k
Imperfection Machines: The Place of Print at Facebook
scottboms
264
13k
The Power of CSS Pseudo Elements
geoffreycrofte
71
5.3k
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
46
2.1k
No one is an island. Learnings from fostering a developers community.
thoeni
19
2.9k
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