Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,13 @@ def self.install(tracer)

define_method(:p) do |*args|
loc = caller_locations(1, 1).first
content = if args.length == 1 && args.first.is_a?(Array)
args.first.map(&:inspect).join("\n")
else
args.map(&:inspect).join("\n")
end
@@tracers.each do |t|
t.record_event(loc.path, loc.lineno, args.map(&:inspect).join("\n"))
t.record_event(loc.path, loc.lineno, content)
end
codetracer_original_p(*args)
end
Expand Down
63 changes: 38 additions & 25 deletions gems/codetracer-pure-ruby-recorder/lib/trace.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,19 @@
require 'json'
require 'optparse'
require_relative 'recorder'
require_relative '../../../codetracer/kernel_patches'
require_relative 'codetracer/kernel_patches'

# Helper to access the original +puts+ implementation when kernel
# methods are patched by {Codetracer::KernelPatches}. This avoids
# tracing debug output while still functioning even if the patches
# are not installed.
def codetracer_puts_no_trace(*args)
if Kernel.private_method_defined?(:codetracer_original_puts)
Kernel.send(:codetracer_original_puts, *args)
else
Kernel.puts(*args)
end
end


# Warning:
Expand Down Expand Up @@ -127,7 +139,7 @@ def record_call(tp)
method_name_prefix = module_name == 'Object' ? '' : "#{module_name}#"
method_name = "#{method_name_prefix}#{tp.method_id}"

old_puts "call #{method_name} with #{tp.parameters}" if $tracer.debug
codetracer_puts_no_trace "call #{method_name} with #{tp.parameters}" if $tracer.debug

arg_records = prepare_args(tp)

Expand All @@ -139,7 +151,7 @@ def record_call(tp)

def record_return(tp)
if self.tracks_call?(tp)
old_puts "return" if $tracer.debug
codetracer_puts_no_trace "return" if $tracer.debug
return_value = to_value(tp.return_value)
@record.register_step(tp.path, tp.lineno)
# return value support inspired by existing IDE-s/envs like
Expand All @@ -160,22 +172,23 @@ def record_step(tp)
end
end

def record_event(caller, content)
# reason/effect are on different steps:
# reason: before `p` is called;
# effect: now, when the args are evaluated
# which can happen after many calls/steps;
# maybe add a step for this call?
begin
location = caller[0].split[0].split(':')[0..1]
path, line = location[0], location[1].to_i
@record.register_step(path, line)
rescue
# ignore for now: we'll just jump to last previous step
# which might be from args
def record_event(*args)
if args.length == 2
caller, content = args
begin
location = caller[0].split[0].split(':')[0..1]
path, line = location[0], location[1].to_i
@record.register_step(path, line)
rescue
# ignore for now
end
@record.events << [:Event, RecordEvent.new(EVENT_KIND_WRITE, content, "")]
elsif args.length == 3
path, line, content = args
record_event(["#{path}:#{line}"], content)
else
raise ArgumentError, "wrong number of arguments"
end
# start is last step on this level: log for reason: the previous step on this level
@record.events << [:Event, RecordEvent.new(EVENT_KIND_WRITE, content, "")]
end

def record_exception(tp)
Expand Down Expand Up @@ -254,13 +267,13 @@ def load_variables(binding)
Kernel.load(program)
rescue Exception => e
if $tracer.debug
old_puts ''
old_puts '==== trace.rb error while tracing program ==='
old_puts 'ERROR'
old_puts e
old_puts e.backtrace
old_puts '====================='
old_puts ''
codetracer_puts_no_trace ''
codetracer_puts_no_trace '==== trace.rb error while tracing program ==='
codetracer_puts_no_trace 'ERROR'
codetracer_puts_no_trace e
codetracer_puts_no_trace e.backtrace
codetracer_puts_no_trace '====================='
codetracer_puts_no_trace ''
end
end

Expand Down
65 changes: 65 additions & 0 deletions gems/codetracer-ruby-recorder/lib/codetracer/kernel_patches.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# SPDX-License-Identifier: MIT

module Codetracer
module KernelPatches
@@tracers = []

def self.install(tracer)
return if @@tracers.include?(tracer)
@@tracers << tracer

if @@tracers.length == 1
Kernel.module_eval do
alias_method :codetracer_original_p, :p unless method_defined?(:codetracer_original_p)
alias_method :codetracer_original_puts, :puts unless method_defined?(:codetracer_original_puts)
alias_method :codetracer_original_print, :print unless method_defined?(:codetracer_original_print)

define_method(:p) do |*args|
loc = caller_locations(1, 1).first
content = if args.length == 1 && args.first.is_a?(Array)
args.first.map(&:inspect).join("\n")
else
args.map(&:inspect).join("\n")
end
@@tracers.each do |t|
t.record_event(loc.path, loc.lineno, content)
end
codetracer_original_p(*args)
end

define_method(:puts) do |*args|
loc = caller_locations(1, 1).first
@@tracers.each do |t|
t.record_event(loc.path, loc.lineno, args.join("\n"))
end
codetracer_original_puts(*args)
end

define_method(:print) do |*args|
loc = caller_locations(1, 1).first
@@tracers.each do |t|
t.record_event(loc.path, loc.lineno, args.join)
end
codetracer_original_print(*args)
end
end
end
end

def self.uninstall(tracer)
@@tracers.delete(tracer)

if @@tracers.empty? && Kernel.private_method_defined?(:codetracer_original_p)
Kernel.module_eval do
alias_method :p, :codetracer_original_p
alias_method :puts, :codetracer_original_puts
alias_method :print, :codetracer_original_print

remove_method :codetracer_original_p
remove_method :codetracer_original_puts
remove_method :codetracer_original_print
end
end
end
end
end
2 changes: 1 addition & 1 deletion gems/codetracer-ruby-recorder/lib/native_trace.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
require 'optparse'
require 'fileutils'
require 'rbconfig'
require_relative '../../../codetracer/kernel_patches'
require_relative 'codetracer/kernel_patches'

options = {}
parser = OptionParser.new do |opts|
Expand Down
2 changes: 1 addition & 1 deletion test/fixtures/more_types_trace.json
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,7 @@
{
"Event": {
"kind": 0,
"content": "1.5\n{:a=>1, :b=>2}\n1..3\n#<Set: {1, 2, 3}>\n1970-01-01 00:00:00 +0000\n(?-mix:ab)\n#<struct Point x=5, y=6>\n#<OpenStruct foo=7, bar=8>",
"content": "1.5\n{:a=>1, :b=>2}\n1..3\n#<Set: {1, 2, 3}>\n1970-01-01 00:00:00 +0000\n/ab/\n#<struct Point x=5, y=6>\n#<OpenStruct foo=7, bar=8>",
"metadata": ""
}
}
Expand Down
2 changes: 1 addition & 1 deletion test/fixtures/point_representation_trace.json
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@
{
"Event": {
"kind": 0,
"content": "(3, 4)",
"content": "\"(3, 4)\"",
"metadata": ""
}
}
Expand Down
2 changes: 1 addition & 1 deletion test/test_kernel_patches.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: MIT

require 'minitest/autorun'
require_relative '../codetracer/kernel_patches' # Adjust path as necessary
require_relative '../gems/codetracer-pure-ruby-recorder/lib/codetracer/kernel_patches'

class MockTracer
attr_reader :events, :name
Expand Down
Loading