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
125 126 127 128 129 |
# File 'lib/rails_otel_context/activerecord_context.rb', line 125 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
83 84 85 86 87 88 89 90 91 92 93 94 95 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 |
# File 'lib/rails_otel_context/activerecord_context.rb', line 83 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 |