class ChaosDetector::Walkman
Constants
- COL_COUNT
- COL_INDEXES
- CSV_HEADER
- DEFALT_BUFFER_LENGTH
- PLAYBACK_MSG
Public Class Methods
new(options:)
click to toggle source
# File lib/chaos_detector/walkman.rb, line 20 def initialize(options:) @buffer_length = options.walkman_buffer_length || DEFALT_BUFFER_LENGTH @options = options flush_csv @csv_path = nil @log_buffer = [] @rownum = 0 end
Public Instance Methods
autosave_csv()
click to toggle source
# File lib/chaos_detector/walkman.rb, line 95 def autosave_csv csvp = csv_path if FileTest.exist?(csvp) 1.upto(100) do |n| p = "#{csvp}.#{n}" next if FileTest.exist?(p) log("Autosaving #{csvp} to #{p}") cp_result = `cp #{csvp} #{p}` log(cp_result) break end end end
buffered_trigger()
click to toggle source
# File lib/chaos_detector/walkman.rb, line 110 def buffered_trigger if @log_buffer.length > @buffer_length # log("Triggering flush @#{@log_buffer.length} / @buffer_length") flush_csv end end
count()
click to toggle source
# File lib/chaos_detector/walkman.rb, line 80 def count `wc -l #{csv_path}`.to_i end
csv_path()
click to toggle source
# File lib/chaos_detector/walkman.rb, line 91 def csv_path @csv_path ||= @options.path_with_root(key: :frame_csv_path) end
flush_csv()
click to toggle source
# File lib/chaos_detector/walkman.rb, line 121 def flush_csv # log("Flushing...") if @log_buffer&.any? CSV.open(csv_path, 'a') do |csv| @log_buffer.each do |log_line| csv << log_line end end @log_buffer.clear end end
frame_at(row_index:)
click to toggle source
Return frame at given index or nil if nothing:
# File lib/chaos_detector/walkman.rb, line 39 def frame_at(row_index:) frames_within(row_range: row_index..row_index).first end
frames_within(row_range: nil)
click to toggle source
Return any frames within specified row range; empty array if not found:
# File lib/chaos_detector/walkman.rb, line 44 def frames_within(row_range: nil) to_enum(:playback, row_range: row_range).map { |_r, frame| frame } end
log(msg, **opts)
click to toggle source
# File lib/chaos_detector/walkman.rb, line 117 def log(msg, **opts) ChaosUtils.log_msg(msg, subject: 'Walkman', **opts) end
playback(row_range: nil) { |rownum, playback_row(row)| ... }
click to toggle source
Play back CSV from path configured in Walkman
options @param row_range optionally specify range of rows. Leave nil for all. yields each row as
frame A Frame object with its attributes contained in the CSV row
# File lib/chaos_detector/walkman.rb, line 52 def playback(row_range: nil) started_at = Time.now if row_range log('Walkman replaying CSV with (row_range) %d/%d lines: %s' % [ [count, row_range.max].min, count, csv_path ]) else log("Walkman replaying CSV with #{count} lines: #{csv_path}") end @rownum = 0 row_cur = nil CSV.foreach(csv_path, headers: true) do |row| row_cur = row yield @rownum, playback_row(row) if row_range.nil? || row_range.include?(@rownum) @rownum += 1 break if row_range && @rownum > row_range.max end rescue StandardError => e log("%s:\n%s" % [e.to_s, e.backtrace.join("\n")]) raise ScriptError, log(format(PLAYBACK_MSG, @rownum, csv_path, row_cur, e.inspect)) ensure log('Replayed %d items in %.2f seconds' % [@rownum, Time.now - started_at]) end
record_start()
click to toggle source
# File lib/chaos_detector/walkman.rb, line 29 def record_start flush_csv @csv_path = nil @log_buffer = [] @rownum = 0 autosave_csv init_file_with_header(csv_path) end
stop()
click to toggle source
Call when done to flush any buffers as necessary
# File lib/chaos_detector/walkman.rb, line 85 def stop flush_csv log("Stopped with #{count} lines.") self end
write_frame(frame, frame_offset: nil)
click to toggle source
# File lib/chaos_detector/walkman.rb, line 133 def write_frame(frame, frame_offset: nil) csv_row = [@rownum] csv_row.concat(frame_csv_fields(frame)) @log_buffer << csv_row @rownum += 1 buffered_trigger end
Private Instance Methods
csv_row_val(row, col_header)
click to toggle source
# File lib/chaos_detector/walkman.rb, line 144 def csv_row_val(row, col_header) r = COL_INDEXES[col_header] raise ArgumentError, "#{col_header} not found in CSV_HEADER: #{CSV_HEADER}" if r.nil? || r < 0 || r > COL_COUNT row[r] end
frame_csv_fields(f)
click to toggle source
# File lib/chaos_detector/walkman.rb, line 151 def frame_csv_fields(f) [ f.event, f.mod_info&.mod_name, f.mod_info&.mod_type, f.fn_info.fn_path, f.fn_info.fn_line, f.fn_info.fn_name, f.caller_info&.component_type, f.caller_info&.path, f.caller_info&.info, f.caller_info&.name ] end
init_file_with_header(filepath)
click to toggle source
# File lib/chaos_detector/walkman.rb, line 166 def init_file_with_header(filepath) ChaosDetector::Utils::FSUtil.ensure_paths_to_file(filepath) File.open(filepath, 'w') { |f| f.puts CSV_HEADER.join(',')} end
playback_row(row)
click to toggle source
Play back a single given row returns the event and frame as described in playback
# File lib/chaos_detector/walkman.rb, line 173 def playback_row(row) event = csv_row_val(row, :event) fn_path = csv_row_val(row, :fn_path) fn_line = csv_row_val(row, :fn_line)&.to_i mod_info = ChaosDetector::Stacker::ModInfo.new( mod_name: csv_row_val(row, :mod_name), mod_path: fn_path, mod_type: csv_row_val(row, :mod_type) ) fn_info = ChaosDetector::Stacker::FnInfo.new( fn_name: csv_row_val(row, :fn_name), fn_line: fn_line, fn_path: fn_path ) caller_info = ChaosUtils.with(csv_row_val(row, :caller_type)) do |caller_type| if caller_type.to_sym == :function ChaosDetector::Stacker::FnInfo.new( fn_name: csv_row_val(row, :caller_name), fn_line: csv_row_val(row, :caller_info)&.to_i, fn_path: csv_row_val(row, :caller_path) ) else ChaosDetector::Stacker::ModInfo.new( mod_name: csv_row_val(row, :caller_name), mod_path: csv_row_val(row, :caller_path), mod_type: csv_row_val(row, :caller_info) ) end end ChaosDetector::Stacker::Frame.new( event: event.to_sym, mod_info: mod_info, fn_info: fn_info, caller_info: caller_info ) end