X-Git-Url: http://git.efficios.com/?p=babeltrace.git;a=blobdiff_plain;f=doc%2Fbindings%2Fpython%2Fsource%2Fexamples.rst;fp=doc%2Fbindings%2Fpython%2Fsource%2Fexamples.rst;h=21e5f438ab1b5f7674bbf8c22939f04f78cbb3ef;hp=0000000000000000000000000000000000000000;hb=ba64dfcccb1f1bd7a259dc5d563ba422b8375582;hpb=aa7407227594c8e5ebff8e1944a902760f2c9a17 diff --git a/doc/bindings/python/source/examples.rst b/doc/bindings/python/source/examples.rst new file mode 100644 index 00000000..21e5f438 --- /dev/null +++ b/doc/bindings/python/source/examples.rst @@ -0,0 +1,910 @@ +.. include:: common.rst + +.. _examples: + +Examples +======== +This section contains a few short and straightforward examples which +show how to use the Babeltrace |~| 2 Python bindings. + +The :mod:`bt2` package provides the Babeltrace |~| 2 Python bindings. +Note that the :mod:`babeltrace` package is part of the Babeltrace |~| 1 +project: it's somewhat out-of-date and not compatible with the +:mod:`bt2` package. + +Assume that all the examples below are named :file:`example.py`. + +.. _examples_tcmi: + +Iterate trace events +-------------------- +The most convenient and high-level way to iterate the events of one or +more traces is with a :class:`bt2.TraceCollectionMessageIterator` +object. + +A :class:`bt2.TraceCollectionMessageIterator` object roughly offers the +same features as the ``convert`` command of the :command:`babeltrace2` +command-line program (see the :bt2man:`babeltrace2-convert(1)` manual +page), but in a programmatic, Pythonic way. + +As of Babeltrace |~| |version|, the trace collection message iterator +class is a Python bindings-only feature: the Python code uses +libbabeltrace2 internally, but the latter does not offer this utility as +such. + +The :class:`bt2.TraceCollectionMessageIterator` interface features: + +* **Automatic source component (trace format) discovery**. + + ``convert`` command equivalent example: + + .. code-block:: text + + $ babeltrace2 /path/to/my/trace + +* **Explicit component class instantiation**. + + ``convert`` command equivalent example: + + .. code-block:: text + + $ babeltrace2 --component=source.my.format + +* **Passing initialization parameters to both auto-discovered and + explicitly created components**. + + ``convert`` command equivalent example: + + .. code-block:: text + + $ babeltrace2 /path/to/my/trace --params=detailed=no \ + --component=source.ctf.fs \ + --params='inputs=["/path/to/my/trace"]' + +* **Trace event muxing**. + + The message iterator muxes (combines) the events from multiple + compatible streams into a single, time-sorted sequence of events. + + .. code-block:: text + + $ babeltrace2 /path/to/trace1 /path/to/trace2 /path/to/trace3 + +* **Stream intersection mode**. + + ``convert`` command equivalent example: + + .. code-block:: text + + $ babeltrace2 /path/to/my/trace --stream-intersection + +* **Stream trimming with beginning and/or end times**. + + ``convert`` command equivalent example: + + .. code-block:: text + + $ babeltrace2 /path/to/my/trace --begin=22:14:38 --end=22:15:07 + +While the :command:`babeltrace2 convert` command creates a ``sink.text.pretty`` +component class (by default) to pretty-print events as plain text lines, +a :class:`bt2.TraceCollectionMessageIterator` object is a Python +iterator which makes its user a message consumer (there's no sink +component):: + + import bt2 + + for msg in bt2.TraceCollectionMessageIterator('/path/to/trace'): + if type(msg) is bt2._EventMessageConst: + print(msg.event.name) + +.. _examples_tcmi_autodisc: + +Discover traces +~~~~~~~~~~~~~~~ +Pass one or more file paths, directory paths, or other strings when you +build a :class:`bt2.TraceCollectionMessageIterator` object to let it +automatically determine which source components to create for you. + +If you pass a directory path, the message iterator traverses the +directory recursively to find traces, automatically selecting the +appropriate source component classes to instantiate. + +The :class:`bt2.TraceCollectionMessageIterator` object and the +:command:`babeltrace2 convert` CLI command share the same automatic +component discovery algorithm. See the +:bt2link:`Create implicit components from non-option arguments ` +section of the :bt2man:`babeltrace2-convert(1)` manual page for more +details. + +The following example shows how to use a +:class:`bt2.TraceCollectionMessageIterator` object to automatically +discover one or more traces from a single path (file or directory). For +each trace event, the example prints its name:: + + import bt2 + import sys + + # Get the trace path from the first command-line argument. + path = sys.argv[1] + + # Create a trace collection message iterator with this path. + msg_it = bt2.TraceCollectionMessageIterator(path) + + # Iterate the trace messages. + for msg in msg_it: + # `bt2._EventMessageConst` is the Python type of an event message. + if type(msg) is bt2._EventMessageConst: + # An event message holds a trace event. + event = msg.event + + # Print event's name. + print(event.name) + +Run this example: + +.. code-block:: text + + $ python3 example.py /path/to/one/or/more/traces + +Output example: + +.. code-block:: text + + kmem_kmalloc + kmem_kfree + kmem_cache_alloc_node + block_getrq + kmem_kmalloc + block_plug + kmem_kfree + block_rq_insert + kmem_kmalloc + kmem_kfree + kmem_kmalloc + kmem_kfree + +The example above is simplistic; it does not catch the exceptions that +some statements can raise: + +* ``bt2.TraceCollectionMessageIterator(path)`` raises an exception if + it cannot find any trace. + +* Each iteration of the loop, or, more precisely, the + :meth:`bt2.TraceCollectionMessageIterator.__next__` method, raises + an exception if there's any error during the iteration process. + + For example, an internal source component message iterator can fail + when trying to decode a malformed trace file. + +.. _examples_tcmi_expl: + +Create explicit source components +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +If `automatic source component discovery <#examples-tcmi-autodisc>`_ +doesn't work for you (for example, because the source component class +you actually need to instantiate doesn't offer the +``babeltrace.support-info`` query object), create explicit source +components when you build a :class:`bt2.TraceCollectionMessageIterator` +object. + +The following example builds a trace collection message iterator to +explicitly instantiate a ``source.ctf.fs`` component class (found in the +``ctf`` plugin). Again, for each trace event, the example prints its +name:: + + import bt2 + import sys + + # Find the `ctf` plugin (shipped with Babeltrace 2). + ctf_plugin = bt2.find_plugin('ctf') + + # Get the `source.ctf.fs` component class from the plugin. + fs_cc = ctf_plugin.source_component_classes['fs'] + + # Create a trace collection message iterator, instantiating a single + # `source.ctf.fs` component class with the `inputs` initialization + # parameter set to open a single CTF trace. + msg_it = bt2.TraceCollectionMessageIterator(bt2.ComponentSpec(fs_cc, { + # Get the CTF trace path from the first command-line argument. + 'inputs': [sys.argv[1]], + })) + + # Iterate the trace messages. + for msg in msg_it: + # `bt2._EventMessageConst` is the Python type of an event message. + if type(msg) is bt2._EventMessageConst: + # Print event's name. + print(msg.event.name) + +Run this example: + +.. code-block:: text + + $ python3 example.py /path/to/ctf/trace + +Output example: + +.. code-block:: text + + kmem_kmalloc + kmem_kfree + kmem_cache_alloc_node + block_getrq + kmem_kmalloc + block_plug + kmem_kfree + block_rq_insert + kmem_kmalloc + kmem_kfree + kmem_kmalloc + kmem_kfree + +The example above looks similar to the previous one using +`automatic source component discovery <#examples-tcmi-autodisc>`_, +but there are notable differences: + +* A ``source.ctf.fs`` component expects to receive the path to a + *single* `CTF `_ trace (a directory + containing a file named ``metadata``). + + Unlike the previous example, you must pass the exact + :abbr:`CTF (Common Trace Format)` trace directory path, *not* a + parent directory path. + +* Unlike the previous example, the example above can only read a single + trace. + + If you want to read multiple :abbr:`CTF (Common Trace Format)` traces + using explicit component class instantiation with a single trace + collection message iterator, you must create one ``source.ctf.fs`` + component per trace. + +Note that the :class:`bt2.ComponentSpec` class offers the +:meth:`from_named_plugin_and_component_class` convenience static method +which finds the plugin and component class for you. You could therefore +rewrite the trace collection message iterator creation part of the +example above as:: + + # Create a trace collection message iterator, instantiating a single + # `source.ctf.fs` component class with the `inputs` initialization + # parameter set to open a single CTF trace. + msg_it = bt2.TraceCollectionMessageIterator( + bt2.ComponentSpec.from_named_plugin_and_component_class('ctf', 'fs', { + # Get the CTF trace path from the first command-line argument. + 'inputs': [sys.argv[1]], + }) + ) + +.. _examples_tcmi_ev_field: + +Get a specific event field's value +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The :ref:`examples_tcmi_autodisc` and :ref:`examples_tcmi_expl` examples +show that a :class:`bt2.TraceCollectionMessageIterator` iterates the +time-sorted *messages* of one or more traces. + +One specific type of message is :class:`bt2._EventMessageConst`, which +holds a trace event object. + +.. note:: + + Everything you can find in the :mod:`bt2` package is publicly + accessible. + + Names which start with ``_`` (underscore), like + :class:`bt2._EventMessageConst`, indicate that you can't + *instantiate* such a class (you cannot call the class). However, the + type itself remains public so that you can use its name to check an + object's type: + + .. code-block:: python + + if type(msg) is bt2._EventMessageConst: + # ... + + .. code-block:: python + + if isinstance(field, bt2._IntegerFieldConst): + # ... + +Access an event object's field by using the event as a simple mapping +(like a read-only :class:`dict`), where keys are field names. The field +can belong to any part of the event (contexts or payload) and to its +packet's context, if any:: + + import bt2 + import sys + + # Create a trace collection message iterator from the first + # command-line argument. + msg_it = bt2.TraceCollectionMessageIterator(sys.argv[1]) + + # Iterate the trace messages. + for msg in msg_it: + # `bt2._EventMessageConst` is the Python type of an event message. + # Only keep such messages. + if type(msg) is not bt2._EventMessageConst: + continue + + # An event message holds a trace event. + event = msg.event + + # Only check `sched_switch` events. + if event.name != 'sched_switch': + continue + + # In an LTTng trace, the `cpu_id` field is a packet context field. + # The mapping interface of `event` can still find it. + cpu_id = event['cpu_id'] + + # Previous and next process short names are found in the event's + # `prev_comm` and `next_comm` fields. + prev_comm = event['prev_comm'] + next_comm = event['next_comm'] + + # Print line, using field values. + msg = 'CPU {}: Switching process `{}` → `{}`' + print(msg.format(cpu_id, prev_comm, next_comm)) + +The example above assumes that the traces to open are +`LTTng `_ Linux kernel traces. + +Run this example: + +.. code-block:: text + + $ python3 example.py /path/to/one/or/more/lttng/traces + +Output example: + +.. code-block:: text + + CPU 2: Switching process `Timer` → `swapper/2` + CPU 0: Switching process `swapper/0` → `firefox` + CPU 0: Switching process `firefox` → `swapper/0` + CPU 0: Switching process `swapper/0` → `rcu_preempt` + CPU 0: Switching process `rcu_preempt` → `swapper/0` + CPU 3: Switching process `swapper/3` → `alsa-sink-ALC26` + CPU 2: Switching process `swapper/2` → `Timer` + CPU 2: Switching process `Timer` → `swapper/2` + CPU 2: Switching process `swapper/2` → `pulseaudio` + CPU 0: Switching process `swapper/0` → `firefox` + CPU 1: Switching process `swapper/1` → `threaded-ml` + CPU 2: Switching process `pulseaudio` → `Timer` + +If you need to access a specific field, use: + +Event payload + :attr:`bt2._EventConst.payload_field` property. + +Event specific context + :attr:`bt2._EventConst.specific_context_field` property. + +Event common context + :attr:`bt2._EventConst.common_context_field` property. + +Packet context + :attr:`bt2._PacketConst.context_field` property. + +Use Python's ``in`` operator to verify if: + +A specific "root" field (in the list above) contains a given field by name + .. code-block:: python + + if 'next_comm' in event.payload_field: + # ... + +Any of the root fields contains a given field by name + .. code-block:: python + + if 'next_comm' in event: + # ... + +The following example iterates the events of a given trace, printing the +value of the ``fd`` payload field if it's available:: + + import bt2 + import sys + + # Create a trace collection message iterator from the first command-line + # argument. + msg_it = bt2.TraceCollectionMessageIterator(sys.argv[1]) + + # Iterate the trace messages. + for msg in msg_it: + # `bt2._EventMessageConst` is the Python type of an event message. + if type(msg) is bt2._EventMessageConst: + # Check if the `fd` event payload field exists. + if 'fd' in msg.event.payload_field: + # Print the `fd` event payload field's value. + print(msg.event.payload_field['fd']) + +Output example: + +.. code-block:: text + + 14 + 15 + 16 + 19 + 30 + 31 + 33 + 42 + 0 + 1 + 2 + 3 + +.. _examples_tcmi_ev_time: + +Get an event's time +~~~~~~~~~~~~~~~~~~~ +The time, or timestamp, of an event object belongs to its message as +a *default clock snapshot*. + +An event's clock snapshot is a *snapshot* (an immutable value) of the +value of the event's stream's clock when the event occurred. As of +Babeltrace |~| |version|, a stream can only have one clock: its default +clock. + +Use the :attr:`default_clock_snapshot` property of an event message +to get its default clock snapshot. A clock snapshot object offers, +amongst other things, the following properties: + +:attr:`value` (:class:`int`) + Value of the clock snapshot in clock cycles. + + A stream clock can have any frequency (Hz). + +:attr:`ns_from_origin` (:class:`int`) + Number of nanoseconds from the stream clock's origin (often the Unix + epoch). + +The following example prints, for each event, its name, its date/time, +and the difference, in seconds, since the previous event's time (if +any):: + + import bt2 + import sys + import datetime + + # Create a trace collection message iterator from the first command-line + # argument. + msg_it = bt2.TraceCollectionMessageIterator(sys.argv[1]) + + # Last event's time (ns from origin). + last_event_ns_from_origin = None + + # Iterate the trace messages. + for msg in msg_it: + # `bt2._EventMessageConst` is the Python type of an event message. + if type(msg) is bt2._EventMessageConst: + # Get event message's default clock snapshot's ns from origin + # value. + ns_from_origin = msg.default_clock_snapshot.ns_from_origin + + # Compute the time difference since the last event message. + diff_s = 0 + + if last_event_ns_from_origin is not None: + diff_s = (ns_from_origin - last_event_ns_from_origin) / 1e9 + + # Create a `datetime.datetime` object from `ns_from_origin` for + # presentation. Note that such an object is less accurate than + # `ns_from_origin` as it holds microseconds, not nanoseconds. + dt = datetime.datetime.fromtimestamp(ns_from_origin / 1e9) + + # Print line. + fmt = '{} (+{:.6f} s): {}' + print(fmt.format(dt, diff_s, msg.event.name)) + + # Update last event's time. + last_event_ns_from_origin = ns_from_origin + +Run this example: + +.. code-block:: text + + $ python3 example.py /path/to/one/or/more/traces + +Output example: + +.. code-block:: text + + 2015-09-09 22:40:41.551451 (+0.000004 s): lttng_ust_statedump:end + 2015-09-09 22:40:43.003397 (+1.451946 s): lttng_ust_dl:dlopen + 2015-09-09 22:40:43.003412 (+0.000015 s): lttng_ust_dl:build_id + 2015-09-09 22:40:43.003861 (+0.000449 s): lttng_ust_dl:dlopen + 2015-09-09 22:40:43.003865 (+0.000004 s): lttng_ust_dl:build_id + 2015-09-09 22:40:43.003879 (+0.000014 s): my_provider:my_first_tracepoint + 2015-09-09 22:40:43.003895 (+0.000016 s): my_provider:my_first_tracepoint + 2015-09-09 22:40:43.003898 (+0.000003 s): my_provider:my_other_tracepoint + 2015-09-09 22:40:43.003922 (+0.000023 s): lttng_ust_dl:dlclose + +Bonus: Print top 5 running processes using LTTng +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +As :ref:`examples_tcmi_ev_field` shows, a +:class:`bt2.TraceCollectionMessageIterator` can read +`LTTng `_ traces. + +The following example is similar to :ref:`examples_tcmi_ev_time`: it +reads a whole LTTng Linux kernel trace, but instead of printing the time +difference for each event, it accumulates them to print the short names +of the top |~| 5 running processes on CPU |~| 0 during the whole trace. + +.. code-block:: python + + import bt2 + import sys + import collections + + # Create a trace collection message iterator from the first command-line + # argument. + msg_it = bt2.TraceCollectionMessageIterator(sys.argv[1]) + + # This counter dictionary will hold execution times: + # + # Task command name -> Total execution time (ns) + exec_times = collections.Counter() + + # This holds the last `sched_switch` event time. + last_ns_from_origin = None + + for msg in msg_it: + # `bt2._EventMessageConst` is the Python type of an event message. + # Only keep such messages. + if type(msg) is not bt2._EventMessageConst: + continue + + # An event message holds a trace event. + event = msg.event + + # Only check `sched_switch` events. + if event.name != 'sched_switch': + continue + + # Keep only events which occurred on CPU 0. + if event['cpu_id'] != 0: + continue + + # Get event message's default clock snapshot's ns from origin value. + ns_from_origin = msg.default_clock_snapshot.ns_from_origin + + if last_ns_from_origin is None: + # We start here. + last_ns_from_origin = ns_from_origin + + # Previous process's short name. + prev_comm = str(event['prev_comm']) + + # Initialize an entry in our dictionary if not done yet. + if prev_comm not in exec_times: + exec_times[prev_comm] = 0 + + # Compute previous process's execution time. + diff_ns = ns_from_origin - last_ns_from_origin + + # Update execution time of this command. + exec_times[prev_comm] += diff_ns + + # Update last event's time. + last_ns_from_origin = ns_from_origin + + # Print top 5. + for comm, ns in exec_times.most_common(5): + print('{:20}{} s'.format(comm, ns / 1e9)) + +Run this example: + +.. code-block:: text + + $ python3 example.py /path/to/lttng/trace + +Output example: + +.. code-block:: text + + swapper/0 326.294314471 s + chromium 2.500456202 s + Xorg.bin 0.546656895 s + threaded-ml 0.545098185 s + pulseaudio 0.53677713 s + +Note that ``swapper/0`` is the "idle" process of CPU |~| 0 on Linux; +since we weren't using the CPU that much when tracing, its first +position in the list makes sense. + +Inspect event classes +~~~~~~~~~~~~~~~~~~~~~ +Each event stream is a *stream class* instance. + +A stream class contains *event classes*. A stream class's event classes +describe all the possible events you can find in its instances. Stream +classes and event classes form the *metadata* of streams and events. + +The following example shows how to list all the event classes of a +stream class. For each event class, the example also prints the names of +its payload field class's first-level members. + +.. note:: + + As of Babeltrace |~| |version|, there's no way to access a stream class + without consuming at least one message for one of its instances + (streams). + + A source component can add new event classes to existing stream + classes during the trace processing task. Therefore, this example + only lists the initial stream class's event classes. + +.. code-block:: python + + import bt2 + import sys + + # Create a trace collection message iterator from the first command-line + # argument. + msg_it = bt2.TraceCollectionMessageIterator(sys.argv[1]) + + # Get the message iterator's first stream beginning message. + for msg in msg_it: + # `bt2._StreamBeginningMessageConst` is the Python type of a stream + # beginning message. + if type(msg) is bt2._StreamBeginningMessageConst: + break + + # A stream beginning message holds a stream. + stream = msg.stream + + # Get the stream's class. + stream_class = stream.cls + + # The stream class object offers a mapping interface (like a read-only + # `dict`), where keys are event class IDs and values are + # `bt2._EventClassConst` objects. + for event_class in stream_class.values(): + print('{}:'.format(event_class.name)) + + # The `payload_field_class` property of an event class returns a + # `bt2._StructureFieldClassConst` object. This object offers a + # mapping interface, where keys are member names and values are + # `bt2._StructureFieldClassMemberConst` objects. + for member in event_class.payload_field_class.values(): + fmt = ' {}: `{}.{}`' + print(fmt.format(member.name, bt2.__name__, + member.field_class.__class__.__name__)) + +Run this example: + +.. code-block:: text + + $ python3 example.py /path/to/trace + +Output example: + +.. code-block:: text + + sched_migrate_task: + comm: `bt2._StringFieldClassConst` + tid: `bt2._SignedIntegerFieldClassConst` + prio: `bt2._SignedIntegerFieldClassConst` + orig_cpu: `bt2._SignedIntegerFieldClassConst` + dest_cpu: `bt2._SignedIntegerFieldClassConst` + sched_switch: + prev_comm: `bt2._StringFieldClassConst` + prev_tid: `bt2._SignedIntegerFieldClassConst` + prev_prio: `bt2._SignedIntegerFieldClassConst` + prev_state: `bt2._SignedIntegerFieldClassConst` + next_comm: `bt2._StringFieldClassConst` + next_tid: `bt2._SignedIntegerFieldClassConst` + next_prio: `bt2._SignedIntegerFieldClassConst` + sched_wakeup_new: + comm: `bt2._StringFieldClassConst` + tid: `bt2._SignedIntegerFieldClassConst` + prio: `bt2._SignedIntegerFieldClassConst` + target_cpu: `bt2._SignedIntegerFieldClassConst` + +.. _examples_graph: + +Build and run a trace processing graph +-------------------------------------- +Internally, a :class:`bt2.TraceCollectionMessageIterator` object (see +:ref:`examples_tcmi`) builds a *trace processing graph*, just like the +:bt2man:`babeltrace2-convert(1)` CLI command, and then offers a +Python iterator interface on top of it. + +See the :bt2man:`babeltrace2-intro(7)` manual page to learn more about +the Babeltrace |~| 2 project and its core concepts. + +The following examples shows how to manually build and then run a trace +processing graph yourself (like the :bt2man:`babeltrace2-run(1)` CLI +command does). The general steps to do so are: + +#. Create an empty graph. + +#. Add components to the graph. + + This process is also known as *instantiating a component class* + because the graph must first create the component from its class + before adding it. + + A viable graph contains at least one source component and one sink + component. + +#. Connect component ports. + + On initialization, components add input and output ports, depending + on their type. + + You can connect component output ports to input ports within a graph. + +#. Run the graph. + + This is a blocking operation which makes each sink component consume + some messages in a round robin fashion until there are no more. + +.. code-block:: python + + import bt2 + import sys + + # Create an empty graph. + graph = bt2.Graph() + + # Add a `source.text.dmesg` component. + # + # graph.add_component() returns the created and added component. + # + # Such a component reads Linux kernel ring buffer messages (see + # `dmesg(1)`) from the standard input and creates corresponding event + # messages. See `babeltrace2-source.text.dmesg(7)`. + # + # `my source` is the unique name of this component within `graph`. + comp_cls = bt2.find_plugin('text').source_component_classes['dmesg'] + src_comp = graph.add_component(comp_cls, 'my source') + + # Add a `sink.text.pretty` component. + # + # Such a component pretty-prints event messages on the standard output + # (one message per line). See `babeltrace2-sink.text.pretty(7)`. + # + # The `babeltrace2 convert` CLI command uses a `sink.text.pretty` + # sink component by default. + comp_cls = bt2.find_plugin('text').sink_component_classes['pretty'] + sink_comp = graph.add_component(comp_cls, 'my sink') + + # Connect the `out` output port of the `source.text.dmesg` component + # to the `in` input port of the `sink.text.pretty` component. + graph.connect_ports(src_comp.output_ports['out'], + sink_comp.input_ports['in']) + + # Run the trace processing graph. + graph.run() + +Run this example: + +.. code-block:: text + + $ dmesg -t | python3 example.py + +Output example: + +.. code-block:: text + + string: { str = "ata1.00: NCQ Send/Recv Log not supported" } + string: { str = "ata1.00: ACPI cmd ef/02:00:00:00:00:a0 (SET FEATURES) succeeded" } + string: { str = "ata1.00: ACPI cmd f5/00:00:00:00:00:a0 (SECURITY FREEZE LOCK) filtered out" } + string: { str = "ata1.00: ACPI cmd ef/10:03:00:00:00:a0 (SET FEATURES) filtered out" } + string: { str = "ata1.00: NCQ Send/Recv Log not supported" } + string: { str = "ata1.00: configured for UDMA/133" } + string: { str = "ata1.00: Enabling discard_zeroes_data" } + string: { str = "OOM killer enabled." } + string: { str = "Restarting tasks ... done." } + string: { str = "PM: suspend exit" } + +Query a component class +----------------------- +Component classes, provided by plugins, can implement a method to +support *query operations*. + +A query operation is similar to a function call: the caller makes a +request (a query) with parameters and the component class's query +method returns a result object. + +The query operation feature exists so that you can benefit from a +component class's implementation to get information about a trace, a +stream, a distant server, and so on. For example, the +``source.ctf.lttng-live`` component class (see +:bt2man:`babeltrace2-source.ctf.lttng-live(7)`) offers the ``sessions`` +object to list the available +`LTTng live `_ tracing +session names and other properties. + +The semantics of the query parameters and the returned object are +completely defined by the component class implementation: the library +and its Python bindings don't enforce or suggest any layout. +The best way to know which objects you can query from a component class, +what are the expected and optional parameters, and what the returned +object contains is to read this component class's documentation. + +The following example queries the "standard" ``babeltrace.support-info`` +query object (see +:bt2man:`babeltrace2-query-babeltrace.support-info(7)`) from the +``source.ctf.fs`` component class +(see :bt2man:`babeltrace2-source.ctf.fs(7)`) and +pretty-prints the result. The ``babeltrace.support-info`` query object +indicates whether or not a given path locates a +:abbr:`CTF (Common Trace Format)` trace directory:: + + import bt2 + import sys + + # Get the `source.ctf.fs` component class from the `ctf` plugin. + comp_cls = bt2.find_plugin('ctf').source_component_classes['fs'] + + # The `babeltrace.support-info` query operation expects a `type` + # parameter (set to `directory` here) and an `input` parameter (the + # actual path or string to check, in this case the first command-line + # argument). + # + # See `babeltrace2-query-babeltrace.support-info(7)`. + params = { + 'type': 'directory', + 'input': sys.argv[1], + } + + # Create a query executor. + # + # This is the environment in which query operations happens. The + # queried component class has access to this executor, for example to + # retrieve the query operation's logging level. + query_exec = bt2.QueryExecutor(comp_cls, 'babeltrace.support-info', + params) + + # Query the component class through the query executor. + # + # This method returns the result. + result = query_exec.query() + + # Print the result. + print(result) + +As you can see, no trace processing graph is involved (like in +:ref:`examples_tcmi` and :ref:`examples_graph`): a query operation +is *not* a sequential trace processing task, but a simple, atomic +procedure call. + +Run this example: + +.. code-block:: text + + $ python3 example.py /path/to/ctf/trace + +Output example: + +.. code-block:: text + + {'group': '21c63a42-40bc-4c08-9761-3815ae01f43d', 'weight': 0.75} + +This result indicates that the component class is 75 |~| % confident that +:file:`/path/to/ctf/trace` is a CTF trace directory path. It also shows +that this specific CTF trace belongs to the +``21c63a42-40bc-4c08-9761-3815ae01f43d`` group; a single component can +handle multiple traces which belong to the same group. + +Let's try the sample example with a path that doesn't locate a CTF +trace: + +.. code-block:: text + + $ python3 example.py /etc + +Output: + +.. code-block:: text + + {'weight': 0.0} + +As expected, the zero weight indicates that ``/etc`` isn't a CTF trace +directory path.