Skip to content

Instantly share code, notes, and snippets.

@amkisko
Last active April 23, 2025 08:24
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 grape-ruby, rspec test examples, show SQL traces, show stack calls and all exceptions in stack, helper to find out which spec file stuck, store logs to files
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["PATH_INFO"]].join("_").downcase.gsub(/[^a-z0-9_]+/, "_")
context = [env["REQUEST_METHOD"], env["PATH_INFO"]].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