|
1 | | -#!/usr/bin/env ruby |
2 | 1 | # SPDX-License-Identifier: MIT |
3 | | -# Simple utility loading the native tracer extension and executing a program. |
| 2 | +# Library providing a helper method to execute the native tracer. |
4 | 3 |
|
5 | 4 | require 'optparse' |
6 | 5 | require 'fileutils' |
7 | 6 | require 'rbconfig' |
8 | 7 | require_relative 'codetracer/kernel_patches' |
9 | 8 |
|
10 | | -options = {} |
11 | | -parser = OptionParser.new do |opts| |
12 | | - opts.banner = "usage: ruby native_trace.rb [options] <program> [args]" |
13 | | - opts.on('-o DIR', '--out-dir DIR', 'Directory to write trace files') do |dir| |
14 | | - options[:out_dir] = dir |
15 | | - end |
16 | | - opts.on('-h', '--help', 'Print this help') do |
17 | | - puts opts |
18 | | - exit |
19 | | - end |
20 | | -end |
21 | | -parser.order! |
| 9 | +module NativeTrace |
| 10 | + # Execute the native tracer CLI logic with the provided +argv+. |
| 11 | + def self.execute(argv) |
| 12 | + options = {} |
| 13 | + parser = OptionParser.new do |opts| |
| 14 | + opts.banner = 'usage: codetracer-ruby-recorder [options] <program> [args]' |
| 15 | + opts.on('-o DIR', '--out-dir DIR', 'Directory to write trace files') do |dir| |
| 16 | + options[:out_dir] = dir |
| 17 | + end |
| 18 | + opts.on('-h', '--help', 'Print this help') do |
| 19 | + puts opts |
| 20 | + return 0 |
| 21 | + end |
| 22 | + end |
| 23 | + parser.order!(argv) |
22 | 24 |
|
23 | | -if ARGV.empty? |
24 | | - $stderr.puts parser |
25 | | - exit 1 |
26 | | -end |
| 25 | + if argv.empty? |
| 26 | + $stderr.puts parser |
| 27 | + return 1 |
| 28 | + end |
27 | 29 |
|
28 | | -out_dir = options[:out_dir] || ENV['CODETRACER_RUBY_RECORDER_OUT_DIR'] || Dir.pwd |
29 | | -ENV['CODETRACER_RUBY_RECORDER_OUT_DIR'] = out_dir |
| 30 | + out_dir = options[:out_dir] || ENV['CODETRACER_RUBY_RECORDER_OUT_DIR'] || Dir.pwd |
| 31 | + ENV['CODETRACER_RUBY_RECORDER_OUT_DIR'] = out_dir |
30 | 32 |
|
31 | | -# Path to the compiled native extension |
32 | | -ext_dir = File.expand_path('../ext/native_tracer/target/release', __dir__) |
33 | | -dlext = RbConfig::CONFIG['DLEXT'] |
34 | | -target_path = File.join(ext_dir, "codetracer_ruby_recorder.#{dlext}") |
35 | | -unless File.exist?(target_path) |
36 | | - extensions = %w[so bundle dylib dll] |
37 | | - alt_path = extensions |
38 | | - .map { |ext| File.join(ext_dir, "libcodetracer_ruby_recorder.#{ext}") } |
39 | | - .find { |path| File.exist?(path) } |
40 | | - if alt_path |
41 | | - begin |
42 | | - File.symlink(alt_path, target_path) |
43 | | - rescue StandardError |
44 | | - FileUtils.cp(alt_path, target_path) |
| 33 | + ext_dir = File.expand_path('../ext/native_tracer/target/release', __dir__) |
| 34 | + dlext = RbConfig::CONFIG['DLEXT'] |
| 35 | + target_path = File.join(ext_dir, "codetracer_ruby_recorder.#{dlext}") |
| 36 | + unless File.exist?(target_path) |
| 37 | + extensions = %w[so bundle dylib dll] |
| 38 | + alt_path = extensions |
| 39 | + .map { |ext| File.join(ext_dir, "libcodetracer_ruby_recorder.#{ext}") } |
| 40 | + .find { |path| File.exist?(path) } |
| 41 | + if alt_path |
| 42 | + begin |
| 43 | + File.symlink(alt_path, target_path) |
| 44 | + rescue StandardError |
| 45 | + FileUtils.cp(alt_path, target_path) |
| 46 | + end |
| 47 | + end |
45 | 48 | end |
46 | | - end |
47 | | -end |
48 | 49 |
|
49 | | -recorder = nil |
50 | | -begin |
51 | | - require target_path |
52 | | - recorder = RubyRecorder.new |
53 | | - $recorder = recorder |
54 | | - ::Codetracer::KernelPatches.install(recorder) |
| 50 | + recorder = nil |
| 51 | + begin |
| 52 | + require target_path |
| 53 | + recorder = RubyRecorder.new |
| 54 | + $recorder = recorder |
55 | 55 |
|
56 | | -rescue Exception => e |
57 | | - warn "native tracer unavailable: #{e}" |
58 | | -end |
| 56 | + Kernel.module_eval do |
| 57 | + alias :old_p :p |
| 58 | + alias :old_puts :puts |
| 59 | + alias :old_print :print |
59 | 60 |
|
60 | | -program = ARGV.shift |
61 | | -recorder.enable_tracing if recorder |
62 | | -load program |
63 | | -if recorder |
64 | | - recorder.disable_tracing |
65 | | - ::Codetracer::KernelPatches.uninstall(recorder) |
66 | | - recorder.flush_trace(out_dir) |
67 | | -end |
| 61 | + define_method(:p) do |*args| |
| 62 | + if $recorder |
| 63 | + loc = caller_locations(1,1).first |
| 64 | + $recorder.record_event(loc.path, loc.lineno, args.join("\n")) |
| 65 | + end |
| 66 | + old_p(*args) |
| 67 | + end |
68 | 68 |
|
| 69 | + define_method(:puts) do |*args| |
| 70 | + if $recorder |
| 71 | + loc = caller_locations(1,1).first |
| 72 | + $recorder.record_event(loc.path, loc.lineno, args.join("\n")) |
| 73 | + end |
| 74 | + old_puts(*args) |
| 75 | + end |
| 76 | + |
| 77 | + define_method(:print) do |*args| |
| 78 | + if $recorder |
| 79 | + loc = caller_locations(1,1).first |
| 80 | + $recorder.record_event(loc.path, loc.lineno, args.join("\n")) |
| 81 | + end |
| 82 | + old_print(*args) |
| 83 | + end |
| 84 | + end |
| 85 | + rescue Exception => e |
| 86 | + warn "native tracer unavailable: #{e}" |
| 87 | + end |
| 88 | + |
| 89 | + program = argv.shift |
| 90 | + recorder.enable_tracing if recorder |
| 91 | + load program |
| 92 | + if recorder |
| 93 | + recorder.disable_tracing |
| 94 | + recorder.flush_trace(out_dir) |
| 95 | + end |
| 96 | + 0 |
| 97 | + end |
| 98 | +end |
0 commit comments