Class: RailsOtelContext::ActiveRecordContext::Subscriber
- Inherits:
-
Object
- Object
- RailsOtelContext::ActiveRecordContext::Subscriber
- Defined in:
- lib/rails_otel_context/activerecord_context.rb
Overview
Subscriber for sql.active_record notifications.
Instance Method Summary collapse
Instance Method Details
#finish(_name, _id, _payload) ⇒ Object
138 139 140 141 142 |
# File 'lib/rails_otel_context/activerecord_context.rb', line 138 def finish(_name, _id, _payload) ensure Thread.current[THREAD_KEY] = nil Thread.current[PENDING_PREPARE_KEY] = nil # clear any leftovers from skipped notifications end |
#start(_name, _id, payload) ⇒ Object
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/rails_otel_context/activerecord_context.rb', line 96 def start(_name, _id, payload) ar_name = payload[:name] return if ar_name == 'SCHEMA' || ar_name&.start_with?('CACHE') ctx = if ar_name.nil? || ar_name == 'SQL' ActiveRecordContext.parse_sql_context(payload[:sql]) else ActiveRecordContext.parse_ar_name(ar_name) end return unless ctx # Include scope name if one was captured by RelationScopeCapture scope = Thread.current[SCOPE_THREAD_KEY] ctx[:scope_name] = scope if scope query_key = ctx[:query_key] counts = (Thread.current[RequestContext::QUERY_COUNT_KEY] ||= {}) count = (counts[query_key] = (counts[query_key] || 0) + 1) ctx[:query_count] = count if count > 1 ctx[:async] = true if payload[:async] Thread.current[THREAD_KEY] = ctx return unless defined?(OpenTelemetry::Trace) # Enrich the current span directly. When OTel instruments via driver-level # prepend (Trilogy, PG, Mysql2), the span is created BEFORE this notification # fires, so CallContextProcessor#on_start sees nil AR context. Applying here # fixes those spans after the fact. ActiveRecordContext.apply_to_span(OpenTelemetry::Trace.current_span, ctx) # Retroactively enrich any PREPARE spans that finished before this notification # fired. PG's prepared-statement flow sends PREPARE then EXECUTE as separate wire # operations; the PREPARE span finishes before sql.active_record starts, so it # never sees AR context. CallContextProcessor#on_finish stashes those spans here. pending = Thread.current[PENDING_PREPARE_KEY] return unless pending pending.each { |s| ActiveRecordContext.retroactively_apply_to_span(s, ctx) } Thread.current[PENDING_PREPARE_KEY] = nil end |