|
@@ -9,6 +9,7 @@
|
|
|
#
|
|
|
# For help see docs/devel/tracing.rst
|
|
|
|
|
|
+import sys
|
|
|
import struct
|
|
|
import inspect
|
|
|
from tracetool import read_events, Event
|
|
@@ -51,7 +52,6 @@ def get_record(edict, idtoname, rechdr, fobj):
|
|
|
try:
|
|
|
event = edict[name]
|
|
|
except KeyError as e:
|
|
|
- import sys
|
|
|
sys.stderr.write('%s event is logged but is not declared ' \
|
|
|
'in the trace events file, try using ' \
|
|
|
'trace-events-all instead.\n' % str(e))
|
|
@@ -172,11 +172,28 @@ def end(self):
|
|
|
pass
|
|
|
|
|
|
def process(events, log, analyzer, read_header=True):
|
|
|
- """Invoke an analyzer on each event in a log."""
|
|
|
+ """Invoke an analyzer on each event in a log.
|
|
|
+ Args:
|
|
|
+ events (file-object or list or str): events list or file-like object or file path as str to read event data from
|
|
|
+ log (file-object or str): file-like object or file path as str to read log data from
|
|
|
+ analyzer (Analyzer): Instance of Analyzer to interpret the event data
|
|
|
+ read_header (bool, optional): Whether to read header data from the log data. Defaults to True.
|
|
|
+ """
|
|
|
+
|
|
|
if isinstance(events, str):
|
|
|
- events = read_events(open(events, 'r'), events)
|
|
|
+ with open(events, 'r') as f:
|
|
|
+ events_list = read_events(f, events)
|
|
|
+ elif isinstance(events, list):
|
|
|
+ # Treat as a list of events already produced by tracetool.read_events
|
|
|
+ events_list = events
|
|
|
+ else:
|
|
|
+ # Treat as an already opened file-object
|
|
|
+ events_list = read_events(events, events.name)
|
|
|
+
|
|
|
+ close_log = False
|
|
|
if isinstance(log, str):
|
|
|
log = open(log, 'rb')
|
|
|
+ close_log = True
|
|
|
|
|
|
if read_header:
|
|
|
read_trace_header(log)
|
|
@@ -187,12 +204,12 @@ def process(events, log, analyzer, read_header=True):
|
|
|
edict = {"dropped": dropped_event}
|
|
|
idtoname = {dropped_event_id: "dropped"}
|
|
|
|
|
|
- for event in events:
|
|
|
+ for event in events_list:
|
|
|
edict[event.name] = event
|
|
|
|
|
|
# If there is no header assume event ID mapping matches events list
|
|
|
if not read_header:
|
|
|
- for event_id, event in enumerate(events):
|
|
|
+ for event_id, event in enumerate(events_list):
|
|
|
idtoname[event_id] = event.name
|
|
|
|
|
|
def build_fn(analyzer, event):
|
|
@@ -225,24 +242,25 @@ def build_fn(analyzer, event):
|
|
|
fn_cache[event_num](event, rec)
|
|
|
analyzer.end()
|
|
|
|
|
|
+ if close_log:
|
|
|
+ log.close()
|
|
|
+
|
|
|
def run(analyzer):
|
|
|
"""Execute an analyzer on a trace file given on the command-line.
|
|
|
|
|
|
This function is useful as a driver for simple analysis scripts. More
|
|
|
advanced scripts will want to call process() instead."""
|
|
|
- import sys
|
|
|
-
|
|
|
- read_header = True
|
|
|
- if len(sys.argv) == 4 and sys.argv[1] == '--no-header':
|
|
|
- read_header = False
|
|
|
- del sys.argv[1]
|
|
|
- elif len(sys.argv) != 3:
|
|
|
- sys.stderr.write('usage: %s [--no-header] <trace-events> ' \
|
|
|
- '<trace-file>\n' % sys.argv[0])
|
|
|
+
|
|
|
+ try:
|
|
|
+ # NOTE: See built-in `argparse` module for a more robust cli interface
|
|
|
+ *no_header, trace_event_path, trace_file_path = sys.argv[1:]
|
|
|
+ assert no_header == [] or no_header == ['--no-header'], 'Invalid no-header argument'
|
|
|
+ except (AssertionError, ValueError):
|
|
|
+ sys.stderr.write(f'usage: {sys.argv[0]} [--no-header] <trace-events> <trace-file>\n')
|
|
|
sys.exit(1)
|
|
|
|
|
|
- events = read_events(open(sys.argv[1], 'r'), sys.argv[1])
|
|
|
- process(events, sys.argv[2], analyzer, read_header=read_header)
|
|
|
+ with open(trace_event_path, 'r') as events_fobj, open(trace_file_path, 'rb') as log_fobj:
|
|
|
+ process(events_fobj, log_fobj, analyzer, read_header=not no_header)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
class Formatter(Analyzer):
|