Created
May 7, 2012 12:47
-
-
Save wvdschel/2627572 to your computer and use it in GitHub Desktop.
Cats parser
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Stats about a single log | |
class Log | |
# Load a file and parse every line as a print. | |
def self.parse(file_path) | |
Log.new(file_path, File.readlines(file_path)) | |
end | |
# Number of lines in the file and number of lines that are valid CATS prints | |
attr_reader :linecount, :cats_linecount, | |
# Number of characters that are in the file, part of CATS prints and part of CATS header overhead, respectively | |
:charcount, :cats_charcount, :cats_header_charcount, | |
# Hash of trace symbols and trace lines, by symbol name/line identifier, and list of TracePrints | |
:symbols, :lines, :prints, | |
# Name of the log | |
:name | |
def initialize(log_name, log_lines = []) | |
@name = log_name | |
@linecount = @cats_linecount = @charcount = @cats_charcount = @cats_header_charcount = 0 | |
@symbols = {} | |
@lines = {} | |
@prints = [] | |
log_lines.each { |line| self << line } | |
end | |
# Add prints to this log, accepts either strings, TraceLines or TracePrints, or an array of these things | |
def <<(trace_line_or_print) | |
trace_print = nil | |
if trace_line_or_print.is_a? TraceLine # TraceLine | |
# Add all the prints | |
self << trace_line_or_print.trace_prints | |
return nil | |
elsif trace_line_or_print.is_a? Array # Array | |
trace_line_or_print.each do |print| | |
self << print | |
end | |
rerturn nil | |
elsif trace_line_or_print.is_a? TracePrint # TracePrint | |
trace_print = trace_line_or_print | |
else # String or others | |
# It's not a TracePrint, trying making one | |
if TracePrint.cats? trace_line_or_print | |
trace_print = TracePrint.new(trace_line_or_print) | |
else # Not a CATS print or a corrupted print | |
@linecount += 1 | |
@charcount += trace_line_or_print.to_s.length | |
return nil | |
end | |
end | |
# Beyond this points, trace_print is certainly a TracePrint | |
@linecount += 1 | |
@charcount += trace_print.to_s.length | |
@cats_linecount += 1 | |
@cats_charcount += trace_print.to_s.length | |
@cats_header_charcount += trace_print.to_s.length - trace_print.payload.length | |
@lines[trace_print.trace_line] ||= TraceLine.new(trace_print.trace_symbol, trace_print.line) | |
@symbols[trace_print.trace_symbol] ||= TraceSymbol.new(trace_print.trace_symbol) | |
@symbols[trace_print.trace_symbol] << trace_print | |
@lines[trace_print.trace_line] << trace_print | |
@prints << trace_print | |
nil | |
end | |
# Combine two logs | |
def +(log) | |
raise "TODO" | |
end | |
end | |
# Stats about specific trace symbol | |
class TraceSymbol | |
attr_reader :name, :lines, :prints, :charcount | |
def initialize(trace_symbol) | |
@name = trace_symbol | |
@charcount = 0 | |
@lines = {} | |
@prints = [] | |
end | |
def <<(trace_print) | |
@lines[trace_print.trace_line] ||= TraceLine.new(trace_print.trace_symbol, trace_print.line) | |
@lines[trace_print.trace_line] << trace_print | |
@prints << trace_print | |
@charcount += trace_print.to_s.length | |
end | |
def +(trace_symbol) | |
raise "TODO" | |
end | |
end | |
# Stats about specific TraceXxx calls | |
class TraceLine | |
attr_reader :symbol, :line, :trace_line, :prints, :charcount | |
alias :name :trace_line | |
def initialize(symbol, line) | |
@symbol = symbol | |
@line = line | |
@charcount = 0 | |
@trace_line = "%s:%04d" % [@symbol, @line] | |
@prints = [] | |
end | |
def <<(trace_print) | |
@prints << trace_print | |
@charcount += trace_print.to_s.length | |
end | |
def +(trace_line) | |
raise "TODO" | |
end | |
end | |
class TracePrint | |
# A5 00090.005.621 euApp: 382 /ceapsubtitle_m(01077) SUBTITLE: type = Digital | |
LEGACY_CATS = %r{ | |
(?<cpu> [AP]){0} | |
(?<level> \d){0} | |
(?<timestamp>\d{5}\.\d{3}.\d{3}){0} | |
(?<process> [^:]+){0} | |
(?<thread_id>[^ ]+){0} | |
(?<symbol> [^\(]+){0} | |
(?<line> \d+){0} | |
(?<payload> .*){0} | |
\g<cpu>\g<level>\s\g<timestamp>\s+\g<process>:\s*\g<thread_id>\s+\g<symbol>\(\g<line>\)\s*\g<payload> | |
}x | |
# 5P23.46451 plfapp:455 /legacy/printf:0000 ##papi_mute_smt_MuteOutputs ## outputs=0x00 OutputsMuted = 0x00 | |
MODERN_CATS = %r{ | |
(?<cpu> [AP]){0} | |
(?<level> \d){0} | |
(?<timestamp>\d+\.\d{5}){0} | |
(?<process> [^:]+){0} | |
(?<thread_id>\d+){0} | |
(?<symbol> [^:]+){0} | |
(?<line> \d+){0} | |
(?<payload> .*){0} | |
\g<level>\g<cpu>\g<timestamp>\t+\g<process>:\g<thread_id>\t+\g<symbol>:\g<line>\t*\g<payload> | |
}x | |
def self.cats?(cats_print) | |
cats_print && not(cats_print[LEGACY_CATS].nil? && cats_print[MODERN_CATS].nil?) | |
end | |
def initialize(cats_print) | |
raise Error.new("#{cats_prints.inspect} is not a CATS prints.") unless TracePrint.cats?(cats_print) | |
match = LEGACY_CATS.match(cats_print) || MODERN_CATS.match(cats_print) | |
# Filter out second dot from timestamp for legacy prints | |
@time = match[:timestamp].sub(/\.(\d\d\d)$/, '\1') | |
@line = match[:line].to_i | |
@trace_symbol = match[:symbol] | |
@trace_line = "%s:%04d" % [@trace_symbol, @line] | |
@payload = match[:payload] | |
@cpu = match[:cpu] | |
@level = match[:level] | |
@process = match[:process] | |
@thread_id = match[:thread_id] | |
@payload = match[:payload] | |
@raw = match.to_s | |
end | |
attr_reader :time, :trace_line, :line, :trace_symbol, :payload, :thread_id, :process, :cpu, :level, :raw | |
def to_s | |
@raw.clone | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment