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
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ gem install codetracer_pure_ruby_recorder
After installing, load the tracer:

```ruby
require 'codetracer_ruby_recorder'
require 'codetracer_ruby_recorder' # native implementation
# require 'codetracer_pure_ruby_recorder' # pure Ruby implementation

recorder = RubyRecorder.new
recorder.enable_tracing
Expand Down
18 changes: 18 additions & 0 deletions examples/selective_tracing_pure.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/usr/bin/env ruby

# Load the pure Ruby tracer library if RubyRecorder is not already defined
unless defined?(RubyRecorder)
lib_base = File.expand_path('../gems/pure-ruby-tracer/lib/codetracer_pure_ruby_recorder', __dir__)
require lib_base
end

recorder = RubyRecorder.new

puts 'start trace'
recorder.disable_tracing
puts 'this will not be traced'
recorder.enable_tracing
puts 'this will be traced'
recorder.disable_tracing
puts 'tracing disabled'
recorder.flush_trace(Dir.pwd)
43 changes: 43 additions & 0 deletions gems/pure-ruby-tracer/lib/codetracer_pure_ruby_recorder.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
require_relative 'trace'

# Ruby implementation of the RubyRecorder API used by the native tracer.
# Provides basic tracing controls and serialization using the pure Ruby tracer.
class RubyRecorder
def initialize(debug: ENV['CODETRACER_RUBY_RECORDER_DEBUG'] == '1')
@record = $codetracer_record
@tracer = Tracer.new(@record, debug: debug)
setup_defaults
end

# Enable tracing of Ruby code execution.
def enable_tracing
@tracer.activate
end

# Disable tracing without discarding collected data.
def disable_tracing
@tracer.deactivate
end

# Serialize the trace to +out_dir+.
def flush_trace(out_dir)
@tracer.stop_tracing
@record.serialize('', out_dir)
end

# Record a custom event at +path+ and +line+ with +content+.
def record_event(path, line, content)
@tracer.record_event(["#{path}:#{line}"], content)
end

private

def setup_defaults
@record.register_call('', 1, '<top-level>', [])
@tracer.ignore('lib/ruby')
@tracer.ignore('trace.rb')
@tracer.ignore('recorder.rb')
@tracer.ignore('<internal:')
@tracer.ignore('gems/')
end
end
64 changes: 35 additions & 29 deletions gems/pure-ruby-tracer/lib/trace.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,39 +18,44 @@
# however this seems as a risky solution, as it clears global gem state!
# BE CAREFUL if you have other ruby projects/data there!

# override some of the IO methods to record them for event log
module Kernel
alias :old_p :p
alias :old_puts :puts
alias :old_print :print

def p(*args)
if $tracer.tracing
$tracer.deactivate
$tracer.record_event(caller, args.join("\n"))
$tracer.activate
end
old_p(*args)
end
# instrumentation helpers for recording IO calls
module CodetracerKernelPatches
def self.install(tracer)
Kernel.module_eval do
unless method_defined?(:old_p)
alias :old_p :p
alias :old_puts :puts
alias :old_print :print
end

def puts(*args)
if $tracer.tracing
$tracer.deactivate
$tracer.record_event(caller, args.join("\n"))
$tracer.activate
end
old_puts(*args)
end
define_method(:p) do |*args|
if tracer.tracing
tracer.deactivate
tracer.record_event(caller, args.join("\n"))
tracer.activate
end
old_p(*args)
end

def print(*args)
if $tracer.tracing
$tracer.deactivate
$tracer.record_event(caller, args.join("\n"))
$tracer.activate
define_method(:puts) do |*args|
if tracer.tracing
tracer.deactivate
tracer.record_event(caller, args.join("\n"))
tracer.activate
end
old_puts(*args)
end

define_method(:print) do |*args|
if tracer.tracing
tracer.deactivate
tracer.record_event(caller, args.join("\n"))
tracer.activate
end
old_print(*args)
end
end
old_print(*args)
end

end

# class IO
Expand Down Expand Up @@ -252,6 +257,7 @@ def load_variables(binding)

if __FILE__ == $PROGRAM_NAME
$tracer = Tracer.new($codetracer_record, debug: ENV['CODETRACER_RUBY_RECORDER_DEBUG'] == '1')
CodetracerKernelPatches.install($tracer)

options = {}
parser = OptionParser.new do |opts|
Expand Down
Loading