cpp-common/bt2c/fmt.hpp: use `wise_enum::string_type` in `EnableIfIsWiseEnum` definition
[babeltrace.git] / doc / bindings / python / source / examples.rst
1 ..
2 SPDX-FileCopyrightText: 2020 Philippe Proulx <eeppeliteloop@gmail.com>
3 SPDX-License-Identifier: CC-BY-SA-4.0
4
5 .. include:: common.rst
6
7 .. _examples:
8
9 Examples
10 ========
11 This section contains a few short and straightforward examples which
12 show how to use the Babeltrace |~| 2 Python bindings.
13
14 The :mod:`bt2` package provides the Babeltrace |~| 2 Python bindings.
15 Note that the :mod:`babeltrace` package is part of the Babeltrace |~| 1
16 project: it's somewhat out-of-date and not compatible with the
17 :mod:`bt2` package.
18
19 Assume that all the examples below are named :file:`example.py`.
20
21 .. _examples_tcmi:
22
23 Iterate trace events
24 --------------------
25 The most convenient and high-level way to iterate the events of one or
26 more traces is with a :class:`bt2.TraceCollectionMessageIterator`
27 object.
28
29 A :class:`bt2.TraceCollectionMessageIterator` object roughly offers the
30 same features as the ``convert`` command of the :command:`babeltrace2`
31 command-line program (see the :bt2man:`babeltrace2-convert(1)` manual
32 page), but in a programmatic, Pythonic way.
33
34 As of Babeltrace |~| |version|, the trace collection message iterator
35 class is a Python bindings-only feature: the Python code uses
36 libbabeltrace2 internally, but the latter does not offer this utility as
37 such.
38
39 The :class:`bt2.TraceCollectionMessageIterator` interface features:
40
41 * **Automatic source component (trace format) discovery**.
42
43 ``convert`` command equivalent example:
44
45 .. code-block:: text
46
47 $ babeltrace2 /path/to/my/trace
48
49 * **Explicit component class instantiation**.
50
51 ``convert`` command equivalent example:
52
53 .. code-block:: text
54
55 $ babeltrace2 --component=source.my.format
56
57 * **Passing initialization parameters to both auto-discovered and
58 explicitly created components**.
59
60 ``convert`` command equivalent example:
61
62 .. code-block:: text
63
64 $ babeltrace2 /path/to/my/trace --params=detailed=no \
65 --component=source.ctf.fs \
66 --params='inputs=["/path/to/my/trace"]'
67
68 * **Trace event muxing**.
69
70 The message iterator muxes (combines) the events from multiple
71 compatible streams into a single, time-sorted sequence of events.
72
73 .. code-block:: text
74
75 $ babeltrace2 /path/to/trace1 /path/to/trace2 /path/to/trace3
76
77 * **Stream intersection mode**.
78
79 ``convert`` command equivalent example:
80
81 .. code-block:: text
82
83 $ babeltrace2 /path/to/my/trace --stream-intersection
84
85 * **Stream trimming with beginning and/or end times**.
86
87 ``convert`` command equivalent example:
88
89 .. code-block:: text
90
91 $ babeltrace2 /path/to/my/trace --begin=22:14:38 --end=22:15:07
92
93 While the :command:`babeltrace2 convert` command creates a ``sink.text.pretty``
94 component class (by default) to pretty-print events as plain text lines,
95 a :class:`bt2.TraceCollectionMessageIterator` object is a Python
96 iterator which makes its user a message consumer (there's no sink
97 component)::
98
99 import bt2
100
101 for msg in bt2.TraceCollectionMessageIterator('/path/to/trace'):
102 if type(msg) is bt2._EventMessageConst:
103 print(msg.event.name)
104
105 .. _examples_tcmi_autodisc:
106
107 Discover traces
108 ~~~~~~~~~~~~~~~
109 Pass one or more file paths, directory paths, or other strings when you
110 build a :class:`bt2.TraceCollectionMessageIterator` object to let it
111 automatically determine which source components to create for you.
112
113 If you pass a directory path, the message iterator traverses the
114 directory recursively to find traces, automatically selecting the
115 appropriate source component classes to instantiate.
116
117 The :class:`bt2.TraceCollectionMessageIterator` object and the
118 :command:`babeltrace2 convert` CLI command share the same automatic
119 component discovery algorithm. See the
120 :bt2link:`Create implicit components from non-option arguments <https://babeltrace.org/docs/v@ver@/man1/babeltrace2-convert.1/#doc-comp-create-impl-non-opt>`
121 section of the :bt2man:`babeltrace2-convert(1)` manual page for more
122 details.
123
124 The following example shows how to use a
125 :class:`bt2.TraceCollectionMessageIterator` object to automatically
126 discover one or more traces from a single path (file or directory). For
127 each trace event, the example prints its name::
128
129 import bt2
130 import sys
131
132 # Get the trace path from the first command-line argument.
133 path = sys.argv[1]
134
135 # Create a trace collection message iterator with this path.
136 msg_it = bt2.TraceCollectionMessageIterator(path)
137
138 # Iterate the trace messages.
139 for msg in msg_it:
140 # `bt2._EventMessageConst` is the Python type of an event message.
141 if type(msg) is bt2._EventMessageConst:
142 # An event message holds a trace event.
143 event = msg.event
144
145 # Print event's name.
146 print(event.name)
147
148 Run this example:
149
150 .. code-block:: text
151
152 $ python3 example.py /path/to/one/or/more/traces
153
154 Output example:
155
156 .. code-block:: text
157
158 kmem_kmalloc
159 kmem_kfree
160 kmem_cache_alloc_node
161 block_getrq
162 kmem_kmalloc
163 block_plug
164 kmem_kfree
165 block_rq_insert
166 kmem_kmalloc
167 kmem_kfree
168 kmem_kmalloc
169 kmem_kfree
170
171 The example above is simplistic; it does not catch the exceptions that
172 some statements can raise:
173
174 * ``bt2.TraceCollectionMessageIterator(path)`` raises an exception if
175 it cannot find any trace.
176
177 * Each iteration of the loop, or, more precisely, the
178 :meth:`bt2.TraceCollectionMessageIterator.__next__` method, raises
179 an exception if there's any error during the iteration process.
180
181 For example, an internal source component message iterator can fail
182 when trying to decode a malformed trace file.
183
184 .. _examples_tcmi_expl:
185
186 Create explicit source components
187 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
188 If `automatic source component discovery <#examples-tcmi-autodisc>`_
189 doesn't work for you (for example, because the source component class
190 you actually need to instantiate doesn't offer the
191 ``babeltrace.support-info`` query object), create explicit source
192 components when you build a :class:`bt2.TraceCollectionMessageIterator`
193 object.
194
195 The following example builds a trace collection message iterator to
196 explicitly instantiate a ``source.ctf.fs`` component class (found in the
197 ``ctf`` plugin). Again, for each trace event, the example prints its
198 name::
199
200 import bt2
201 import sys
202
203 # Find the `ctf` plugin (shipped with Babeltrace 2).
204 ctf_plugin = bt2.find_plugin('ctf')
205
206 # Get the `source.ctf.fs` component class from the plugin.
207 fs_cc = ctf_plugin.source_component_classes['fs']
208
209 # Create a trace collection message iterator, instantiating a single
210 # `source.ctf.fs` component class with the `inputs` initialization
211 # parameter set to open a single CTF trace.
212 msg_it = bt2.TraceCollectionMessageIterator(bt2.ComponentSpec(fs_cc, {
213 # Get the CTF trace path from the first command-line argument.
214 'inputs': [sys.argv[1]],
215 }))
216
217 # Iterate the trace messages.
218 for msg in msg_it:
219 # `bt2._EventMessageConst` is the Python type of an event message.
220 if type(msg) is bt2._EventMessageConst:
221 # Print event's name.
222 print(msg.event.name)
223
224 Run this example:
225
226 .. code-block:: text
227
228 $ python3 example.py /path/to/ctf/trace
229
230 Output example:
231
232 .. code-block:: text
233
234 kmem_kmalloc
235 kmem_kfree
236 kmem_cache_alloc_node
237 block_getrq
238 kmem_kmalloc
239 block_plug
240 kmem_kfree
241 block_rq_insert
242 kmem_kmalloc
243 kmem_kfree
244 kmem_kmalloc
245 kmem_kfree
246
247 The example above looks similar to the previous one using
248 `automatic source component discovery <#examples-tcmi-autodisc>`_,
249 but there are notable differences:
250
251 * A ``source.ctf.fs`` component expects to receive the path to a
252 *single* `CTF <https://diamon.org/ctf/>`_ trace (a directory
253 containing a file named ``metadata``).
254
255 Unlike the previous example, you must pass the exact
256 :abbr:`CTF (Common Trace Format)` trace directory path, *not* a
257 parent directory path.
258
259 * Unlike the previous example, the example above can only read a single
260 trace.
261
262 If you want to read multiple :abbr:`CTF (Common Trace Format)` traces
263 using explicit component class instantiation with a single trace
264 collection message iterator, you must create one ``source.ctf.fs``
265 component per trace.
266
267 Note that the :class:`bt2.ComponentSpec` class offers the
268 :meth:`from_named_plugin_and_component_class` convenience static method
269 which finds the plugin and component class for you. You could therefore
270 rewrite the trace collection message iterator creation part of the
271 example above as::
272
273 # Create a trace collection message iterator, instantiating a single
274 # `source.ctf.fs` component class with the `inputs` initialization
275 # parameter set to open a single CTF trace.
276 msg_it = bt2.TraceCollectionMessageIterator(
277 bt2.ComponentSpec.from_named_plugin_and_component_class('ctf', 'fs', {
278 # Get the CTF trace path from the first command-line argument.
279 'inputs': [sys.argv[1]],
280 })
281 )
282
283 .. _examples_tcmi_ev_field:
284
285 Get a specific event field's value
286 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
287 The :ref:`examples_tcmi_autodisc` and :ref:`examples_tcmi_expl` examples
288 show that a :class:`bt2.TraceCollectionMessageIterator` iterates the
289 time-sorted *messages* of one or more traces.
290
291 One specific type of message is :class:`bt2._EventMessageConst`, which
292 holds a trace event object.
293
294 .. note::
295
296 Everything you can find in the :mod:`bt2` package is publicly
297 accessible.
298
299 Names which start with ``_`` (underscore), like
300 :class:`bt2._EventMessageConst`, indicate that you can't
301 *instantiate* such a class (you cannot call the class). However, the
302 type itself remains public so that you can use its name to check an
303 object's type:
304
305 .. code-block:: python
306
307 if type(msg) is bt2._EventMessageConst:
308 # ...
309
310 .. code-block:: python
311
312 if isinstance(field, bt2._IntegerFieldConst):
313 # ...
314
315 Access an event object's field by using the event as a simple mapping
316 (like a read-only :class:`dict`), where keys are field names. The field
317 can belong to any part of the event (contexts or payload) and to its
318 packet's context, if any::
319
320 import bt2
321 import sys
322
323 # Create a trace collection message iterator from the first
324 # command-line argument.
325 msg_it = bt2.TraceCollectionMessageIterator(sys.argv[1])
326
327 # Iterate the trace messages.
328 for msg in msg_it:
329 # `bt2._EventMessageConst` is the Python type of an event message.
330 # Only keep such messages.
331 if type(msg) is not bt2._EventMessageConst:
332 continue
333
334 # An event message holds a trace event.
335 event = msg.event
336
337 # Only check `sched_switch` events.
338 if event.name != 'sched_switch':
339 continue
340
341 # In an LTTng trace, the `cpu_id` field is a packet context field.
342 # The mapping interface of `event` can still find it.
343 cpu_id = event['cpu_id']
344
345 # Previous and next process short names are found in the event's
346 # `prev_comm` and `next_comm` fields.
347 prev_comm = event['prev_comm']
348 next_comm = event['next_comm']
349
350 # Print line, using field values.
351 msg = 'CPU {}: Switching process `{}` → `{}`'
352 print(msg.format(cpu_id, prev_comm, next_comm))
353
354 The example above assumes that the traces to open are
355 `LTTng <https://lttng.org/>`_ Linux kernel traces.
356
357 Run this example:
358
359 .. code-block:: text
360
361 $ python3 example.py /path/to/one/or/more/lttng/traces
362
363 Output example:
364
365 .. code-block:: text
366
367 CPU 2: Switching process `Timer` → `swapper/2`
368 CPU 0: Switching process `swapper/0` → `firefox`
369 CPU 0: Switching process `firefox` → `swapper/0`
370 CPU 0: Switching process `swapper/0` → `rcu_preempt`
371 CPU 0: Switching process `rcu_preempt` → `swapper/0`
372 CPU 3: Switching process `swapper/3` → `alsa-sink-ALC26`
373 CPU 2: Switching process `swapper/2` → `Timer`
374 CPU 2: Switching process `Timer` → `swapper/2`
375 CPU 2: Switching process `swapper/2` → `pulseaudio`
376 CPU 0: Switching process `swapper/0` → `firefox`
377 CPU 1: Switching process `swapper/1` → `threaded-ml`
378 CPU 2: Switching process `pulseaudio` → `Timer`
379
380 If you need to access a specific field, use:
381
382 Event payload
383 :attr:`bt2._EventConst.payload_field` property.
384
385 Event specific context
386 :attr:`bt2._EventConst.specific_context_field` property.
387
388 Event common context
389 :attr:`bt2._EventConst.common_context_field` property.
390
391 Packet context
392 :attr:`bt2._PacketConst.context_field` property.
393
394 Use Python's ``in`` operator to verify if:
395
396 A specific "root" field (in the list above) contains a given field by name
397 .. code-block:: python
398
399 if 'next_comm' in event.payload_field:
400 # ...
401
402 Any of the root fields contains a given field by name
403 .. code-block:: python
404
405 if 'next_comm' in event:
406 # ...
407
408 The following example iterates the events of a given trace, printing the
409 value of the ``fd`` payload field if it's available::
410
411 import bt2
412 import sys
413
414 # Create a trace collection message iterator from the first command-line
415 # argument.
416 msg_it = bt2.TraceCollectionMessageIterator(sys.argv[1])
417
418 # Iterate the trace messages.
419 for msg in msg_it:
420 # `bt2._EventMessageConst` is the Python type of an event message.
421 if type(msg) is bt2._EventMessageConst:
422 # Check if the `fd` event payload field exists.
423 if 'fd' in msg.event.payload_field:
424 # Print the `fd` event payload field's value.
425 print(msg.event.payload_field['fd'])
426
427 Output example:
428
429 .. code-block:: text
430
431 14
432 15
433 16
434 19
435 30
436 31
437 33
438 42
439 0
440 1
441 2
442 3
443
444 .. _examples_tcmi_ev_time:
445
446 Get an event's time
447 ~~~~~~~~~~~~~~~~~~~
448 The time, or timestamp, of an event object belongs to its message as
449 a *default clock snapshot*.
450
451 An event's clock snapshot is a *snapshot* (an immutable value) of the
452 value of the event's stream's clock when the event occurred. As of
453 Babeltrace |~| |version|, a stream can only have one clock: its default
454 clock.
455
456 Use the :attr:`default_clock_snapshot` property of an event message
457 to get its default clock snapshot. A clock snapshot object offers,
458 amongst other things, the following properties:
459
460 :attr:`value` (:class:`int`)
461 Value of the clock snapshot in clock cycles.
462
463 A stream clock can have any frequency (Hz).
464
465 :attr:`ns_from_origin` (:class:`int`)
466 Number of nanoseconds from the stream clock's origin (often the Unix
467 epoch).
468
469 The following example prints, for each event, its name, its date/time,
470 and the difference, in seconds, since the previous event's time (if
471 any)::
472
473 import bt2
474 import sys
475 import datetime
476
477 # Create a trace collection message iterator from the first command-line
478 # argument.
479 msg_it = bt2.TraceCollectionMessageIterator(sys.argv[1])
480
481 # Last event's time (ns from origin).
482 last_event_ns_from_origin = None
483
484 # Iterate the trace messages.
485 for msg in msg_it:
486 # `bt2._EventMessageConst` is the Python type of an event message.
487 if type(msg) is bt2._EventMessageConst:
488 # Get event message's default clock snapshot's ns from origin
489 # value.
490 ns_from_origin = msg.default_clock_snapshot.ns_from_origin
491
492 # Compute the time difference since the last event message.
493 diff_s = 0
494
495 if last_event_ns_from_origin is not None:
496 diff_s = (ns_from_origin - last_event_ns_from_origin) / 1e9
497
498 # Create a `datetime.datetime` object from `ns_from_origin` for
499 # presentation. Note that such an object is less accurate than
500 # `ns_from_origin` as it holds microseconds, not nanoseconds.
501 dt = datetime.datetime.fromtimestamp(ns_from_origin / 1e9)
502
503 # Print line.
504 fmt = '{} (+{:.6f} s): {}'
505 print(fmt.format(dt, diff_s, msg.event.name))
506
507 # Update last event's time.
508 last_event_ns_from_origin = ns_from_origin
509
510 Run this example:
511
512 .. code-block:: text
513
514 $ python3 example.py /path/to/one/or/more/traces
515
516 Output example:
517
518 .. code-block:: text
519
520 2015-09-09 22:40:41.551451 (+0.000004 s): lttng_ust_statedump:end
521 2015-09-09 22:40:43.003397 (+1.451946 s): lttng_ust_dl:dlopen
522 2015-09-09 22:40:43.003412 (+0.000015 s): lttng_ust_dl:build_id
523 2015-09-09 22:40:43.003861 (+0.000449 s): lttng_ust_dl:dlopen
524 2015-09-09 22:40:43.003865 (+0.000004 s): lttng_ust_dl:build_id
525 2015-09-09 22:40:43.003879 (+0.000014 s): my_provider:my_first_tracepoint
526 2015-09-09 22:40:43.003895 (+0.000016 s): my_provider:my_first_tracepoint
527 2015-09-09 22:40:43.003898 (+0.000003 s): my_provider:my_other_tracepoint
528 2015-09-09 22:40:43.003922 (+0.000023 s): lttng_ust_dl:dlclose
529
530 Bonus: Print top 5 running processes using LTTng
531 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
532 As :ref:`examples_tcmi_ev_field` shows, a
533 :class:`bt2.TraceCollectionMessageIterator` can read
534 `LTTng <https://lttng.org/>`_ traces.
535
536 The following example is similar to :ref:`examples_tcmi_ev_time`: it
537 reads a whole LTTng Linux kernel trace, but instead of printing the time
538 difference for each event, it accumulates them to print the short names
539 of the top |~| 5 running processes on CPU |~| 0 during the whole trace.
540
541 .. code-block:: python
542
543 import bt2
544 import sys
545 import collections
546
547 # Create a trace collection message iterator from the first command-line
548 # argument.
549 msg_it = bt2.TraceCollectionMessageIterator(sys.argv[1])
550
551 # This counter dictionary will hold execution times:
552 #
553 # Task command name -> Total execution time (ns)
554 exec_times = collections.Counter()
555
556 # This holds the last `sched_switch` event time.
557 last_ns_from_origin = None
558
559 for msg in msg_it:
560 # `bt2._EventMessageConst` is the Python type of an event message.
561 # Only keep such messages.
562 if type(msg) is not bt2._EventMessageConst:
563 continue
564
565 # An event message holds a trace event.
566 event = msg.event
567
568 # Only check `sched_switch` events.
569 if event.name != 'sched_switch':
570 continue
571
572 # Keep only events which occurred on CPU 0.
573 if event['cpu_id'] != 0:
574 continue
575
576 # Get event message's default clock snapshot's ns from origin value.
577 ns_from_origin = msg.default_clock_snapshot.ns_from_origin
578
579 if last_ns_from_origin is None:
580 # We start here.
581 last_ns_from_origin = ns_from_origin
582
583 # Previous process's short name.
584 prev_comm = str(event['prev_comm'])
585
586 # Initialize an entry in our dictionary if not done yet.
587 if prev_comm not in exec_times:
588 exec_times[prev_comm] = 0
589
590 # Compute previous process's execution time.
591 diff_ns = ns_from_origin - last_ns_from_origin
592
593 # Update execution time of this command.
594 exec_times[prev_comm] += diff_ns
595
596 # Update last event's time.
597 last_ns_from_origin = ns_from_origin
598
599 # Print top 5.
600 for comm, ns in exec_times.most_common(5):
601 print('{:20}{} s'.format(comm, ns / 1e9))
602
603 Run this example:
604
605 .. code-block:: text
606
607 $ python3 example.py /path/to/lttng/trace
608
609 Output example:
610
611 .. code-block:: text
612
613 swapper/0 326.294314471 s
614 chromium 2.500456202 s
615 Xorg.bin 0.546656895 s
616 threaded-ml 0.545098185 s
617 pulseaudio 0.53677713 s
618
619 Note that ``swapper/0`` is the "idle" process of CPU |~| 0 on Linux;
620 since we weren't using the CPU that much when tracing, its first
621 position in the list makes sense.
622
623 Inspect event classes
624 ~~~~~~~~~~~~~~~~~~~~~
625 Each event stream is a *stream class* instance.
626
627 A stream class contains *event classes*. A stream class's event classes
628 describe all the possible events you can find in its instances. Stream
629 classes and event classes form the *metadata* of streams and events.
630
631 The following example shows how to list all the event classes of a
632 stream class. For each event class, the example also prints the names of
633 its payload field class's first-level members.
634
635 .. note::
636
637 As of Babeltrace |~| |version|, there's no way to access a stream class
638 without consuming at least one message for one of its instances
639 (streams).
640
641 A source component can add new event classes to existing stream
642 classes during the trace processing task. Therefore, this example
643 only lists the initial stream class's event classes.
644
645 .. code-block:: python
646
647 import bt2
648 import sys
649
650 # Create a trace collection message iterator from the first command-line
651 # argument.
652 msg_it = bt2.TraceCollectionMessageIterator(sys.argv[1])
653
654 # Get the message iterator's first stream beginning message.
655 for msg in msg_it:
656 # `bt2._StreamBeginningMessageConst` is the Python type of a stream
657 # beginning message.
658 if type(msg) is bt2._StreamBeginningMessageConst:
659 break
660
661 # A stream beginning message holds a stream.
662 stream = msg.stream
663
664 # Get the stream's class.
665 stream_class = stream.cls
666
667 # The stream class object offers a mapping interface (like a read-only
668 # `dict`), where keys are event class IDs and values are
669 # `bt2._EventClassConst` objects.
670 for event_class in stream_class.values():
671 print('{}:'.format(event_class.name))
672
673 # The `payload_field_class` property of an event class returns a
674 # `bt2._StructureFieldClassConst` object. This object offers a
675 # mapping interface, where keys are member names and values are
676 # `bt2._StructureFieldClassMemberConst` objects.
677 for member in event_class.payload_field_class.values():
678 fmt = ' {}: `{}.{}`'
679 print(fmt.format(member.name, bt2.__name__,
680 member.field_class.__class__.__name__))
681
682 Run this example:
683
684 .. code-block:: text
685
686 $ python3 example.py /path/to/trace
687
688 Output example:
689
690 .. code-block:: text
691
692 sched_migrate_task:
693 comm: `bt2._StringFieldClassConst`
694 tid: `bt2._SignedIntegerFieldClassConst`
695 prio: `bt2._SignedIntegerFieldClassConst`
696 orig_cpu: `bt2._SignedIntegerFieldClassConst`
697 dest_cpu: `bt2._SignedIntegerFieldClassConst`
698 sched_switch:
699 prev_comm: `bt2._StringFieldClassConst`
700 prev_tid: `bt2._SignedIntegerFieldClassConst`
701 prev_prio: `bt2._SignedIntegerFieldClassConst`
702 prev_state: `bt2._SignedIntegerFieldClassConst`
703 next_comm: `bt2._StringFieldClassConst`
704 next_tid: `bt2._SignedIntegerFieldClassConst`
705 next_prio: `bt2._SignedIntegerFieldClassConst`
706 sched_wakeup_new:
707 comm: `bt2._StringFieldClassConst`
708 tid: `bt2._SignedIntegerFieldClassConst`
709 prio: `bt2._SignedIntegerFieldClassConst`
710 target_cpu: `bt2._SignedIntegerFieldClassConst`
711
712 .. _examples_graph:
713
714 Build and run a trace processing graph
715 --------------------------------------
716 Internally, a :class:`bt2.TraceCollectionMessageIterator` object (see
717 :ref:`examples_tcmi`) builds a *trace processing graph*, just like the
718 :bt2man:`babeltrace2-convert(1)` CLI command, and then offers a
719 Python iterator interface on top of it.
720
721 See the :bt2man:`babeltrace2-intro(7)` manual page to learn more about
722 the Babeltrace |~| 2 project and its core concepts.
723
724 The following examples shows how to manually build and then run a trace
725 processing graph yourself (like the :bt2man:`babeltrace2-run(1)` CLI
726 command does). The general steps to do so are:
727
728 #. Create an empty graph.
729
730 #. Add components to the graph.
731
732 This process is also known as *instantiating a component class*
733 because the graph must first create the component from its class
734 before adding it.
735
736 A viable graph contains at least one source component and one sink
737 component.
738
739 #. Connect component ports.
740
741 On initialization, components add input and output ports, depending
742 on their type.
743
744 You can connect component output ports to input ports within a graph.
745
746 #. Run the graph.
747
748 This is a blocking operation which makes each sink component consume
749 some messages in a round robin fashion until there are no more.
750
751 .. code-block:: python
752
753 import bt2
754 import sys
755
756 # Create an empty graph.
757 graph = bt2.Graph()
758
759 # Add a `source.text.dmesg` component.
760 #
761 # graph.add_component() returns the created and added component.
762 #
763 # Such a component reads Linux kernel ring buffer messages (see
764 # `dmesg(1)`) from the standard input and creates corresponding event
765 # messages. See `babeltrace2-source.text.dmesg(7)`.
766 #
767 # `my source` is the unique name of this component within `graph`.
768 comp_cls = bt2.find_plugin('text').source_component_classes['dmesg']
769 src_comp = graph.add_component(comp_cls, 'my source')
770
771 # Add a `sink.text.pretty` component.
772 #
773 # Such a component pretty-prints event messages on the standard output
774 # (one message per line). See `babeltrace2-sink.text.pretty(7)`.
775 #
776 # The `babeltrace2 convert` CLI command uses a `sink.text.pretty`
777 # sink component by default.
778 comp_cls = bt2.find_plugin('text').sink_component_classes['pretty']
779 sink_comp = graph.add_component(comp_cls, 'my sink')
780
781 # Connect the `out` output port of the `source.text.dmesg` component
782 # to the `in` input port of the `sink.text.pretty` component.
783 graph.connect_ports(src_comp.output_ports['out'],
784 sink_comp.input_ports['in'])
785
786 # Run the trace processing graph.
787 graph.run()
788
789 Run this example:
790
791 .. code-block:: text
792
793 $ dmesg -t | python3 example.py
794
795 Output example:
796
797 .. code-block:: text
798
799 string: { str = "ata1.00: NCQ Send/Recv Log not supported" }
800 string: { str = "ata1.00: ACPI cmd ef/02:00:00:00:00:a0 (SET FEATURES) succeeded" }
801 string: { str = "ata1.00: ACPI cmd f5/00:00:00:00:00:a0 (SECURITY FREEZE LOCK) filtered out" }
802 string: { str = "ata1.00: ACPI cmd ef/10:03:00:00:00:a0 (SET FEATURES) filtered out" }
803 string: { str = "ata1.00: NCQ Send/Recv Log not supported" }
804 string: { str = "ata1.00: configured for UDMA/133" }
805 string: { str = "ata1.00: Enabling discard_zeroes_data" }
806 string: { str = "OOM killer enabled." }
807 string: { str = "Restarting tasks ... done." }
808 string: { str = "PM: suspend exit" }
809
810 Query a component class
811 -----------------------
812 Component classes, provided by plugins, can implement a method to
813 support *query operations*.
814
815 A query operation is similar to a function call: the caller makes a
816 request (a query) with parameters and the component class's query
817 method returns a result object.
818
819 The query operation feature exists so that you can benefit from a
820 component class's implementation to get information about a trace, a
821 stream, a distant server, and so on. For example, the
822 ``source.ctf.lttng-live`` component class (see
823 :bt2man:`babeltrace2-source.ctf.lttng-live(7)`) offers the ``sessions``
824 object to list the available
825 `LTTng live <https://lttng.org/docs/#doc-lttng-live>`_ tracing
826 session names and other properties.
827
828 The semantics of the query parameters and the returned object are
829 completely defined by the component class implementation: the library
830 and its Python bindings don't enforce or suggest any layout.
831 The best way to know which objects you can query from a component class,
832 what are the expected and optional parameters, and what the returned
833 object contains is to read this component class's documentation.
834
835 The following example queries the "standard" ``babeltrace.support-info``
836 query object (see
837 :bt2man:`babeltrace2-query-babeltrace.support-info(7)`) from the
838 ``source.ctf.fs`` component class
839 (see :bt2man:`babeltrace2-source.ctf.fs(7)`) and
840 pretty-prints the result. The ``babeltrace.support-info`` query object
841 indicates whether or not a given path locates a
842 :abbr:`CTF (Common Trace Format)` trace directory::
843
844 import bt2
845 import sys
846
847 # Get the `source.ctf.fs` component class from the `ctf` plugin.
848 comp_cls = bt2.find_plugin('ctf').source_component_classes['fs']
849
850 # The `babeltrace.support-info` query operation expects a `type`
851 # parameter (set to `directory` here) and an `input` parameter (the
852 # actual path or string to check, in this case the first command-line
853 # argument).
854 #
855 # See `babeltrace2-query-babeltrace.support-info(7)`.
856 params = {
857 'type': 'directory',
858 'input': sys.argv[1],
859 }
860
861 # Create a query executor.
862 #
863 # This is the environment in which query operations happens. The
864 # queried component class has access to this executor, for example to
865 # retrieve the query operation's logging level.
866 query_exec = bt2.QueryExecutor(comp_cls, 'babeltrace.support-info',
867 params)
868
869 # Query the component class through the query executor.
870 #
871 # This method returns the result.
872 result = query_exec.query()
873
874 # Print the result.
875 print(result)
876
877 As you can see, no trace processing graph is involved (like in
878 :ref:`examples_tcmi` and :ref:`examples_graph`): a query operation
879 is *not* a sequential trace processing task, but a simple, atomic
880 procedure call.
881
882 Run this example:
883
884 .. code-block:: text
885
886 $ python3 example.py /path/to/ctf/trace
887
888 Output example:
889
890 .. code-block:: text
891
892 {'group': '21c63a42-40bc-4c08-9761-3815ae01f43d', 'weight': 0.75}
893
894 This result indicates that the component class is 75 |~| % confident that
895 :file:`/path/to/ctf/trace` is a CTF trace directory path. It also shows
896 that this specific CTF trace belongs to the
897 ``21c63a42-40bc-4c08-9761-3815ae01f43d`` group; a single component can
898 handle multiple traces which belong to the same group.
899
900 Let's try the sample example with a path that doesn't locate a CTF
901 trace:
902
903 .. code-block:: text
904
905 $ python3 example.py /etc
906
907 Output:
908
909 .. code-block:: text
910
911 {'weight': 0.0}
912
913 As expected, the zero weight indicates that ``/etc`` isn't a CTF trace
914 directory path.
This page took 0.048319 seconds and 4 git commands to generate.