ActiveSupport::EventReporter (original) (raw)

Active Support Event Reporter

ActiveSupport::EventReporter provides an interface for reporting structured events to subscribers.

To report an event, you can use the notify method:

Rails.event.notify("user_created", { id: 123 })

The notify API can receive either an event name and a payload hash, or an event object. Names are coerced to strings.

Event Objects

If an event object is passed to the notify API, it will be passed through to subscribers as-is, and the name of the object’s class will be used as the event name.

class UserCreatedEvent def initialize(id:, name:) @id = id @name = name end

def serialize { id: @id, name: @name } end end

Rails.event.notify(UserCreatedEvent.new(id: 123, name: "John Doe"))

An event is any Ruby object representing a schematized event. While payload hashes allow arbitrary, implicitly-structured data, event objects are intended to enforce a particular schema.

Subscribers are responsible for serializing event objects.

Subscribers

Subscribers must implement the emit method, which will be called with the event hash.

The event hash has the following keys:

name: String (The name of the event) payload: Hash, Object (The payload of the event, or the event object itself) tags: Hash (The tags of the event) context: Hash (The context of the event) timestamp: Float (The timestamp of the event, in nanoseconds) source_location: Hash (The source location of the event, containing the filepath, lineno, and label)

Subscribers are responsible for encoding events to their desired format before emitting them to their target destination, such as a streaming platform, a log device, or an alerting service.

class JSONEventSubscriber def emit(event) json_data = JSON.generate(event) LogExporter.export(json_data) end end

class LogSubscriber def emit(event) payload = event[:payload].map { |key, value| "#{key}=#{value}" }.join(" ") source_location = event[:source_location] log = "[#{event[:name]}] #{payload} at #{source_location[:filepath]}:#{source_location[:lineno]}" Rails.logger.info(log) end end

Note that event objects are passed through to subscribers as-is, and may need to be serialized before being encoded:

class UserCreatedEvent def initialize(id:, name:) @id = id @name = name end

def serialize { id: @id, name: @name } end end

class LogSubscriber def emit(event) payload = event[:payload] json_data = JSON.generate(payload.serialize) LogExporter.export(json_data) end end

Filtered Subscriptions

Subscribers can be configured with an optional filter proc to only receive a subset of events:

Rails.event.subscribe(user_subscriber) { |event| event[:name].start_with?("user.") }

Rails.event.subscribe(audit_subscriber) { |event| event[:payload].is_a?(AuditEvent) }

Debug Events

You can use the debug method to report an event that will only be reported if the event reporter is in debug mode:

Rails.event.debug("my_debug_event", { foo: "bar" })

Tags

To add additional context to an event, separate from the event payload, you can add tags via the tagged method:

Rails.event.tagged("graphql") do Rails.event.notify("user_created", { id: 123 }) end

Context Store

You may want to attach metadata to every event emitted by the reporter. While tags provide domain-specific context for a series of events, context is scoped to the job / request and should be used for metadata associated with the execution context. Context can be set via the set_context method:

Rails.event.set_context(request_id: "abcd123", user_agent: "TestAgent") Rails.event.notify("user_created", { id: 123 })

Context is reset automatically before and after each request.

A custom context store can be configured via config.active_support.event_reporter_context_store.

config.active_support.event_reporter_context_store = CustomContextStore

class CustomContextStore class << self def context

end

def set_context(context_hash)
  
end

def clear
  
end

end end

The Event Reporter standardizes on symbol keys for all payload data, tags, and context store entries. String keys are automatically converted to symbols for consistency.

Rails.event.notify("user.created", { "id" => 123 })

Security

When reporting events, Hash-based payloads are automatically filtered to remove sensitive data based on Rails.application.filter_parameters.

If an event object is given instead, subscribers will need to filter sensitive data themselves, e.g. with ActiveSupport::ParameterFilter.