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
71
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
130
RDSのパスワードローテーションについて考えてみた話
hoshinotsuyoshi
1
100
「技術的負債」について私から言えること私から言えないこと
hoshinotsuyoshi
2
1k
spreeのrails updateの戦いの歴史と github上のPR作成時の工夫
hoshinotsuyoshi
0
920
Ruby is fun but difficult
hoshinotsuyoshi
0
340
バッチ処理でhakoを使う話
hoshinotsuyoshi
0
9.5k
docker swarm 触ってみた #dockerlt
hoshinotsuyoshi
0
1.1k
貧者のためのCoreOS(Jenkinsを例に)
hoshinotsuyoshi
1
1.5k
個人で使ってみた Docker と CoreOSとか
hoshinotsuyoshi
7
3.6k
Other Decks in Technology
See All in Technology
権威ドキュメントで振り返る2024 #年忘れセキュリティ2024
hirotomotaguchi
2
740
20241220_S3 tablesの使い方を検証してみた
handy
3
360
開発生産性向上! 育成を「改善」と捉えるエンジニア育成戦略
shoota
1
290
Amazon SageMaker Unified Studio(Preview)、Lakehouse と Amazon S3 Tables
ishikawa_satoru
0
150
.NET 9 のパフォーマンス改善
nenonaninu
0
780
PHPからGoへのマイグレーション for DMMアフィリエイト
yabakokobayashi
1
170
統計データで2024年の クラウド・インフラ動向を眺める
ysknsid25
2
840
ブラックフライデーで購入したPixel9で、Gemini Nanoを動かしてみた
marchin1989
1
520
Snowflake女子会#3 Snowpipeの良さを5分で語るよ
lana2548
0
230
フロントエンド設計にモブ設計を導入してみた / 20241212_cloudsign_TechFrontMeetup
bengo4com
0
1.9k
Jetpack Composeで始めるServer Cache State
ogaclejapan
2
170
アップデート紹介:AWS Data Transfer Terminal
stknohg
PRO
0
180
Featured
See All Featured
Unsuck your backbone
ammeep
669
57k
Designing for Performance
lara
604
68k
Raft: Consensus for Rubyists
vanstee
137
6.7k
Writing Fast Ruby
sferik
628
61k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
26
1.9k
Rails Girls Zürich Keynote
gr2m
94
13k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
159
15k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
47
5.1k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
5
440
Intergalactic Javascript Robots from Outer Space
tanoku
270
27k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
232
17k
Why You Should Never Use an ORM
jnunemaker
PRO
54
9.1k
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