lib/builder_apm/models/instrumenter.rb in builder_apm-0.2.5 vs lib/builder_apm/models/instrumenter.rb in builder_apm-0.3.0

- old
+ new

@@ -52,18 +52,29 @@ class_name: '' } end def store_sql_query_data(sql_query_data) - Thread.current[:sql_event_id] = sql_query_data[:sql_id] - - if Thread.current[:stack]&.any? - Thread.current[:stack].last[:sql_events].push(sql_query_data) - else - (Thread.current[:stack] ||= []).push({sql_events: [sql_query_data], children: []}) - end + Thread.current[:sql_event_id] = sql_query_data[:sql_id] + + # Create the stack if it doesn't exist yet + stack = (Thread.current[:stack] ||= []) + + if stack&.any? + stack.last[:sql_events].push(sql_query_data) + else + stack.push({sql_events: [sql_query_data], children: []}) end + # Do the N+1 check if it wasn't done yet + if BuilderApm.configuration.enable_n_plus_one_profiler && Thread.current[:has_n_plus_one] == false + start_time = Time.now.to_f * 1000 + perform_n_plus_one_check(stack) + duration = (Time.now.to_f * 1000) - start_time + Thread.current[:n_plus_one_duration] ||= 0 + Thread.current[:n_plus_one_duration] += duration + end + end def update_last_sql_query_data_with_instantiation_info(event) stack = Thread.current[:stack] request_id = Thread.current[:request_id] @@ -79,9 +90,33 @@ end Thread.current[:stack].last[:sql_events].push(last_sql) ensure Thread.current[:sql_event_id] = nil end - end + end + + # Add this method to perform the N+1 check + def perform_n_plus_one_check(stack) + sql_queries = stack.map { |frame| frame[:sql_events] }.flatten + + # Group queries count by table and triggering_line + queries_count = Hash.new { |h, k| h[k] = {count: 0, indices: []} } + sql_queries.each_with_index do |query, index| + match = query[:sql].match(/FROM ['`"]*([^ '`"]+)['`"]*/i) + if match + table_and_line = "#{match[1]}|#{query[:triggering_line]}" + queries_count[table_and_line][:count] += 1 + queries_count[table_and_line][:indices].push(index) + end + end + + # If any N+1 issue is found, set 'has_n_plus_one' to true and return + queries_count.each do |_, value| + if value[:count] > 1 + Thread.current[:has_n_plus_one] = true + return + end + end + end end end end