[lttng-dev] [BABELTRACE PATCH] Automatic Python trace parser generator
Julien Desfossez
jdesfossez at efficios.com
Fri Nov 21 16:55:21 EST 2014
This script takes a trace in parameter and generates a ready to use
Python script customized for the events and fields present in the trace.
Signed-off-by: Julien Desfossez <jdesfossez at efficios.com>
---
bindings/python/examples/parser_generator.py | 150 +++++++++++++++++++++++++++
1 file changed, 150 insertions(+)
create mode 100755 bindings/python/examples/parser_generator.py
diff --git a/bindings/python/examples/parser_generator.py b/bindings/python/examples/parser_generator.py
new file mode 100755
index 0000000..ad219bd
--- /dev/null
+++ b/bindings/python/examples/parser_generator.py
@@ -0,0 +1,150 @@
+#!/usr/bin/env python3
+#
+# Copyright 2014 Julien Desfossez <jdesfossez at efficios.com>
+#
+# This script takes a trace in argument and generates a Python parser ready to
+# process the events (and all the fields) of the trace. It is used to generate
+# all the boilerplate required to create an analysis script of a CTF trace in
+# Python and allow the user to focus on the core logic of the analysis.
+#
+# The default resulting script can process all the events of the trace, and
+# print all the fields for each event (except if you pass -q/--quiet). At the
+# end of the trace, it displays also global statistics about the number of each
+# event encountered.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+
+import sys
+import os
+import stat
+import argparse
+
+try:
+ from babeltrace import TraceCollection, CTFScope
+except ImportError:
+ # quick fix for debian-based distros
+ sys.path.append("/usr/local/lib/python%d.%d/site-packages" %
+ (sys.version_info.major, sys.version_info.minor))
+ from babeltrace import TraceCollection, CTFScope
+
+preambule = """#!/usr/bin/env python3
+
+import sys
+import time
+import argparse
+
+NSEC_PER_SEC = 1000000000
+
+try:
+ from babeltrace import TraceCollection
+except ImportError:
+ # quick fix for debian-based distros
+ sys.path.append("/usr/local/lib/python%d.%d/site-packages" %
+ (sys.version_info.major, sys.version_info.minor))
+ from babeltrace import TraceCollection
+
+
+class TraceParser:
+ def __init__(self, trace):
+ self.trace = trace
+ self.event_count = {}
+
+ def ns_to_hour_nsec(self, ns):
+ d = time.localtime(ns/NSEC_PER_SEC)
+ return "%02d:%02d:%02d.%09d" % (d.tm_hour, d.tm_min, d.tm_sec,
+ ns % NSEC_PER_SEC)
+
+ def parse(self):
+ # iterate over all the events
+ for event in self.trace.events:
+ if not event.name in self.event_count.keys():
+ self.event_count[event.name] = 0
+ method_name = "handle_%s" % event.name.replace(":", "_").replace("+", "_")
+ # call the function to handle each event individually
+ if hasattr(TraceParser, method_name):
+ func = getattr(TraceParser, method_name)
+ func(self, event)
+ # print statistics after parsing the trace
+ print("Total event count:")
+ for e in self.event_count.keys():
+ print("- %s: %d" % (e, self.event_count[e]))
+
+"""
+
+end = """
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(description='Trace parser')
+ parser.add_argument('path', metavar="<path/to/trace>", help='Trace path')
+ args = parser.parse_args()
+
+ traces = TraceCollection()
+ handle = traces.add_trace(args.path, "ctf")
+ if handle is None:
+ sys.exit(1)
+
+ t = TraceParser(traces)
+ t.parse()
+
+ traces.remove_trace(handle)
+"""
+
+
+def gen_parser(handle, fd, args):
+ for event in handle.events:
+ fmt_str = "[%s] %s: { cpu_id = %s }, { "
+ fmt_fields = "self.ns_to_hour_nsec(timestamp), event.name, cpu_id, "
+ name = event.name.replace(":", "_").replace("+", "_")
+ fd.write(" def handle_%s(self, event):\n" % (name))
+ fd.write(" timestamp = event.timestamp\n")
+ fd.write(" cpu_id = event[\"cpu_id\"]\n")
+ for field in event.fields:
+ if field.scope == CTFScope.EVENT_FIELDS:
+ fd.write(" %s = event[\"%s\"]\n" % (field.name,
+ field.name))
+ fmt_str = fmt_str + field.name + " = %s, "
+ fmt_fields = fmt_fields + "%s, " % (field.name)
+ fd.write("\n self.event_count[event.name] += 1\n")
+ if not args.quiet:
+ fd.write(" print(\"%s }\" %% (%s))\n\n" % (fmt_str[0:-2],
+ fmt_fields[0:-1]))
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(description='Trace parser generator')
+ parser.add_argument('path', metavar="<path/to/trace>", help='Trace path')
+ parser.add_argument('-o', '--output', type=str, default=0,
+ metavar="<output-script-name>",
+ help='Output script name')
+ parser.add_argument('-q', '--quiet', action="store_true",
+ help='Generate a quiet parser (no print)')
+ args = parser.parse_args()
+
+ traces = TraceCollection()
+ handle = traces.add_trace(args.path, "ctf")
+ if handle is None:
+ sys.exit(1)
+
+ if args.output == 0:
+ output = "generated-parser.py"
+ else:
+ output = args.output
+
+ fd = open(output, "w")
+ fd.write(preambule)
+ gen_parser(handle, fd, args)
+
+ traces.remove_trace(handle)
+ fd.write(end)
+ fd.close()
+ os.chmod(output, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR |
+ stat.S_IRGRP | stat.S_IXGRP |
+ stat.S_IROTH | stat.S_IXOTH)
+ print("A trace parser for this trace has been written in", output)
--
1.9.1
More information about the lttng-dev
mailing list