Skip to content

Instantly share code, notes, and snippets.

@amkisko
Last active April 22, 2025 16:27
Show Gist options
  • Save amkisko/b18991b421daa65934b310f442352d06 to your computer and use it in GitHub Desktop.
Save amkisko/b18991b421daa65934b310f442352d06 to your computer and use it in GitHub Desktop.
Amazing debugging for rspec test examples, show SQL traces, show stack calls and all exceptions in stack, helper to find out which spec file stuck
require "amazing_print"
class Debug
def self.print_message(message, output_path: nil)
if output_path
File.open(output_path, "a") do |file|
file.puts(message)
end
else
ap(message)
end
end
def self.trace(with_sql: false, output_path: nil)
if output_path
File.write(output_path, "")
end
if with_sql
subscriber = ActiveSupport::Notifications.subscribe("sql.active_record") do |event|
payload = event.payload[:sql]
next if payload.match?(/^(SELECT|SET|SHOW|BEGIN|COMMIT|ROLLBACK|RELEASE|SAVEPOINT)/)
# next if payload.include?("audits")
event.payload[:type_casted_binds].each_with_index do |bind, index|
payload = payload.gsub("$#{index + 1}", "'#{bind}'")
end
print_message({sql: payload}, output_path: output_path)
end
end
trace = TracePoint.new do |tp|
if tp.event == :call && tp.path.start_with?(Rails.root.to_s)
print_message({
event: tp.event,
path: "#{tp.path}:#{tp.lineno}"
}, output_path: output_path)
elsif tp.event == :raise
print_message({
event: tp.event,
raised_exception: tp.raised_exception,
path: "#{tp.path}:#{tp.lineno}",
method_id: tp.method_id
}, output_path: output_path)
end
end
trace.enable
yield
trace.disable
ActiveSupport::Notifications.unsubscribe(subscriber) if with_sql
end
end
require "amazing_print"
class Debug
def self.print_message(message, output_file: nil)
if output_file
output_file.puts(message)
else
ap(message)
end
end
def self.trace(with_sql: false, with_stack: false, store_file: false, output_path: nil, context: nil, file_prefix: nil)
file = if store_file
root_dir = Rails.root.join("tmp/traces")
FileUtils.mkdir_p(root_dir)
output_path ||= root_dir.join("#{Time.now.strftime("%Y%m%d%H%M")}_#{file_prefix}_trace.txt")
File.open(output_path, "a")
end
file.puts("\n\n---\nBEGIN CONTEXT: #{context}\n\n") if file
if with_sql
subscriber = ActiveSupport::Notifications.subscribe("sql.active_record") do |event|
payload = event.payload[:sql]
# next if payload.match?(/^(SET|SHOW|BEGIN|COMMIT|ROLLBACK|RELEASE|SAVEPOINT)/)
# next if payload.include?("audits")
next if payload.include?("pg_attribute")
if event.payload[:type_casted_binds].is_a?(Array)
event.payload[:type_casted_binds].each_with_index do |bind, index|
payload = payload.gsub("$#{index + 1}", "'#{bind}'")
end
end
print_message({sql: payload}, output_file: file)
end
end
if with_stack
trace = TracePoint.new do |tp|
if tp.event == :call && tp.path.start_with?(Rails.root.to_s)
print_message({
event: tp.event,
path: "#{tp.path}:#{tp.lineno}"
}, output_file: file)
elsif tp.event == :raise
print_message({
event: tp.event,
raised_exception: tp.raised_exception,
path: "#{tp.path}:#{tp.lineno}",
method_id: tp.method_id
}, output_file: file)
end
end
trace.enable
end
yield
ensure
trace.disable if with_stack
ActiveSupport::Notifications.unsubscribe(subscriber) if with_sql
end
end
module GrapeDebug
class GrapeTracer < ::Grape::Middleware::Base
TRACE_ENABLED = ENV["TRACE"]
def call!(env)
if TRACE_ENABLED
file_prefix = [env["REQUEST_METHOD"], env["REQUEST_PATH"]].join("_").downcase.gsub(/[^a-z0-9_]+/, "_")
context = [env["REQUEST_METHOD"], env["REQUEST_PATH"]].join(" ")
Debug.trace(with_sql: true, with_stack: false, store_file: true, file_prefix: file_prefix, context: context) do
@app.call(env)
end
else
@app.call(env)
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment