Module: Vivarium::CLI

Defined in:
lib/vivarium/cli.rb

Class Method Summary collapse

Class Method Details

.resolve_report_filter(options) ⇒ Object

Resolve the report display filter by precedence:

--all  >  --filter JSON  >  --event NAMES  >  DEFAULT_FILTER


86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/vivarium/cli.rb', line 86

def self.resolve_report_filter(options)
  return nil if options[:show_all]

  if options[:filter_json]
    begin
      return JSON.parse(options[:filter_json])
    rescue JSON::ParserError => e
      abort "Invalid --filter JSON: #{e.message}"
    end
  end

  names = options[:event_names]
  return { include_events: names } if names && !names.empty?

  Vivarium::DEFAULT_FILTER
end

.run!(argv = ARGV) ⇒ Object



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/vivarium/cli.rb', line 8

def self.run!(argv = ARGV)
  options = { socket_path: Vivarium.socket_path, dest: $stdout }
  parser = OptionParser.new do |opts|
    opts.banner = "Usage: vivarium [options] <command> [args]"
    opts.separator ""
    opts.separator "Commands:"
    opts.separator "  load <script>       Load and observe a Ruby script"
    opts.separator "  report <raw-file>   Render a saved raw event file"
    opts.separator ""
    opts.separator "Options:"
    opts.on("--socket PATH", "vivariumd Unix domain socket path") { |v| options[:socket_path] = v }
    opts.on("-o", "--output PATH", "Log output file (default: stdout)") { |v| options[:dest] = File.open(v, "a") }
    opts.on("--save-raw PATH", "load: save raw events to PATH instead of rendering") { |v| options[:save_raw] = v }
    opts.on("--all", "report: show all events (ignore default filter)") { options[:show_all] = true }
    opts.on("--filter JSON", "report: filter as a JSON object (overrides --event/default)") { |v| options[:filter_json] = v }
    opts.on("--event NAMES", "report: comma-separated event names to include") do |v|
      options[:event_names] = v.split(",").map(&:strip).reject(&:empty?)
    end
    opts.on("--max-span-depth N", Integer, "report: collapse method spans deeper than N (events kept)") do |v|
      options[:max_span_depth] = v
    end
  end
  parser.order!(argv)

  command = argv.shift
  case command
  when "load"
    run_load!(argv, options)
  when "report"
    run_report!(argv, options)
  else
    abort parser.help
  end
end

.run_load!(argv, options) ⇒ Object



43
44
45
46
47
48
49
50
51
52
# File 'lib/vivarium/cli.rb', line 43

def self.run_load!(argv, options)
  script = argv.shift
  abort "Usage: vivarium load <script>" unless script
  abort "File not found: #{script}" unless File.exist?(script)

  Vivarium.observe(socket_path: options[:socket_path], dest: options[:dest],
                   filter: Vivarium::DEFAULT_FILTER, save_raw: options[:save_raw]) do
    Kernel.load(File.expand_path(script))
  end
end

.run_report!(argv, options) ⇒ Object



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/vivarium/cli.rb', line 54

def self.run_report!(argv, options)
  raw = argv.shift
  abort "Usage: vivarium report <raw-file>" unless raw
  abort "File not found: #{raw}" unless File.exist?(raw)

  data =
    begin
      File.open(raw, "rb") { |io| Vivarium::RawStore.load(io) }
    rescue Vivarium::RawStore::FormatError => e
      abort "Invalid vivarium-raw file #{raw}: #{e.message}"
    end
  meta = data[:meta]
  filter = resolve_report_filter(options)
  if options[:max_span_depth]
    filter = (filter || {}).merge(max_span_depth: options[:max_span_depth])
  end

  Vivarium::TreeRenderer.new(
    events: data[:events],
    observer_pid: meta[:observer_pid],
    main_tid: meta[:main_tid],
    session_start_iso: meta[:session_start_iso],
    session_start_ktime: meta[:session_start_ktime],
    session_stop_iso: meta[:session_stop_iso],
    session_stop_ktime: meta[:session_stop_ktime],
    filter: filter,
    dest: options[:dest]
  ).render
end