
はじめに
ゼネットの土屋です。
先日 2025/10/22 に Rails 8.1.0 がリリースされました。
今回の記事では、Rails 8.1 で追加された注目機能 Structured Event Reporter を紹介します。
これは「Rails.logger」と「ActiveSupport::Notifications」を進化的に統合し、アプリケーションの“観測性”を大きく高める仕組みです。
Structured Event Reporter(Rails.event) とは
これまで Rails.logger や ActiveSupport::Notifications などに分散していた「イベントの記録・監視」を、統一的かつ機械可読な形式で扱えるようにした仕組みです。
Rails イベントを構造化して扱えるようになり、ログや監視システム(CloudWatch や Elasticsearch など)との連携がより強力になりました。
タグ付けやコンテキストの設定にも対応しており、大規模アプリケーションでの監視・トレーシング・分析を Rails 標準で行えるようになりました。
Rails.logger・ActiveSupport::Notifications・Rails.event の違い
| API | 目的 | 出力形式 | 主な使い道 |
|---|---|---|---|
| Rails.logger | 人間向けログ | テキスト | 本番運用のログ監視・集約/開発・デバッグ |
| ActiveSupport::Notifications | 内部計測 | イベント | パフォーマンス監視/APM 連携 |
| Rails.event(新機能) | 構造化イベント | JSON などの構造化データ | ログ集約・観測・監査/分散トレーシングの文脈付与 |
それぞれの違いを実例で見てみましょう。
Rails.logger:最もシンプルなログ出力
Rails.logger.info("User signed up: id=123, email=user@example.com")
出力は人間が読む前提のテキスト形式です(構造を持たないため後処理がしにくい点に注意):
INFO -- : User signed up: id=123, email=user@example.com
特徴
- シンプルで導入しやすい
- しかし構造がないため、分析や集計には不向き
- 「どのリクエストで」「誰が」「いつ」などの文脈を自動で持たない
ActiveSupport::Notifications:内部イベントの発火とsubscribe
ActiveSupport::Notifications.instrument("user.signup", id: 123) do end
subscribe 側で処理を定義できます:
ActiveSupport::Notifications.subscribe("user.signup") do |name, start, finish, id, payload| puts "#{name} took #{(finish - start).round(3)}s: #{payload.inspect}" end
特徴
- Rails 内部(DB、View、Cache など)もこの仕組みで通知している
- 処理時間の計測などに強い
- ただし、統一的なデータ構造や文脈共有が弱い
Rails.event:構造化イベントとして統一的に扱う
Rails.event.set_context(request_id: "req-42", user_id: 123) Rails.event.tagged("signup") do Rails.event.notify("user.signup", email: "user@example.com") end
Subscriber を登録してイベントを受け取ります:
class JsonSubscriber def emit(event) Rails.logger.info(event) end end Rails.event.subscribe(JsonSubscriber.new)
以下は、Rails.event.notify の呼び出しによって出力される JSON 構造の一例です。
{ "name": "user.signup", "payload": { "email": "user@example.com" }, "tags": { "signup": true }, "context": { "request_id": "req-42", "user_id": 123 }, "timestamp": "2025-10-20T12:34:56Z", "source_location": { "filepath": "app/controllers/users_controller.rb", "lineno": 42 } }
特徴
- 完全に構造化されたイベントとして出力可能
- タグやコンテキストを付与して システム横断的なトレース ができる
- JSON 形式のため、CloudWatch や Elasticsearch などに容易に連携できる
Rails.event の仕組みを理解する:イベントはどう構築されるのか
Structured Event Reporter は、単に「イベントを通知する API」ではありません。
内部では ActiveSupport::EventReporter::Event オブジェクト を生成し、その中に「アプリケーションで起きた出来事」を構造化して保持します。
Rails.event.notify の内部で何が起きているか
例えば、次のようなコードを考えてみましょう。
before_action do Rails.event.set_context(request_id: "abc123", user_id: 42) end def create Rails.event.notify("user.signup", email: "user@example.com") end
これは 「user.signup というイベントを発行する」 という操作を行い、
Rails 内部では次のような Event オブジェクトが生成されます。
{
name: "user.signup",
payload: { email: "user@example.com" },
context: { request_id: "abc123", user_id: 42 },
tags: {},
timestamp: "2025-10-20T13:55:00Z",
source_location: {
filepath: "app/controllers/users_controller.rb",
lineno: 5
}
}
この構造体は、Subscriber にそのまま渡されます。
イベントを受け取るSubscriber
class JsonLogger def emit(event) Rails.logger.info(event) end end Rails.event.subscribe(JsonLogger.new)
このSubscriber を登録しておくと、notify が呼ばれるたびに
上記の event オブジェクトが JSON に変換され、ログ出力されます。
出力結果の例
{ "name": "user.signup", "payload": { "email": "user@example.com" }, "context": { "request_id": "abc123", "user_id": 42 }, "tags": {}, "timestamp": "2025-10-20T13:55:00Z", "source_location": { "filepath": "app/controllers/users_controller.rb", "lineno": 5 } }
このように、notify の引数で渡した email だけでも、
Rails は自動的に context・timestamp・source_location を補完してくれます。
各フィールドの意味
| フィールド名 | 生成元 | 内容 | 自動/手動 |
|---|---|---|---|
name |
notify の第 1 引数 |
イベント名(例: "user.signup") |
手動 |
payload |
notify のキーワード引数 |
イベント固有データ | 手動 |
context |
Rails.event.set_context(...) |
リクエストやユーザーなど共通情報 | 自動 |
tags |
Rails.event.tagged(...) |
イベントの分類(例: "graphql") |
自動 |
timestamp |
Rails 内部 | イベント発火時刻(UTC) | 自動 |
source_location |
Rails 内部 | ファイルパスと行番号 | 自動 |
仕組みをまとめると
notify() でイベントを送る
↓
ActiveSupport::EventReporter::Event が生成される
↓
context / tags / timestamp / source_location が自動付与される
↓
Subscriber#emit に渡される
↓
ログや監視ツールへ送信される
この流れにより、アプリケーション全体の“出来事”を
構造化された一貫したフォーマットで観測できるようになっています。
まとめ
Rails.event.notifyは「名前+データ」だけを渡せば OKcontext(文脈)とtimestamp(時刻)は Rails が自動で補完- Subscriber を通じて、ログ・監視・トレースなどに容易に統合可能
- 「ログを書く」ではなく「イベントを発行する」 という発想への転換が、Rails 8.1 以降の観測性向上の鍵となります。
コメント