Babeltrace 2 C API  2.0.4
Open-source trace manipulation framework
Simple sink component class

This example shows a basic sink component class packaged as a shared object plugin.

The name of the plugin is epitome and the name of the sink component class is output. Therefore the component class is identified in the babeltrace2 command-line tool as sink.epitome.output.

A sink.epitome.output component prints one text line to the standard output for each event message it consumes, for example:

1 #1: kmem_kmalloc (5 payload members)
2 #2: kmem_kfree (2 payload members)
3 #3: sched_waking (4 payload members)
4 #4: sched_migrate_task (5 payload members)
5 #5: sched_stat_runtime (4 payload members)
6 #6: sched_wakeup (4 payload members)
7 #7: rcu_utilization (1 payload member)
8 #8: rcu_utilization (1 payload member)
9 #9: sched_switch (7 payload members)
10 #10: syscall_entry_write (3 payload members)
11 ...

For each line, there is:

A sink.epitome.output component does not need any initialization parameter: it just prints to the standard output.

A sink.epitome.output component creates a single input port named in.

To simplify this example, a sink.epitome.output component doesn't check the return status codes of API functions, but you must check them in production code.

The sink component class implementation and the shared object plugin macros are in the same file, epitome.c:

#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <string.h>
#include <babeltrace2/babeltrace.h>
/* Sink component's private data */
struct epitome_out {
/* Upstream message iterator (owned by this) */
bt_message_iterator *message_iterator;
/* Current event message index */
uint64_t index;
};
/*
* Initializes the sink component.
*/
static
bt_self_component_sink *self_component_sink,
const bt_value *params, void *initialize_method_data)
{
/* Allocate a private data structure */
struct epitome_out *epitome_out = malloc(sizeof(*epitome_out));
/* Initialize the first event message's index */
epitome_out->index = 1;
/* Set the component's user data to our private data structure */
epitome_out);
/*
* Add an input port named `in` to the sink component.
*
* This is needed so that this sink component can be connected to a
* filter or a source component. With a connected upstream
* component, this sink component can create a message iterator
* to consume messages.
*/
"in", NULL, NULL);
}
/*
* Finalizes the sink component.
*/
static
void epitome_out_finalize(bt_self_component_sink *self_component_sink)
{
/* Retrieve our private data from the component's user data */
struct epitome_out *epitome_out = bt_self_component_get_data(
/* Free the allocated structure */
free(epitome_out);
}
/*
* Called when the trace processing graph containing the sink component
* is configured.
*
* This is where we can create our upstream message iterator.
*/
static
epitome_out_graph_is_configured(bt_self_component_sink *self_component_sink)
{
/* Retrieve our private data from the component's user data */
struct epitome_out *epitome_out = bt_self_component_get_data(
/* Borrow our unique port */
self_component_sink, 0);
/* Create the uptream message iterator */
in_port, &epitome_out->message_iterator);
}
/*
* Prints a line for `message`, if it's an event message, to the
* standard output.
*/
static
void print_message(struct epitome_out *epitome_out, const bt_message *message)
{
/* Discard if it's not an event message */
goto end;
}
/* Borrow the event message's event and its class */
const bt_event *event =
const bt_event_class *event_class = bt_event_borrow_class_const(event);
/* Get the number of payload field members */
const bt_field *payload_field =
bt_field_borrow_class_const(payload_field));
/* Write a corresponding line to the standard output */
printf("#%" PRIu64 ": %s (%" PRIu64 " payload member%s)\n",
epitome_out->index, bt_event_class_get_name(event_class),
member_count, member_count == 1 ? "" : "s");
/* Increment the current event message's index */
epitome_out->index++;
end:
return;
}
/*
* Consumes a batch of messages and writes the corresponding lines to
* the standard output.
*/
bt_self_component_sink *self_component_sink)
{
/* Retrieve our private data from the component's user data */
struct epitome_out *epitome_out = bt_self_component_get_data(
/* Consume a batch of messages from the upstream message iterator */
uint64_t message_count;
bt_message_iterator_next(epitome_out->message_iterator, &messages,
&message_count);
switch (next_status) {
/* End of iteration: put the message iterator's reference */
bt_message_iterator_put_ref(epitome_out->message_iterator);
goto end;
goto end;
goto end;
goto end;
default:
break;
}
/* For each consumed message */
for (uint64_t i = 0; i < message_count; i++) {
/* Current message */
const bt_message *message = messages[i];
/* Print line for current message if it's an event message */
print_message(epitome_out, message);
/* Put this message's reference */
}
end:
return status;
}
/* Mandatory */
/* Define the `epitome` plugin */
BT_PLUGIN(epitome);
/* Define the `output` sink component class */
BT_PLUGIN_SINK_COMPONENT_CLASS(output, epitome_out_consume);
/* Set some of the `output` sink component class's optional methods */
epitome_out_initialize);
BT_PLUGIN_SINK_COMPONENT_CLASS_FINALIZE_METHOD(output, epitome_out_finalize);
epitome_out_graph_is_configured);

As per the Compile and link a Babeltrace 2 shared object plugin guide, you can build the shared object plugin as such:

1 $ cc epitome.c -fPIC -c $(pkg-config --cflags babeltrace2)
2 $ ld epitome.o -o epitome.so -shared $(pkg-config --libs babeltrace2)

With the babeltrace2 tool, you can use a sink.epitome.output component, reading a CTF trace (see babeltrace2-source.ctf.fs(7)) for example:

1 $ babeltrace2 --plugin-path=. /path/to/ctf/trace --component=sink.epitome.output