[lttng-dev] [BABELTRACE PATCH] Automatic Python trace parser generator
Julien Desfossez
jdesfossez at efficios.com
Wed Dec 10 10:32:23 EST 2014
After offline discussion, we decided to merge this parser into the
lttng-analyses tree instead of Babeltrace.
So if you want the maintained version, checkout this tree
https://github.com/jdesfossez/lttng-analyses.git
Or if you just want to copy the script and run with it:
wget
https://raw.githubusercontent.com/jdesfossez/lttng-analyses/master/parser_generator.py
Feedbacks and improvement suggestions are very welcome !
Thanks,
Julien
On 14-11-21 04:55 PM, Julien Desfossez wrote:
> 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)
>
More information about the lttng-dev
mailing list