Module: Pinot::Instrumentation

Defined in:
lib/pinot/instrumentation.rb

Overview

Low-level instrumentation hook that fires after every query executed via Connection#execute_sql. This is the extension point used by Pinot::ActiveSupportNotifications, Pinot::OpenTelemetry, and any custom observability layer.

Subscribing (multiple listeners supported)

listener = Pinot::Instrumentation.subscribe(->(event) do
  MyMetrics.record(event[:table], event[:duration_ms], event[:success])
end)

# Remove later:
Pinot::Instrumentation.unsubscribe(listener)

Legacy single-callback API (still supported)

Pinot::Instrumentation.on_query = ->(event) { ... }
Pinot::Instrumentation.on_query = nil  # remove

Around-execution hook (for OTel and similar span-based tools)

The ‘around` hook wraps the entire query execution — the block yields the query, and the hook is responsible for calling Instrumentation.notify when done. Only one around hook can be registered at a time.

Pinot::Instrumentation.around = ->(table:, query:) do
  MyTracer.in_span("pinot") { yield }
end

Event Hash keys

:table        => String  — table name passed to execute_sql
:query        => String  — SQL string
:duration_ms  => Float   — wall-clock time in milliseconds
:success      => Boolean — false when an exception was raised
:error        => Exception or nil — the exception on failure, nil on success

Class Method Summary collapse

Class Method Details

.aroundObject



60
61
62
# File 'lib/pinot/instrumentation.rb', line 60

def self.around
  @around
end

.around=(wrapper) ⇒ Object

Register an around-execution wrapper. Only one wrapper is supported; the new value replaces any previous one. Set to nil to remove.



56
57
58
# File 'lib/pinot/instrumentation.rb', line 56

def self.around=(wrapper)
  @around = wrapper
end

.instrument(table:, query:) ⇒ Object



75
76
77
78
79
80
81
# File 'lib/pinot/instrumentation.rb', line 75

def self.instrument(table:, query:)
  if @around
    @around.call(table: table, query: query) { yield }
  else
    _timed_instrument(table: table, query: query) { yield }
  end
end

.notify(event) ⇒ Object

Fire all registered listeners with an event hash. Called by the default instrument path and by the OTel around wrapper.



85
86
87
# File 'lib/pinot/instrumentation.rb', line 85

def self.notify(event)
  @listeners.each { |l| l.call(event) }
end

.on_queryObject

Returns the first registered listener (legacy compat).



71
72
73
# File 'lib/pinot/instrumentation.rb', line 71

def self.on_query
  @listeners.first
end

.on_query=(callback) ⇒ Object

Legacy single-callback setter. Replaces all listeners with the given callback (or clears them when nil).



66
67
68
# File 'lib/pinot/instrumentation.rb', line 66

def self.on_query=(callback)
  @listeners = callback ? [callback] : []
end

.subscribe(listener) ⇒ Object

Add a post-execution listener. Returns the listener so it can be passed to unsubscribe later.



44
45
46
47
# File 'lib/pinot/instrumentation.rb', line 44

def self.subscribe(listener)
  @listeners << listener
  listener
end

.unsubscribe(listener) ⇒ Object

Remove a previously subscribed listener.



50
51
52
# File 'lib/pinot/instrumentation.rb', line 50

def self.unsubscribe(listener)
  @listeners.delete(listener)
end