Class: LittleGhost::Events::Reporter
- Inherits:
-
Object
- Object
- LittleGhost::Events::Reporter
- Defined in:
- lib/little_ghost/events.rb
Overview
Thread-safe event publisher with process-wide and fiber-scoped listeners.
Reporters start without listeners so applications opt into their preferred
event destination, including ConsoleListener for JSON-line diagnostics.
Instance Method Summary collapse
-
#context ⇒ Object
Copies the event context active in the current execution.
-
#emit(level, name, payload = {}) ⇒ Object
Delivers an event and returns a detached copy of its complete hash.
-
#initialize(listeners: []) ⇒ Reporter
constructor
Starts with
listenersin subscription order. -
#subscribe(listener, &filter) ⇒ Object
Subscribes
listener. -
#unsubscribe(listener) ⇒ Object
Unsubscribes every entry matching
listener. -
#with_context(attributes) ⇒ Object
Adds attributes to events emitted while the block runs.
Constructor Details
#initialize(listeners: []) ⇒ Reporter
Starts with listeners in subscription order.
58 59 60 61 62 |
# File 'lib/little_ghost/events.rb', line 58 def initialize(listeners: []) @mutex = Mutex.new @listeners = [] Array(listeners).each { |listener| subscribe(listener) } end |
Instance Method Details
#context ⇒ Object
Copies the event context active in the current execution.
114 115 116 |
# File 'lib/little_ghost/events.rb', line 114 def context deep_copy(ExecutionState[context_key] || {}) end |
#emit(level, name, payload = {}) ⇒ Object
Delivers an event and returns a detached copy of its complete hash.
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/little_ghost/events.rb', line 83 def emit(level, name, payload = {}) level = level.to_sym raise ArgumentError, "unknown event level: #{level}" unless LEVELS.include?(level) raise ArgumentError, "event payload must be a hash" unless payload.is_a?(Hash) event = { name: normalize_string(name.to_s), level:, payload: deep_copy(payload), context: context, timestamp: Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond) } listeners.each do |entry| listener = entry.fetch(:listener) filter = entry[:filter] next if filter && !filter.call(deep_copy(event)) listener.emit(deep_copy(event)) rescue nil end event end |
#subscribe(listener, &filter) ⇒ Object
Subscribes listener. The optional block filters copied event hashes.
65 66 67 68 69 70 71 72 |
# File 'lib/little_ghost/events.rb', line 65 def subscribe(listener, &filter) unless listener.respond_to?(:emit) raise ArgumentError, "event listener must respond to emit" end @mutex.synchronize { @listeners << {listener:, filter:} } listener end |
#unsubscribe(listener) ⇒ Object
Unsubscribes every entry matching listener.
75 76 77 78 79 80 |
# File 'lib/little_ghost/events.rb', line 75 def unsubscribe(listener) @mutex.synchronize do @listeners.delete_if { |entry| listener === entry.fetch(:listener) } end listener end |
#with_context(attributes) ⇒ Object
Adds attributes to events emitted while the block runs.
108 109 110 111 |
# File 'lib/little_ghost/events.rb', line 108 def with_context(attributes) values = context.merge(deep_copy(attributes.compact)) ExecutionState.with(context_key => values) { yield } end |